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

\[H(z)=\frac{B(z)}{A(z)},\]

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

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()