use std::ops::{Mul, Sub};
use crate::{
units::{RadiansPerSecond, Seconds},
Sin, Zero,
};
pub fn zero<T>(size: usize) -> impl Fn(Seconds<T>) -> Vec<T>
where
T: Clone + Zero,
{
move |_| vec![T::zero(); size]
}
pub fn impulse<T>(k: T, o: Seconds<T>, size: usize) -> impl Fn(Seconds<T>) -> Vec<T>
where
T: Clone + PartialEq + Zero,
{
move |t| {
if t == o {
vec![k.clone(); size]
} else {
vec![T::zero(); size]
}
}
}
pub fn step<T>(k: T, size: usize) -> impl Fn(Seconds<T>) -> Vec<T>
where
T: Clone,
{
move |_| vec![k.clone(); size]
}
pub fn sin_siso<T>(a: T, omega: RadiansPerSecond<T>, phi: T) -> impl Fn(Seconds<T>) -> Vec<T>
where
T: Clone + Mul<Output = T> + Sin + Sub<Output = T>,
{
move |t| vec![a.clone() * (omega.0.clone() * t.0 - phi.clone()).sin()]
}
#[cfg(test)]
mod tests {
use super::*;
use proptest::prelude::*;
use std::f64::consts::PI;
proptest! {
#[test]
fn qc_zero_input(s: f64) {
assert_relative_eq!(0., zero(1)(Seconds(s))[0]);
}
}
#[test]
fn impulse_input() {
let imp = impulse(10., Seconds(1.), 1);
assert_relative_eq!(0., imp(Seconds(0.5))[0]);
assert_relative_eq!(10., imp(Seconds(1.))[0]);
}
proptest! {
#[test]
fn qc_step_input(s: f64) {
assert_relative_eq!(3., step(3., 1)(Seconds(s))[0]);
}
}
proptest! {
#[test]
fn qc_sin_input(t in (0.0..100.0)) {
let sine = sin_siso(1., RadiansPerSecond(0.5), 0.)(Seconds(t))[0];
let traslated_sine = sin_siso(1., RadiansPerSecond(0.5), PI)(Seconds(t))[0];
assert_relative_eq!(sine, -traslated_sine, max_relative = 1e-9);
}
}
#[test]
fn sin_input_regression() {
let t = -81.681_343_796_796_53;
let sine = sin_siso(1., RadiansPerSecond(0.5), 0.)(Seconds(t))[0];
let traslated_sine = sin_siso(1., RadiansPerSecond(0.5), PI)(Seconds(t))[0];
assert_relative_eq!(sine, -traslated_sine, max_relative = 1e-9);
}
}