extern crate nalgebra as na;
use na::*;
use nalgebra::{
base::allocator::Allocator, DefaultAllocator, Dim, DimName, DimNameAdd, MatrixMN, RealField,
Scalar,
};
use rand::prelude::*;
use std::ops::Add;
extern crate docify;
use nalgebra;
use nalgebra::DimMinimum;
pub struct Kalman {
pub x_hat: Matrix2x1<f64>, pub F: Matrix2<f64>, pub H: Matrix1x2<f64>, pub B: Matrix2<f64>, pub K: Matrix2x1<f64>, pub Q: Matrix2<f64>, pub R: Matrix1<f64>, pub P: Matrix2<f64>, }
#[doc = docify::embed!("src/robotics/kalman.rs", test_kalman)]
impl Kalman {
pub fn predict(&mut self, u: Matrix2x1<f64>) {
self.x_hat = self.F * self.x_hat + self.B * u;
self.P = self.F * self.P * self.F.transpose() + self.Q;
}
pub fn update(&mut self, z: f64) {
let _inv = self.H * self.P * self.H.transpose() + self.R;
let inv = _inv.try_inverse().unwrap();
self.K = self.P * self.H.transpose() * inv;
let y = self.H * self.x_hat; let dif = z - y[(0, 0)];
self.x_hat = self.x_hat + self.K * dif;
let eye = Matrix2::<f64>::identity();
self.P = (eye - self.K * self.H) * self.P;
}
}
#[test]
#[docify::export]
fn test_kalman() {
let F = Matrix2::new(1., 0., 1., 1.);
let B = Matrix2::new(1., 0., 1., 1.);
let H = Matrix1x2::new(1., 0.);
let Q = Matrix2::<f64>::identity() * 0.01;
let R = Matrix1::new(0.1);
let x_hat = Matrix2x1::<f64>::zeros();
let P = Matrix2::<f64>::identity() * 0.1;
let u = Matrix2x1::<f64>::zeros();
let k = Matrix2x1::<f64>::zeros();
let mut kal = Kalman {
x_hat: x_hat,
F: F,
H: H,
B: B,
K: k,
Q: Q,
R: R,
P: P,
};
let mut rng = rand::thread_rng();
let true_state: Vec<f64> = (0..100).map(|_| rng.gen::<f64>() / 10.0).collect();
let measurements: Vec<f64> = true_state
.iter()
.map(|v| v + rng.gen::<f64>() / 10.0)
.collect();
for z in measurements {
&kal.predict(u);
&kal.update(z);
}
}