Skip to main content

Ekf

Struct Ekf 

Source
pub struct Ekf<T: FloatScalar, const N: usize, const M: usize> {
    pub x: Vector<T, N>,
    pub p: Matrix<T, N, N>,
    /* private fields */
}
Expand description

Extended Kalman Filter with const-generic state and measurement dimensions.

N is the state dimension, M is the measurement dimension. The EKF linearizes nonlinear dynamics and measurement models via user-supplied or finite-difference Jacobians.

All operations are stack-allocated — no heap, fully no-std compatible.

§Robustness features

  • Joseph form covariance update: P = (I-KH)P(I-KH)ᵀ + KRKᵀ
  • Cholesky with jitter: retries with small diagonal ε·I when S is near-singular
  • Covariance floor: set_min_variance clamps P diagonal entries to a minimum
  • Fading memory: set_fading_memory scales predicted covariance by γ≥1
  • Innovation gating: update_gated / update_fd_gated reject outlier measurements
  • Iterated EKF: update_iterated / update_fd_iterated re-linearize at each step

§Example

use numeris::estimate::Ekf;
use numeris::{Vector, Matrix};

// Constant-velocity model: state = [position, velocity]
let x0 = Vector::from_array([0.0_f64, 1.0]);
let p0 = Matrix::new([[1.0, 0.0], [0.0, 1.0]]);
let mut ekf = Ekf::<f64, 2, 1>::new(x0, p0);

let dt = 0.1;
let q = Matrix::new([[0.01, 0.0], [0.0, 0.01]]);
let r = Matrix::new([[0.5]]);

// Predict (with process noise)
ekf.predict(
    |x| Vector::from_array([x[0] + dt * x[1], x[1]]),
    |_x| Matrix::new([[1.0, dt], [0.0, 1.0]]),
    Some(&q),
);

// Update with position measurement
ekf.update(
    &Vector::from_array([0.12]),
    |x| Vector::from_array([x[0]]),
    |_x| Matrix::new([[1.0, 0.0]]),
    &r,
).unwrap();

Fields§

§x: Vector<T, N>

State estimate.

§p: Matrix<T, N, N>

State covariance.

Implementations§

Source§

impl<T: FloatScalar, const N: usize, const M: usize> Ekf<T, N, M>

Source

pub fn new(x0: Vector<T, N>, p0: Matrix<T, N, N>) -> Self

Create a new EKF with initial state x0 and covariance p0.

Source

pub fn with_min_variance(self, min_variance: T) -> Self

Set a minimum diagonal variance floor applied after every predict/update.

Prevents covariance from degenerating to zero or going negative from accumulated numerical subtractions. Pass 0 to disable (default).

Source

pub fn with_fading_memory(self, gamma: T) -> Self

Set a fading-memory factor γ ≥ 1 applied to the propagated covariance.

The predicted covariance becomes γ · F P Fᵀ + Q. Values γ > 1 inflate uncertainty after prediction to compensate for unmodeled dynamics. Default is 1.0 (standard filter).

Source

pub fn state(&self) -> &Vector<T, N>

Reference to the current state estimate.

Source

pub fn covariance(&self) -> &Matrix<T, N, N>

Reference to the current state covariance.

Source

pub fn predict( &mut self, f: impl Fn(&Vector<T, N>) -> Vector<T, N>, fj: impl Fn(&Vector<T, N>) -> Matrix<T, N, N>, q: Option<&Matrix<T, N, N>>, )

Predict step with explicit dynamics Jacobian.

  • f — state transition: x_{k+1} = f(x_k)
  • fj — Jacobian of f evaluated at x_k: F = ∂f/∂x
  • q — process noise covariance (pass None for zero process noise)

Updates: x = f(x), P = γ · F P Fᵀ + Q.

Source

pub fn predict_fd( &mut self, f: impl Fn(&Vector<T, N>) -> Vector<T, N>, q: Option<&Matrix<T, N, N>>, )

Predict step with finite-difference Jacobian.

Computes the Jacobian of f automatically using forward differences. Pass None for q if there is no process noise.

Source

pub fn update( &mut self, z: &Vector<T, M>, h: impl Fn(&Vector<T, N>) -> Vector<T, M>, hj: impl Fn(&Vector<T, N>) -> Matrix<T, M, N>, r: &Matrix<T, M, M>, ) -> Result<T, EstimateError>

