Filters¶
kalman_py.KalmanFilter ¶
KalmanFilter(
F: ArrayLike,
H: ArrayLike,
Q: ArrayLike,
R: ArrayLike,
x0: ArrayLike,
P0: ArrayLike,
*,
square_root: bool = False,
)
Linear Kalman filter for x_k = F x_{k-1} + w, z_k = H x_k + v.
w ~ N(0, Q) and v ~ N(0, R). (x0, P0) is the prior before the first
prediction, so every measurement is preceded by a predict step (the FilterPy
convention).
Use predict and
update in real-time loops, or
filter to process a whole measurement sequence at once,
then smooth to refine it with future data.
square_root=True propagates a factor S of the covariance (P = S S') with QR
decompositions instead of using the Joseph form. The covariance then stays positive
semi-definite even for extremely precise sensors, at the cost of a QR per step. In this
mode P is derived from the factor after every step, so assigning to it has no effect.
predict ¶
predict(
F: ArrayLike | None = None, Q: ArrayLike | None = None
) -> None
Advance the current estimate (x, P) by one time step.
F and Q replace the model's matrices for this step only, e.g. for a varying
time step.
update ¶
update(
z: ArrayLike,
H: ArrayLike | None = None,
R: ArrayLike | None = None,
) -> None
Condition the current estimate on one measurement.
H and R replace the measurement model for this update only, e.g. to fuse sensors
that measure different things: H may then have any number of rows k, with z
of length k and R of shape (k, k) (R is required when k differs from
the model's measurement dimension).
filter ¶
filter(
zs: ArrayLike, backend: Literal["numpy"] = ...
) -> FilterResult[Array]
filter(
zs: ArrayLike | Array, backend: Literal["jax"]
) -> FilterResult[Array]
filter(
zs: ArrayLike | Array, backend: Backend = "numpy"
) -> FilterResult[Array] | FilterResult[Array]
Filter a measurement sequence of shape (T, dim_z), starting from (x0, P0).
This does not change the step-by-step state (x, P). A 1-D zs is accepted when
dim_z == 1. With backend="jax" the result holds JAX arrays, and JAX arrays
passed as zs stay on their device.
smooth ¶
smooth(
result: FilterResult[Array],
) -> SmootherResult[Array]
smooth(
result: FilterResult[Array],
) -> SmootherResult[Array]
smooth(
result: FilterResult[Array] | FilterResult[Array],
) -> SmootherResult[Array] | SmootherResult[Array]
Run the RTS smoother over the output of filter,
on the same backend.
kalman_py.ExtendedKalmanFilter ¶
ExtendedKalmanFilter(
f: TransitionFn,
h: MeasurementFn,
Q: ArrayLike,
R: ArrayLike,
x0: ArrayLike,
P0: ArrayLike,
*,
jac_f: TransitionFn | None = None,
jac_h: MeasurementFn | None = None,
residual_z: ResidualFn | None = None,
square_root: bool = False,
)
Extended Kalman filter for x_k = f(x_{k-1}, dt) + w, z_k = h(x_k) + v.
w ~ N(0, Q) and v ~ N(0, R); (x0, P0) is the prior before the first prediction.
Jacobians jac_f(x, dt) and jac_h(x) are optional: when omitted they are derived
automatically with jax.jacfwd, which needs JAX and requires f and h to be written
with jax.numpy. The JAX backend also traces f, h and residual_z, so they must
be jax.numpy code there too. residual_z(z, z_pred) replaces z - z_pred, e.g. to
wrap angle differences into [-pi, pi).
For the JAX backend, pass module-level functions rather than fresh lambdas: compiled code is cached per function object.
square_root=True selects the square-root covariance form; see
KalmanFilter.
filter ¶
filter(
zs: ArrayLike,
dt: ArrayLike,
backend: Literal["numpy"] = ...,
) -> ExtendedFilterResult[Array]
filter(
zs: ArrayLike | Array,
dt: ArrayLike,
backend: Literal["jax"],
) -> ExtendedFilterResult[Array]
filter(
zs: ArrayLike | Array,
dt: ArrayLike,
backend: Backend = "numpy",
) -> (
ExtendedFilterResult[Array]
| ExtendedFilterResult[Array]
)
Filter a (T, dim_z) measurement sequence, starting from (x0, P0).
dt is the time step before each measurement: a scalar, or one value per
measurement for irregular sampling. This does not change the step-by-step state.
smooth ¶
smooth(
result: ExtendedFilterResult[Array],
) -> SmootherResult[Array]
smooth(
result: ExtendedFilterResult[Array],
) -> SmootherResult[Array]
smooth(
result: ExtendedFilterResult[Array]
| ExtendedFilterResult[Array],
) -> SmootherResult[Array] | SmootherResult[Array]
Extended RTS smoother over the output of
filter, on the same backend.
kalman_py.UnscentedKalmanFilter ¶
UnscentedKalmanFilter(
f: TransitionFn,
h: MeasurementFn,
Q: ArrayLike,
R: ArrayLike,
x0: ArrayLike,
P0: ArrayLike,
*,
alpha: float = 1.0,
beta: float = 2.0,
kappa: float = 0.0,
residual_z: ResidualFn | None = None,
square_root: bool = False,
vectorized: bool = False,
)
Unscented Kalman filter for x_k = f(x_{k-1}, dt) + w, z_k = h(x_k) + v.
w ~ N(0, Q) and v ~ N(0, R); (x0, P0) is the prior before the first prediction.
No Jacobians are needed: f and h are evaluated at Van der Merwe scaled sigma points.
The defaults alpha=1, beta=2, kappa=0 keep every covariance weight nonnegative, so the
predicted covariance cannot become indefinite. Small alpha (e.g. 1e-3, common in the
literature) concentrates the points but makes the central weight strongly negative.
residual_z(z, z_pred) replaces z - z_pred, e.g. to wrap angles into [-pi, pi). It is
also used to average the sigma-point measurements, so angle measurements near +-pi need no
separate mean function. Sigma points are redrawn from the predicted distribution before
each update, so the process noise is reflected in the measurement prediction.
The JAX backend vmaps f, h and residual_z over sigma points, so they must be
jax.numpy code there; pass module-level functions so compiled code is reused.
vectorized=True declares that f(X, dt), h(X) and residual_z(Z, z) accept a
stack of points with a leading axis (shape (N, n)) and return one row per point. The
NumPy backend then makes one call per step instead of one per sigma point, which is much
faster; write the functions with [..., i] indexing so they also work on single points.
square_root=True propagates a Cholesky factor of P (the square-root UKF of Van der
Merwe and Wan), so covariances stay positive-definite by construction. With a negative
central weight (small alpha) a factor downdate can fail; that raises
CovarianceDowndateError rather than continuing with an invalid covariance. P0 must be
positive-definite in this mode.
filter ¶
filter(
zs: ArrayLike,
dt: ArrayLike,
backend: Literal["numpy"] = ...,
) -> UnscentedFilterResult[Array]
filter(
zs: ArrayLike | Array,
dt: ArrayLike,
backend: Literal["jax"],
) -> UnscentedFilterResult[Array]
filter(
zs: ArrayLike | Array,
dt: ArrayLike,
backend: Backend = "numpy",
) -> (
UnscentedFilterResult[Array]
| UnscentedFilterResult[Array]
)
Filter a (T, dim_z) measurement sequence, starting from (x0, P0).
dt is the time step before each measurement: a scalar, or one value per
measurement. This does not change the step-by-step state.
smooth ¶
smooth(
result: UnscentedFilterResult[Array],
) -> SmootherResult[Array]
smooth(
result: UnscentedFilterResult[Array],
) -> SmootherResult[Array]
smooth(
result: UnscentedFilterResult[Array]
| UnscentedFilterResult[Array],
) -> SmootherResult[Array] | SmootherResult[Array]
Unscented RTS smoother over the output of
filter, on the same backend.