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