Skip to content

sidLTVdisc

Python equivalent: sid.ltv_disc

Identify discrete-time LTV state-space model.

result = sidLTVdisc(X, U)
result = sidLTVdisc(X, U, 'Lambda', lambda)
result = sidLTVdisc(X, U, 'Lambda', 'auto')
result = sidLTVdisc(X, U, 'Lambda', lambda, 'Uncertainty', true)
result = sidLTVdisc(X, U, ..., 'NoiseCov', Sigma)

Identifies time-varying system matrices A(k), B(k) from state and input trajectory data for the discrete LTV system:

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

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

Inputs

Name Description
X State data, one of:
(N+1 x p) — single trajectory
(N+1 x p x L) — L trajectories, same horizon
{X1, X2, ...} — cell array of L trajectories with
variable horizons (N_l+1 x p each)
U Input data, matching format:
(N x q) — single trajectory
(N x q x L) — L trajectories, same horizon
{U1, U2, ...} — cell array, (N_l x q) each

Name-value options

Name Description
'Lambda' Regularization strength. Options:
scalar — uniform lambda at all time steps
(N-1x1) — per-step lambda vector
'auto' — automatic selection via L-curve
Default: 'auto'.
'LambdaGrid' Candidate lambda values for L-curve auto selection.
Only used when Lambda is 'auto'. Vector of positive
scalars. Default: logspace(-3, 15, 50).
'Precondition' Apply block-diagonal preconditioning to improve
numerical stability. Default: false.
'Algorithm' Identification algorithm. Currently only 'cosmic'
is supported. Default: 'cosmic'.
'Uncertainty' Compute Bayesian posterior uncertainty for A(k),
B(k). Doubles computation cost. Default: false.
'NoiseCov' Measurement noise covariance. Options:
(p x p) — known noise covariance matrix
'estimate' — estimate from residuals (default)
Requires 'Uncertainty' to be true (set automatically).
'CovarianceMode' How to estimate noise covariance (when not
user-provided). Options:
'diagonal' — diagonal Sigma (default)
'full' — full p x p covariance
'isotropic' — scalar * I_p
Ignored when 'NoiseCov' is a matrix.

Outputs

Name Description
result Struct with fields:
.A (p x p x N) time-varying dynamics matrices
.B (p x q x N) time-varying input matrices
.Lambda regularization values used, (N-1 x 1)
.Cost [total, data_fidelity, regularization]
.DataLength N (number of time steps)
.StateDim p
.InputDim q
.NumTrajectories L
.Algorithm 'cosmic'
.Preconditioned logical
.Method 'sidLTVdisc'
When 'Uncertainty' is true, these fields are added:
.AStd (p x p x N) std dev of A(k) entries
.BStd (p x q x N) std dev of B(k) entries
.P (d x d x N) row covariance, d = p+q
.NoiseCov (p x p) noise covariance (provided or estimated)
.NoiseCovEstimated logical, true if estimated from residuals
.NoiseVariance scalar, trace(NoiseCov)/p
.DegreesOfFreedom effective d.o.f. (NaN if NoiseCov provided)

Examples

% Basic identification with automatic lambda
result = sidLTVdisc(X, U);
% Manual uniform lambda
result = sidLTVdisc(X, U, 'Lambda', 1e5);
% With uncertainty estimation
result = sidLTVdisc(X, U, 'Lambda', 1e5, 'Uncertainty', true);
% With known noise covariance
Sigma = diag([0.01, 0.05]);  % known from sensor specs
result = sidLTVdisc(X, U, 'Lambda', 1e5, 'NoiseCov', Sigma);
% Per-step lambda (lower near a known transient at step 50)
lam = 1e5 * ones(N-1, 1);
lam(48:52) = 1e2;
result = sidLTVdisc(X, U, 'Lambda', lam);

Algorithm

COSMIC: Closed-form solution via block tridiagonal LU decomposition. Forward pass computes Lbd_k and Y_k; backward pass recovers C(k). Uncertainty: backward recursion on P(k) = [\(A^{-1}\)]_{kk} reusing stored Lbd_k, then Cov(vec(C(k))) = Sigma \otimes P(k). Complexity: O(N * (p+q)^3), linear in time steps.

References

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

Specification

SPEC.md §8 — Discrete-Time LTV State-Space Identification

See also

sidLTVdiscTune, sidLTVdiscFrozen, sidFreqMap

Changelog

  • 2026-03-29: First version by Pedro Lourenço.
  • 2026-04-01: Refactored into modular internal functions.