From 43a760e57a6b65d615de51513a4d9c92a50b8638 Mon Sep 17 00:00:00 2001 From: Matt Huszagh Date: Fri, 4 Dec 2020 09:09:23 -0800 Subject: [PATCH] dsp testing: improve api for tolerance checking --- dsp/src/lockin.rs | 58 +++++++++++++++++++++++++++++++++------------- dsp/src/testing.rs | 47 ++++++++----------------------------- 2 files changed, 52 insertions(+), 53 deletions(-) diff --git a/dsp/src/lockin.rs b/dsp/src/lockin.rs index d4e635d..bb649ad 100644 --- a/dsp/src/lockin.rs +++ b/dsp/src/lockin.rs @@ -315,9 +315,7 @@ pub fn magnitude_phase(signal: &mut [Complex]) { #[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; 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 diff --git a/dsp/src/testing.rs b/dsp/src/testing.rs index 0fe9e4f..1a8e109 100644 --- a/dsp/src/testing.rs +++ b/dsp/src/testing.rs @@ -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, b: Complex) -> bool { - f32_is_close(a.0, b.0) && f32_is_close(a.1, b.1) -} - -pub fn complex_array_is_close(a: &[Complex], b: &[Complex]) -> 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, b: Complex, - 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], b: &[Complex], - 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 }