use nalgebra::{ComplexField, DMatrix, RealField};
use num_traits::Float;
use super::Method;
use crate::{Continuous, Discrete, StateSpace, StateSpaceError, TransferFunction};
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct Zoh;
impl<T: Float + ComplexField + RealField> Method<T, StateSpace<T, Continuous>> for Zoh {
type Output = StateSpace<T, Discrete>;
type Error = StateSpaceError;
fn apply(&self, system: &StateSpace<T, Continuous>, ts: T) -> Result<Self::Output, Self::Error> {
let (a, b) = {
let n = system.order.system;
let m = system.order.input;
let mut aug = DMatrix::<T>::zeros(n + m, n + m);
aug.view_mut((0, 0), (n, n)).copy_from(&system.a);
aug.view_mut((0, n), (n, m)).copy_from(&system.b);
let aug_exp = aug.scale(ts).exp();
let a = aug_exp.view((0, 0), (n, n)).into_owned();
let b = aug_exp.view((0, n), (n, m)).into_owned();
(a, b)
};
StateSpace::new(a, b, system.c.clone(), system.d.clone())
}
}
impl<T: Float + ComplexField + RealField> Method<T, TransferFunction<T, Continuous>> for Zoh {
type Output = TransferFunction<T, Discrete>;
type Error = StateSpaceError;
fn apply(&self, tf: &TransferFunction<T, Continuous>, ts: T) -> Result<Self::Output, Self::Error> {
match StateSpace::controllable_canonical(tf) {
Ok(ssr) => self.apply(&ssr, ts)?.transfer_function(),
Err(StateSpaceError::EmptySystem) => {
Ok(TransferFunction::from_polynomials(tf.numerator.clone(), tf.denominator.clone()))
}
Err(e) => Err(e),
}
}
}