Lattice-ladder realization versus direct numerator coefficients¶
Tutorial goal
Show that lattice-ladder taps can realize the same transfer function as direct numerator coefficients.
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¶
A lattice filter gives a stable recursive denominator. Ladder taps then combine the internal lattice states to realize a numerator. This example is a sanity check that the lattice-ladder representation and a direct numerator representation agree sample-by-sample.
Key idea and equations¶
The transfer function is still
but A is controlled by reflection coefficients while B is represented by ladder
taps.
How to read the result¶
The important number is the maximum absolute output difference; it should be close to floating-point roundoff.
Run command¶
python examples/lattice_ladder_realization.py
Run status¶
Return code: 0
Captured stdout¶
reflection: [0.35, -0.2, 0.1]
direct numerator: [0.2, -0.1, 0.05, 0.75]
ladder taps: [0.07164000000000001, 0.06959999999999998, -0.14499999999999996, 0.75]
lattice numerator reconstruction: [0.2, -0.1, 0.04999999999999999, 0.75]
max |direct - lattice|: 8.882e-16
Source code¶
1"""Compare direct-form and synthesis lattice-ladder realizations.
2
3This example starts from SciPy-style direct numerator taps, converts them to
4ladder taps for the true synthesis lattice-ladder structure, and verifies that
5both realizations produce the same transfer-function behavior.
6"""
7
8from __future__ import annotations
9
10import numpy as np
11
12from lattice_dsp import LatticeIIR, LatticeLadderIIR, numerator_to_ladder
13
14
15def main() -> None:
16 rng = np.random.default_rng(0)
17 x = rng.normal(size=2048)
18
19 reflection = [0.35, -0.2, 0.1]
20 direct_numerator = [0.2, -0.1, 0.05, 0.75]
21 ladder_taps = numerator_to_ladder(reflection, direct_numerator)
22
23 direct = LatticeIIR(reflection, direct_numerator)
24 lattice = LatticeLadderIIR(reflection, ladder_taps)
25
26 y_direct = direct.process(x)
27 y_lattice = lattice.process(x)
28 max_abs_err = float(np.max(np.abs(y_direct - y_lattice)))
29
30 print("reflection:", reflection)
31 print("direct numerator:", direct_numerator)
32 print("ladder taps:", ladder_taps)
33 print("lattice numerator reconstruction:", lattice.numerator)
34 print(f"max |direct - lattice|: {max_abs_err:.3e}")
35
36
37if __name__ == "__main__":
38 main()