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 IIR struct contains the data required to calculate the iir data.
/// It contains a buffer for the old samples, as well as the description of the fir and iir systems.
/// Since each node in the network needs to be of the same size, the IIR struct will be boxed, and
/// passed in as a pointer.
pub struct IIR<T> {
    /// FIR system description
    fir: Vec<T>,
    /// IIR system description
    iir: Vec<T>,
    /// FIR sample buffer
    fir_samples: VecDeque<T>,
    /// IIR sample buffer
    iir_samples: VecDeque<T>,
}

impl<T> IIR<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 iir system.
    /// https://en.wikipedia.org/wiki/Infinite_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 of both the FIR as well
    /// as the IIR part.
    /// 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::iir::IIR;
    ///
    /// let mut test_vector = Vec::new();
    /// test_vector.push(&[0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0][..]);
    ///
    /// let fir = [1.0].iter().map(|v| v.clone()).collect();
    /// let iir = [1.0, 1.0].iter().map(|v| v.clone()).collect();
    ///
    /// let mut iir = IIR::new(fir, iir);
    ///
    /// iir.process((test_vector, 9));
    /// let result = Vec::from(iir.poll());
    ///
    /// let control_vector: Vec<f64> = [0, 1, 0, 1, 0, 1, 0, 1, 0].iter().map(|v| v.clone() as f64).collect();
    ///
    /// assert_eq!(result, control_vector);
    /// ```
    pub fn new(fir: Vec<T>, iir: Vec<T>) -> Node<T>
    {
        let fir_len = fir.len();
        let iir_len = iir.len() - 1;
        let mut internal: IIR<T> = IIR {
            fir: fir,
            iir: iir,
            fir_samples: VecDeque::with_capacity(fir_len),
            iir_samples: VecDeque::with_capacity(iir_len),
        };

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

        let storage = Box::new(internal) as Box<dyn Any>;
        Node::new(storage, | data_input, data_container, output| {
            let iir: &mut IIR<T> = data_container.downcast_mut::<IIR<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 = IIR::calculate(*v, iir);
                    output.push(y_0);
                })
            })
        })
    }

    #[inline(always)]
    pub fn calculate(sample: T, data: &mut IIR<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;
        }

        // Calculate Y
        for i in 1..data.iir.len() {
            let y = *data.iir_samples.get(i - 1).unwrap();
            let a = *data.iir.get(i).unwrap();
            y_0 = y_0 - a * y;
        }

        // Discard oldest sample
        data.iir_samples.pop_back();
        // Push y value
        data.iir_samples.push_front(y_0);

        return y_0;
    }
}

#[cfg(test)]
mod tests {

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

    #[test]
    fn test_iir_actual() {

        let fir = [-0.06, 0.4].iter().map(|v| v.clone() as f64).collect();
        let iir = [1.0, -1.6, 0.78].iter().map(|v| v.clone() as f64).collect();

        let mut iir = IIR::new(fir, iir);

        let mut result = Vec::new();

        let mut input = Vec::new();
        let slice_ref = &[0.0][..];
        input.push(slice_ref);
        iir.process((input, 1));
        result.push(iir.data.get(0).unwrap().clone());

        for _i in 1..100 {
            let mut input = Vec::new();
            let slice_ref = &[1.0][..];
            input.push(slice_ref);
            iir.process((input, 1));
            result.push(iir.data.get(0).unwrap().clone());
        }


        let test_vector: Vec<f64> = [ 0.        , -0.06      ,  0.244     ,  0.7772    ,  1.3932    ,
            1.962904  ,  2.3939504 ,  2.63925552,  2.69552752,  2.59422473,
            2.3882481 ,  2.13770167,  1.89748915,  1.70857534,  1.59367901,
            1.55719765,  1.58844661,  1.66690041,  1.7680523 ,  1.86870136,
            1.95084138,  2.00375915,  2.02435836,  2.01604124,  1.98666647,
            1.94615418,  1.90424684,  1.86879468,  1.84475896,  1.83395448,
            1.83541518,  1.8461798 ,  1.86226383,  1.87960189,  1.89479723,
            1.9055861 ,  1.91099592,  1.91123631,  1.90740128,  1.90107773,
            1.89395136,  1.88748156,  1.88268842,  1.88006587,  1.87960841,
            1.88092209,  1.88338078,  1.88629001,  1.88902702,  1.89113702,
            1.89237815,  1.89271817,  1.89229412,  1.89135041,  1.89017125,
            1.88902068,  1.88809951,  1.88752309,  1.88731932,  1.88744291,
            1.88779958,  1.88827386,  1.88875451,  1.8891536 ,  1.88941724,
            1.88952778,  1.889499  ,  1.88936673,  1.88917755,  1.88897803,
            1.88880636,  1.88868731,  1.88863074,  1.88863308,  1.88868095,
            1.88875572,  1.88883801,  1.88891135,  1.88896452,  1.88899237,
            1.88899547,  1.88897871,  1.88894946,  1.88891575,  1.88888461,
            1.8888611 ,  1.88884776,  1.88884476,  1.88885036,  1.88886167,
            1.88887538,  1.88888851,  1.88889882,  1.88890508,  1.88890704,
            1.8889053 ,  1.888901  ,  1.88889546,  1.88888995,  1.88888547].iter().map(|v| v.clone() as f64).collect();


        for i in 0..100 {
            assert_approx_eq!(result[i], test_vector[i]);
        }
    }


    #[test]
    fn test_iir_simple() {

        let mut test_vector = Vec::new();
        test_vector.push(&[0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0][..]);

        let fir = [1.0].iter().map(|v| v.clone()).collect();
        let iir = [1.0, 1.0].iter().map(|v| v.clone()).collect();

        let mut iir = IIR::new(fir, iir);

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

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

        assert_eq!(result, control_vector);
    }
}