use super::TimeDomain;
use crate::{Continuous, PartialFraction, PoleTerm, TransferFunction};
use num_complex::Complex;
use num_traits::{Float, Zero};
use std::ops::AddAssign;
impl<T: Float + AddAssign> TransferFunction<T, Continuous> {
pub fn inverse_laplace(&self) -> impl Fn(T) -> T + use<T>
where
T: 'static,
{
self.partial_fraction().time_function()
}
}
impl<T: Float> PartialFraction<T> {
pub fn time_response(&self, t: T) -> T {
if t < T::zero() {
return T::zero();
}
eval_terms(&self.terms, t)
}
pub fn time_function(&self) -> impl Fn(T) -> T + use<T>
where
T: 'static,
{
let expr = self.time_expression();
move |t| if t < T::zero() { T::zero() } else { expr.eval(t) }
}
pub fn time_domain(&self) -> TimeDomain<T> {
TimeDomain::from(self.time_expression())
}
}
pub(super) fn eval_terms<T: Float>(terms: &[PoleTerm<T>], t: T) -> T {
let mut sum = Complex::zero();
for term in terms {
let exp_pt = (term.pole * t).exp();
let mut basis = T::one();
for (k, &r) in term.residues.iter().enumerate() {
if k > 0 {
basis = basis * t / T::from(k).unwrap();
}
sum = sum + r * exp_pt * basis;
}
}
sum.re
}