au/signals/
mod.rs

1//! Collection of commons input signals.
2
3pub mod continuous {
4    //! Collection of continuous signals.
5    use crate::units::{RadiansPerSecond, Seconds};
6    use num_traits::Float;
7
8    /// Zero input function
9    ///
10    /// # Arguments
11    ///
12    /// * `size` - Output size
13    pub fn zero<T: Float>(size: usize) -> impl Fn(Seconds<T>) -> Vec<T> {
14        move |_| vec![T::zero(); size]
15    }
16
17    /// Impulse function
18    ///
19    /// # Arguments
20    ///
21    /// * `k` - Impulse size
22    /// * `o` - Impulse time
23    /// * `size` - Output size
24    pub fn impulse<T: Float>(k: T, o: Seconds<T>, size: usize) -> impl Fn(Seconds<T>) -> Vec<T> {
25        move |t| {
26            if t == o {
27                vec![k; size]
28            } else {
29                vec![T::zero(); size]
30            }
31        }
32    }
33
34    /// Step function
35    ///
36    /// # Arguments
37    ///
38    /// * `k` - Step size
39    /// * `size` - Output size
40    pub fn step<T: Float>(k: T, size: usize) -> impl Fn(Seconds<T>) -> Vec<T> {
41        move |_| vec![k; size]
42    }
43
44    /// Sine input (single input single output).
45    ///
46    /// `sin(omega*t - phase)`
47    ///
48    /// # Arguments
49    ///
50    /// * `a` - sine amplitude
51    /// * `omega` - sine pulse in radians per second
52    /// * `phi` - sine phase in radians
53    pub fn sin_siso<T: Float>(
54        a: T,
55        omega: RadiansPerSecond<T>,
56        phi: T,
57    ) -> impl Fn(Seconds<T>) -> Vec<T> {
58        move |t| vec![a * T::sin(omega.0 * t.0 - phi)]
59    }
60
61    #[cfg(test)]
62    mod tests {
63        use super::*;
64        use proptest::prelude::*;
65        use std::f64::consts::PI;
66
67        proptest! {
68            #[test]
69            fn qc_zero_input(s: f64) {
70                assert_relative_eq!(0., zero(1)(Seconds(s))[0]);
71            }
72        }
73
74        #[test]
75        fn impulse_input() {
76            let imp = impulse(10., Seconds(1.), 1);
77            assert_relative_eq!(0., imp(Seconds(0.5))[0]);
78            assert_relative_eq!(10., imp(Seconds(1.))[0]);
79        }
80
81        proptest! {
82            #[test]
83            fn qc_step_input(s: f64) {
84                assert_relative_eq!(3., step(3., 1)(Seconds(s))[0]);
85            }
86        }
87
88        proptest! {
89            #[test]
90            fn qc_sin_input(t in (0.0..100.0)) {
91                // Reduce the maximum input since sine may have convergence
92                // issues with big numbers.
93                let sine = sin_siso(1., RadiansPerSecond(0.5), 0.)(Seconds(t))[0];
94                let traslated_sine = sin_siso(1., RadiansPerSecond(0.5), PI)(Seconds(t))[0];
95                assert_relative_eq!(sine, -traslated_sine, max_relative = 1e-9)
96            }
97        }
98
99        #[test]
100        fn sin_input_regression() {
101            // The following t value fails if the max_relative error is 1e-10.
102            let t = -81.681_343_796_796_53;
103            let sine = sin_siso(1., RadiansPerSecond(0.5), 0.)(Seconds(t))[0];
104            let traslated_sine = sin_siso(1., RadiansPerSecond(0.5), PI)(Seconds(t))[0];
105            assert_relative_eq!(sine, -traslated_sine, max_relative = 1e-9);
106        }
107    }
108}
109
110pub mod discrete {
111    //! Collection of discrete signals.
112    use num_traits::Float;
113
114    /// Zero input function
115    ///
116    /// # Arguments
117    ///
118    /// * `size` - Output size
119    pub fn zero<T: Float>(size: usize) -> impl Fn(usize) -> Vec<T> {
120        move |_| vec![T::zero(); size]
121    }
122
123    /// Step function
124    ///
125    /// # Arguments
126    ///
127    /// * `k` - Step size
128    /// * `time` - Time at which step occurs
129    pub fn step<T: Float>(k: T, time: usize) -> impl Fn(usize) -> T {
130        move |t| {
131            if t < time {
132                T::zero()
133            } else {
134                k
135            }
136        }
137    }
138
139    /// Step function
140    ///
141    /// # Arguments
142    ///
143    /// * `k` - Step size
144    /// * `time` - Time at which step occurs
145    /// * `size` - Output size
146    pub fn step_vec<T: Float>(k: T, time: usize, size: usize) -> impl Fn(usize) -> Vec<T> {
147        move |t| {
148            if t < time {
149                vec![T::zero(); size]
150            } else {
151                vec![k; size]
152            }
153        }
154    }
155
156    /// Impulse function at given time
157    ///
158    /// # Arguments
159    ///
160    /// * `k` - Step size
161    /// * `time` - Impulse time
162    pub fn impulse<T: Float>(k: T, time: usize) -> impl Fn(usize) -> T {
163        move |t| {
164            if t == time {
165                k
166            } else {
167                T::zero()
168            }
169        }
170    }
171
172    /// Impulse function at given time
173    ///
174    /// # Arguments
175    ///
176    /// * `k` - Step size
177    /// * `time` - Impulse time
178    /// * `size` - Output size
179    pub fn impulse_vec<T: Float>(k: T, time: usize, size: usize) -> impl Fn(usize) -> Vec<T> {
180        move |t| {
181            if t == time {
182                vec![k; size]
183            } else {
184                vec![T::zero(); size]
185            }
186        }
187    }
188
189    #[cfg(test)]
190    mod tests {
191        use super::*;
192        use proptest::prelude::*;
193
194        proptest! {
195            #[test]
196            fn qc_zero_input(s: usize) {
197                assert_relative_eq!(0., zero(1)(s)[0]);
198            }
199        }
200
201        proptest! {
202            #[test]
203            fn qc_step_single_input(s: f32) {
204                let f = step(s, 2);
205                assert_relative_eq!(0., f(1));
206                assert_relative_eq!(s, f(2));
207            }
208        }
209
210        proptest! {
211            #[test]
212            fn qc_step_input(s: usize) {
213                let f = step_vec(3., 1, 1);
214                if s == 0 {
215                    assert_relative_eq!(0., f(s)[0]);
216                } else {
217                    assert_relative_eq!(3., f(s)[0]);
218                }
219            }
220        }
221
222        #[test]
223        fn step_input_at_zero() {
224            let f = step_vec(3., 1, 1);
225            assert_relative_eq!(0., f(0)[0]);
226        }
227
228        proptest! {
229            #[test]
230            fn qc_impulse_single_input(i: f32) {
231                let f = impulse(i, 2);
232                assert_relative_eq!(0., f(1));
233                assert_relative_eq!(i, f(2));
234            }
235        }
236
237        #[test]
238        fn impulse_input() {
239            let mut out: Vec<_> = (0..20).map(|t| impulse_vec(10., 15, 1)(t)[0]).collect();
240            assert_relative_eq!(10., out[15]);
241            out.remove(15);
242            assert!(out.iter().all(|&o| o == 0.))
243        }
244    }
245}