use crate::error::SignalError;
use crate::scalar::Numeric;
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct OnePoleLowPass<T: Numeric = f64> {
smoothing: T,
state: T,
initialized: bool,
}
impl<T: Numeric> OnePoleLowPass<T> {
pub fn new(smoothing: T) -> Result<Self, SignalError> {
if !smoothing.is_finite() {
return Err(SignalError::NonFinite);
}
if smoothing < T::ZERO || smoothing > T::ONE {
return Err(SignalError::CoefficientOutOfRange);
}
Ok(Self {
smoothing,
state: T::ZERO,
initialized: false,
})
}
pub fn from_cutoff(cutoff_hz: T, dt: T) -> Result<Self, SignalError> {
if !cutoff_hz.is_finite() || !dt.is_finite() {
return Err(SignalError::NonFinite);
}
if dt <= T::ZERO {
return Err(SignalError::NonPositiveTimestep);
}
if cutoff_hz < T::ZERO {
return Err(SignalError::FrequencyOutOfRange);
}
let a = T::TWO * T::PI * cutoff_hz * dt;
let smoothing = a / (a + T::ONE);
Self::new(smoothing)
}
#[inline]
#[must_use]
pub fn filter(&mut self, input: T) -> T {
if self.initialized {
self.state = self.smoothing * input + (T::ONE - self.smoothing) * self.state;
} else {
self.state = input;
self.initialized = true;
}
self.state
}
#[inline]
pub fn reset(&mut self) {
self.state = T::ZERO;
self.initialized = false;
}
#[inline]
#[must_use]
pub fn value(&self) -> T {
self.state
}
}