Skip to content

Commit d066bee

Browse files
committed
Refactor: yin returns a Result with possible Err value instead of YinResult. This is necessary to communicate clearly that yin can fail if no argmin for CMNDF is found, for which get_frequency would return inf because the best lag would be 0. Added a test for this case.
1 parent 82159fe commit d066bee

File tree

1 file changed

+60
-15
lines changed

1 file changed

+60
-15
lines changed

src/signal_analysis/yin.rs

Lines changed: 60 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -57,14 +57,20 @@ impl Yin {
5757
}
5858
}
5959

60-
pub fn yin(&self, frequencies: &[f64]) -> YinResult {
60+
pub fn yin(&self, frequencies: &[f64]) -> Result<YinResult, String> {
6161
let df = difference_function_values(frequencies, self.max_lag);
6262
let cmndf = cumulative_mean_normalized_difference_function(&df, self.max_lag);
6363
let best_lag = find_cmndf_argmin(&cmndf, self.min_lag, self.max_lag, self.threshold);
64-
YinResult {
65-
sample_rate: self.sample_rate,
66-
best_lag,
67-
cmndf,
64+
match best_lag {
65+
_ if best_lag == 0 => Err(format!(
66+
"Could not find lag value which minimizes CMNDF below the given threshold {}",
67+
self.threshold
68+
)),
69+
_ => Ok(YinResult {
70+
sample_rate: self.sample_rate,
71+
best_lag,
72+
cmndf,
73+
}),
6874
}
6975
}
7076
}
@@ -162,20 +168,23 @@ mod tests {
162168
max_expected_frequency,
163169
sample_rate,
164170
);
171+
165172
let result = yin.yin(signal.as_slice());
173+
assert!(result.is_ok());
174+
let yin_result = result.unwrap();
166175

167176
assert!(diff_from_actual_frequency_smaller_than_threshold(
168-
result.get_frequency(),
177+
yin_result.get_frequency(),
169178
frequency,
170179
1.0
171180
));
172181
assert!(diff_from_actual_frequency_smaller_than_threshold(
173-
result.get_frequency_with_interpolation(),
182+
yin_result.get_frequency_with_interpolation(),
174183
frequency,
175184
1.0,
176185
));
177186

178-
assert!(interpolation_better_than_raw_result(result, frequency));
187+
assert!(interpolation_better_than_raw_result(yin_result, frequency));
179188
}
180189

181190
#[test]
@@ -196,22 +205,24 @@ mod tests {
196205
sample_rate,
197206
);
198207
let result = yin.yin(signal.as_slice());
208+
assert!(result.is_ok());
209+
let yin_result = result.unwrap();
199210

200211
if (sample_rate as i32 % freq) == 0 {
201-
assert_eq!(result.get_frequency(), frequency);
212+
assert_eq!(yin_result.get_frequency(), frequency);
202213
} else {
203214
assert!(diff_from_actual_frequency_smaller_than_threshold(
204-
result.get_frequency(),
215+
yin_result.get_frequency(),
205216
frequency,
206217
1.0
207218
));
208219
assert!(diff_from_actual_frequency_smaller_than_threshold(
209-
result.get_frequency_with_interpolation(),
220+
yin_result.get_frequency_with_interpolation(),
210221
frequency,
211222
1.0,
212223
));
213224

214-
assert!(interpolation_better_than_raw_result(result, frequency));
225+
assert!(interpolation_better_than_raw_result(yin_result, frequency));
215226
}
216227
}
217228
}
@@ -243,9 +254,11 @@ mod tests {
243254
.collect();
244255

245256
let result = yin.yin(&combined_signal);
257+
assert!(result.is_ok());
258+
let yin_result = result.unwrap();
246259

247260
assert!(diff_from_actual_frequency_smaller_than_threshold(
248-
result.get_frequency(),
261+
yin_result.get_frequency(),
249262
frequency_1,
250263
1.0
251264
));
@@ -278,16 +291,48 @@ mod tests {
278291
.collect();
279292

280293
let result = yin.yin(&combined_signal);
294+
assert!(result.is_ok());
295+
let yin_result = result.unwrap();
281296

282297
let expected_frequency = (frequency_1 - frequency_2).abs();
283298
assert!(diff_from_actual_frequency_smaller_than_threshold(
284-
result.get_frequency(),
299+
yin_result.get_frequency(),
285300
expected_frequency,
286301
1.0
287302
));
288303
assert!(interpolation_better_than_raw_result(
289-
result,
304+
yin_result,
290305
expected_frequency
291306
));
292307
}
308+
309+
#[test]
310+
fn test_err() {
311+
let sample_rate = 2500.0;
312+
let seconds = 2.0;
313+
let frequency = 440.0;
314+
315+
// Can't find frequency 440 between 500 and 700
316+
let min_expected_frequency = 500.0;
317+
let max_expected_frequency = 700.0;
318+
let yin = Yin::init(
319+
0.1,
320+
min_expected_frequency,
321+
max_expected_frequency,
322+
sample_rate,
323+
);
324+
325+
let signal = generate_sine_wave(frequency, sample_rate, seconds);
326+
let result = yin.yin(&signal);
327+
assert!(result.is_err());
328+
329+
let yin_with_suitable_frequency_range = Yin::init(
330+
0.1,
331+
min_expected_frequency - 100.0,
332+
max_expected_frequency,
333+
sample_rate,
334+
);
335+
let result = yin_with_suitable_frequency_range.yin(&signal);
336+
assert!(result.is_ok());
337+
}
293338
}

0 commit comments

Comments
 (0)