use num::{Float, NumCast};
use array_matrix::*;
pub struct StateSpace<F: Float, const VARCOUNT: usize>
where
[[F; VARCOUNT]; VARCOUNT]: SquareMatrix,
[[F; 1]; VARCOUNT]: Matrix,
[[F; VARCOUNT]; 1]: Matrix
{
pub a: [[F; VARCOUNT]; VARCOUNT],
pub b: [[F; 1]; VARCOUNT],
pub c: [[F; VARCOUNT]; 1],
pub d: F
}
impl<F: Float, const VARCOUNT: usize> StateSpace<F, VARCOUNT>
where
[[F; VARCOUNT]; VARCOUNT]: SquareMatrix,
[[F; 1]; VARCOUNT]: Matrix,
[[F; VARCOUNT]; 1]: Matrix
{
pub fn new_control_canonical_form(a: [F; VARCOUNT], b: [F; VARCOUNT]) -> Self
{
Self {
a: array_init::array_init(|r| if r == 0 {
a.map(|ai| -ai)
} else {
array_init::array_init(|c| if r == c + 1 {F::one()} else {F::zero()})
}),
b: array_init::array_init(|r| if r == 0 {[F::one()]} else {[F::zero()]}),
c: [b],
d: F::zero()
}
}
pub fn new_observer_canonical_form(a: [F; VARCOUNT], b: [F; VARCOUNT]) -> Self
{
Self {
a: array_init::array_init(|r| if r == 0 {
a.map(|ai| -ai)
} else {
array_init::array_init(|c| if r == c + 1 {F::one()} else {F::zero()})
}).transpose(),
b: [b].transpose(),
c: [array_init::array_init(|r| if r == 0 {F::one()} else {F::zero()})],
d: F::zero()
}
}
pub fn controllability(&self) -> [[F; VARCOUNT]; VARCOUNT]
{
array_init::array_init(|n| {
let mut b: [[F; 1]; VARCOUNT] = self.b;
for _ in 0..n
{
b = self.a.mul(b);
}
b.transpose()[0]
}).transpose()
}
pub fn is_controllable(&self) -> bool
where
[[F; VARCOUNT]; VARCOUNT]: Det<Output = F>
{
!self.controllability().det().is_zero()
}
pub fn observability(&self) -> [[F; VARCOUNT]; VARCOUNT]
{
array_init::array_init(|n| {
let mut c: [[F; VARCOUNT]; 1] = self.c;
for _ in 0..n
{
c = c.mul(self.a);
}
c[0]
})
}
pub fn is_observable(&self) -> bool
where
[[F; VARCOUNT]; VARCOUNT]: Det<Output = F>
{
!self.observability().det().is_zero()
}
pub fn transform_state(&self, t: [[F; VARCOUNT]; VARCOUNT]) -> Option<Self>
where [[F; VARCOUNT]; VARCOUNT]: MInv<Output = [[F; VARCOUNT]; VARCOUNT]>
{
t.inv().map(|t_| Self {
a: t_.mul(self.a).mul(t),
b: t_.mul(self.b),
c: self.c.mul(t),
d: self.d
})
}
pub fn transform_into_control_canonical_form(&self) -> Option<Self>
where [[F; VARCOUNT]; VARCOUNT]: MInv<Output = [[F; VARCOUNT]; VARCOUNT]>
{
self.controllability().inv().map(|cc_| {
let tn = [array_init::array_init(|c| if c == 0 {F::one()} else {F::zero()})].mul(cc_);
let mut tna = tn;
let mut t = array_init::array_init(|_| {
let tn = tna;
tna = tna.mul(self.a);
tn[0]
});
t.reverse();
return self.transform_state(t)
}).flatten()
}
pub fn transform_into_observer_canonical_form(&self) -> Option<Self>
where [[F; VARCOUNT]; VARCOUNT]: MInv<Output = [[F; VARCOUNT]; VARCOUNT]>
{
self.transform_into_control_canonical_form().map(|ccf| Self {
a: ccf.a.transpose(),
b: ccf.c.transpose(),
c: ccf.b.transpose(),
d: ccf.d
})
}
pub fn dxdt(&self, x: [[F; 1]; VARCOUNT], u: F) -> [[F; 1]; VARCOUNT]
{
self.a.mul(x).add(self.b.mul(u))
}
pub fn y(&self, x: [[F; 1]; VARCOUNT], u: F) -> F
{
self.c.mul(x)[0][0] + self.d*u
}
}