signal_processing 0.3.0

A signal processing library.
Documentation
use array_math::max_len;
use num::{complex::ComplexFloat, NumCast};
use option_trait::Maybe;

use crate::{gen::filter::{Cheby1, FilterGenPlane, FilterGenType, Fir1, Fir1Type}, util::ComplexOp, operations::filtering::{FftFilt, FiltFilt}, quantities::{List, MaybeLists, ListOrSingle, Lists}, System, systems::{Tf, IrType}};

pub trait Decimate<T, Q, Y>: Lists<T>
where
    T: ComplexFloat,
    Y: List<T>,
    Q: Maybe<usize>
{
    fn decimate<N, F>(self, ratio: Q, order: N, filter_type: F) -> Self::RowsMapped<Y>
    where
        N: Maybe<usize>,
        F: Maybe<IrType>;
}

impl<T, L> Decimate<T, usize, Vec<T>> for L
where
    L: Lists<T, RowOwned: List<T>>,
    T: ComplexFloat<Real: ComplexOp<T, Output = T> + ComplexFloat<Real = T::Real>>,
    Tf<T::Real, Vec<T::Real>, ()>: Fir1<usize, [T::Real; 1], T::Real, (), false> + System<Set = T::Real> + for<'a> FftFilt<'a, T, Vec<T>, Output = Vec<T>>,
    Tf<T::Real, Vec<T::Real>, Vec<T::Real>>: Cheby1<usize> + System<Set = T::Real> + for<'a> FiltFilt<'a, T, Vec<T>, Output = Vec<T>>
{
    fn decimate<N, F>(self, ratio: usize, order: N, filter_type: F) -> Self::RowsMapped<Vec<T>>
    where
        N: Maybe<usize>,
        F: Maybe<IrType>
    {
        let ftype = filter_type.into_option()
            .unwrap_or(IrType::IIR);
        let n = order.into_option()
            .unwrap_or_else(|| match ftype

            {
                IrType::FIR => 30,
                IrType::IIR => 8
            });
        let qf = <T::Real as NumCast>::from(ratio).unwrap();

        self.map_rows_into_owned(|x| {
            let x = x.into_vec();

            let y = match ftype
            {
                IrType::FIR => {
                    let tf = Tf::fir1(
                            n,
                            [qf.recip()],
                            Fir1Type::LowPass,
                            (),
                            true,
                            None
                        ).unwrap();
                    tf.fftfilt(x, ())
                },
                IrType::IIR => {
                    let tf = Tf::cheby1(
                            n,
                            <T::Real as NumCast>::from(0.05).unwrap(),
                            [<T::Real as NumCast>::from(0.8).unwrap()/qf],
                            FilterGenType::LowPass,
                            FilterGenPlane::Z {sampling_frequency: None}
                        ).unwrap();
                    tf.filtfilt(x)
                }
            };

            y.into_iter()
                .step_by(ratio)
                .collect()
        })
    }
}

impl<T, L, const M: usize> Decimate<T, (), [T; M]> for L
where
    L: Lists<T, Width = usize> + Decimate<T, usize, Vec<T>>,
    L::RowsMapped<Vec<T>>: Lists<T, RowsMapped<[T; M]> = L::RowsMapped<[T; M]>, RowOwned = Vec<T>>,
    T: ComplexFloat,
    [(); 0 - M % max_len(L::WIDTH, 1)]:
{
    fn decimate<N, F>(self, (): (), order: N, filter_type: F) -> Self::RowsMapped<[T; M]>
    where
        N: Maybe<usize>,
        F: Maybe<IrType>
    {
        let n = M / L::WIDTH.max(1);

        self.decimate(n, order, filter_type)
            .map_rows_into_owned(|y| {
                TryInto::<[T; M]>::try_into(y)
                    .ok()
                    .unwrap()
            })
    }
}