pub mod bilinear_transform;
pub mod matched_z_transform;
pub mod zoh;
pub(crate) mod state_variable_filter;
pub use bilinear_transform::Tustin;
pub use matched_z_transform::{MatchedZ, ZerosAtInfinity};
use serde::Serialize;
pub use state_variable_filter::InterSample;
pub use zoh::Zoh;
pub use matched_z_transform::MatchedZError;
use std::convert::Infallible;
use thiserror::Error;
use crate::{Continuous, StateSpace, StateSpaceError, TransferFunction, TransferFunctionWithDelay};
pub trait Method<T, S> {
type Output;
type Error;
fn apply(&self, system: &S, ts: T) -> Result<Self::Output, Self::Error>;
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)]
pub enum DiscretizeMethod {
Zoh,
Tustin,
MatchedZ(ZerosAtInfinity),
}
#[derive(Clone, Debug, Error, PartialEq)]
pub enum DiscretizeError {
#[error(transparent)]
StateSpace(#[from] StateSpaceError),
#[error(transparent)]
MatchedZ(#[from] MatchedZError),
}
impl From<Infallible> for DiscretizeError {
fn from(never: Infallible) -> Self {
match never {}
}
}
impl<T, S, O> Method<T, S> for DiscretizeMethod
where
Zoh: Method<T, S, Output = O>,
Tustin: Method<T, S, Output = O>,
MatchedZ: Method<T, S, Output = O>,
DiscretizeError: From<<Zoh as Method<T, S>>::Error> + From<<Tustin as Method<T, S>>::Error> + From<<MatchedZ as Method<T, S>>::Error>,
{
type Output = O;
type Error = DiscretizeError;
fn apply(&self, system: &S, ts: T) -> Result<O, DiscretizeError> {
match *self {
Self::Zoh => Ok(Zoh.apply(system, ts)?),
Self::Tustin => Ok(Tustin.apply(system, ts)?),
Self::MatchedZ(zeros_at_infinity) => Ok(MatchedZ(zeros_at_infinity).apply(system, ts)?),
}
}
}
impl<T> TransferFunction<T, Continuous> {
pub fn discretize<M: Method<T, Self>>(&self, method: M, ts: T) -> Result<M::Output, M::Error> {
method.apply(self, ts)
}
}
impl<T> StateSpace<T, Continuous> {
pub fn discretize<M: Method<T, Self>>(&self, method: M, ts: T) -> Result<M::Output, M::Error> {
method.apply(self, ts)
}
}
impl<T> TransferFunctionWithDelay<T> {
pub fn discretize<M: Method<T, Self>>(&self, method: M, ts: T) -> Result<M::Output, M::Error> {
method.apply(self, ts)
}
}