use alloc::vec::Vec;
use super::remez_impl::pm_remez;
pub fn low_pass(
gain: f64,
fs: usize,
freq1: f64,
freq2: f64,
passband_ripple_db: f64,
stopband_atten_db: f64,
nextra_taps: Option<usize>,
) -> Vec<f64> {
let nextra_taps = nextra_taps.unwrap_or(2);
let passband_dev = passband_ripple_to_dev(passband_ripple_db);
let stopband_dev = stopband_atten_to_dev(stopband_atten_db);
let (n, fo, ao, w) = remezord(
&[freq1, freq2],
&[gain, 0.0_f64],
&[passband_dev, stopband_dev],
Some(fs),
);
pm_remez(n + nextra_taps, &fo, &ao, &w, "bandpass", None)
}
fn stopband_atten_to_dev(atten_db: f64) -> f64 {
10.0_f64.powf(-atten_db / 20.)
}
fn passband_ripple_to_dev(ripple_db: f64) -> f64 {
(10.0_f64.powf(ripple_db / 20.) - 1.) / (10.0_f64.powf(ripple_db / 20.) + 1.)
}
fn remezord(
fcuts: &[f64],
mags: &[f64],
devs: &[f64],
fsamp: Option<usize>,
) -> (usize, Vec<f64>, Vec<f64>, Vec<f64>) {
let fsamp = fsamp.unwrap_or(2);
let fcuts: Vec<f64> = fcuts.iter().map(|&x| x / fsamp as f64).collect();
let nf = fcuts.len();
let nm = mags.len();
let nd = devs.len();
let nbands = nm;
assert!(nm == nd, "Length of mags and devs must be equal");
assert!(
nf == 2 * (nbands - 1),
"Length of f must be 2 * len (mags) - 2"
);
let devs: Vec<f64> = devs
.iter()
.zip(mags.iter())
.map(|(&d, &m)| if m == 0. { d } else { d / m })
.collect();
let f1: Vec<f64> = fcuts.iter().step_by(2).copied().collect();
let f2: Vec<f64> = fcuts[1..].iter().step_by(2).copied().collect();
let mut n = 0;
let mut min_delta: f64 = 2.;
for i in 0..f1.len() {
if f2[i] - f1[i] < min_delta {
n = i;
min_delta = f2[i] - f1[i];
}
}
let l = if nbands == 2 {
lporder(f1[n], f2[n], devs[0], devs[1])
} else {
let mut l_tmp: f64 = 0.;
for i in 1..(nbands - 1) {
let l1 = lporder(f1[i - 1], f2[i - 1], devs[i], devs[i - 1]);
let l2 = lporder(f1[i], f2[i], devs[i], devs[i + 1]);
l_tmp = l_tmp.max(l1.max(l2));
}
l_tmp
};
let n = l.ceil() as usize - 1;
let mut ff: Vec<f64> = fcuts.iter().copied().map(|x| 2. * x).collect();
ff.push(1.);
ff.insert(0, 0.);
let aa = mags
.iter()
.zip(mags.iter())
.fold(vec![], |mut vec, (&a_1, &a_2)| {
vec.push(a_1);
vec.push(a_2);
vec
});
let max_dev = devs.iter().max_by(|a, b| a.total_cmp(b)).unwrap();
let wts: Vec<f64> = devs.iter().map(|&x| max_dev / x).collect();
(n, ff, aa, wts)
}
fn lporder(freq1: f64, freq2: f64, delta_p: f64, delta_s: f64) -> f64 {
let df = (freq2 - freq1).abs();
let ddp = delta_p.log10();
let dds = delta_s.log10();
let a1 = 5.309e-3;
let a2 = 7.114e-2;
let a3 = -4.761e-1;
let a4 = -2.66e-3;
let a5 = -5.941e-1;
let a6 = -4.278e-1;
let b1 = 11.01217;
let b2 = 0.5124401;
let t1 = a1 * ddp * ddp;
let t2 = a2 * ddp;
let t3 = a4 * ddp * ddp;
let t4 = a5 * ddp;
let dinf = ((t1 + t2 + a3) * dds) + (t3 + t4 + a6);
let ff = b1 + b2 * (ddp - dds);
dinf / df - ff * df + 1.
}