baseline: the published sim-numerics artifact as it stands (490 tests, verify_article.py checks all 72 paper numbers against sweep_full.json)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
"""Stage 17 - the third domain: the step size of an adaptive noise canceller.
|
||||
|
||||
Root finding: the method lands second behind Chandrupatla 1997.
|
||||
ODE step control: level with a five-constant PI controller, behind the
|
||||
three-constant classical one.
|
||||
Softening somebody else's acceptance test: fails, three times over.
|
||||
|
||||
Active noise control is the domain where the object we have - a step size
|
||||
that is a safety factor on an exact step - is exactly the object the field
|
||||
argues about, and where the standard answers are openly constant-ridden.
|
||||
|
||||
The acoustic paths, the noise regimes and the scenarios come from our earlier
|
||||
ANC benchmark (SEM repository, branch feature/sem-anc-benchmark), so the
|
||||
environment is one that existed before this question was asked.
|
||||
|
||||
Metric: noise reduction in dB on the second half of each run, so that the
|
||||
adaptation transient is not counted. Higher is better. Ten seeds per cell.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import math
|
||||
|
||||
import numpy as np
|
||||
|
||||
from anc.bench import (FS, SCENARIOS, make_primary_path, make_secondary_path,
|
||||
run_nlms)
|
||||
from anc.rules import ALL
|
||||
|
||||
N = 8000 # one second
|
||||
SEEDS = 10
|
||||
SNRS = (30.0, 15.0)
|
||||
|
||||
|
||||
def main():
|
||||
print(f"{len(SCENARIOS)} scenarios x {len(SNRS)} noise levels x {SEEDS} "
|
||||
f"seeds, {N / FS:g} s each\n")
|
||||
grand = {r.name: [] for r in ALL}
|
||||
for snr in SNRS:
|
||||
print("=" * 88)
|
||||
print(f"reference SNR {snr:g} dB noise reduction, dB (higher is "
|
||||
f"better)")
|
||||
print("=" * 88)
|
||||
print(f"{'scenario':22s}" + "".join(f"{r.name[:13]:>13s}" for r in ALL))
|
||||
print("-" * 88)
|
||||
for sname, gen in SCENARIOS:
|
||||
row = {r.name: [] for r in ALL}
|
||||
for s in range(SEEDS):
|
||||
rng = np.random.default_rng(1000 + s)
|
||||
noise = gen(N, rng)
|
||||
prim = make_primary_path(rng)
|
||||
sec = make_secondary_path(rng)
|
||||
for r in ALL:
|
||||
nr = run_nlms(noise, prim, sec, r, snr_db=snr, seed=s)
|
||||
if math.isfinite(nr):
|
||||
row[r.name].append(nr)
|
||||
grand[r.name].append(nr)
|
||||
cells = []
|
||||
for r in ALL:
|
||||
v = row[r.name]
|
||||
cells.append(f"{(sum(v) / len(v)) if v else float('nan'):>13.2f}")
|
||||
print(f"{sname:22s}" + "".join(cells), flush=True)
|
||||
print()
|
||||
|
||||
print("=" * 88)
|
||||
print("OVERALL")
|
||||
print("=" * 88)
|
||||
print(f"{'rule':26s}{'constants':>11s}{'mean NR dB':>13s}"
|
||||
f"{'worst cell':>13s}{'diverged':>11s}")
|
||||
print("-" * 88)
|
||||
for r in ALL:
|
||||
v = grand[r.name]
|
||||
n_bad = SEEDS * len(SCENARIOS) * len(SNRS) - len(v)
|
||||
print(f"{r.name:26s}{r.constants:>11d}"
|
||||
f"{(sum(v) / len(v)) if v else float('nan'):>13.2f}"
|
||||
f"{min(v) if v else float('nan'):>13.2f}{n_bad:>11d}")
|
||||
print("\n'diverged' counts runs whose residual power was not finite - the "
|
||||
"failure mode\na step size that is too large actually produces.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user