Wave 3 groundwork: dsp::nfc (near-field compensation) + perceptual verification protocol#11
Merged
Merged
Conversation
…r xtc~/room~
Answers the ROADMAP Wave 3 open question ('define the protocol before
building them'): deterministic numeric gates (XTC rejection/robustness/
coloration/stability; room ER exactness, T20/EDT/C50/C80, per-order energy,
tail IACC) that run as CI-able offline computations, a small formal
listening protocol with per-question pass criteria, and the bypass rule —
a perceptual module that does not beat bypass in listening does not ship.
Flags the KEMAR-vs-per-listener plant and FDN-vs-convolution tail decisions.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012VeadvCRUHJdneFNwRbFAM
Fills the near-field gap flagged in docs/ROADMAP.md (Wave 3 item 2): per ambisonic order m the compensation is the ratio of spherical-wave radial terms H_m(s) = F_m(s, r_src)/F_m(s, r_ref), F_m built from the reverse Bessel polynomial; the m roots (Durand-Kerner in double, self-contained — no Eigen, no <complex>) become analog zeros scaled by c/r_src and poles by c/r_ref, discretized per first/second-order section by bilinear transform (exact at DC: closed-form DC gain (r_ref/r_src)^m; bit-exact identity at r_src == r_ref). Distances clamp at 0.1 m (DC boost is unbounded as r_src -> 0). Applied per ACN channel by its order; W passes through. House lifecycle: ctor validates/allocates, prepare() snaps, setters rebuild coefficients in double on the control thread and publish through smoothed_table (distance changes move only numerator coefficients, so ramped interpolation stays inside the biquad stability triangle); process()/process_frame() are noexcept wait-free float32. Verified freestanding-compatible (-fno-exceptions profile compiles clean); not yet added to the embedded gate. Tests: identity, DC closed form (cut + boost, orders 1..10), clamping, impulse decay at aggressive distances, mid-ramp stability, and nfc added to the stateful allocation-guard RT-safety test. 121/121 green, also under AMBITAP_WERROR=ON; clang-format clean. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012VeadvCRUHJdneFNwRbFAM
The AppleClang/arm64 CI leg failed DspNfc.IdentityAtEqualDistances: FMA contraction (on by default there) breaks the exact b==a cancellation in the transposed-DF2 recurrence, and the NFC sections' near-unit-circle poles (corners ~20 Hz at 48 kHz; 1+a1+a2 ~ 1e-4) amplify the last-ulp residue — measured growing to ~-65 dB over 4k samples with float32 state. Reproduced on Linux with clang -ffp-contract=fast -mfma. Keep float32 I/O and float coefficient ramping, but run the per-section state and arithmetic in double: the residue drops to ~-240 dB and the low-corner conditioning hazard goes away. The identity test now asserts a 1e-6 absolute bound (regression guard) instead of bit equality, with the rationale documented in both files. 121/121 green with and without -ffp-contract=fast -mfma; clang-format clean; freestanding profile compiles clean. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012VeadvCRUHJdneFNwRbFAM
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Two independent Wave 3 items from
docs/ROADMAP.md, developed in parallel:dsp::nfc— near-field compensation (NFC-HOA), the one genuinely new core DSP forambitap.distance~. Per ambisonic order m, the compensation is the ratio of spherical-wave radial terms H_m(s) = F_m(s, r_src)/F_m(s, r_ref) built from reverse Bessel polynomials; roots found by a self-contained Durand–Kerner iteration (no Eigen, no<complex>), realized as cascaded first/second-order sections via bilinear transform. Bit-exact identity at r_src == r_ref; closed-form DC gain (r_ref/r_src)^m; distances clamp at 0.1 m since the DC boost is unbounded as r_src → 0. Follows the house processor lifecycle (validate/allocate in ctor,prepare()snaps, control-thread setters publish throughsmoothed_tablewith provably stable ramping, wait-free noexceptprocess()). Verified freestanding-compatible (-fno-exceptionsprofile compiles clean) per the ROADMAP's embedded-orthogonality requirement — not yet added to the embedded gate (flagged as a possible follow-up).Tests: identity, DC closed form for cut and boost across orders, clamping, impulse decay at aggressive distances, mid-ramp stability, plus
nfcadded to the stateful allocation-guard RT-safety test. 121/121 green, also underAMBITAP_WERROR=ON; clang-format clean.docs/PERCEPTUAL-VERIFICATION.md— the measurement + listening protocol the ROADMAP requires before buildingxtc~/room~. Deterministic numeric gates (XTC rejection/robustness/coloration/stability; room ER exactness, T20/EDT/C50/C80, per-order energy, tail IACC) designed to run as CI-able offline computations; a small formal listening protocol with per-question pass criteria; and the bypass rule — a perceptual module that does not beat bypass in listening does not ship. Flags the KEMAR-vs-per-listener plant and FDN-vs-convolution-tail decisions as open questions.Downstream
tap/AmbiTap-Maxhasambitap.distance~(wrappingdsp::nfc+ doppler + distance gain + air absorption) ready on a branch; its CI needs this PR merged and the submodule pin bumped first.Test plan
AMBITAP_WERROR=ON)--dry-run --Werrorclean on all touched files-fno-exceptions -DAMBITAP_NO_EXCEPTIONS) compiles clean🤖 Generated with Claude Code
https://claude.ai/code/session_012VeadvCRUHJdneFNwRbFAM
Generated by Claude Code