Skip to content

ltv_disc

MATLAB equivalent: sidLTVdisc

ltv_disc

Discrete-time LTV state-space identification via the COSMIC algorithm.

ltv_disc

ltv_disc(X: ndarray | list, U: ndarray | list, *, lambda_: float | ndarray | str = 'auto', lambda_grid: ndarray | None = None, precondition: bool = False, algorithm: str = 'cosmic', uncertainty: bool = False, noise_cov: ndarray | str = 'estimate', covariance_mode: str = 'diagonal') -> LTVResult

Identify a discrete-time LTV state-space model from trajectory data.

Estimates time-varying system matrices A(k) and B(k) for the model

.. math::

x(k+1) = A(k)\,x(k) + B(k)\,u(k), \quad k = 0, \ldots, N-1

using the COSMIC algorithm (Carvalho et al., 2022), which solves a regularized least-squares problem balancing data fidelity against temporal smoothness of the system matrices. The closed-form block-tridiagonal solver has O(N (p+q)^3) complexity.

This is an open-source replacement for proprietary LTV identification routines.

Parameters:

Name Type Description Default
X ndarray or list of ndarray

State trajectory data. Accepted formats:

  • (N+1, p) -- single trajectory with p states
  • (N+1, p, L) -- L trajectories, same horizon N
  • [X_1, X_2, ...] -- list of L arrays (N_l+1, p) with variable horizons (N = max(N_l))
required
U ndarray or list of ndarray

Input trajectory data, matching format of X:

  • (N, q) -- single trajectory with q inputs
  • (N, q, L) -- L trajectories
  • [U_1, U_2, ...] -- list of L arrays (N_l, q)
required
lambda_ float, ndarray, or ``'auto'``

Regularization strength. Options:

  • scalar -- uniform regularization at all time steps
  • ndarray of shape (N-1,) -- per-step regularization
  • 'auto' -- automatic selection via L-curve (default)

Must be positive (scalar or all elements).

'auto'
lambda_grid ndarray or None

Candidate lambda values for L-curve auto-selection. Only used when lambda_='auto'. Default is logspace(-3, 15, 50).

None
precondition bool

Apply block-diagonal preconditioning. Currently disabled in v1.0. Default is False.

False
algorithm str

Identification algorithm. Only 'cosmic' is supported in v1.0. Default is 'cosmic'.

'cosmic'
uncertainty bool

Compute Bayesian posterior uncertainty for A(k), B(k). Doubles computation cost. Default is False.

False
noise_cov ndarray or ``'estimate'``

Measurement noise covariance. Options:

  • (p, p) ndarray -- known noise covariance (automatically enables uncertainty)
  • 'estimate' -- estimate from residuals (default)
'estimate'
covariance_mode str

How to estimate noise covariance when noise_cov is 'estimate'. One of 'diagonal', 'full', or 'isotropic'. Default is 'diagonal'.

'diagonal'

Returns:

Type Description
LTVResult

Frozen dataclass with fields:

  • a (ndarray, shape (p, p, N)) -- Time-varying dynamics.
  • b (ndarray, shape (p, q, N)) -- Time-varying input.
  • a_std (ndarray or None) -- Std dev of a entries.
  • b_std (ndarray or None) -- Std dev of b entries.
  • p_cov (ndarray or None) -- Row covariance blocks.
  • noise_cov (ndarray or None) -- Noise covariance.
  • noise_cov_estimated (bool or None) -- Whether estimated.
  • noise_variance (float or None) -- trace(Sigma)/p.
  • degrees_of_freedom (float or None) -- Effective DOF.
  • lambda_ (ndarray, shape (N-1,)) -- Lambda vector used.
  • cost (ndarray, shape (3,)) -- [total, fidelity, reg].
  • data_length (int) -- N.
  • state_dim (int) -- p.
  • input_dim (int) -- q.
  • num_trajectories (int) -- L.
  • algorithm (str) -- 'cosmic'.
  • preconditioned (bool) -- Preconditioning flag.
  • method (str) -- 'ltv_disc'.

Raises:

Type Description
SidError

If data contains NaN/Inf (code: 'non_finite').

SidError

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

SidError

If trajectories are too short, N < 2 (code: 'too_short').

SidError

If lambda is invalid (code: 'bad_lambda').

SidError

If algorithm is unsupported (code: 'bad_algorithm').

SidError

If noise_cov is invalid (code: 'bad_noise_cov').

SidError

If covariance_mode is invalid (code: 'bad_cov_mode').

Examples:

Basic identification with automatic lambda:

>>> import numpy as np
>>> import sid
>>> N = 100; p = 2; q = 1
>>> rng = np.random.default_rng(0)
>>> X = rng.standard_normal((N + 1, p))
>>> U = rng.standard_normal((N, q))
>>> result = sid.ltv_disc(X, U)
>>> result.a.shape
(2, 2, 100)

Manual uniform lambda:

>>> result = sid.ltv_disc(X, U, lambda_=1e5)

With uncertainty estimation:

>>> result = sid.ltv_disc(X, U, lambda_=1e5, uncertainty=True)
>>> result.a_std.shape
(2, 2, 100)

Variable-length trajectories:

>>> X_list = [rng.standard_normal((51, 2)), rng.standard_normal((31, 2))]
>>> U_list = [rng.standard_normal((50, 1)), rng.standard_normal((30, 1))]
>>> result = sid.ltv_disc(X_list, U_list, lambda_=1e3)
Notes

Algorithm:

  1. Validate and orient input data; detect variable-length mode.
  2. Build per-step data matrices D(k), X_lead(k) from trajectories (SPEC.md S8.3.2).
  3. If lambda_='auto', run L-curve selection over a grid of candidate values.
  4. Build block-tridiagonal terms S(k), Theta(k) (SPEC.md S8.3.3).
  5. COSMIC forward-backward pass: forward pass computes Lbd(k) and Y(k), backward pass recovers C(k) = [A(k)'; B(k)'] (SPEC.md S8.3.4).
  6. Extract A(k), B(k) from C(k).
  7. Evaluate total cost = fidelity + regularization.
  8. If uncertainty requested: backward recursion on P(k), noise covariance estimation, and standard deviation extraction (SPEC.md S8.9).

Specification: SPEC.md S8 -- Discrete-Time LTV State-Space Identification

References

.. [1] Carvalho, Soares, Lourenco, Ventura. "COSMIC: fast closed-form identification from large-scale data for LTV systems." arXiv:2112.04355, 2022.

See Also

sid.ltv_disc_tune : Tune lambda via cross-validation. sid.ltv_disc_frozen : Identify with frozen (constant) segments. sid.freq_map : Time-varying frequency response estimation.

Changelog

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