use num_traits::Float;
pub fn high_pass<T: Float>(u: &[T], y: &[T], cutoff: T, ts: T, order: usize) -> (Vec<T>, Vec<T>) {
let two_pi = T::from(2.0 * std::f64::consts::PI).unwrap();
let a = T::one() / (T::one() + two_pi * cutoff * ts);
let filter = |x: &[T]| {
let mut x = x.to_vec();
for _ in 0..order {
let (mut previous_in, mut previous_out) = (T::zero(), T::zero());
for v in x.iter_mut() {
let out = a * (previous_out + *v - previous_in);
previous_in = *v;
previous_out = out;
*v = out;
}
}
x
};
(filter(u), filter(y))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn removes_a_constant_and_keeps_high_frequencies() {
let ts = 1e-3;
let x: Vec<f64> = (0..5000).map(|k| 1.0 + (2.0 * std::f64::consts::PI * 50.0 * k as f64 * ts).sin()).collect();
let (xf, _) = high_pass(&x, &x, 1.0, ts, 2);
let tail = &xf[4000..];
let mean = tail.iter().sum::<f64>() / tail.len() as f64;
let amplitude = tail.iter().fold(0.0f64, |m, v| m.max((v - mean).abs()));
assert!(mean.abs() < 1e-3 && (amplitude - 1.0).abs() < 0.01, "mean {mean}, amplitude {amplitude}");
}
}