mod ekf;
#[cfg(feature = "alloc")]
mod ukf;
mod cholupdate;
#[cfg(feature = "alloc")]
mod srukf;
#[cfg(feature = "alloc")]
mod ckf;
#[cfg(feature = "alloc")]
mod rts;
mod batch;
#[cfg(test)]
mod tests;
pub use ekf::Ekf;
#[cfg(feature = "alloc")]
pub use ukf::Ukf;
#[cfg(feature = "alloc")]
pub use srukf::SrUkf;
#[cfg(feature = "alloc")]
pub use ckf::Ckf;
#[cfg(feature = "alloc")]
pub use rts::{EkfStep, rts_smooth};
pub use batch::BatchLsq;
use crate::linalg::CholeskyDecomposition;
use crate::matrix::vector::Vector;
use crate::traits::FloatScalar;
use crate::Matrix;
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum EstimateError {
CovarianceNotPD,
SingularInnovation,
CholdowndateFailed,
}
impl core::fmt::Display for EstimateError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
EstimateError::CovarianceNotPD => {
write!(f, "covariance matrix is not positive definite")
}
EstimateError::SingularInnovation => {
write!(f, "innovation covariance is singular")
}
EstimateError::CholdowndateFailed => {
write!(f, "Cholesky downdate failed: result not positive definite")
}
}
}
}
pub(crate) fn cholesky_with_jitter<T: FloatScalar, const N: usize>(
p: &Matrix<T, N, N>,
) -> Result<CholeskyDecomposition<T, N>, EstimateError> {
if let Ok(c) = CholeskyDecomposition::new(p) {
return Ok(c);
}
for exp in [9u32, 7, 5] {
let eps = T::from(10.0f64.powi(-(exp as i32))).unwrap();
let mut pj = *p;
for i in 0..N {
pj[(i, i)] = pj[(i, i)] + eps;
}
if let Ok(c) = CholeskyDecomposition::new(&pj) {
return Ok(c);
}
}
Err(EstimateError::CovarianceNotPD)
}
pub(crate) fn apply_var_floor<T: FloatScalar, const N: usize>(
p: &mut Matrix<T, N, N>,
min_var: T,
) {
if min_var > T::zero() {
for i in 0..N {
if p[(i, i)] < min_var {
p[(i, i)] = min_var;
}
}
}
}
pub(crate) fn fd_jacobian<T: FloatScalar, const N: usize, const M: usize>(
f: &impl Fn(&Vector<T, N>) -> Vector<T, M>,
x: &Vector<T, N>,
) -> Matrix<T, M, N> {
let sqrt_eps = T::epsilon().sqrt();
let f0 = f(x);
let mut jac = Matrix::<T, M, N>::zeros();
for j in 0..N {
let xj = x[j];
let h = sqrt_eps * xj.abs().max(T::one());
let mut x_pert = *x;
x_pert[j] = xj + h;
let f_pert = f(&x_pert);
for i in 0..M {
jac[(i, j)] = (f_pert[i] - f0[i]) / h;
}
}
jac
}