use nalgebra::Matrix2;
use num_complex::Complex;
use std::fmt;
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone, Default, PartialEq)]
pub struct Exponential {
pub tau: f64,
q: (f64, f64, f64, f64),
m: (f64, f64),
b: Vec<f64>,
c: Vec<f64>,
pub y: Vec<f64>,
x: (f64, f64),
}
impl Exponential {
pub fn n_inputs(&self) -> usize {
self.b.len()
}
pub fn n_outputs(&self) -> usize {
self.c.len()
}
}
impl super::Solver for Exponential {
fn from_second_order(
tau: f64,
omega: f64,
zeta: f64,
continuous_bb: Vec<f64>,
continuous_cc: Vec<f64>,
) -> Self {
let i = Matrix2::<f64>::identity();
let n = continuous_cc.len();
if omega == 0f64 {
Self {
tau,
q: (1f64, tau, 0f64, 1f64),
m: (0.5 * tau * tau, tau),
b: continuous_bb,
c: continuous_cc,
y: vec![0.; n],
x: (0f64, 0f64),
}
} else {
let x = Complex { re: omega, im: 0. };
let y = Complex { re: zeta, im: 0. };
let ia = Matrix2::new((-2. * y / x).re, -1. / (x * x).re, 1., 0.);
let z = (x * x * (y * y - 1.)).sqrt();
let zmxy = z - x * y;
let zpxy = z + x * y;
let ezmxy = (tau * zmxy).exp();
let ezpxy = (-tau * zpxy).exp();
let ad = Matrix2::new(
((zpxy * ezmxy + zmxy * ezpxy) / (2. * z)).re,
((ezmxy - ezpxy) / (2. * z)).re,
(x * x * (ezpxy - ezmxy) / (2. * z)).re,
((zmxy * ezmxy + zpxy * ezpxy) / (2. * z)).re,
);
let bd_ = ia * (ad - i); Self {
tau,
q: (ad[0], ad[2], ad[1], ad[3]),
m: (bd_[2], bd_[3]),
b: continuous_bb,
c: continuous_cc,
y: vec![0.; n],
x: (0f64, 0f64),
}
}
}
fn solve(&mut self, u: &[f64]) -> &[f64] {
let (x0, x1) = self.x;
self.y.iter_mut().zip(self.c.iter()).for_each(|(y, c)| {
*y = c * x0;
});
let v = self.b.iter().zip(u).fold(0., |s, (b, u)| s + b * u);
self.x.0 = self.q.0 * x0 + self.q.1 * x1 + self.m.0 * v;
self.x.1 = self.q.2 * x0 + self.q.3 * x1 + self.m.1 * v;
self.y.as_slice()
}
}
impl fmt::Display for Exponential {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"2x2 discrete state space model: {}->{} ({:.3}Hz)\n - A: {:.9?}\n - B: {:.9?}",
self.b.len(),
self.c.len(),
self.tau.recip(),
self.q,
self.m
)
}
}