use std::fmt;
use num_traits::{Num, Zero};
use signalo_traits::Filter;
use signalo_traits::{FromGuts, Guts, IntoGuts, Reset, State as StateTrait, StateMut};
use crate::circular_buffer::CircularBuffer;
#[derive(Clone)]
pub struct State<T, const N: usize> {
pub mean: Option<T>,
pub taps: CircularBuffer<T, N>,
pub weight: T,
}
impl<T, const N: usize> fmt::Debug for State<T, N>
where
T: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("State")
.field("mean", &self.mean)
.field("taps", &self.taps)
.field("weight", &self.weight)
.finish()
}
}
#[derive(Clone)]
pub struct Mean<T, const N: usize> {
state: State<T, N>,
}
impl<T, const N: usize> Default for Mean<T, N>
where
T: Zero,
{
fn default() -> Self {
let state = {
let mean = None;
let taps = CircularBuffer::default();
let weight = T::zero();
State { mean, taps, weight }
};
Self { state }
}
}
impl<T, const N: usize> fmt::Debug for Mean<T, N>
where
T: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Mean").field("state", &self.state).finish()
}
}
impl<T, const N: usize> StateTrait for Mean<T, N> {
type State = State<T, N>;
}
impl<T, const N: usize> StateMut for Mean<T, N> {
unsafe fn state_mut(&mut self) -> &mut Self::State {
&mut self.state
}
}
impl<T, const N: usize> Guts for Mean<T, N> {
type Guts = State<T, N>;
}
impl<T, const N: usize> FromGuts for Mean<T, N> {
fn from_guts(guts: Self::Guts) -> Self {
let state = guts;
Self { state }
}
}
impl<T, const N: usize> IntoGuts for Mean<T, N> {
fn into_guts(self) -> Self::Guts {
self.state
}
}
impl<T, const N: usize> Reset for Mean<T, N>
where
T: Zero,
{
fn reset(self) -> Self {
Self::default()
}
}
#[cfg(feature = "derive_reset_mut")]
impl<T, N> ResetMut for Mean<T, N> where Self: Reset {}
impl<T, const N: usize> Filter<T> for Mean<T, N>
where
T: Clone + Num,
{
type Output = T;
fn filter(&mut self, input: T) -> Self::Output {
let old_mean = self.state.mean.clone().unwrap_or_else(|| input.clone());
let old_weight = self.state.weight.clone();
#[allow(clippy::option_if_let_else)]
let (mean, weight) = if let Some(old_input) = self.state.taps.push_back(input.clone()) {
let mean = old_mean - old_input + input;
(mean, old_weight)
} else {
let mean = old_mean + input;
let weight = old_weight + T::one();
(mean, weight)
};
self.state.mean = Some(mean.clone());
self.state.weight = weight.clone();
mean / weight
}
}
#[cfg(test)]
mod tests {
use super::*;
fn get_input() -> Vec<f32> {
vec![
0.0, 1.0, 7.0, 2.0, 5.0, 8.0, 16.0, 3.0, 19.0, 6.0, 14.0, 9.0, 9.0, 17.0, 17.0, 4.0,
12.0, 20.0, 20.0, 7.0, 7.0, 15.0, 15.0, 10.0, 23.0, 10.0, 111.0, 18.0, 18.0, 18.0,
106.0, 5.0, 26.0, 13.0, 13.0, 21.0, 21.0, 21.0, 34.0, 8.0, 109.0, 8.0, 29.0, 16.0,
16.0, 16.0, 104.0, 11.0, 24.0, 24.0,
]
}
fn get_output() -> Vec<f32> {
vec![
0.000, 0.500, 2.667, 3.333, 4.667, 5.000, 9.667, 9.000, 12.667, 9.333, 13.000, 9.667,
10.667, 11.667, 14.333, 12.667, 11.000, 12.000, 17.333, 15.667, 11.333, 9.667, 12.333,
13.333, 16.000, 14.333, 48.000, 46.333, 49.000, 18.000, 47.333, 43.000, 45.667, 14.667,
17.333, 15.667, 18.333, 21.000, 25.333, 21.000, 50.333, 41.667, 48.667, 17.667, 20.333,
16.000, 45.333, 43.667, 46.333, 19.667,
]
}
#[test]
fn test() {
let filter: Mean<f32, 3> = Mean::default();
let input = get_input();
let output: Vec<_> = input
.iter()
.scan(filter, |filter, &input| Some(filter.filter(input)))
.collect();
assert_nearly_eq!(output, get_output(), 0.001);
}
}