Choosing the right lattice-dsp algorithm¶
Tutorial goal
Map common DSP tasks to the package APIs, diagnostics, and validation scope.
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¶
New users often know the problem they want to solve before they know the package vocabulary. This tutorial gives a compact decision table for stable IIR filtering, adaptive identification, AR estimation, finite-Hankel reduction, Nehari/AAK-style finite diagnostics, MIMO reduction, and matrix-lattice experiments.
Key idea and equations¶
The organizing principle is to choose the coordinate system that matches the constraint: reflection coefficients for scalar stability, AR recursions for prediction, Hankel singular values for input-output memory, and state-space Markov parameters for MIMO reduction.
How to read the result¶
Use the printed table as a routing guide, then follow the linked examples for the selected algorithm family.
Run command¶
python examples/algorithm_selection_demo.py
Source code¶
1"""Algorithm-selection map for lattice-dsp.
2
3This example is an onboarding companion to ``docs/theory/choosing_algorithms``.
4It prints a compact decision table and writes the same information as CSV so the
5example gallery has a concrete artifact.
6"""
7
8from __future__ import annotations
9
10import csv
11import os
12from dataclasses import dataclass
13from pathlib import Path
14
15import numpy as np
16
17import lattice_dsp as ld
18
19
20@dataclass(frozen=True)
21class Choice:
22 goal: str
23 recommended_api: str
24 first_diagnostic: str
25 scope: str
26
27
28def artifact_dir() -> Path:
29 path = Path(os.environ.get("LATTICE_DSP_ARTIFACT_DIR", "reports/example-artifacts"))
30 path.mkdir(parents=True, exist_ok=True)
31 return path
32
33
34def choices() -> list[Choice]:
35 return [
36 Choice(
37 "stable scalar IIR filtering",
38 "LatticeIIR, reflection_to_denominator",
39 "reflection bounds and pole radius",
40 "stable scalar recursive filtering",
41 ),
42 Choice(
43 "stable IIR with a numerator",
44 "LatticeLadderIIR, numerator_to_ladder",
45 "sample-by-sample agreement with B(z)/A(z)",
46 "lattice denominator plus ladder numerator",
47 ),
48 Choice(
49 "adaptive recursive system identification",
50 "AdaptiveLatticeLadderNLMS, LatticeLadderRLS",
51 "learning curve, final MSE, learned pole radius",
52 "controlled online identification examples",
53 ),
54 Choice(
55 "AR spectral estimation",
56 "burg_denominator, levinson_durbin_denominator",
57 "prediction error and spectrum residuals",
58 "stationary AR modeling diagnostics",
59 ),
60 Choice(
61 "finite SISO model reduction",
62 "hankel_singular_values, finite_hankel_reduce_iir",
63 "Hankel singular-value decay and response error",
64 "finite-Hankel/Ho-Kalman baseline",
65 ),
66 Choice(
67 "finite Nehari/AAK-style diagnostics",
68 "finite_aak_siso_certificate, finite_aak_reduce_iir",
69 "tail error, rational error, pole radius",
70 "finite-section candidate workflow",
71 ),
72 Choice(
73 "MIMO state-space reduction",
74 "mimo_state_space_markov_response, finite_hankel_reduce_mimo",
75 "block-Hankel singular values and state-space response error",
76 "finite block-Hankel baseline",
77 ),
78 Choice(
79 "matrix-lattice all-pass experiments",
80 "MatrixLatticeAllPass, contractive_matrix_from_raw",
81 "frequency-response singular values",
82 "all-pass/paraunitary tutorial scaffold",
83 ),
84 ]
85
86
87def write_csv(path: Path, rows: list[Choice]) -> None:
88 with path.open("w", newline="", encoding="utf-8") as f:
89 writer = csv.DictWriter(
90 f, fieldnames=["goal", "recommended_api", "first_diagnostic", "scope"]
91 )
92 writer.writeheader()
93 for row in rows:
94 writer.writerow(row.__dict__)
95
96
97def smoke_checks() -> dict[str, object]:
98 """Run tiny checks that touch representative public APIs."""
99
100 reflection = np.array([0.55, -0.25], dtype=float)
101 denominator = np.asarray(ld.reflection_to_denominator(reflection), dtype=float)
102 impulse = np.asarray(ld.iir_impulse_response(denominator, [1.0], 48), dtype=float)
103 hsv = np.asarray(ld.hankel_singular_values(impulse, rows=12, cols=12), dtype=float)
104
105 autocorr = ld.autocorrelation(impulse, 4)
106 ar_den = np.asarray(ld.levinson_durbin_denominator(autocorr, 2), dtype=float)
107
108 return {
109 "denominator": np.round(denominator, 6).tolist(),
110 "leading_hankel_sv": np.round(hsv[:3], 6).tolist(),
111 "levinson_denominator": np.round(ar_den, 6).tolist(),
112 }
113
114
115def main() -> None:
116 rows = choices()
117 print("lattice-dsp algorithm-selection map")
118 print("=" * 40)
119 for i, row in enumerate(rows, start=1):
120 print(f"{i}. {row.goal}")
121 print(f" use: {row.recommended_api}")
122 print(f" diagnostic: {row.first_diagnostic}")
123 print(f" scope: {row.scope}")
124
125 checks = smoke_checks()
126 print("\nrepresentative tiny smoke checks")
127 for key, value in checks.items():
128 print(f"{key}: {value}")
129
130 out = artifact_dir() / "algorithm_selection_map.csv"
131 write_csv(out, rows)
132 print(f"\nwrote {out}")
133
134
135if __name__ == "__main__":
136 main()