automatica 1.0.0

Automatic control systems library
Documentation
//! Collection of common discrete input signals.

use crate::Zero;

/// Zero input function
///
/// # Arguments
///
/// * `size` - Output size
pub fn zero<T>(size: usize) -> impl Fn(usize) -> Vec<T>
where
    T: Clone + Zero,
{
    move |_| vec![T::zero(); size]
}

/// Step function
///
/// # Arguments
///
/// * `k` - Step size
/// * `time` - Time at which step occurs
pub fn step<T>(k: T, time: usize) -> impl Fn(usize) -> T
where
    T: Clone + Zero,
{
    move |t| {
        if t < time {
            T::zero()
        } else {
            k.clone()
        }
    }
}

/// Step function
///
/// # Arguments
///
/// * `k` - Step size
/// * `time` - Time at which step occurs
/// * `size` - Output size
pub fn step_vec<T>(k: T, time: usize, size: usize) -> impl Fn(usize) -> Vec<T>
where
    T: Clone + Zero,
{
    move |t| {
        if t < time {
            vec![T::zero(); size]
        } else {
            vec![k.clone(); size]
        }
    }
}

/// Impulse function at given time
///
/// # Arguments
///
/// * `k` - Step size
/// * `time` - Impulse time
pub fn impulse<T>(k: T, time: usize) -> impl Fn(usize) -> T
where
    T: Clone + Zero,
{
    move |t| {
        if t == time {
            k.clone()
        } else {
            T::zero()
        }
    }
}

/// Impulse function at given time
///
/// # Arguments
///
/// * `k` - Step size
/// * `time` - Impulse time
/// * `size` - Output size
pub fn impulse_vec<T>(k: T, time: usize, size: usize) -> impl Fn(usize) -> Vec<T>
where
    T: Clone + Zero,
{
    move |t| {
        if t == time {
            vec![k.clone(); size]
        } else {
            vec![T::zero(); size]
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use proptest::prelude::*;

    proptest! {
        #[test]
        fn qc_zero_input(s: usize) {
            assert_relative_eq!(0., zero(1)(s)[0]);
        }
    }

    proptest! {
        #[test]
        fn qc_step_single_input(s: f32) {
            let f = step(s, 2);
            assert_relative_eq!(0., f(1));
            assert_relative_eq!(s, f(2));
        }
    }

    proptest! {
        #[test]
        fn qc_step_input(s: usize) {
            let f = step_vec(3., 1, 1);
            if s == 0 {
                assert_relative_eq!(0., f(s)[0]);
            } else {
                assert_relative_eq!(3., f(s)[0]);
            }
        }
    }

    #[test]
    fn step_input_at_zero() {
        let f = step_vec(3., 1, 1);
        assert_relative_eq!(0., f(0)[0]);
    }

    proptest! {
        #[test]
        fn qc_impulse_single_input(i: f32) {
            let f = impulse(i, 2);
            assert_relative_eq!(0., f(1));
            assert_relative_eq!(i, f(2));
        }
    }

    #[test]
    fn impulse_input() {
        let mut out: Vec<_> = (0..20).map(|t| impulse_vec(10., 15, 1)(t)[0]).collect();
        assert_relative_eq!(10., out[15]);
        out.remove(15);
        assert!(out.iter().all(|&o| o == 0.));
    }
}