feat(filters): shared remez bandpass prototype — unified filter tuning (D1–D5) #51
No reviewers
Labels
No labels
accessibility
bug
documentation
duplicate
enhancement
good first issue
help wanted
invalid
question
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
ykp/gensig!51
Loading…
Reference in a new issue
No description provided.
Delete branch "remez-filter-rewrite"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Operator-confirmed rewrite (decisions D1–D5) of the bandpass primitive on the protected-band notches' Parks–McClellan core — one shared remez prototype, two band layouts.
What was wrong
Two FIR designs coexisted:
bandpass.py): Kaiser+firwin, fixed 70 dB, shape-factor transition, a decimated narrow-transition apply path, and the AGWN quarter-point geometry needed to place its −3 dB edges; the post-chain BandFilter duplicated the Kaiser recipe inpipeline.py; band isolation was gated by the geometry heuristicband_isolation_min_gap_ratio(1.1 × max-BW) that silently degraded withfallback_union.The rewrite
fir_prototype.py(new): the notch design machinery extracted —order_estimate,stopband_weight(δp/δs),design_remez_prototype(stopband-first = the notch layout, byte-identical after the refactor; passband-first = the bandpass layout),apply_mixed(mix → convolve "same" → remix),PrototypeDesign(warnings collected, callers emit them).bandpass.pyrewritten on the passband layout: flat top exactly on[fmin, fmax](the AGWN quarter-point −3 dB trick retired, D3); explicittransition_hz/rejection_db/ripple_db/tap_capparameters — the fixed 70 dB constant, the 1.08 shape factor and the decimated narrow-transition path retired (D4); real odd taps;FilterParams.from_settings()as the single settings funnel; loudValueErrorwhen remez refuses even the minimal design.agwn._band_filtersandband_isolation._band_design_mapmove to exact-edge geometry (direct / mirrored+conjugate / DC-straddle split, each half flat at DC);pipeline._apply_band_filterbecomes the DC-centred form of the same prototype (no_design_lowpassduplicate, no decimation).notch_passband_ripple_db→filter_passband_ripple_dbandnotch_tap_cap→filter_tap_cap(legacy JSON keys mapped on load); newband_rejection_db(default 70, range 10–120) andfilter_transition_mhz(default 1.0);band_isolation_min_gap_ratioremoved — the band-isolation fitness gate is nowmin_adjacent_gap_mhz ≥ filter_transition_mhz(refuse/fallback_unionpolicy unchanged, L17 wording updated,band_gap_ratiohelper removed). Settings-dialog rows relabelled ("Filter passband ripple (dB)", "Filter tap cap", "Band rejection (dB)", "Filter transition band (MHz)").spec.md§3.1 / §5.3.2 / §5.3.3,architecture.mdmodule map,subband-filtering.mdQ-F2/Q-F3.Tests
test_bandpass.pyrewritten for the remez acceptance: exact-edge flatness within the ripple bound, stopband at the rejection target (both lobes), transition crossover inside the transition region, in/out-of-band tone apply, tap-cap clamp + achievable-rejection warning, validation errors, factory parity.test_pipeline.py:ref_band_stagere-pinned bitwise to the new_apply_band_filter; narrow-span/short-length tests de-decimated.test_agwn.py: the byte-identity oracle re-pinned to an independent replay of the current design (the ticket-27 single-block invariant, now against the remez bandpass).test_protected_notch.py: renamed settings + legacy-key mapping + form round-trip; the design contract tests untouched and green (notch behavior unchanged).test_comb_iq.py: k=0 periodicity assertion moved to the float-noise floor (the 865-tap remez span filter drives scipy's FFT convolution path).Gate: 1294 passed / 64 skipped (headless UI tier),
ruff checkclean,mypyclean.