RLS-style lattice-ladder identification¶
Tutorial goal
Compare RLS-style adaptation with NLMS on a small stable identification problem.
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¶
RLS updates can converge faster than NLMS when the input is correlated, at the cost of more state and computation. This example keeps the denominator stable and focuses on the adaptive numerator/tap behavior.
Key idea and equations¶
RLS maintains an inverse covariance estimate P and uses a gain vector that depends on the
current regressor and forgetting factor.
How to read the result¶
Compare the final errors and convergence behavior for the RLS and NLMS paths.
Run command¶
python examples/rls_lattice_identification.py
Source code¶
1"""Fixed-denominator RLS adaptation of stable lattice/IIR numerator taps."""
2
3from __future__ import annotations
4
5import numpy as np
6
7from lattice_dsp import LatticeIIR, LatticeLadderNLMS, LatticeLadderRLS
8
9
10def main() -> None:
11 rng = np.random.default_rng(0)
12 n = 5000
13 x = rng.normal(size=n)
14 reflection = [0.55, -0.25]
15 target_taps = [0.25, -0.15, 0.65]
16 desired = np.asarray(LatticeIIR(reflection, target_taps).process(x), dtype=float)
17
18 nlms = LatticeLadderNLMS(reflection, [0.0, 0.0, 0.0], mu=0.12)
19 rls = LatticeLadderRLS(reflection, [0.0, 0.0, 0.0], forgetting_factor=0.995)
20
21 _, e_nlms = nlms.process_adapt(x, desired)
22 _, e_rls = rls.process_adapt(x, desired)
23
24 print("target taps:", np.round(target_taps, 4))
25 print("NLMS taps: ", np.round(nlms.taps, 4))
26 print("RLS taps: ", np.round(rls.taps, 4))
27 print("tail MSE NLMS:", float(np.mean(np.asarray(e_nlms)[-1000:] ** 2)))
28 print("tail MSE RLS: ", float(np.mean(np.asarray(e_rls)[-1000:] ** 2)))
29
30
31if __name__ == "__main__":
32 main()