From b69131f5f54c623e0c537bc9cd465ce8e9b5bb94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Wed, 17 Feb 2021 16:13:30 +0100 Subject: [PATCH 1/3] impl trait on type alias instead of newtypes --- dsp/src/iir.rs | 21 ++++++++++----------- dsp/src/iir_int.rs | 27 +++++++++++++++------------ src/bin/dual-iir.rs | 18 +++++++++--------- 3 files changed, 34 insertions(+), 32 deletions(-) diff --git a/dsp/src/iir.rs b/dsp/src/iir.rs index 4206c2b..31c9db1 100644 --- a/dsp/src/iir.rs +++ b/dsp/src/iir.rs @@ -11,8 +11,7 @@ use core::f32; /// To represent the IIR coefficients, this contains the feed-forward /// coefficients (b0, b1, b2) followd by the negated feed-back coefficients /// (-a1, -a2), all five normalized such that a0 = 1. -#[derive(Copy, Clone, Default, Deserialize, Serialize)] -pub struct Vec5(pub [f32; 5]); +pub type Vec5 = [f32; 5]; /// IIR configuration. /// @@ -50,7 +49,7 @@ pub struct IIR { impl IIR { pub const fn new(gain: f32, y_min: f32, y_max: f32) -> Self { Self { - ba: Vec5([gain, 0., 0., 0., 0.]), + ba: [gain, 0., 0., 0., 0.], y_offset: 0., y_min, y_max, @@ -84,13 +83,13 @@ impl IIR { } (a1, b0, b1) }; - self.ba.0.copy_from_slice(&[b0, b1, 0., a1, 0.]); + self.ba.copy_from_slice(&[b0, b1, 0., a1, 0.]); Ok(()) } /// Compute the overall (DC feed-forward) gain. pub fn get_k(&self) -> f32 { - self.ba.0[..3].iter().sum() + self.ba[..3].iter().sum() } /// Compute input-referred (`x`) offset from output (`y`) offset. @@ -118,21 +117,21 @@ impl IIR { /// * `xy` - Current filter state. /// * `x0` - New input. pub fn update(&self, xy: &mut Vec5, x0: f32) -> f32 { - let n = self.ba.0.len(); - debug_assert!(xy.0.len() == n); + let n = self.ba.len(); + debug_assert!(xy.len() == n); // `xy` contains x0 x1 y0 y1 y2 // Increment time x1 x2 y1 y2 y3 // Shift x1 x1 x2 y1 y2 // This unrolls better than xy.rotate_right(1) - xy.0.copy_within(0..n - 1, 1); + xy.copy_within(0..n - 1, 1); // Store x0 x0 x1 x2 y1 y2 - xy.0[0] = x0; + xy[0] = x0; // Compute y0 by multiply-accumulate - let y0 = macc(self.y_offset, &xy.0, &self.ba.0); + let y0 = macc(self.y_offset, xy, &self.ba); // Limit y0 let y0 = max(self.y_min, min(self.y_max, y0)); // Store y0 x0 x1 y0 y1 y2 - xy.0[n / 2] = y0; + xy[n / 2] = y0; y0 } } diff --git a/dsp/src/iir_int.rs b/dsp/src/iir_int.rs index f0ce157..e3ec5b8 100644 --- a/dsp/src/iir_int.rs +++ b/dsp/src/iir_int.rs @@ -4,10 +4,9 @@ use serde::{Deserialize, Serialize}; /// Generic vector for integer IIR filter. /// This struct is used to hold the x/y input/output data vector or the b/a coefficient /// vector. -#[derive(Copy, Clone, Default, Deserialize, Serialize)] -pub struct Vec5(pub [i32; 5]); +pub type Vec5 = [i32; 5]; -impl Vec5 { +trait Coeff { /// Lowpass biquad filter using cutoff and sampling frequencies. Taken from: /// https://webaudio.github.io/Audio-EQ-Cookbook/audio-eq-cookbook.html /// @@ -19,7 +18,11 @@ impl Vec5 { /// /// # Returns /// 2nd-order IIR filter coefficients in the form [b0,b1,b2,a1,a2]. a0 is set to -1. - pub fn lowpass(f: f64, q: f64, k: f64) -> Self { + fn lowpass(f: f64, q: f64, k: f64) -> Self; +} + +impl Coeff for Vec5 { + fn lowpass(f: f64, q: f64, k: f64) -> Self { // 3rd order Taylor approximation of sin and cos. let f = f * 2. * PI; let f2 = f * f * 0.5; @@ -32,7 +35,7 @@ impl Vec5 { let a1 = (2. * fcos / a0 + 0.5) as _; let a2 = ((alpha - 1.) / a0 + 0.5) as _; - Self([b0, 2 * b0, b0, a1, a2]) + [b0, 2 * b0, b0, a1, a2] } } @@ -72,21 +75,21 @@ impl IIR { /// * `xy` - Current filter state. /// * `x0` - New input. pub fn update(&self, xy: &mut Vec5, x0: i32) -> i32 { - let n = self.ba.0.len(); - debug_assert!(xy.0.len() == n); + let n = self.ba.len(); + debug_assert!(xy.len() == n); // `xy` contains x0 x1 y0 y1 y2 // Increment time x1 x2 y1 y2 y3 // Shift x1 x1 x2 y1 y2 // This unrolls better than xy.rotate_right(1) - xy.0.copy_within(0..n - 1, 1); + xy.copy_within(0..n - 1, 1); // Store x0 x0 x1 x2 y1 y2 - xy.0[0] = x0; + xy[0] = x0; // Compute y0 by multiply-accumulate - let y0 = macc(0, &xy.0, &self.ba.0, IIR::SHIFT); + let y0 = macc(0, xy, &self.ba, IIR::SHIFT); // Limit y0 // let y0 = y0.max(self.y_min).min(self.y_max); // Store y0 x0 x1 y0 y1 y2 - xy.0[n / 2] = y0; + xy[n / 2] = y0; y0 } } @@ -98,6 +101,6 @@ mod test { #[test] fn lowpass_gen() { let ba = Vec5::lowpass(1e-5, 1. / 2f64.sqrt(), 2.); - println!("{:?}", ba.0); + println!("{:?}", ba); } } diff --git a/src/bin/dual-iir.rs b/src/bin/dual-iir.rs index b90452d..d037bfb 100644 --- a/src/bin/dual-iir.rs +++ b/src/bin/dual-iir.rs @@ -33,7 +33,7 @@ const APP: () = { net_interface: hardware::Ethernet, // Format: iir_state[ch][cascade-no][coeff] - #[init([[iir::Vec5([0.; 5]); IIR_CASCADE_LENGTH]; 2])] + #[init([[[0.; 5]; IIR_CASCADE_LENGTH]; 2])] iir_state: [[iir::Vec5; IIR_CASCADE_LENGTH]; 2], #[init([[iir::IIR::new(1., -SCALE, SCALE); IIR_CASCADE_LENGTH]; 2])] iir_ch: [[iir::IIR; IIR_CASCADE_LENGTH]; 2], @@ -158,10 +158,10 @@ const APP: () = { let state = c.resources.iir_state.lock(|iir_state| server::Status { t: time, - x0: iir_state[0][0].0[0], - y0: iir_state[0][0].0[2], - x1: iir_state[1][0].0[0], - y1: iir_state[1][0].0[2], + x0: iir_state[0][0][0], + y0: iir_state[0][0][2], + x1: iir_state[1][0][0], + y1: iir_state[1][0][2], }); Ok::(state) @@ -170,10 +170,10 @@ const APP: () = { "stabilizer/iir_b/state": (|| { let state = c.resources.iir_state.lock(|iir_state| server::Status { t: time, - x0: iir_state[0][IIR_CASCADE_LENGTH-1].0[0], - y0: iir_state[0][IIR_CASCADE_LENGTH-1].0[2], - x1: iir_state[1][IIR_CASCADE_LENGTH-1].0[0], - y1: iir_state[1][IIR_CASCADE_LENGTH-1].0[2], + x0: iir_state[0][IIR_CASCADE_LENGTH-1][0], + y0: iir_state[0][IIR_CASCADE_LENGTH-1][2], + x1: iir_state[1][IIR_CASCADE_LENGTH-1][0], + y1: iir_state[1][IIR_CASCADE_LENGTH-1][2], }); Ok::(state) From 07714fbca409faa7f0c3dccbf0271aaf56762310 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Wed, 17 Feb 2021 16:24:45 +0100 Subject: [PATCH 2/3] test: trait in scope --- dsp/src/iir_int.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dsp/src/iir_int.rs b/dsp/src/iir_int.rs index e3ec5b8..25c5b2f 100644 --- a/dsp/src/iir_int.rs +++ b/dsp/src/iir_int.rs @@ -96,7 +96,7 @@ impl IIR { #[cfg(test)] mod test { - use super::Vec5; + use super::{Vec5, Coeff}; #[test] fn lowpass_gen() { From b1d45d831c09bcf7838ac949f3152e6dacd68443 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Wed, 17 Feb 2021 16:25:21 +0100 Subject: [PATCH 3/3] fmt --- dsp/src/iir_int.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dsp/src/iir_int.rs b/dsp/src/iir_int.rs index 25c5b2f..4af50f1 100644 --- a/dsp/src/iir_int.rs +++ b/dsp/src/iir_int.rs @@ -96,7 +96,7 @@ impl IIR { #[cfg(test)] mod test { - use super::{Vec5, Coeff}; + use super::{Coeff, Vec5}; #[test] fn lowpass_gen() {