c4dynamics.filters.kalman.kalman.update

Contents

c4dynamics.filters.kalman.kalman.update#

kalman.update(z: ndarray | None = None, R: ndarray | None = None, hx: ndarray | None = None, innov: ndarray | None = None, gate: float | None = None)[source]#

Updates (corrects) the state estimate based on the given measurements.

Parameters:
  • z (numpy.ndarray, optional) – Measurement vector. Required unless innov is provided directly.

  • R (numpy.ndarray, optional) – Measurement noise covariance matrix. Defaults to None.

  • hx (numpy.ndarray, optional) – Predicted measurement, i.e. h(x), used to form the innovation as z - hx. Defaults to the linear prediction H @ X. Useful for a nonlinear measurement function whose output does not equal H @ X (as in ekf). Ignored if innov is provided directly.

  • innov (numpy.ndarray, optional) – The innovation (measurement residual) itself, overriding the default z - hx. Use this when the residual is not a plain subtraction, for example a circular (angle-wrapped) measurement. z is not required when innov is given.

  • gate (float, optional) – Chi-squared gating threshold on the normalized innovation squared (NIS = innov.T @ inv(S) @ innov, with S = H @ P @ H.T + R). If the NIS exceeds gate, the update is rejected: X and P are left unchanged and update returns None. Defaults to None (no gating).

Returns:

K (numpy.ndarray or None) – Kalman gain, or None if the update was rejected by gate, or if S = H @ P @ H.T + R is numerically singular (in which case X and P are likewise left unchanged, exactly as for a gate rejection).

Raises:
  • ValueError – If neither z nor innov is provided.

  • ValueError – If the number of elements in z (or innov) does not match the number of rows in the measurement matrix H.

  • ValueError – If R is missing (neither provided during construction nor passed to update).

Examples

For more detailed usage, see the examples in the introduction to the filters module and the kalman class.

Import required packages:

>>> from c4dynamics.filters import kalman

Plain update step (update in steady-state mode where the measurement covariance matrix remains and is provided once during filter initialization):

>>> kf = kalman({'x': 0},
...       P0 = 0.5**2,
...       F = 1,
...       H = 1,
...       Q = 0.05,
...       R = 200,
...       steadystate = True
... )
>>> print(kf)
[ x ]
>>> kf.X   
[0]
>>> kf.P                
[[3.187...]]
>>> kf.update(z = 100)  # returns Kalman gain   
[[0.0156...]]
>>> kf.X                
[1.568...]
>>> kf.P                
[[3.187...]]

Update with modified measurement noise covariance matrix:

>>> kf = kalman({'x': 0}, P0 = 0.5**2, F = 1, G = 150, H = 1, R = 200, Q = 0.05)
>>> kf.X   
[0]
>>> kf.P   
[[0.25]]
>>> K = kf.update(z = 150, R = 0)
>>> K   
[[1]]
>>> kf.X  
[150]
>>> kf.P  
[[0]]