#![forbid(unsafe_code)]
#[cfg(feature = "std")]
#[allow(unused)]
use colored::Colorize;
use lazy_static::lazy_static;
use minikalman::regular::builder::KalmanFilterBuilder;
use minikalman::prelude::*;
const NUM_STATES: usize = 3;
const NUM_OBSERVATIONS: usize = 1;
lazy_static! {
static ref REAL_DISTANCE: [I16F16; 15] = [
I16F16::from_num(0.0),
I16F16::from_num(4.905),
I16F16::from_num(19.62),
I16F16::from_num(44.145),
I16F16::from_num(78.48),
I16F16::from_num(122.63),
I16F16::from_num(176.58),
I16F16::from_num(240.35),
I16F16::from_num(313.92),
I16F16::from_num(397.31),
I16F16::from_num(490.5),
I16F16::from_num(593.51),
I16F16::from_num(706.32),
I16F16::from_num(828.94),
I16F16::from_num(961.38),
];
static ref OBSERVATION_ERROR: [I16F16; 15] = [
I16F16::from_num(0.13442),
I16F16::from_num(0.45847),
I16F16::from_num(-0.56471),
I16F16::from_num(0.21554),
I16F16::from_num(0.079691),
I16F16::from_num(-0.32692),
I16F16::from_num(-0.1084),
I16F16::from_num(0.085656),
I16F16::from_num(0.8946),
I16F16::from_num(0.69236),
I16F16::from_num(-0.33747),
I16F16::from_num(0.75873),
I16F16::from_num(0.18135),
I16F16::from_num(-0.015764),
I16F16::from_num(0.17869),
];
}
#[allow(non_snake_case)]
fn main() {
let builder = KalmanFilterBuilder::<NUM_STATES, I16F16>::default();
let mut filter = builder.build();
let mut measurement = builder.observations().build::<NUM_OBSERVATIONS>();
initialize_state_vector(filter.state_vector_mut());
initialize_state_transition_matrix(filter.state_transition_mut());
initialize_state_covariance_matrix(filter.estimate_covariance_mut());
initialize_position_measurement_transformation_matrix(measurement.observation_matrix_mut());
initialize_position_measurement_process_noise_matrix(
measurement.measurement_noise_covariance_mut(),
);
for t in 0..REAL_DISTANCE.len() {
filter.predict();
print_state_prediction(t, filter.state_vector());
let m = REAL_DISTANCE[t] + OBSERVATION_ERROR[t];
measurement.measurement_vector_mut().apply(|z| z[0] = m);
print_measurement(t);
filter.correct(&mut measurement);
print_state_correction(t, filter.state_vector());
}
let gravity_x = filter.state_vector();
let g_estimated = gravity_x[2];
assert!(g_estimated > 9.0 && g_estimated < 10.0);
}
fn initialize_state_vector(filter: &mut impl StateVectorMut<NUM_STATES, I16F16>) {
filter.as_matrix_mut().apply(|state| {
state[0] = I16F16::ZERO; state[1] = I16F16::ZERO; state[2] = I16F16::from_num(6.0); });
}
fn initialize_state_transition_matrix(
filter: &mut impl StateTransitionMatrixMut<NUM_STATES, I16F16>,
) {
filter.as_matrix_mut().apply(|a| {
const T: I16F16 = I16F16::ONE;
a.set_at(0, 0, I16F16::ONE); a.set_at(0, 1, T as _); a.set_at(0, 2, I16F16::from_num(0.5) * T * T);
a.set_at(1, 0, I16F16::ZERO); a.set_at(1, 1, I16F16::ONE); a.set_at(1, 2, T as _);
a.set_at(2, 0, I16F16::ZERO); a.set_at(2, 1, I16F16::ZERO); a.set_at(2, 2, I16F16::ONE); });
}
fn initialize_state_covariance_matrix(
filter: &mut impl EstimateCovarianceMatrix<NUM_STATES, I16F16>,
) {
filter.as_matrix_mut().apply(|p| {
p.set_at(0, 0, I16F16::from_num(0.1)); p.set_at(0, 1, I16F16::ZERO); p.set_at(0, 2, I16F16::ZERO);
p.set_at(1, 1, I16F16::ONE); p.set_at(1, 2, I16F16::ZERO);
p.set_at(2, 2, I16F16::ONE); });
}
fn initialize_position_measurement_transformation_matrix(
measurement: &mut impl ObservationMatrixMut<NUM_OBSERVATIONS, NUM_STATES, I16F16>,
) {
measurement.as_matrix_mut().apply(|h| {
h.set_at(0, 0, I16F16::ONE); h.set_at(0, 1, I16F16::ZERO); h.set_at(0, 2, I16F16::ZERO); });
}
fn initialize_position_measurement_process_noise_matrix(
measurement: &mut impl MeasurementNoiseCovarianceMatrix<NUM_OBSERVATIONS, I16F16>,
) {
measurement.as_matrix_mut().apply(|r| {
r.set_at(0, 0, I16F16::from_num(0.5)); });
}
#[allow(unused)]
fn print_state_prediction<T>(t: usize, x: T)
where
T: AsRef<[I16F16]>,
{
let x = x.as_ref();
#[cfg(feature = "std")]
println!(
"At t = {}, predicted state: s = {}, v = {}, a = {}",
format!("{}", t).bright_white(),
format!("{} m", x[0]).magenta(),
format!("{} m/s", x[1]).magenta(),
format!("{} m/s²", x[2]).magenta(),
);
}
#[allow(unused)]
fn print_state_correction<T>(t: usize, x: T)
where
T: AsRef<[I16F16]>,
{
let x = x.as_ref();
#[cfg(feature = "std")]
println!(
"At t = {}, corrected state: s = {}, v = {}, a = {}",
format!("{}", t).bright_white(),
format!("{} m", x[0]).yellow(),
format!("{} m/s", x[1]).yellow(),
format!("{} m/s²", x[2]).yellow(),
);
}
#[allow(unused)]
fn print_measurement(t: usize) {
#[cfg(feature = "std")]
println!(
"At t = {}, measurement: s = {}, noise ε = {}",
format!("{}", t).bright_white(),
format!("{} m", REAL_DISTANCE[t]).green(),
format!("{} m", OBSERVATION_ERROR[t]).blue()
);
}