Python implementation of the sid system identification toolbox. Numerically identical to the MATLAB/Octave reference implementation — every public function produces the same output to within floating-point tolerance.
Requires Python 3.10+, NumPy, and SciPy. Matplotlib is optional (needed only for plotting functions and examples).
From the repository root:
pip install -e ./pythonWith plotting support:
pip install -e "./python[plot]"For development (tests + linting + notebook validation):
pip install -e "./python[dev]"import numpy as np
import sid
# Generate example data: first-order system with noise
N = 1000
Ts = 0.01
rng = np.random.default_rng(42)
u = rng.standard_normal(N)
y = np.convolve(u, [1.0], mode="full")[:N] # placeholder; use scipy.signal.lfilter
from scipy.signal import lfilter
y = lfilter([1], [1, -0.9], u) + 0.1 * rng.standard_normal(N)
# Estimate frequency response (Blackman-Tukey)
result = sid.freq_bt(y, u, sample_time=Ts)
# Plot Bode diagram and noise spectrum with confidence bands
sid.bode_plot(result)
sid.spectrum_plot(result)Time-series mode (output spectrum only, no input signal):
result_ts = sid.freq_bt(y, None)
sid.spectrum_plot(result_ts)See the examples for more usage patterns, including ETFE, frequency-dependent resolution, MIMO, time-varying maps, spectrograms, LTV state-space identification, multi-trajectory ensemble averaging, and partial-observation Output-COSMIC.
| Python function | MATLAB equivalent | Description |
|---|---|---|
sid.freq_bt |
sidFreqBT / spa |
Blackman-Tukey frequency response and noise spectrum |
sid.freq_btfdr |
sidFreqBTFDR / spafdr |
Blackman-Tukey with frequency-dependent resolution |
sid.freq_etfe |
sidFreqETFE / etfe |
Empirical transfer function estimate (FFT ratio) |
| Python function | MATLAB equivalent | Description |
|---|---|---|
sid.freq_map |
sidFreqMap / tfestimate |
Time-varying frequency response map (BT or Welch) |
sid.spectrogram |
sidSpectrogram / spectrogram |
Short-time FFT spectrogram |
| Python function | MATLAB equivalent | Description |
|---|---|---|
sid.ltv_disc |
sidLTVdisc |
Discrete LTV state-space identification (COSMIC algorithm) |
sid.ltv_disc_io |
sidLTVdiscIO |
LTV identification from partial observations (Output-COSMIC) |
sid.ltv_disc_tune |
sidLTVdiscTune |
Regularization tuning via validation loss or frequency consistency |
sid.ltv_disc_frozen |
sidLTVdiscFrozen |
Frozen transfer function G(w,k) with uncertainty propagation |
sid.lti_freq_io |
sidLTIfreqIO |
LTI realization from I/O frequency response (Ho-Kalman) |
sid.ltv_state_est |
sidLTVStateEst |
Batch LTV state estimation (RTS smoother) |
sid.model_order |
sidModelOrder |
Model order estimation via Hankel SVD |
| Python function | MATLAB equivalent | Description |
|---|---|---|
sid.bode_plot |
sidBodePlot |
Bode diagram with shaded confidence bands |
sid.spectrum_plot |
sidSpectrumPlot |
Power spectrum plot with confidence bands |
sid.map_plot |
sidMapPlot |
Time-frequency color map for freq_map results |
sid.spectrogram_plot |
sidSpectrogramPlot |
Spectrogram color map |
| Python function | MATLAB equivalent | Description |
|---|---|---|
sid.detrend |
sidDetrend |
Remove mean, linear, or polynomial trends from signals |
sid.residual |
sidResidual |
Residual analysis with auto/cross-correlation diagnostics |
sid.compare |
sidCompare |
Simulate model output and compute fit percentage |
All estimation functions return frozen dataclasses with tab-completable fields.
Options are passed as keyword arguments (MATLAB name-value pairs become
snake_case kwargs).
Every public function returns a typed, frozen dataclass from sid._results:
| Result type | Returned by | Key fields |
|---|---|---|
FreqResult |
freq_bt, freq_etfe, freq_btfdr |
response, noise_spectrum, coherence, frequency |
FreqMapResult |
freq_map |
response, noise_spectrum, coherence, time, frequency |
SpectrogramResult |
spectrogram |
power, power_db, complex_stft, time, frequency |
LTVResult |
ltv_disc |
a, b, a_std, b_std, lambda_, cost |
LTVIOResult |
ltv_disc_io |
a, b, x, cost, iterations |
FrozenResult |
ltv_disc_frozen |
response, response_std, time_steps, frequency |
ResidualResult |
residual |
residual, auto_corr, whiteness_pass, independence_pass |
CompareResult |
compare |
predicted, measured, fit, residual |
All result objects are immutable (frozen) and support tab-completion in
IPython/Jupyter. Access fields with dot notation: result.response,
result.fit, etc.
Examples are provided as Jupyter notebooks in python/examples/.
Each notebook mirrors a MATLAB example script, combining narrative, code, and
inline plots. Every example is built on a physical spring-mass-damper plant
from the shared catalog defined in spec/EXAMPLES.md:
| Notebook | Plant | Functions |
|---|---|---|
example_siso.ipynb |
1-DoF SMD (m=1, k=100, c=2, ω_n=10 rad/s) |
freq_bt, bode_plot, detrend, residual, compare |
example_etfe.ipynb |
Same 1-DoF SMD as siso |
freq_etfe, bode_plot, spectrum_plot |
example_freq_dep_res.ipynb |
3-mass chain with three closely-spaced modes | freq_bt, freq_btfdr, bode_plot |
example_coherence.ipynb |
2-mass chain with colored force disturbance at mass 2 | freq_bt, bode_plot (with coherence) |
example_method_comparison.ipynb |
Same 1-DoF SMD as siso |
freq_bt, freq_btfdr, freq_etfe, compare |
example_mimo.ipynb |
2-mass chain, 2-in/2-out | freq_bt (MIMO mode) |
example_freq_map.ipynb |
2-mass LTI + continuous/discrete LTV + Duffing hardening SDOF | freq_map, map_plot |
example_spectrogram.ipynb |
SDOF (ω_n ≈ 32 Hz) driven by a 20→60 Hz chirp force |
spectrogram, spectrogram_plot |
example_ltv_disc.ipynb |
1-DoF LTV (ramping stiffness) plus Duffing linearization | ltv_disc, ltv_disc_tune, ltv_disc_frozen |
example_multi_trajectory.ipynb |
2-mass ensemble + step-change LTV + chirp-in-noise + LTV/freq_map consistency |
freq_bt, freq_map, spectrogram, ltv_disc |
example_output_cosmic.ipynb |
2-mass chain, position-only measurements (velocities hidden) | freq_bt, model_order, ltv_disc_io |
Launch any notebook locally:
jupyter notebook python/examples/example_siso.ipynbOr try them online — click the Binder badge above to launch a ready-to-run Jupyter environment in the browser (no installation required).
| Dependency | Minimum version |
|---|---|
| Python | 3.10 |
| NumPy | 1.22 |
| SciPy | 1.8 |
| Matplotlib | 3.5 (optional) |
# Unit tests
pytest python/tests/ -v
# Notebook execution (requires nbmake)
pytest --nbmake python/examples/
# Cross-language validation (requires testdata/*.json from MATLAB CI)
pytest python/tests/test_cross_validation.py -v