use super::TransferFunction;
use crate::Polynomial;
use num_traits::Float;
use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign};
impl<T: Float + AddAssign, D> Mul for &TransferFunction<T, D> {
type Output = TransferFunction<T, D>;
fn mul(self, rhs: &TransferFunction<T, D>) -> TransferFunction<T, D> {
TransferFunction::from_polynomials(
&self.numerator * &rhs.numerator,
&self.denominator * &rhs.denominator,
)
.reduced()
}
}
impl<T: Float + AddAssign, D> Mul for TransferFunction<T, D> {
type Output = TransferFunction<T, D>;
fn mul(self, rhs: TransferFunction<T, D>) -> TransferFunction<T, D> {
&self * &rhs
}
}
impl<T: Float + AddAssign, D> Div for &TransferFunction<T, D> {
type Output = TransferFunction<T, D>;
fn div(self, rhs: &TransferFunction<T, D>) -> TransferFunction<T, D> {
let rhs_inv = TransferFunction::from_polynomials(rhs.denominator.clone(), rhs.numerator.clone());
self * &rhs_inv
}
}
impl<T: Float + AddAssign, D> Div for TransferFunction<T, D> {
type Output = TransferFunction<T, D>;
fn div(self, rhs: TransferFunction<T, D>) -> TransferFunction<T, D> {
&self / &rhs
}
}
impl<T: Float + AddAssign, D> Add for &TransferFunction<T, D> {
type Output = TransferFunction<T, D>;
fn add(self, rhs: &TransferFunction<T, D>) -> TransferFunction<T, D> {
let n1d2 = &self.numerator * &rhs.denominator;
let n2d1 = &self.denominator * &rhs.numerator;
let numerator = &n1d2 + &n2d1;
let denominator = &self.denominator * &rhs.denominator;
TransferFunction::from_polynomials(numerator, denominator).reduced()
}
}
impl<T: Float + AddAssign, D> Add for TransferFunction<T, D> {
type Output = TransferFunction<T, D>;
fn add(self, rhs: TransferFunction<T, D>) -> TransferFunction<T, D> {
&self + &rhs
}
}
impl<T: Float, D> MulAssign<T> for TransferFunction<T, D> {
fn mul_assign(&mut self, k: T) {
self.numerator.iter_mut().for_each(|c| *c = *c * k);
}
}
impl<T: Float, D> DivAssign<T> for TransferFunction<T, D> {
fn div_assign(&mut self, k: T) {
self.numerator.iter_mut().for_each(|c| *c = *c / k);
}
}
impl<T: Float, D> Mul<T> for TransferFunction<T, D> {
type Output = TransferFunction<T, D>;
fn mul(mut self, k: T) -> TransferFunction<T, D> {
self *= k;
self
}
}
impl<T: Float, D> Mul<T> for &TransferFunction<T, D> {
type Output = TransferFunction<T, D>;
fn mul(self, k: T) -> TransferFunction<T, D> {
TransferFunction::from_polynomials(self.numerator.clone(), self.denominator.clone()) * k
}
}
impl<T: Float, D> Div<T> for TransferFunction<T, D> {
type Output = TransferFunction<T, D>;
fn div(mut self, k: T) -> TransferFunction<T, D> {
self /= k;
self
}
}
impl<T: Float, D> Div<T> for &TransferFunction<T, D> {
type Output = TransferFunction<T, D>;
fn div(self, k: T) -> TransferFunction<T, D> {
TransferFunction::from_polynomials(self.numerator.clone(), self.denominator.clone()) / k
}
}
impl<T: Float + AddAssign, D> TransferFunction<T, D> {
pub fn unity_feedback(&self) -> Self {
TransferFunction::from_polynomials(self.numerator.clone(), &self.denominator + &self.numerator)
}
}
impl<T: Float + AddAssign, D> AddAssign<T> for TransferFunction<T, D> {
fn add_assign(&mut self, k: T) {
let kd = Polynomial(self.denominator.iter().map(|&c| c * k).collect());
self.numerator += &kd;
}
}
impl<T: Float + AddAssign, D> Add<T> for TransferFunction<T, D> {
type Output = TransferFunction<T, D>;
fn add(mut self, k: T) -> TransferFunction<T, D> {
self += k;
self
}
}
impl<T: Float + AddAssign, D> Add<T> for &TransferFunction<T, D> {
type Output = TransferFunction<T, D>;
fn add(self, k: T) -> TransferFunction<T, D> {
TransferFunction::from_polynomials(self.numerator.clone(), self.denominator.clone()) + k
}
}
macro_rules! impl_scalar_lhs_ops {
($($t:ty),*) => {$(
impl<D> Mul<TransferFunction<$t, D>> for $t {
type Output = TransferFunction<$t, D>;
fn mul(self, tf: TransferFunction<$t, D>) -> TransferFunction<$t, D> {
tf * self
}
}
impl<D> Mul<&TransferFunction<$t, D>> for $t {
type Output = TransferFunction<$t, D>;
fn mul(self, tf: &TransferFunction<$t, D>) -> TransferFunction<$t, D> {
tf * self
}
}
impl<D> Add<TransferFunction<$t, D>> for $t {
type Output = TransferFunction<$t, D>;
fn add(self, tf: TransferFunction<$t, D>) -> TransferFunction<$t, D> {
tf + self
}
}
impl<D> Add<&TransferFunction<$t, D>> for $t {
type Output = TransferFunction<$t, D>;
fn add(self, tf: &TransferFunction<$t, D>) -> TransferFunction<$t, D> {
tf + self
}
}
)*};
}
impl_scalar_lhs_ops!(f64);