1pub mod continuous {
4 use crate::units::{RadiansPerSecond, Seconds};
6 use num_traits::Float;
7
8 pub fn zero<T: Float>(size: usize) -> impl Fn(Seconds<T>) -> Vec<T> {
14 move |_| vec![T::zero(); size]
15 }
16
17 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 pub fn step<T: Float>(k: T, size: usize) -> impl Fn(Seconds<T>) -> Vec<T> {
41 move |_| vec![k; size]
42 }
43
44 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 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 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 use num_traits::Float;
113
114 pub fn zero<T: Float>(size: usize) -> impl Fn(usize) -> Vec<T> {
120 move |_| vec![T::zero(); size]
121 }
122
123 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 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 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 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}