use std::ops::AddAssign;
use nalgebra::{DVector, Scalar};
use num_traits::Float;
use crate::{Discrete, TransferFunction};
#[derive(Clone, Debug)]
pub struct Arx<T> {
pub u: DVector<T>,
pub x: DVector<T>,
pub parameter: DVector<T>,
input_order: usize,
state_order: usize,
input_delay: usize,
}
impl<T: Float + AddAssign + Scalar> Arx<T> {
pub fn new(input_order: usize, state_order: usize) -> Self {
Self {
u: DVector::zeros(input_order + 1),
x: DVector::zeros(state_order),
parameter: DVector::zeros(input_order + state_order + 1),
input_order,
state_order,
input_delay: 0,
}
}
pub fn with_input_delay(mut self, input_delay: usize) -> Self {
self.input_delay = input_delay;
self.u = DVector::zeros(input_delay + self.input_order + 1);
self
}
pub fn input_order(&self) -> usize {
self.input_order
}
pub fn state_order(&self) -> usize {
self.state_order
}
pub fn input_delay(&self) -> usize {
self.input_delay
}
pub fn parameter_len(&self) -> usize {
self.state_order + self.input_order + 1
}
pub fn clear_history(&mut self) {
self.u.fill(T::zero());
self.x.fill(T::zero());
}
pub fn push(&mut self, u: T, x: T) {
for i in (1..self.u.len()).rev() {
self.u[i] = self.u[i - 1]
}
self.u[0] = u;
for i in (1..self.state_order).rev() {
self.x[i] = self.x[i - 1]
}
if self.state_order > 0 {
self.x[0] = x;
}
}
pub fn regressor(&self) -> DVector<T> {
let mut phi = DVector::zeros(self.parameter_len());
for i in 0..self.state_order {
phi[i] = self.x[i]
}
for i in 0..(self.input_order + 1) {
phi[i + self.state_order] = self.u[i + self.input_delay]
}
phi
}
pub fn predict(&self) -> T {
self.regressor().iter().zip(self.parameter.iter()).fold(T::zero(), |acc, (&p, &t)| acc + p * t)
}
pub fn transfer_function(&self) -> TransferFunction<T, Discrete> {
let (a, b) = self.parameter.as_slice().split_at(self.state_order);
let order = a.len().max(self.input_delay + b.len().saturating_sub(1));
let mut denom = Vec::with_capacity(order + 1);
denom.push(T::one());
denom.extend(a.iter().map(|&ai| -ai));
denom.resize(order + 1, T::zero());
let mut numer = vec![T::zero(); self.input_delay];
numer.extend_from_slice(b);
numer.resize(order + 1, T::zero());
TransferFunction::discrete(&numer, &denom)
}
}