Skip to content

ltv_state_est

MATLAB equivalent: sidLTVStateEst

ltv_state_est

Batch LTV state estimation (RTS smoother).

ltv_state_est

ltv_state_est(Y: ndarray | list[ndarray], U: ndarray | list[ndarray], A: ndarray, B: ndarray, H: ndarray, *, R: ndarray | None = None, Q: ndarray | None = None) -> ndarray | list[ndarray]

Estimate state trajectories for a partially observed LTV system.

This is the Python port of sidLTVStateEst.m.

Estimates state trajectories for a discrete-time LTV system with partial observations by minimising

.. math::

J = \sum_k \|y(k) - H\,x(k)\|^2_{R^{-1}}
  + \sum_k \|x(k{+}1) - A(k)\,x(k) - B(k)\,u(k)\|^2_{Q^{-1}}

This is equivalent to a Rauch-Tung-Striebel (RTS) fixed-interval smoother. Solved via a block tridiagonal forward-backward pass in O(N n^3) per trajectory.

Parameters:

Name Type Description Default
Y ndarray or list of ndarray

Output data. Accepted formats:

  • (N+1, py) -- single trajectory with py outputs
  • (N+1, py, L) -- L trajectories, same horizon N
  • [Y_1, Y_2, ...] -- list of L arrays (N_l+1, py) for variable-length trajectories
required
U ndarray or list of ndarray

Input data, matching format of Y:

  • (N, q) -- single trajectory with q inputs
  • (N, q, L) -- L trajectories
  • [U_1, U_2, ...] -- list of L arrays (N_l, q)
required
A ndarray, shape ``(n, n, N)``

Time-varying dynamics matrices.

required
B ndarray, shape ``(n, q, N)``

Time-varying input matrices.

required
H ndarray, shape ``(py, n)``

Observation matrix.

required
R ndarray, shape ``(py, py)`` or None

Measurement noise covariance (symmetric positive definite). Default: eye(py).

None
Q ndarray, shape ``(n, n)`` or None

Process noise covariance (symmetric positive definite). Default: eye(n).

None

Returns:

Name Type Description
X_hat ndarray or list of ndarray

Estimated states.

  • (N+1, n, L) when Y is an ndarray.
  • [X_1, X_2, ...] list of (N_l+1, n) when Y is a list.

Raises:

Type Description
SidError

If Y is a list but U is not (code: 'bad_input').

SidError

If data dimensions are inconsistent (code: 'dim_mismatch').

Examples:

State estimation with known dynamics:

>>> import numpy as np
>>> import sid
>>> X_hat = sid.ltv_state_est(Y, U, A, B, H)

With known measurement and process noise:

>>> X_hat = sid.ltv_state_est(
...     Y, U, A, B, H, R=R_meas, Q=Q_proc
... )
Notes

Specification: SPEC.md section 8.12 -- Output-COSMIC state step; docs/cosmic_output.md -- Appendix A

Algorithm:

  1. Precompute R^{-1}, Q^{-1}, H^T R^{-1} H, H^T R^{-1}.
  2. Build shared block tridiagonal system:

  3. Diagonal blocks S[k] encoding observation and dynamics information.

  4. Off-diagonal blocks U_c[k] = -A(k)^T Q^{-1}.

  5. Per trajectory, construct the right-hand side Theta[k] from the output data and input data.

  6. Solve the block tridiagonal system via :func:~sid._internal.ltv_blk_tri_solve.blk_tri_solve.
  7. Extract state estimates from the solution.

Complexity: O(L * N * n^3).

See Also

sid._internal.ltv_blk_tri_solve.blk_tri_solve : Block tridiagonal solver used internally. sid.ltv_disc : LTV state-space identification via COSMIC.

Changelog

2026-04-09 : First version (Python port) by Pedro Lourenco.