pub mod continuous {
use crate::units::{RadiansPerSecond, Seconds};
use num_traits::Float;
pub fn zero<T: Float>(size: usize) -> impl Fn(Seconds<T>) -> Vec<T> {
move |_| vec![T::zero(); size]
}
pub fn impulse<T: Float>(k: T, o: Seconds<T>, size: usize) -> impl Fn(Seconds<T>) -> Vec<T> {
move |t| {
if t == o {
vec![k; size]
} else {
vec![T::zero(); size]
}
}
}
pub fn step<T: Float>(k: T, size: usize) -> impl Fn(Seconds<T>) -> Vec<T> {
move |_| vec![k; size]
}
pub fn sin_siso<T: Float>(
a: T,
omega: RadiansPerSecond<T>,
phi: T,
) -> impl Fn(Seconds<T>) -> Vec<T> {
move |t| vec![a * T::sin(omega.0 * t.0 - phi)]
}
#[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);
}
}
}
pub mod discrete {
use num_traits::Float;
pub fn zero<T: Float>(size: usize) -> impl Fn(usize) -> Vec<T> {
move |_| vec![T::zero(); size]
}
pub fn step<T: Float>(k: T, time: usize) -> impl Fn(usize) -> T {
move |t| {
if t < time {
T::zero()
} else {
k
}
}
}
pub fn step_vec<T: Float>(k: T, time: usize, size: usize) -> impl Fn(usize) -> Vec<T> {
move |t| {
if t < time {
vec![T::zero(); size]
} else {
vec![k; size]
}
}
}
pub fn impulse<T: Float>(k: T, time: usize) -> impl Fn(usize) -> T {
move |t| {
if t == time {
k
} else {
T::zero()
}
}
}
pub fn impulse_vec<T: Float>(k: T, time: usize, size: usize) -> impl Fn(usize) -> Vec<T> {
move |t| {
if t == time {
vec![k; 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.))
}
}
}