use crate::traits::FloatScalar;
use super::biquad::{
assemble_cascade, bilinear_hp_pair, bilinear_hp_real, bilinear_lp_pair, bilinear_lp_real,
prewarp, BiquadCascade,
};
use super::{validate_design_params, ControlError};
pub fn butterworth_lowpass<T: FloatScalar, const N: usize>(
order: usize,
cutoff: T,
sample_rate: T,
) -> Result<BiquadCascade<T, N>, ControlError> {
validate_design_params::<T, N>(order, cutoff, sample_rate)?;
let (wa, c) = prewarp(cutoff, sample_rate);
Ok(assemble_cascade(
order,
|k| {
let (sigma, omega) = butterworth_pole(order, k, wa);
bilinear_lp_pair(sigma, omega, wa, c)
},
|| bilinear_lp_real(-wa, wa, c),
))
}
pub fn butterworth_highpass<T: FloatScalar, const N: usize>(
order: usize,
cutoff: T,
sample_rate: T,
) -> Result<BiquadCascade<T, N>, ControlError> {
validate_design_params::<T, N>(order, cutoff, sample_rate)?;
let (wa, c) = prewarp(cutoff, sample_rate);
Ok(assemble_cascade(
order,
|k| {
let (sigma, omega) = butterworth_pole(order, k, wa);
bilinear_hp_pair(sigma, omega, wa, c)
},
|| bilinear_hp_real(-wa, wa, c),
))
}
fn butterworth_pole<T: FloatScalar>(order: usize, k: usize, wa: T) -> (T, T) {
let two = T::one() + T::one();
let pi = T::from(core::f64::consts::PI).unwrap();
let nf = T::from(order).unwrap();
let kf = T::from(k).unwrap();
let theta = pi * (two * kf + nf + T::one()) / (two * nf);
(wa * theta.cos(), wa * theta.sin())
}