dsp testing: improve api for tolerance checking
This commit is contained in:
parent
1b02f558f6
commit
43a760e57a
@ -315,9 +315,7 @@ pub fn magnitude_phase(signal: &mut [Complex<f32>]) {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::testing::{
|
use crate::testing::complex_allclose;
|
||||||
complex_array_is_close, complex_array_within_tolerance,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn array_push() {
|
fn array_push() {
|
||||||
@ -334,41 +332,62 @@ mod tests {
|
|||||||
fn magnitude_phase_length_1_quadrant_1() {
|
fn magnitude_phase_length_1_quadrant_1() {
|
||||||
let mut signal: [Complex<f32>; 1] = [(1., 1.)];
|
let mut signal: [Complex<f32>; 1] = [(1., 1.)];
|
||||||
magnitude_phase(&mut signal);
|
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.)];
|
signal = [(3_f32.sqrt() / 2., 1. / 2.)];
|
||||||
magnitude_phase(&mut signal);
|
magnitude_phase(&mut signal);
|
||||||
assert!(complex_array_is_close(&signal, &[(1., PI / 6.)]));
|
assert!(complex_allclose(
|
||||||
|
&signal,
|
||||||
|
&[(1., PI / 6.)],
|
||||||
|
f32::EPSILON,
|
||||||
|
0.
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn magnitude_phase_length_1_quadrant_2() {
|
fn magnitude_phase_length_1_quadrant_2() {
|
||||||
let mut signal = [(-1., 1.)];
|
let mut signal = [(-1., 1.)];
|
||||||
magnitude_phase(&mut signal);
|
magnitude_phase(&mut signal);
|
||||||
assert!(complex_array_is_close(
|
assert!(complex_allclose(
|
||||||
&signal,
|
&signal,
|
||||||
&[(2_f32.sqrt(), 3. * PI / 4.)]
|
&[(2_f32.sqrt(), 3. * PI / 4.)],
|
||||||
|
f32::EPSILON,
|
||||||
|
0.
|
||||||
));
|
));
|
||||||
|
|
||||||
signal = [(-1. / 2., 3_f32.sqrt() / 2.)];
|
signal = [(-1. / 2., 3_f32.sqrt() / 2.)];
|
||||||
magnitude_phase(&mut signal);
|
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]
|
#[test]
|
||||||
fn magnitude_phase_length_1_quadrant_3() {
|
fn magnitude_phase_length_1_quadrant_3() {
|
||||||
let mut signal = [(-1. / 2_f32.sqrt(), -1. / 2_f32.sqrt())];
|
let mut signal = [(-1. / 2_f32.sqrt(), -1. / 2_f32.sqrt())];
|
||||||
magnitude_phase(&mut signal);
|
magnitude_phase(&mut signal);
|
||||||
assert!(complex_array_is_close(
|
assert!(complex_allclose(
|
||||||
&signal,
|
&signal,
|
||||||
&[(1_f32.sqrt(), -3. * PI / 4.)]
|
&[(1_f32.sqrt(), -3. * PI / 4.)],
|
||||||
|
f32::EPSILON,
|
||||||
|
0.
|
||||||
));
|
));
|
||||||
|
|
||||||
signal = [(-1. / 2., -2_f32.sqrt())];
|
signal = [(-1. / 2., -2_f32.sqrt())];
|
||||||
magnitude_phase(&mut signal);
|
magnitude_phase(&mut signal);
|
||||||
assert!(complex_array_is_close(
|
assert!(complex_allclose(
|
||||||
&signal,
|
&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() {
|
fn magnitude_phase_length_1_quadrant_4() {
|
||||||
let mut signal = [(1. / 2_f32.sqrt(), -1. / 2_f32.sqrt())];
|
let mut signal = [(1. / 2_f32.sqrt(), -1. / 2_f32.sqrt())];
|
||||||
magnitude_phase(&mut signal);
|
magnitude_phase(&mut signal);
|
||||||
assert!(complex_array_is_close(
|
assert!(complex_allclose(
|
||||||
&signal,
|
&signal,
|
||||||
&[(1_f32.sqrt(), -1. * PI / 4.)]
|
&[(1_f32.sqrt(), -1. * PI / 4.)],
|
||||||
|
f32::EPSILON,
|
||||||
|
0.
|
||||||
));
|
));
|
||||||
|
|
||||||
signal = [(3_f32.sqrt() / 2., -1. / 2.)];
|
signal = [(3_f32.sqrt() / 2., -1. / 2.)];
|
||||||
magnitude_phase(&mut signal);
|
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]
|
#[test]
|
||||||
@ -483,7 +509,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
let result = lockin.demodulate(&adc_samples, timestamps).unwrap();
|
let result = lockin.demodulate(&adc_samples, timestamps).unwrap();
|
||||||
assert!(
|
assert!(
|
||||||
complex_array_within_tolerance(&result, &signal, 0., 1e-5),
|
complex_allclose(&result, &signal, 0., 1e-5),
|
||||||
"\nsignal computed: {:?},\nsignal expected: {:?}",
|
"\nsignal computed: {:?},\nsignal expected: {:?}",
|
||||||
result,
|
result,
|
||||||
signal
|
signal
|
||||||
|
@ -1,54 +1,27 @@
|
|||||||
use super::Complex;
|
use super::Complex;
|
||||||
|
|
||||||
pub fn f32_is_close(a: f32, b: f32) -> bool {
|
pub fn isclose(a: f32, b: f32, rtol: f32, atol: f32) -> bool {
|
||||||
(a - b).abs() <= a.abs().max(b.abs()) * f32::EPSILON
|
(a - b).abs() <= a.abs().max(b.abs()) * rtol + atol
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn complex_is_close(a: Complex<f32>, b: Complex<f32>) -> bool {
|
pub fn complex_isclose(
|
||||||
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(
|
|
||||||
a: Complex<f32>,
|
a: Complex<f32>,
|
||||||
b: Complex<f32>,
|
b: Complex<f32>,
|
||||||
relative_tolerance: f32,
|
rtol: f32,
|
||||||
fixed_tolerance: f32,
|
atol: f32,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
within_tolerance(a.0, b.0, relative_tolerance, fixed_tolerance)
|
isclose(a.0, b.0, rtol, atol) && isclose(a.1, b.1, rtol, atol)
|
||||||
&& within_tolerance(a.1, b.1, relative_tolerance, fixed_tolerance)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn complex_array_within_tolerance(
|
pub fn complex_allclose(
|
||||||
a: &[Complex<f32>],
|
a: &[Complex<f32>],
|
||||||
b: &[Complex<f32>],
|
b: &[Complex<f32>],
|
||||||
relative_tolerance: f32,
|
rtol: f32,
|
||||||
fixed_tolerance: f32,
|
atol: f32,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let mut result: bool = true;
|
let mut result: bool = true;
|
||||||
a.iter().zip(b.iter()).for_each(|(i, j)| {
|
a.iter().zip(b.iter()).for_each(|(i, j)| {
|
||||||
result &= complex_within_tolerance(
|
result &= complex_isclose(*i, *j, rtol, atol);
|
||||||
*i,
|
|
||||||
*j,
|
|
||||||
relative_tolerance,
|
|
||||||
fixed_tolerance,
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user