signal_processing 0.3.0

A signal processing library.
Documentation
use core::ops::{Add, Div, Mul, Neg, Sub};

use num::{complex::ComplexFloat, traits::Inv};

use crate::quantities::{MaybeList, MaybeLists, Polynomial};

moddef::moddef!(
    mod {
        add,
        default,
        div,
        from,
        inv,
        mul,
        neg,
        one,
        pow,
        product,
        sub,
        sum,
        zero
    }
);

#[derive(Debug, Clone, Copy)]
pub struct Tf<T: ComplexFloat, B: MaybeLists<T> = (), A: MaybeList<T> = ()>
{
    pub b: Polynomial<T, B>,
    pub a: Polynomial<T, A>
}

impl<T: ComplexFloat, B: MaybeLists<T>, A: MaybeList<T>> Tf<T, B, A>
{
    pub type View<'a> = Tf<T, B::View<'a>, A::View<'a>>
    where
        B::View<'a>: MaybeLists<T>,
        A::View<'a>: MaybeList<T>,
        B: 'a,
        A: 'a;
    pub type Owned = Tf<T, B::Owned, A::Owned>
    where
        B::Owned: MaybeLists<T>,
        A::Owned: MaybeList<T>;

    pub fn as_view<'a>(&'a self) -> Tf<T, B::View<'a>, A::View<'a>>
    where
        B::View<'a>: MaybeLists<T>,
        A::View<'a>: MaybeList<T>
    {
        Tf {
            b: self.b.as_view(),
            a: self.a.as_view()
        }
    }
    pub fn to_owned(&self) -> Tf<T, B::Owned, A::Owned>
    where
        B::Owned: MaybeLists<T>,
        A::Owned: MaybeList<T>
    {
        Tf {
            b: self.b.to_owned(),
            a: self.a.to_owned()
        }
    }
    pub fn into_owned(self) -> Tf<T, B::Owned, A::Owned>
    where
        B::Owned: MaybeLists<T>,
        A::Owned: MaybeList<T>
    {
        Tf {
            b: self.b.into_owned(),
            a: self.a.into_owned()
        }
    }
    pub fn new(b: B, a: A) -> Self
    {
        Self {
            b: Polynomial::new(b),
            a: Polynomial::new(a)
        }
    }
    pub fn one() -> Self
    where
        Self: Default,
    {
        Tf::default()
    }
    pub fn zero() -> Self
    where
        Polynomial<T, [T; 0]>: Into<Polynomial<T, B>>,
        Polynomial<T, ()>: Into<Polynomial<T, A>>
    {
        Tf {
            b: Polynomial::new([]).into(),
            a: Polynomial::new(()).into()
        }
    }
    pub fn is_one(&self) -> bool
    where
        B: MaybeList<T>
    {
        !self.b.is_zero() && !self.a.is_zero() && self.a == self.b
    }
    pub fn is_zero(&self) -> bool
    where
        B: MaybeLists<T>
    {
        self.b.is_zero() && !self.a.is_zero()
    }
    pub fn s() -> Self
    where
        for<'a> &'a Tf<T, [T; 2], ()>: Into<Self>
    {
        (&Tf {
            b: Polynomial::new([T::one(), T::zero()]),
            a: Polynomial::new(())
        }).into()
    }
    pub fn z() -> Self
    where
        for<'a> &'a Tf<T, [T; 2], ()>: Into<Self>
    {
        (&Tf {
            b: Polynomial::new([T::one(), T::zero()]),
            a: Polynomial::new(())
        }).into()
    }
    pub fn truncate<'a, const N: usize, const M: usize>(&'a self) -> Tf<T, [T; N], [T; M]>
    where
        B::View<'a>: MaybeLists<T>,
        A::View<'a>: MaybeLists<T>,
        Polynomial<T, B::View<'a>>: Into<Polynomial<T, Vec<T>>>,
        Polynomial<T, A::View<'a>>: Into<Polynomial<T, Vec<T>>>
    {
        Tf {
            b: self.b.as_view().truncate(),
            a: self.a.as_view().truncate()
        }
    }
}

macro_rules! impl_op1_extra {
    ($t:ident :: $f:tt) => {
        impl<'a, T, B, A, O> $t for &'a Tf<T, B, A>
        where
            T: ComplexFloat,
            B: MaybeLists<T>,
            A: MaybeList<T>,
            B::View<'a>: MaybeLists<T>,
            A::View<'a>: MaybeList<T>,
            Tf<T, B::View<'a>, A::View<'a>>: $t<Output = O>
        {
            type Output = O;

            fn $f(self) -> Self::Output
            {
                self.as_view().$f()
            }
        }
    };
}
impl_op1_extra!(Neg::neg);
impl_op1_extra!(Inv::inv);

