use crate::traits::FloatScalar;
use super::ControlError;
#[derive(Debug, Clone, Copy)]
pub struct Biquad<T> {
b: [T; 3],
a: [T; 3], z: [T; 2], }
impl<T: FloatScalar> Biquad<T> {
pub fn new(b: [T; 3], a: [T; 3]) -> Self {
let a0 = a[0];
Self {
b: [b[0] / a0, b[1] / a0, b[2] / a0],
a: [T::one(), a[1] / a0, a[2] / a0],
z: [T::zero(); 2],
}
}
pub fn try_new(b: [T; 3], a: [T; 3]) -> Result<Self, ControlError> {
let two_eps = T::epsilon() * (T::one() + T::one());
if a[0].abs() < two_eps {
return Err(ControlError::NearZeroDenominator);
}
Ok(Self::new(b, a))
}
pub fn passthrough() -> Self {
Self {
b: [T::one(), T::zero(), T::zero()],
a: [T::one(), T::zero(), T::zero()],
z: [T::zero(); 2],
}
}
#[inline]
pub fn tick(&mut self, x: T) -> T {
let y = self.b[0] * x + self.z[0];
self.z[0] = self.b[1] * x - self.a[1] * y + self.z[1];
self.z[1] = self.b[2] * x - self.a[2] * y;
y
}
pub fn reset(&mut self) {
self.z = [T::zero(); 2];
}
pub fn process(&mut self, input: &[T], output: &mut [T]) {
assert!(output.len() >= input.len());
for (i, &x) in input.iter().enumerate() {
output[i] = self.tick(x);
}
}
pub fn process_inplace(&mut self, data: &mut [T]) {
for sample in data.iter_mut() {
*sample = self.tick(*sample);
}
}
pub fn coefficients(&self) -> ([T; 3], [T; 3]) {
(self.b, self.a)
}
}
#[derive(Debug, Clone, Copy)]
pub struct BiquadCascade<T, const N: usize> {
pub sections: [Biquad<T>; N],
}
impl<T: FloatScalar, const N: usize> BiquadCascade<T, N> {
#[inline]
pub fn tick(&mut self, x: T) -> T {
let mut y = x;
for section in self.sections.iter_mut() {
y = section.tick(y);
}
y
}
pub fn reset(&mut self) {
for section in self.sections.iter_mut() {
section.reset();
}
}
pub fn process(&mut self, input: &[T], output: &mut [T]) {
assert!(output.len() >= input.len());
for (i, &x) in input.iter().enumerate() {
output[i] = self.tick(x);
}
}
pub fn process_inplace(&mut self, data: &mut [T]) {
for sample in data.iter_mut() {
*sample = self.tick(*sample);
}
}
pub fn order(&self) -> usize {
if N == 0 {
return 0;
}
let last = &self.sections[N - 1];
let (b, a) = last.coefficients();
if b[2] == T::zero() && a[2] == T::zero() {
2 * N - 1
} else {
2 * N
}
}
}
pub(super) fn bilinear_lp_pair<T: FloatScalar>(sigma: T, omega: T, wa: T, c: T) -> Biquad<T> {
let two = T::one() + T::one();
let d = c * c - two * sigma * c + sigma * sigma + omega * omega;
let wa2 = wa * wa;
let b0 = wa2 / d;
let b1 = two * wa2 / d;
let b2 = b0;
let a1 = two * (sigma * sigma + omega * omega - c * c) / d;
let a2 = (c * c + two * sigma * c + sigma * sigma + omega * omega) / d;
Biquad::new([b0, b1, b2], [T::one(), a1, a2])
}
pub(super) fn bilinear_hp_pair<T: FloatScalar>(sigma: T, omega: T, _wa: T, c: T) -> Biquad<T> {
let two = T::one() + T::one();
let c2 = c * c;
let d = c2 - two * sigma * c + sigma * sigma + omega * omega;
let b0 = c2 / d;
let b1 = -(two * c2) / d;
let b2 = b0;
let a1 = two * (sigma * sigma + omega * omega - c2) / d;
let a2 = (c2 + two * sigma * c + sigma * sigma + omega * omega) / d;
Biquad::new([b0, b1, b2], [T::one(), a1, a2])
}
pub(super) fn bilinear_lp_real<T: FloatScalar>(sigma: T, wa: T, c: T) -> Biquad<T> {
let denom = c - sigma;
let b0 = wa / denom;
Biquad::new([b0, b0, T::zero()], [T::one(), (-c - sigma) / denom, T::zero()])
}
pub(super) fn bilinear_hp_real<T: FloatScalar>(sigma: T, _wa: T, c: T) -> Biquad<T> {
let denom = c - sigma;
let b0 = c / denom;
Biquad::new(
[b0, -b0, T::zero()],
[T::one(), (-c - sigma) / denom, T::zero()],
)
}