#[cfg(not(feature = "std"))]
use num_traits::Float;
use core::num::NonZeroU32;
pub const DEFAULT_SMOOTH_SECONDS: f64 = 15.0 / 1_000.0;
pub const DEFAULT_SETTLE_EPSILON: f64 = 0.001f64;
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct SmoothingFilterCoeff {
pub a0: f64,
pub b1: f64,
}
impl SmoothingFilterCoeff {
pub fn new(sample_rate: NonZeroU32, smooth_secs: f64) -> Self {
let smooth_secs = smooth_secs.max(0.00001);
let b1 = (-1.0f64 / (smooth_secs * sample_rate.get() as f64)).exp();
let a0 = 1.0f64 - b1;
Self { a0, b1 }
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct SmoothingFilter {
pub z1: f64,
}
impl SmoothingFilter {
pub fn new(value: f64) -> Self {
Self { z1: value }
}
#[inline(always)]
pub fn process(&mut self, target: f64, coeff: SmoothingFilterCoeff) -> f64 {
self.z1 = (target * coeff.a0) + (self.z1 * coeff.b1);
self.z1
}
#[inline(always)]
pub fn process_sample_a(&mut self, target_times_a: f64, coeff_b: f64) -> f64 {
self.z1 = target_times_a + (self.z1 * coeff_b);
self.z1
}
pub fn process_into_buffer(
&mut self,
buffer: &mut [f64],
target: f64,
coeff: SmoothingFilterCoeff,
) {
let target_times_a = target * coeff.a0;
for s in buffer.iter_mut() {
*s = self.process_sample_a(target_times_a, coeff.b1);
}
}
pub fn settle(&mut self, target: f64, settle_epsilon: f64) -> bool {
if self.z1 == target {
true
} else if (self.z1 - target).abs() < (target.abs() * settle_epsilon) + settle_epsilon {
self.z1 = target;
true
} else {
false
}
}
pub fn has_settled(&self, target: f64) -> bool {
self.z1 == target
}
}