macro_rules! impl_op2_extra {
    ($t:ident :: $f:tt) => {
        impl<'a, T1, B1, A1, T2, B2, A2, O> $t<Tf<T2, B2, A2>> for &'a Tf<T1, B1, A1>
        where
            T1: ComplexFloat,
            T2: ComplexFloat,
            B1: MaybeLists<T1>,
            A1: MaybeList<T1>,
            B2: MaybeLists<T2>,
            A2: MaybeList<T2>,
            B1::View<'a>: MaybeLists<T1>,
            A1::View<'a>: MaybeList<T1>,
            Tf<T1, B1::View<'a>, A1::View<'a>>: $t<Tf<T2, B2, A2>, Output = O>
        {
            type Output = O;

            fn $f(self, rhs: Tf<T2, B2, A2>) -> Self::Output
            {
                self.as_view().$f(rhs)
            }
        }
        impl<'b, T1, B1, A1, T2, B2, A2, O> $t<&'b Tf<T2, B2, A2>> for Tf<T1, B1, A1>
        where
            T1: ComplexFloat,
            T2: ComplexFloat,
            B1: MaybeLists<T1>,
            A1: MaybeList<T1>,
            B2: MaybeLists<T2>,
            A2: MaybeList<T2>,
            B2::View<'b>: MaybeLists<T2>,
            A2::View<'b>: MaybeList<T2>,
            Tf<T1, B1, A1>: $t<Tf<T2, B2::View<'b>, A2::View<'b>>, Output = O>
        {
            type Output = O;

            fn $f(self, rhs: &'b Tf<T2, B2, A2>) -> Self::Output
            {
                self.$f(rhs.as_view())
            }
        }
        impl<'a, 'b, T1, B1, A1, T2, B2, A2, O> $t<&'b Tf<T2, B2, A2>> for &'a Tf<T1, B1, A1>
        where
            T1: ComplexFloat,
            T2: ComplexFloat,
            B1: MaybeLists<T1>,
            A1: MaybeList<T1>,
            B2: MaybeLists<T2>,
            A2: MaybeList<T2>,
            B1::View<'a>: MaybeLists<T1>,
            A1::View<'a>: MaybeList<T1>,
            B2::View<'b>: MaybeLists<T2>,
            A2::View<'b>: MaybeList<T2>,
            Tf<T1, B1::View<'a>, A1::View<'a>>: $t<Tf<T2, B2::View<'b>, A2::View<'b>>, Output = O>
        {
            type Output = O;

            fn $f(self, rhs: &'b Tf<T2, B2, A2>) -> Self::Output
            {
                self.as_view().$f(rhs.as_view())
            }
        }

        impl<T, B, A, O> $t<T> for Tf<T, B, A>
        where
            T: ComplexFloat,
            B: MaybeLists<T>,
            A: MaybeList<T>,
            Self: $t<Tf<T, [T; 1], ()>, Output = O>
        {
            type Output = O;

            fn $f(self, rhs: T) -> Self::Output
            {
                self.$f(Tf {
                    b: Polynomial::new([rhs]),
                    a: Polynomial::new(())
                })
            }
        }
        impl<'a, T, B, A, O> $t<T> for &'a Tf<T, B, A>
        where
            T: ComplexFloat,
            B: MaybeLists<T>,
            A: MaybeList<T>,
            Self: $t<Tf<T, [T; 1], ()>, Output = O>
        {
            type Output = O;

            fn $f(self, rhs: T) -> Self::Output
            {
                self.$f(Tf {
                    b: Polynomial::new([rhs]),
                    a: Polynomial::new(())
                })
            }
        }
        impl<'b, T, B, A, O> $t<&'b T> for Tf<T, B, A>
        where
            T: ComplexFloat,
            B: MaybeLists<T>,
            A: MaybeList<T>,
            Self: $t<Tf<T, &'b [T; 1], ()>, Output = O>
        {
            type Output = O;

            fn $f(self, rhs: &'b T) -> Self::Output
            {
                self.$f(Tf {
                    b: Polynomial::new(core::array::from_ref(rhs)),
                    a: Polynomial::new(())
                })
            }
        }
        impl<'a, 'b, T, B, A, O> $t<&'b T> for &'a Tf<T, B, A>
        where
            T: ComplexFloat,
            B: MaybeLists<T>,
            A: MaybeList<T>,
            Self: $t<Tf<T, &'b [T; 1], ()>, Output = O>
        {
            type Output = O;

            fn $f(self, rhs: &'b T) -> Self::Output
            {
                self.$f(Tf {
                    b: Polynomial::new(core::array::from_ref(rhs)),
                    a: Polynomial::new(())
                })
            }
        }
    };
}
impl_op2_extra!(Add::add);
impl_op2_extra!(Sub::sub);
impl_op2_extra!(Mul::mul);
impl_op2_extra!(Div::div);

#[allow(unused)]
macro s {
    (s) => {},
    (z) => {},
}
pub macro tf {
    ($t:path[$s:ident]= {$e:expr}) => {
        {
            Tf::<$t, [$t; 2], ()>::$s();
            s!($s);
            $e
        }
    },
    ($t:path[$s:ident]=) => {
        {
            Tf::<$t, [$t; 2], ()>::$s();
            s!($s);
            Tf::<$t, _, _>::new([], ())
        }
    },
    ($t:path[$s:ident]= $c:literal) => {
        {
            Tf::<$t, [$t; 2], ()>::$s();
            s!($s);
            Tf::<$t, _, _>::new([<$t as num::NumCast>::from($c).unwrap()], ())
        }
    },
    ($t:path[$s:ident]= $c:literal + $ci:literal j) => {
        {
            Tf::<$t, [$t; 2], ()>::$s();
            s!($s);
            Tf::<num::Complex<<$t as num::complex::ComplexFloat>::Real>, _, _>::new([num::Complex::new(<$t as num::NumCast>::from($c).unwrap(), <$t as num::NumCast>::from($ci).unwrap())], ())
        }
    },
    ($t:path[$s:ident]= $c:literal - $ci:literal j) => {
        {
            Tf::<$t, [$t; 2], ()>::$s();
            s!($s);
            Tf::<num::Complex<<$t as num::complex::ComplexFloat>::Real>, _, _>::new([num::Complex::new(<$t as num::NumCast>::from($c).unwrap(), -<$t as num::NumCast>::from($ci).unwrap())], ())
        }
    },
    ($t:path[$s:ident]= $ci:literal j) => {
        {
            Tf::<$t, [$t; 2], ()>::$s();
            s!($s);
            Tf::<num::Complex<<$t as num::complex::ComplexFloat>::Real>, _, _>::new([num::Complex::new(<$t as num::NumCast>::from(0).unwrap(), <$t as num::NumCast>::from($ci).unwrap())], ())
        }
    },
    ($t:path[$s:ident]= $ss:ident) => {
        {
            #[allow(unused)]
            let $s: Tf::<$t, [$t; 2], ()> = Tf::<$t, [$t; 2], ()>::$s();
            s!($s);
            s!($ss);
            Tf::<$t, [_; 2], ()>::from($ss)
        }
    },
    ($t:path[$s:ident]= $c:literal^$pc:literal) => {
        {
            Tf::<$t, [$t; 2], ()>::$s();
            s!($s);
            num::traits::Pow::pow(Tf::<$t, _, _>::new([<$t as num::NumCast>::from($c).unwrap()], ()), $pc)
        }
    },
    ($t:path[$s:ident]= $ss:ident^$ps:literal) => {
        {
            #[allow(unused)]
            let $s: Tf::<$t, [$t; 2], ()> = Tf::<$t, [$t; 2], ()>::$s();
            s!($s);
            s!($ss);
            num::traits::Pow::pow(Tf::<$t, [_; 2], ()>::from($ss), $ps)
        }
    },
    ($t:path[$s:ident]= ($($lhs:tt)*)^$lp:literal $($op:tt ($($rhs:tt)*))?) => {
        num::traits::Pow::pow(tf!($t[$s]= $($lhs)*), $lp)$($op tf!($t[$s]= $($rhs)*))*
    },
    ($t:path[$s:ident]= ($($lhs:tt)*) $($op:tt ($($rhs:tt)*))?) => {
        tf!($t[$s]= $($lhs)*)$($op tf!($t[$s]= $($rhs)*))*
    },
    ($t:path[$s:ident]= $lhs:tt$(^$lp:literal)? $($op:tt $rhs:tt$(^$rp:literal)?)*) => {
        tf!($t[$s]= $lhs$(^$lp)?)$($op tf!($t[$s]= $rhs$(^$rp)?))*
    },
}

#[cfg(test)]
mod test
{
    use super::tf;

    #[test]
    fn test()
    {
        let h = tf!(f64[s] = (((2*(s^-3))^-2) + 1 + 2*(s^2))/(s + 1)*2);
        let h2 = tf!(f64[s] = {h}*2);

        println!("{:?}", h2);
    }
}