AGWN round: band-pass filter, generation common, AGWN generator (tickets 08-10) #7

Merged
ykpmusicstudio merged 3 commits from round2-agwn into master 2026-09-06 18:36:29 +02:00
ykpmusicstudio commented 2026-09-06 18:35:21 +02:00 (Migrated from github.com)

First signal-processing round: the AGWN waveform with level shaping and per-band filtering, on two independently-built DSP foundations (bandpass + generation common) that the remaining generators reuse. Three commits, implemented by parallel headless workers with non-overlapping ownership, wired/verified and committed by the orchestrator.

Ticket 08 — band-pass filtering (4c7bbc4)

  • gensig/core/generation/bandpass.py: design_bandpass(fmin_hz, fmax_hz, sample_rate) -> BandPassDesign with .apply(samples) — corrected port of applyBPFilter.m: complex FIR band-pass, ~70 dB rejection, 1.1 shape-factor transition, decimated path for narrow transitions (decimation_factor > 4). Validation 0 <= fmin < fmax <= Fe/2, 1-D input.
  • Measured: in-band ripple <= 0.05 dB, stopband <= -60 dB, -3 dB edges at fcent +- 1.04*fbw (MATLAB geometry), rejection <= -90 dB at fmin-ftrans/fmax+ftrans across direct / dec-16 / dec-64 paths.

Ticket 09 — generation common (a88b531)

  • units.level_to_gain — the single percent-of-full-scale -> linear conversion point (future dB mode swaps the body); 100->1.0 / 50->0.5 / 0->0.0.
  • gensig/core/generation/common.py: frozen GeneratedSignal, quantize_duration_us (MATLAB ceil, quantum<=0 passthrough), sample_count_for, seeded_rng / draw_complex_noise (deterministic, byte-identical per seed), preflight_memory reusing validation.estimate_memory with GenerationMemoryError raised BEFORE allocation.

Ticket 10 — AGWN generator (ff4c276)

  • gensig/core/generation/agwn.py + generation/__init__ re-export: generate_agwn(project) -> GeneratedSignal. Seeded complex Gaussian noise per band, band-limited and summed with Level scaling (RMS-referenced: per-band in-band RMS ~ Level/100), freqC table-center convention, time quantization gated on TimeAlign (round decision), memory preflight before any allocation, no spectrum inversion.
  • Measured: same seed -> byte-identical; in-band RMS 0.256/0.513/1.025 for L=25/50/100; two-band level ratio 2.049 (~2); occupancy -89/-99 dBc (Blackman-windowed FFT); summation sigma ratio 1.3912 (~sqrt 2).

chore(coverage): dropped gensig/core/generation/* and gensig/core/settings.py from the coverage omit list — both now implemented and tested.

Verification: 291 passed / 2 skipped (display-guarded, run under xvfb in CI), coverage 98.0%, ruff check/format + mypy clean (32 files). Headless-only new tests as required.

First signal-processing round: the AGWN waveform with level shaping and per-band filtering, on two independently-built DSP foundations (bandpass + generation common) that the remaining generators reuse. Three commits, implemented by parallel headless workers with non-overlapping ownership, wired/verified and committed by the orchestrator. **Ticket 08 — band-pass filtering** (`4c7bbc4`) - `gensig/core/generation/bandpass.py`: `design_bandpass(fmin_hz, fmax_hz, sample_rate) -> BandPassDesign` with `.apply(samples)` — corrected port of applyBPFilter.m: complex FIR band-pass, ~70 dB rejection, 1.1 shape-factor transition, decimated path for narrow transitions (`decimation_factor > 4`). Validation 0 <= fmin < fmax <= Fe/2, 1-D input. - Measured: in-band ripple <= 0.05 dB, stopband <= -60 dB, -3 dB edges at fcent +- 1.04*fbw (MATLAB geometry), rejection <= -90 dB at fmin-ftrans/fmax+ftrans across direct / dec-16 / dec-64 paths. **Ticket 09 — generation common** (`a88b531`) - `units.level_to_gain` — the single percent-of-full-scale -> linear conversion point (future dB mode swaps the body); 100->1.0 / 50->0.5 / 0->0.0. - `gensig/core/generation/common.py`: frozen `GeneratedSignal`, `quantize_duration_us` (MATLAB ceil, quantum<=0 passthrough), `sample_count_for`, `seeded_rng` / `draw_complex_noise` (deterministic, byte-identical per seed), `preflight_memory` reusing validation.estimate_memory with `GenerationMemoryError` raised BEFORE allocation. **Ticket 10 — AGWN generator** (`ff4c276`) - `gensig/core/generation/agwn.py` + `generation/__init__` re-export: `generate_agwn(project) -> GeneratedSignal`. Seeded complex Gaussian noise per band, band-limited and summed with `Level` scaling (RMS-referenced: per-band in-band RMS ~ Level/100), freqC table-center convention, time quantization gated on TimeAlign (round decision), memory preflight before any allocation, no spectrum inversion. - Measured: same seed -> byte-identical; in-band RMS 0.256/0.513/1.025 for L=25/50/100; two-band level ratio 2.049 (~2); occupancy -89/-99 dBc (Blackman-windowed FFT); summation sigma ratio 1.3912 (~sqrt 2). **chore(coverage)**: dropped `gensig/core/generation/*` and `gensig/core/settings.py` from the coverage omit list — both now implemented and tested. **Verification**: 291 passed / 2 skipped (display-guarded, run under xvfb in CI), coverage 98.0%, ruff check/format + mypy clean (32 files). Headless-only new tests as required.
Sign in to join this conversation.
No description provided.