|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#![cfg_attr(not(feature = "std"), no_std)] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Copy)] |
|
|
#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] |
|
|
pub struct Ema { |
|
|
|
|
|
alpha: f32, |
|
|
|
|
|
value: f32, |
|
|
|
|
|
initialized: bool, |
|
|
} |
|
|
|
|
|
impl Ema { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub const fn new(alpha: f32) -> Self { |
|
|
Self { |
|
|
alpha, |
|
|
value: 0.0, |
|
|
initialized: false, |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
pub fn update(&mut self, x: f32) { |
|
|
if !self.initialized { |
|
|
|
|
|
self.value = x; |
|
|
self.initialized = true; |
|
|
} else { |
|
|
|
|
|
self.value = self.alpha * x + (1.0 - self.alpha) * self.value; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
pub fn get(&self) -> f32 { |
|
|
self.value |
|
|
} |
|
|
|
|
|
|
|
|
pub fn is_ready(&self) -> bool { |
|
|
self.initialized |
|
|
} |
|
|
|
|
|
|
|
|
pub fn reset(&mut self) { |
|
|
self.value = 0.0; |
|
|
self.initialized = false; |
|
|
} |
|
|
|
|
|
|
|
|
pub fn alpha(&self) -> f32 { |
|
|
self.alpha |
|
|
} |
|
|
|
|
|
|
|
|
pub fn set_alpha(&mut self, alpha: f32) { |
|
|
self.alpha = alpha.clamp(0.0, 1.0); |
|
|
} |
|
|
} |
|
|
|
|
|
#[cfg(test)] |
|
|
mod tests { |
|
|
use super::*; |
|
|
|
|
|
#[test] |
|
|
fn test_first_value_becomes_baseline() { |
|
|
let mut ema = Ema::new(0.1); |
|
|
assert!(!ema.is_ready()); |
|
|
ema.update(42.0); |
|
|
assert!(ema.is_ready()); |
|
|
assert_eq!(ema.get(), 42.0); |
|
|
} |
|
|
|
|
|
#[test] |
|
|
fn test_ema_smoothing() { |
|
|
let mut ema = Ema::new(0.1); |
|
|
ema.update(100.0); |
|
|
ema.update(200.0); |
|
|
|
|
|
assert!((ema.get() - 110.0).abs() < 0.001); |
|
|
} |
|
|
|
|
|
#[test] |
|
|
fn test_high_alpha_fast_response() { |
|
|
let mut ema = Ema::new(0.9); |
|
|
ema.update(100.0); |
|
|
ema.update(200.0); |
|
|
|
|
|
assert!((ema.get() - 190.0).abs() < 0.001); |
|
|
} |
|
|
|
|
|
#[test] |
|
|
fn test_reset() { |
|
|
let mut ema = Ema::new(0.1); |
|
|
ema.update(100.0); |
|
|
assert!(ema.is_ready()); |
|
|
ema.reset(); |
|
|
assert!(!ema.is_ready()); |
|
|
assert_eq!(ema.get(), 0.0); |
|
|
} |
|
|
} |
|
|
|