#![allow(non_snake_case)]
use nalgebra::{allocator::Allocator, DefaultAllocator, Dim, OMatrix, OVector, RealField};
use num_traits::FromPrimitive;
use crate::linalg::rcond;
use crate::matrix::check_non_negativ;
use crate::models::{
Estimator, ExtendedLinearObserver, ExtendedLinearPredictor, KalmanEstimator, KalmanState,
};
use crate::noise::CorrelatedNoise;
impl<N: RealField, D: Dim> Estimator<N, D> for KalmanState<N, D>
where
DefaultAllocator: Allocator<N, D, D> + Allocator<N, D>,
{
fn state(&self) -> Result<OVector<N, D>, &str> {
Ok(self.x.clone())
}
}
impl<N: Copy + FromPrimitive + RealField, D: Dim> KalmanState<N, D>
where
DefaultAllocator: Allocator<N, D, D> + Allocator<N, D>,
{
pub fn try_from(state: KalmanState<N, D>) -> Result<Self, &'static str> {
let rcond = rcond::rcond_symetric(&state.X);
check_non_negativ(rcond, "X not PSD")?;
Ok(state)
}
}
impl<N: Copy + RealField, D: Dim> KalmanEstimator<N, D> for KalmanState<N, D>
where
DefaultAllocator: Allocator<N, D, D> + Allocator<N, D>,
{
fn kalman_state(&self) -> Result<KalmanState<N, D>, &str> {
Ok(self.clone())
}
}
impl<N: RealField, D: Dim> ExtendedLinearPredictor<N, D> for KalmanState<N, D>
where
DefaultAllocator: Allocator<N, D, D> + Allocator<N, D>,
{
fn predict(
&mut self,
x_pred: &OVector<N, D>,
fx: &OMatrix<N, D, D>,
noise: &CorrelatedNoise<N, D>,
) -> Result<(), &str> {
self.x = x_pred.clone();
self.X.quadform_tr(N::one(), &fx, &self.X.clone(), N::zero());
self.X += &noise.Q;
Ok(())
}
}
impl<N: RealField, D: Dim, ZD: Dim> ExtendedLinearObserver<N, D, ZD> for KalmanState<N, D>
where
DefaultAllocator: Allocator<N, D, D>
+ Allocator<N, ZD, ZD>
+ Allocator<N, ZD, D>
+ Allocator<N, D, ZD>
+ Allocator<N, D>
+ Allocator<N, ZD>,
{
fn observe_innovation(
&mut self,
s: &OVector<N, ZD>,
hx: &OMatrix<N, ZD, D>,
noise: &CorrelatedNoise<N, ZD>,
) -> Result<(), &str> {
let mut S = noise.Q.clone();
S.quadform_tr(N::one(), hx, &self.X, N::one());
let SI = S.clone().cholesky().ok_or("S not PD in observe")?.inverse();
let W = &self.X * hx.transpose() * SI;
self.x += &W * s;
self.X.quadform_tr(N::one().neg(), &W, &S, N::one());
Ok(())
}
}