Update step with explicit measurement Jacobian.

  • z — measurement vector
  • h — measurement model: z = h(x)
  • hj — Jacobian of h evaluated at x: H = ∂h/∂x
  • r — measurement noise covariance

Uses Joseph form for numerical stability: P = (I - KH) P (I - KH)ᵀ + K R Kᵀ

Returns the Normalized Innovation Squared (NIS): yᵀ S⁻¹ y.

Source

pub fn update_fd( &mut self, z: &Vector<T, M>, h: impl Fn(&Vector<T, N>) -> Vector<T, M>, r: &Matrix<T, M, M>, ) -> Result<T, EstimateError>

Update step with finite-difference measurement Jacobian.

Computes the Jacobian of h automatically using forward differences.

Returns the Normalized Innovation Squared (NIS): yᵀ S⁻¹ y.

Source

pub fn update_gated( &mut self, z: &Vector<T, M>, h: impl Fn(&Vector<T, N>) -> Vector<T, M>, hj: impl Fn(&Vector<T, N>) -> Matrix<T, M, N>, r: &Matrix<T, M, M>, gate: T, ) -> Result<Option<T>, EstimateError>

Update with innovation gating — skips state update if NIS exceeds gate.

Returns Ok(None) when the measurement is rejected (outlier), or Ok(Some(nis)) when accepted and applied.

A chi-squared table gives typical gate thresholds: M=1 → 99%: 6.63 | M=2 → 9.21 | M=3 → 11.34 | M=6 → 16.81

Source

pub fn update_fd_gated( &mut self, z: &Vector<T, M>, h: impl Fn(&Vector<T, N>) -> Vector<T, M>, r: &Matrix<T, M, M>, gate: T, ) -> Result<Option<T>, EstimateError>

Update with gating and finite-difference Jacobian.

Returns Ok(None) when rejected, Ok(Some(nis)) when accepted.

Source

pub fn update_iterated( &mut self, z: &Vector<T, M>, h: impl Fn(&Vector<T, N>) -> Vector<T, M>, hj: impl Fn(&Vector<T, N>) -> Matrix<T, M, N>, r: &Matrix<T, M, M>, max_iter: usize, tol: T, ) -> Result<T, EstimateError>

Iterated EKF update — re-linearizes at the current iterate until convergence.

Substantially more accurate than the standard EKF for highly nonlinear measurement models (e.g., angle/range measurements, attitude-to-pixel projection).

At each iteration the linearization point advances: x_{i+1} = x̄ + K_i (z - h(x_i) - H_i (x̄ - x_i))

Iteration stops when ‖x_{i+1} - x_i‖² < tol². The final covariance is updated with the Joseph form at the converged linearization point.

Returns the Normalized Innovation Squared at the converged solution.

Source

pub fn update_fd_iterated( &mut self, z: &Vector<T, M>, h: impl Fn(&Vector<T, N>) -> Vector<T, M>, r: &Matrix<T, M, M>, max_iter: usize, tol: T, ) -> Result<T, EstimateError>

Iterated EKF update with finite-difference Jacobian.

See update_iterated for details.

Auto Trait Implementations§

§

impl<T, const N: usize, const M: usize> Freeze for Ekf<T, N, M>
where T: Freeze,

§

impl<T, const N: usize, const M: usize> RefUnwindSafe for Ekf<T, N, M>
where T: RefUnwindSafe,

§

impl<T, const N: usize, const M: usize> Send for Ekf<T, N, M>
where T: Send,

§

impl<T, const N: usize, const M: usize> Sync for Ekf<T, N, M>
where T: Sync,

§

impl<T, const N: usize, const M: usize> Unpin for Ekf<T, N, M>
where T: Unpin,

§

impl<T, const N: usize, const M: usize> UnsafeUnpin for Ekf<T, N, M>
where T: UnsafeUnpin,

§

impl<T, const N: usize, const M: usize> UnwindSafe for Ekf<T, N, M>
where T: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<SS, SP> SupersetOf<SS> for SP
where SS: SubsetOf<SP>,

Source§

fn to_subset(&self) -> Option<SS>

The inverse inclusion map: attempts to construct self from the equivalent element of its superset. Read more
Source§

fn is_in_subset(&self) -> bool

Checks if self is actually part of its subset T (and can be converted to it).
Source§

fn to_subset_unchecked(&self) -> SS

Use with care! Same as self.to_subset but without any property checks. Always succeeds.
Source§

fn from_subset(element: &SS) -> SP

The inclusion map: converts self to the equivalent element of its superset.
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.