Skip to content

Wave 3 groundwork: dsp::nfc (near-field compensation) + perceptual verification protocol#11

Merged
tap merged 3 commits into
mainfrom
claude/ambitap-roadmap-max-assessment-tiuszu
Jul 3, 2026
Merged

Wave 3 groundwork: dsp::nfc (near-field compensation) + perceptual verification protocol#11
tap merged 3 commits into
mainfrom
claude/ambitap-roadmap-max-assessment-tiuszu

Conversation

@tap

@tap tap commented Jul 3, 2026

Copy link
Copy Markdown
Owner

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 for ambitap.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 through smoothed_table with provably stable ramping, wait-free noexcept process()). Verified freestanding-compatible (-fno-exceptions profile 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 nfc added to the stateful allocation-guard RT-safety test. 121/121 green, also under AMBITAP_WERROR=ON; clang-format clean.

docs/PERCEPTUAL-VERIFICATION.md — the measurement + listening protocol the ROADMAP requires before building xtc~/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-Max has ambitap.distance~ (wrapping dsp::nfc + doppler + distance gain + air absorption) ready on a branch; its CI needs this PR merged and the submodule pin bumped first.

Test plan

  • 121/121 tests pass (Release, and again with AMBITAP_WERROR=ON)
  • clang-format-18 --dry-run --Werror clean on all touched files
  • Freestanding profile (-fno-exceptions -DAMBITAP_NO_EXCEPTIONS) compiles clean
  • Protocol doc cross-checked against every ROADMAP Wave 3 verification concern
  • CI matrix on this PR

🤖 Generated with Claude Code

https://claude.ai/code/session_012VeadvCRUHJdneFNwRbFAM


Generated by Claude Code

claude added 3 commits July 3, 2026 19:14
…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
@tap tap merged commit 7bb2ab9 into main Jul 3, 2026
13 checks passed
@tap tap deleted the claude/ambitap-roadmap-max-assessment-tiuszu branch July 3, 2026 19:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants