Basic system identification sanity check¶
Tutorial goal
Run a minimal identification example to check package wiring and API behavior.
Note
New to the terminology? See the lattice DSP concept map and the causality/data-use guide for how online, offline, block, and MIMO examples should be read.
Context¶
This page is intentionally simple. It is a first script to run after installation to make sure the compiled extension and Python package import correctly.
Key idea and equations¶
The desired signal is generated by a known system from a reference input:
The model output \(\widehat d[n]\) is compared with \(d[n]\).
This is the two-signal identification form, not causal self-prediction of
x[n] from its own past.
Causality and data use¶
The example is a small causal system-identification sanity check: output is formed from the reference input and current filter state, then compared with the desired signal.
How to read the result¶
A successful run should complete without import/build errors and should report a finite identification error.
Run command¶
python examples/system_identification.py
Run status¶
Return code: 0
Captured stdout¶
true taps: [0.15, -0.2, 0.8]
estimated taps: [0.15295, -0.20368, 0.80146]
initial MSE: 0.010655274351855227
final MSE: 0.00011837750292137641
Source code¶
1"""Fixed stable lattice denominator + adaptive ladder taps demo.
2
3Run after installing the package:
4 python examples/system_identification.py
5"""
6
7import numpy as np
8
9from lattice_dsp import LatticeIIR, LatticeLadderNLMS
10
11
12rng = np.random.default_rng(42)
13n = 4000
14x = rng.normal(size=n)
15
16# Synthetic unknown stable lattice-ladder system.
17true_reflection = [0.35, -0.25]
18true_taps = [0.15, -0.2, 0.8]
19plant = LatticeIIR(true_reflection, true_taps)
20d = plant.process(x) + 0.01 * rng.normal(size=n)
21
22# Estimate ladder taps while keeping the stable denominator fixed.
23adaptive = LatticeLadderNLMS(true_reflection, [0.0, 0.0, 0.0], mu=0.2)
24errors = np.array(adaptive.adapt_block(x.tolist(), d.tolist()))
25
26print("true taps: ", true_taps)
27print("estimated taps:", [round(v, 5) for v in adaptive.taps])
28print("initial MSE: ", float(np.mean(errors[:500] ** 2)))
29print("final MSE: ", float(np.mean(errors[-500:] ** 2)))