dsp testing: improve api for tolerance checking

master
Matt Huszagh 2020-12-04 09:09:23 -08:00
parent 1b02f558f6
commit 43a760e57a
2 changed files with 52 additions and 53 deletions

View File

@ -315,9 +315,7 @@ pub fn magnitude_phase(signal: &mut [Complex<f32>]) {
#[cfg(test)]
mod tests {
use super::*;
use crate::testing::{
complex_array_is_close, complex_array_within_tolerance,
};
use crate::testing::complex_allclose;
#[test]
fn array_push() {
@ -334,41 +332,62 @@ mod tests {
fn magnitude_phase_length_1_quadrant_1() {
let mut signal: [Complex<f32>; 1] = [(1., 1.)];
magnitude_phase(&mut signal);
assert!(complex_array_is_close(&signal, &[(2_f32.sqrt(), PI / 4.)]));
assert!(complex_allclose(
&signal,
&[(2_f32.sqrt(), PI / 4.)],
f32::EPSILON,
0.
));
signal = [(3_f32.sqrt() / 2., 1. / 2.)];
magnitude_phase(&mut signal);
assert!(complex_array_is_close(&signal, &[(1., PI / 6.)]));
assert!(complex_allclose(
&signal,
&[(1., PI / 6.)],
f32::EPSILON,
0.
));
}
#[test]
fn magnitude_phase_length_1_quadrant_2() {
let mut signal = [(-1., 1.)];
magnitude_phase(&mut signal);
assert!(complex_array_is_close(
assert!(complex_allclose(
&signal,
&[(2_f32.sqrt(), 3. * PI / 4.)]
&[(2_f32.sqrt(), 3. * PI / 4.)],
f32::EPSILON,
0.
));
signal = [(-1. / 2., 3_f32.sqrt() / 2.)];
magnitude_phase(&mut signal);
assert!(complex_array_is_close(&signal, &[(1_f32, 2. * PI / 3.)]));
assert!(complex_allclose(
&signal,
&[(1_f32, 2. * PI / 3.)],
f32::EPSILON,
0.
));
}
#[test]
fn magnitude_phase_length_1_quadrant_3() {
let mut signal = [(-1. / 2_f32.sqrt(), -1. / 2_f32.sqrt())];
magnitude_phase(&mut signal);
assert!(complex_array_is_close(
assert!(complex_allclose(
&signal,
&[(1_f32.sqrt(), -3. * PI / 4.)]
&[(1_f32.sqrt(), -3. * PI / 4.)],
f32::EPSILON,
0.
));
signal = [(-1. / 2., -2_f32.sqrt())];
magnitude_phase(&mut signal);
assert!(complex_array_is_close(
assert!(complex_allclose(
&signal,
&[((3. / 2.) as f32, -1.91063323625 as f32)]
&[((3. / 2.) as f32, -1.91063323625 as f32)],
f32::EPSILON,
0.
));
}
@ -376,14 +395,21 @@ mod tests {
fn magnitude_phase_length_1_quadrant_4() {
let mut signal = [(1. / 2_f32.sqrt(), -1. / 2_f32.sqrt())];
magnitude_phase(&mut signal);
assert!(complex_array_is_close(
assert!(complex_allclose(
&signal,
&[(1_f32.sqrt(), -1. * PI / 4.)]
&[(1_f32.sqrt(), -1. * PI / 4.)],
f32::EPSILON,
0.
));
signal = [(3_f32.sqrt() / 2., -1. / 2.)];
magnitude_phase(&mut signal);
assert!(complex_array_is_close(&signal, &[(1_f32, -PI / 6.)]));
assert!(complex_allclose(
&signal,
&[(1_f32, -PI / 6.)],
f32::EPSILON,
0.
));
}
#[test]
@ -483,7 +509,7 @@ mod tests {
}
let result = lockin.demodulate(&adc_samples, timestamps).unwrap();
assert!(
complex_array_within_tolerance(&result, &signal, 0., 1e-5),
complex_allclose(&result, &signal, 0., 1e-5),
"\nsignal computed: {:?},\nsignal expected: {:?}",
result,
signal

View File

@ -1,54 +1,27 @@
use super::Complex;
pub fn f32_is_close(a: f32, b: f32) -> bool {
(a - b).abs() <= a.abs().max(b.abs()) * f32::EPSILON
pub fn isclose(a: f32, b: f32, rtol: f32, atol: f32) -> bool {
(a - b).abs() <= a.abs().max(b.abs()) * rtol + atol
}
pub fn complex_is_close(a: Complex<f32>, b: Complex<f32>) -> bool {
f32_is_close(a.0, b.0) && f32_is_close(a.1, b.1)
}
pub fn complex_array_is_close(a: &[Complex<f32>], b: &[Complex<f32>]) -> bool {
let mut result: bool = true;
a.iter().zip(b.iter()).for_each(|(i, j)| {
result &= complex_is_close(*i, *j);
});
result
}
pub fn within_tolerance(
a: f32,
b: f32,
relative_tolerance: f32,
fixed_tolerance: f32,
) -> bool {
(a - b).abs() <= a.abs().max(b.abs()) * relative_tolerance + fixed_tolerance
}
pub fn complex_within_tolerance(
pub fn complex_isclose(
a: Complex<f32>,
b: Complex<f32>,
relative_tolerance: f32,
fixed_tolerance: f32,
rtol: f32,
atol: f32,
) -> bool {
within_tolerance(a.0, b.0, relative_tolerance, fixed_tolerance)
&& within_tolerance(a.1, b.1, relative_tolerance, fixed_tolerance)
isclose(a.0, b.0, rtol, atol) && isclose(a.1, b.1, rtol, atol)
}
pub fn complex_array_within_tolerance(
pub fn complex_allclose(
a: &[Complex<f32>],
b: &[Complex<f32>],
relative_tolerance: f32,
fixed_tolerance: f32,
rtol: f32,
atol: f32,
) -> bool {
let mut result: bool = true;
a.iter().zip(b.iter()).for_each(|(i, j)| {
result &= complex_within_tolerance(
*i,
*j,
relative_tolerance,
fixed_tolerance,
);
result &= complex_isclose(*i, *j, rtol, atol);
});
result
}