sac-base 0.0.7

Base crate of the sac-signal and sac-control crates
Documentation
use crate::network::node::Node;
use alloc::boxed::Box;
use core::any::Any;
use alloc::vec::Vec;
use alloc::collections::VecDeque;
use core::ops;
use core::default::Default;

/// The FIR struct contains the data required to calculate the fir data.
/// It contains a buffer for the old samples, as well as the description of the fir system.
/// Since each node in the network needs to be of the same size, the FIR struct will be boxed, and
/// passed in as a pointer.
pub struct FIR<T> {
    // fir system description
    fir: Vec<T>,
    // Samples buffer
    fir_samples: VecDeque<T>,
}

impl<T> FIR<T>
    where T: Copy + Clone + 'static + ops::Div<Output=T> + ops::Mul<Output=T> + ops::Add<Output=T> + ops::Sub<Output=T> + Default
{
    /// Allows to calculate samples of a fir system.
    /// https://en.wikipedia.org/wiki/Finite_impulse_response
    /// This can be used in both signal processing as well as control engineering use cases.
    /// This specific implementation calculates samples any given length.
    /// A implementation designed for a known length will certainly be faster. But this allows for
    /// some quick experimentation.
    ///
    /// ## Example
    /// ```rust
    /// use sac_base::operations::math::fir::FIR;
    ///
    /// let mut test_vector: Vec<&[f64]> = Vec::new();
    /// test_vector.push(&[0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0][..]);
    ///
    /// let fir: Vec<f64>  = [1.0, -1.0].iter().map(|v| v.clone()).collect();
    /// let mut fir = FIR::new(fir);
    ///
    /// fir.process((test_vector, 9));
    /// let result = Vec::from(fir.poll());
    ///
    /// assert_eq!([0.0, 1.0, 1.0 ,1.0 , 1.0, 1.0, 1.0, 1.0, 1.0], result[..]);
    /// ```
    pub fn new(fir: Vec<T>) -> Node<T>
    {
        let fir_len = fir.len();
        let mut internal: FIR<T> = FIR {
            fir: fir,
            fir_samples: VecDeque::with_capacity(fir_len),
        };

        // Initialize the buffer properly to avoid checks during runtime
        for _i in 0..fir_len {
            internal.fir_samples.push_back(T::default());
        }

        let storage = Box::new(internal) as Box<dyn Any>;
        Node::new(storage, | data_input, data_container, output| {
            let fir: &mut FIR<T> = data_container.downcast_mut::<FIR<T>>().unwrap();
            let (inputs, max_len) = data_input;
            output.clear();
            inputs.into_iter().take(1).into_iter().for_each(|data| {
                data.into_iter().take(max_len).into_iter().for_each(|v| {
                    let y_0 = FIR::calculate(*v, fir);
                    output.push(y_0);
                })
            })
        })
    }

    #[inline(always)]
    pub fn calculate(sample: T, data: &mut FIR<T>) -> T {
        // Discard oldest sample
        data.fir_samples.pop_back();
        // Push new sample
        data.fir_samples.push_front(sample);

        let mut y_0 = T::default();

        // Calculate X
        for i in 0..data.fir.len() {
            let x = *data.fir_samples.get(i).unwrap();
            let b = *data.fir.get(i).unwrap();
            y_0 = y_0 + b * x;
        }

        return y_0;
    }
}

#[cfg(test)]
mod tests {

    use super::*;
    use alloc::vec::Vec;

    #[test]
    fn test_fir_simple() {

        let test_vector: Vec<f64> = [0,1,1,1,1,1,1,1,1].iter().map(|v| {return v.clone() as f64}).collect();

        let fir: Vec<f64>  = [1.0, 1.0].iter().map(|v| v.clone()).collect();

        let mut fir = FIR::new(fir);

        let mut result = Vec::new();

        for val in test_vector.iter() {
            let mut input = Vec::new();
            let slice_ref = &[*val][..];
            input.push(slice_ref);
            fir.process((input, 1));
            result.push(fir.data.get(0).unwrap().clone());
        }

        let control_vector: Vec<f64> = [0, 1, 2, 2, 2, 2, 2, 2, 2].iter().map(|v| v.clone() as f64).collect();

        assert_eq!(result, control_vector);
    }

    #[test]
    fn test_fir_integrate() {

        let mut test_vector: Vec<&[f64]> = Vec::new();
        test_vector.push(&[0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0][..]);

        let fir: Vec<f64>  = [1.0, -1.0].iter().map(|v| v.clone()).collect();
        let mut fir = FIR::new(fir);

        fir.process((test_vector, 9));
        let result = Vec::from(fir.poll());

        assert_eq!([0.0, 1.0, 1.0 ,1.0 , 1.0, 1.0, 1.0, 1.0, 1.0], result[..]);
    }
}