impl trait on type alias instead of newtypes
This commit is contained in:
parent
b7e4f402aa
commit
b69131f5f5
@ -11,8 +11,7 @@ use core::f32;
|
|||||||
/// To represent the IIR coefficients, this contains the feed-forward
|
/// To represent the IIR coefficients, this contains the feed-forward
|
||||||
/// coefficients (b0, b1, b2) followd by the negated feed-back coefficients
|
/// coefficients (b0, b1, b2) followd by the negated feed-back coefficients
|
||||||
/// (-a1, -a2), all five normalized such that a0 = 1.
|
/// (-a1, -a2), all five normalized such that a0 = 1.
|
||||||
#[derive(Copy, Clone, Default, Deserialize, Serialize)]
|
pub type Vec5 = [f32; 5];
|
||||||
pub struct Vec5(pub [f32; 5]);
|
|
||||||
|
|
||||||
/// IIR configuration.
|
/// IIR configuration.
|
||||||
///
|
///
|
||||||
@ -50,7 +49,7 @@ pub struct IIR {
|
|||||||
impl IIR {
|
impl IIR {
|
||||||
pub const fn new(gain: f32, y_min: f32, y_max: f32) -> Self {
|
pub const fn new(gain: f32, y_min: f32, y_max: f32) -> Self {
|
||||||
Self {
|
Self {
|
||||||
ba: Vec5([gain, 0., 0., 0., 0.]),
|
ba: [gain, 0., 0., 0., 0.],
|
||||||
y_offset: 0.,
|
y_offset: 0.,
|
||||||
y_min,
|
y_min,
|
||||||
y_max,
|
y_max,
|
||||||
@ -84,13 +83,13 @@ impl IIR {
|
|||||||
}
|
}
|
||||||
(a1, b0, b1)
|
(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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compute the overall (DC feed-forward) gain.
|
/// Compute the overall (DC feed-forward) gain.
|
||||||
pub fn get_k(&self) -> f32 {
|
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.
|
/// Compute input-referred (`x`) offset from output (`y`) offset.
|
||||||
@ -118,21 +117,21 @@ impl IIR {
|
|||||||
/// * `xy` - Current filter state.
|
/// * `xy` - Current filter state.
|
||||||
/// * `x0` - New input.
|
/// * `x0` - New input.
|
||||||
pub fn update(&self, xy: &mut Vec5, x0: f32) -> f32 {
|
pub fn update(&self, xy: &mut Vec5, x0: f32) -> f32 {
|
||||||
let n = self.ba.0.len();
|
let n = self.ba.len();
|
||||||
debug_assert!(xy.0.len() == n);
|
debug_assert!(xy.len() == n);
|
||||||
// `xy` contains x0 x1 y0 y1 y2
|
// `xy` contains x0 x1 y0 y1 y2
|
||||||
// Increment time x1 x2 y1 y2 y3
|
// Increment time x1 x2 y1 y2 y3
|
||||||
// Shift x1 x1 x2 y1 y2
|
// Shift x1 x1 x2 y1 y2
|
||||||
// This unrolls better than xy.rotate_right(1)
|
// 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
|
// Store x0 x0 x1 x2 y1 y2
|
||||||
xy.0[0] = x0;
|
xy[0] = x0;
|
||||||
// Compute y0 by multiply-accumulate
|
// 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
|
// Limit y0
|
||||||
let y0 = max(self.y_min, min(self.y_max, y0));
|
let y0 = max(self.y_min, min(self.y_max, y0));
|
||||||
// Store y0 x0 x1 y0 y1 y2
|
// Store y0 x0 x1 y0 y1 y2
|
||||||
xy.0[n / 2] = y0;
|
xy[n / 2] = y0;
|
||||||
y0
|
y0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,10 +4,9 @@ use serde::{Deserialize, Serialize};
|
|||||||
/// Generic vector for integer IIR filter.
|
/// Generic vector for integer IIR filter.
|
||||||
/// This struct is used to hold the x/y input/output data vector or the b/a coefficient
|
/// This struct is used to hold the x/y input/output data vector or the b/a coefficient
|
||||||
/// vector.
|
/// vector.
|
||||||
#[derive(Copy, Clone, Default, Deserialize, Serialize)]
|
pub type Vec5 = [i32; 5];
|
||||||
pub struct Vec5(pub [i32; 5]);
|
|
||||||
|
|
||||||
impl Vec5 {
|
trait Coeff {
|
||||||
/// Lowpass biquad filter using cutoff and sampling frequencies. Taken from:
|
/// Lowpass biquad filter using cutoff and sampling frequencies. Taken from:
|
||||||
/// https://webaudio.github.io/Audio-EQ-Cookbook/audio-eq-cookbook.html
|
/// https://webaudio.github.io/Audio-EQ-Cookbook/audio-eq-cookbook.html
|
||||||
///
|
///
|
||||||
@ -19,7 +18,11 @@ impl Vec5 {
|
|||||||
///
|
///
|
||||||
/// # Returns
|
/// # Returns
|
||||||
/// 2nd-order IIR filter coefficients in the form [b0,b1,b2,a1,a2]. a0 is set to -1.
|
/// 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.
|
// 3rd order Taylor approximation of sin and cos.
|
||||||
let f = f * 2. * PI;
|
let f = f * 2. * PI;
|
||||||
let f2 = f * f * 0.5;
|
let f2 = f * f * 0.5;
|
||||||
@ -32,7 +35,7 @@ impl Vec5 {
|
|||||||
let a1 = (2. * fcos / a0 + 0.5) as _;
|
let a1 = (2. * fcos / a0 + 0.5) as _;
|
||||||
let a2 = ((alpha - 1.) / 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.
|
/// * `xy` - Current filter state.
|
||||||
/// * `x0` - New input.
|
/// * `x0` - New input.
|
||||||
pub fn update(&self, xy: &mut Vec5, x0: i32) -> i32 {
|
pub fn update(&self, xy: &mut Vec5, x0: i32) -> i32 {
|
||||||
let n = self.ba.0.len();
|
let n = self.ba.len();
|
||||||
debug_assert!(xy.0.len() == n);
|
debug_assert!(xy.len() == n);
|
||||||
// `xy` contains x0 x1 y0 y1 y2
|
// `xy` contains x0 x1 y0 y1 y2
|
||||||
// Increment time x1 x2 y1 y2 y3
|
// Increment time x1 x2 y1 y2 y3
|
||||||
// Shift x1 x1 x2 y1 y2
|
// Shift x1 x1 x2 y1 y2
|
||||||
// This unrolls better than xy.rotate_right(1)
|
// 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
|
// Store x0 x0 x1 x2 y1 y2
|
||||||
xy.0[0] = x0;
|
xy[0] = x0;
|
||||||
// Compute y0 by multiply-accumulate
|
// 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
|
// Limit y0
|
||||||
// let y0 = y0.max(self.y_min).min(self.y_max);
|
// let y0 = y0.max(self.y_min).min(self.y_max);
|
||||||
// Store y0 x0 x1 y0 y1 y2
|
// Store y0 x0 x1 y0 y1 y2
|
||||||
xy.0[n / 2] = y0;
|
xy[n / 2] = y0;
|
||||||
y0
|
y0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -98,6 +101,6 @@ mod test {
|
|||||||
#[test]
|
#[test]
|
||||||
fn lowpass_gen() {
|
fn lowpass_gen() {
|
||||||
let ba = Vec5::lowpass(1e-5, 1. / 2f64.sqrt(), 2.);
|
let ba = Vec5::lowpass(1e-5, 1. / 2f64.sqrt(), 2.);
|
||||||
println!("{:?}", ba.0);
|
println!("{:?}", ba);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ const APP: () = {
|
|||||||
net_interface: hardware::Ethernet,
|
net_interface: hardware::Ethernet,
|
||||||
|
|
||||||
// Format: iir_state[ch][cascade-no][coeff]
|
// 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],
|
iir_state: [[iir::Vec5; IIR_CASCADE_LENGTH]; 2],
|
||||||
#[init([[iir::IIR::new(1., -SCALE, SCALE); IIR_CASCADE_LENGTH]; 2])]
|
#[init([[iir::IIR::new(1., -SCALE, SCALE); IIR_CASCADE_LENGTH]; 2])]
|
||||||
iir_ch: [[iir::IIR; 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|
|
let state = c.resources.iir_state.lock(|iir_state|
|
||||||
server::Status {
|
server::Status {
|
||||||
t: time,
|
t: time,
|
||||||
x0: iir_state[0][0].0[0],
|
x0: iir_state[0][0][0],
|
||||||
y0: iir_state[0][0].0[2],
|
y0: iir_state[0][0][2],
|
||||||
x1: iir_state[1][0].0[0],
|
x1: iir_state[1][0][0],
|
||||||
y1: iir_state[1][0].0[2],
|
y1: iir_state[1][0][2],
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok::<server::Status, ()>(state)
|
Ok::<server::Status, ()>(state)
|
||||||
@ -170,10 +170,10 @@ const APP: () = {
|
|||||||
"stabilizer/iir_b/state": (|| { let state = c.resources.iir_state.lock(|iir_state|
|
"stabilizer/iir_b/state": (|| { let state = c.resources.iir_state.lock(|iir_state|
|
||||||
server::Status {
|
server::Status {
|
||||||
t: time,
|
t: time,
|
||||||
x0: iir_state[0][IIR_CASCADE_LENGTH-1].0[0],
|
x0: iir_state[0][IIR_CASCADE_LENGTH-1][0],
|
||||||
y0: iir_state[0][IIR_CASCADE_LENGTH-1].0[2],
|
y0: iir_state[0][IIR_CASCADE_LENGTH-1][2],
|
||||||
x1: iir_state[1][IIR_CASCADE_LENGTH-1].0[0],
|
x1: iir_state[1][IIR_CASCADE_LENGTH-1][0],
|
||||||
y1: iir_state[1][IIR_CASCADE_LENGTH-1].0[2],
|
y1: iir_state[1][IIR_CASCADE_LENGTH-1][2],
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok::<server::Status, ()>(state)
|
Ok::<server::Status, ()>(state)
|
||||||
|
Loading…
Reference in New Issue
Block a user