From 2d02f1f097a8cb073b0d1c9e312105bf724986c8 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 16 Jul 2026 10:22:31 +0000 Subject: [PATCH 1/2] ITU compliance Stage 1: the calibrated signal layer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The instruments and stimuli the compliance suite will run on, validated measured-first (test_itu_signals.cpp, 12 tests; every number in the file header): - tests/support/itu_levels.h: the dBov/dBm0/dBPa calibration plane, prewarped-bilinear A-weighting (spot gains -19.18/0.00/-1.76 dB at 100/1k/10k), 35/5 ms integrators, sliding-window peak, P.56-style active-speech-level meter (definitionally consistent on sparse speech). - tests/support/itu_signals.h: CSS single/double-talk generated from P.501's algorithmic descriptions with the Table 7-1/7-2 voiced segments transcribed from the rec text (sample-exact framing at the native 44.1 kHz rate — a Stage 1 decision, matrix updated), 8192-pt adaptive-systems PN (crest 10.97 dB, bin-flat), shaping and Table 7-7 band-limit filters (NB -85 dB at 4 kHz), the AM-FM orthogonal double-talk pair with comb analysis (94.3 dB separation at the spec's exact band edges), activation sequence, Hoth + synthetic driving noise, moving-reflector time-variant path helper (plus echo_sim::set_echo_path to drive it). - tests/fixtures/rir_cabin.h: the automotive echo path (image-source, ~2.6 m^3, RT60 66.6 ms per G.167's car figure). Existing fixtures verified bit-reproducible before generating; --only flag added to the generator so committed baselines are never touched. No ITU signal files are redistributed; the real-speech attachment WAVs remain to be procured into git-ignored tests/data/itu/. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01TLE2rvptWxV8catE8vTvgx --- .gitignore | 4 + HANDOFF.md | 25 +- docs/itu-compliance.md | 45 +- tests/CMakeLists.txt | 3 +- tests/fixtures/rir_cabin.h | 1047 +++++++++++++++++++++++++++ tests/support/echo_scenario.h | 8 + tests/support/itu_levels.h | 287 ++++++++ tests/support/itu_signals.h | 508 +++++++++++++ tests/test_itu_signals.cpp | 263 +++++++ tools/fixtures/make_rir_fixtures.py | 20 +- 10 files changed, 2196 insertions(+), 14 deletions(-) create mode 100644 tests/fixtures/rir_cabin.h create mode 100644 tests/support/itu_levels.h create mode 100644 tests/support/itu_signals.h create mode 100644 tests/test_itu_signals.cpp diff --git a/.gitignore b/.gitignore index 9bcf3dd..a616c33 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,7 @@ CMakeUserPresets.json .claude/ book/book/ __pycache__/ + +# ITU real-speech test vectors: local test use only, never committed +# (download from the ITU test-signal database; see docs/itu-compliance.md) +tests/data/itu/ diff --git a/HANDOFF.md b/HANDOFF.md index 21eb1cb..f520acf 100644 --- a/HANDOFF.md +++ b/HANDOFF.md @@ -263,13 +263,24 @@ stand-ins marked method-equivalent; (7) P.502 still unobtained — analysis methods reconstructed from the P.340/P.111x test descriptions. Rec PDFs live in the session scratchpad only (never committed).* -**Stage 1 — Calibrated ITU signal layer** (`tests/support/`). Level -calibration conventions (dBov/activity-gated levels), a deterministic -P.501 CSS generator, the P.501 double-talk sequences, per-bandwidth -band-limiting, driving-noise generator + car-cabin echo paths for the -P.1100 series (modeled first; Tim's measured cabin RIRs can join via the -existing fixture pipeline). Pass: generated signals match published -spectral/temporal properties. +**Stage 1 — Calibrated ITU signal layer** (`tests/support/`). *DONE — +`itu_levels.h` (dBov/dBm0/dBPa conventions, prewarped-bilinear +A-weighting, 35/5 ms integrators, sliding peak, P.56-style active-level +meter) + `itu_signals.h` (CSS single/double-talk with the P.501 +Table 7-1/7-2 voiced segments transcribed from the PDF, 8192-pt PN +adaptive-systems variant, shaping + band-limit filters, AM-FM +orthogonal pair + comb analysis, activation sequence, Hoth + synthetic +driving noise, moving-reflector time-variant path) + +`tests/fixtures/rir_cabin.h` (image-source cabin, RT60 66.6 ms) + +`test_itu_signals.cpp` (12 tests, measured-first). KEY DECISION made in +stage: the suite runs natively at 44.1 kHz (CSS is sample-exact only +there; matrix updated). Measured instrument floor worth knowing: the +AM-FM comb separation is 94.3 dB at the spec's exact band edges — and +collapses to 19 dB if any guard band is added (recorded in the test). +Existing fixtures verified bit-reproducible with pyroomacoustics 0.10.1 +before generating the cabin (--only flag added to the generator). Still +open from this stage: the ITU real-speech attachment WAVs +(tests/data/itu/, git-ignored) for the three signal-exact rows.* **Stage 2 — Residual-echo post-filter + comfort noise.** The big DSP item. New header (working name `mutap/postfilter.h`): coherence-based diff --git a/docs/itu-compliance.md b/docs/itu-compliance.md index 8e14b37..b95fd3a 100644 --- a/docs/itu-compliance.md +++ b/docs/itu-compliance.md @@ -65,9 +65,18 @@ approach: detector-free double-talk adaptation is MuTap's measured strength. - **Bandwidth: wideband (P.1110) and SWB/FB (P.1120) are primary**; narrowband (P.1100) variants run as band-limited configurations of the - same tests. Everything executes at 48 kHz with P.501-specified - band-limiting of the receive-direction signals (NB 3.6/4 kHz, WB - 7.2/8 kHz, SWB 14.4/16 kHz, FB 20 kHz low-pass). + same tests, with P.501-specified band-limiting of the receive-direction + signals (NB 3.6/4 kHz, WB 7.2/8 kHz, SWB 14.4/16 kHz). +- **Sample rate: the compliance suite runs at 44.1 kHz** (revised in + Stage 1 from the original 48 kHz intent): P.501's CSS framing is + sample-exact only at its native 44.1 kHz (350 ms period = 15435 + samples), and P.501 7.2.1.1 b lists 44.1 kHz as a preferred + calibration rate — running natively avoids the >60 dB-stopband + resampler P.501 NOTE 2 would otherwise require. Consequence, + documented: the RIR fixtures are 48 kHz tap sequences; played at + 44.1 kHz they represent a proportionally stretched room (times +6.6%, + e.g. the cabin's measured RT60 66.6 ms reads as ~71 ms), which stays + inside every RT envelope the recs specify. - **The simulated echo paths**: the three committed image-source rooms (fixtures) + a new car-cabin family (small volume ~2.5 m^3, RT ~60 ms per G.167 5.2.3.1's car figures) + the P.1110/P.1120 time-variant-path @@ -238,7 +247,35 @@ implementation budget. --- -## Simulation assets required (feeds Stage 1) +## Simulation assets delivered by Stage 1 + +`tests/support/itu_levels.h` + `tests/support/itu_signals.h` + +`tests/fixtures/rir_cabin.h`, validated by `tests/test_itu_signals.cpp` +(measured-first thresholds; the file header carries every number). +Instrument floors that bound what the compliance suite can measure: + +- CSS single/double-talk: sample-exact framing, PN crest 10.97 dB + (spec 11 +- 1), bin-flat PN, level calibration exact, voiced segments + transcribed from P.501 Tables 7-1/7-2. +- AM-FM orthogonal pair: **94.3 dB comb separation** at the spec's exact + band edges — the double-talk echo-loss measurement floor sits far + beyond the >= 33 dB margin targets. (Analysis discipline recorded in + the test: any added guard band collapses the floor.) +- A-weighting: -19.18 / 0.00 / -1.76 dB at 100 / 1k / 10 kHz + (prewarped bilinear; IEC class-1 envelope). +- NB band-limiter: -85 dB at 4 kHz. Cabin fixture: RT60 66.6 ms. +- P.56 active-level meter: definitionally consistent on sparse speech + (activity 0.312, delta = 10 log10(1/activity) exactly); on CSS the + 101 ms pause sits inside the 200 ms hangover, so the G.168 + active-part constants (+1.49 / +1.66 dB) are applied arithmetically. + +**ITU real-speech attachments** (P.501 7.3.2/7.3.3/7.3.5): still to be +procured — download from the ITU test-signal database into +`tests/data/itu/` (git-ignored; local test use only, never committed). +Until then the affected rows run on the CSS/AM-FM signals and are +reported `method-equivalent`. + +## Simulation assets required (original Stage 1 list, for reference) **Signals (all generatable from P.501's algorithmic descriptions):** - CSS single-talk, fullband: voiced 48.62 ms (literal sample table 7-1, diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index c00aea4..3134be9 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -37,7 +37,8 @@ add_executable(mutap_tests test_adaptation_control.cpp test_closed_loop.cpp test_rir_fixtures.cpp - test_aec.cpp) + test_aec.cpp + test_itu_signals.cpp) target_link_libraries(mutap_tests PRIVATE MuTap::MuTap mutap_warnings) diff --git a/tests/fixtures/rir_cabin.h b/tests/fixtures/rir_cabin.h new file mode 100644 index 0000000..8ddea40 --- /dev/null +++ b/tests/fixtures/rir_cabin.h @@ -0,0 +1,1047 @@ +// GENERATED by tools/fixtures/make_rir_fixtures.py — do not edit by hand. +// SPDX-License-Identifier: MIT +// Copyright 2026 MuTap contributors +// +// Physically-modeled room: car cabin, mic at the mirror, speaker in the footwell. +// pyroomacoustics image-source method, shoebox [1.9, 1.45, 0.95] m, +// uniform absorption 0.75, max_order 40, +// speaker at [0.35, 0.4, 0.25], mic at [1.1, 0.7, 0.85], fs 48000 Hz. +// Deterministic: rebuilding with the same parameters reproduces +// this data exactly. Conditioning (delay trim to a 32-sample +// guard, truncation to 4096 taps, unit-energy normalization) +// is documented in the generator script. +#pragma once + +namespace mutap_test::fixtures { + + inline constexpr unsigned k_rir_cabin_fs = 48000; + inline constexpr unsigned k_rir_cabin_taps = 4096; + + inline constexpr float k_rir_cabin[4096] = { + -2.68981883e-03f, -2.69081751e-03f, -2.69181341e-03f, -2.69280655e-03f, + -2.69379691e-03f, -2.69478448e-03f, -2.69576927e-03f, -2.69675125e-03f, + -2.69773043e-03f, -2.69870679e-03f, -2.70453297e-03f, -2.68077281e-03f, + -2.74740681e-03f, -2.61927913e-03f, -2.83671656e-03f, -2.50836227e-03f, + -2.97847363e-03f, -2.34182599e-03f, -3.17909770e-03f, -2.11296935e-03f, + -3.44564922e-03f, -1.81428771e-03f, -3.78618372e-03f, -1.43703218e-03f, + -4.21031464e-03f, -9.70541293e-04f, -4.73002107e-03f, -4.01151659e-04f, + -5.36105133e-03f, 2.88300262e-04f, -6.12018313e-03f, 1.11599588e-03f, + -7.03278365e-03f, 2.11747571e-03f, -8.14467159e-03f, 3.35107577e-03f, + -9.53058131e-03f, 4.91244992e-03f, -1.13156667e-02f, 6.97016888e-03f, + -1.37315975e-02f, 9.85035897e-03f, -1.72522393e-02f, 1.42684737e-02f, + -2.30113377e-02f, 2.21392003e-02f, -3.45361319e-02f, 4.08454469e-02f, + -7.09668552e-02f, 1.50717148e-01f, 6.70920065e-01f, -1.08518615e-01f, + 5.48956889e-02f, -4.24187040e-02f, 2.75668201e-02f, -2.73095573e-02f, + 1.79821552e-02f, -2.07434754e-02f, 1.32735104e-02f, -1.73036663e-02f, + 1.07730540e-02f, -1.55823587e-02f, 9.76998370e-03f, -1.53636903e-02f, + 1.05620137e-02f, -1.77841883e-02f, 1.63658685e-02f, -3.44979173e-02f, + 3.12031877e-01f, 2.76023603e-02f, -1.57715311e-02f, 5.09287534e-03f, + -8.21168839e-03f, 1.37532018e-03f, -6.07121713e-03f, 2.80771393e-05f, + -5.18270055e-03f, -5.81742326e-04f, -4.76100179e-03f, -8.78987432e-04f, + -4.55847686e-03f, -1.01591921e-03f, -4.47818481e-03f, -1.05543019e-03f, + -4.47996882e-03f, -1.01996929e-03f, -4.55430620e-03f, -9.14403317e-04f, + -4.69565040e-03f, -7.42065291e-04f, -4.91346279e-03f, -4.69884702e-04f, + -5.25750324e-03f, -5.19995796e-05f, -5.76603664e-03f, 5.66469852e-04f, + -6.55209110e-03f, 1.62692481e-03f, -8.20482020e-03f, 5.30285242e-03f, + 2.55864031e-01f, -2.53040781e-03f, -5.51744457e-03f, 1.24297961e-03f, + -7.85951850e-03f, 3.39374005e-03f, -1.02067559e-02f, 6.21314382e-03f, + -1.38631169e-02f, 1.13099223e-02f, -2.16505554e-02f, 2.49240741e-02f, + -5.24153822e-02f, 1.91950056e-01f, 1.09946484e-01f, -4.85393316e-02f, + 2.68686960e-02f, -2.52808813e-02f, 1.56700302e-02f, -1.85616511e-02f, + 1.07696354e-02f, -1.35788988e-02f, 1.17781975e-03f, 8.46526707e-02f, + 5.02143219e-02f, -5.29798696e-02f, 1.12427069e-01f, 2.67348794e-02f, + 1.04930880e-03f, -1.78107555e-02f, 2.27230810e-02f, -4.70210217e-02f, + 1.18568409e-01f, 1.59336702e-01f, -4.81993174e-02f, 2.17340372e-02f, + -1.81777286e-02f, 7.11960822e-03f, -8.78521363e-03f, -1.02282714e-04f, + -2.30804120e-03f, -6.93850180e-03f, 6.48193097e-03f, -2.21366766e-02f, + 6.03794573e-02f, 6.84056848e-02f, -2.43786943e-02f, 7.46539182e-03f, + -5.92162082e-03f, -8.42285736e-03f, 2.91342394e-02f, 9.24493817e-02f, + -3.11939096e-02f, 1.57759186e-02f, -1.72205389e-02f, 9.23802183e-03f, + -1.33243736e-02f, 6.65902430e-03f, -1.15512884e-02f, 5.45231087e-03f, + -1.08064372e-02f, 5.13308930e-03f, -1.09508885e-02f, 5.86250142e-03f, + -1.25781362e-02f, 9.20919041e-03f, -2.08362839e-02f, 1.00103595e-01f, + -7.71474604e-04f, 2.90788283e-02f, 2.37675019e-02f, -1.28558986e-02f, + 2.76364454e-03f, -5.88591485e-03f, -1.90105290e-03f, -8.87762411e-04f, + -1.12448024e-02f, 8.08446708e-02f, 2.19145419e-02f, -1.68630909e-02f, + 8.40421269e-03f, -1.30977995e-02f, 7.56018796e-03f, -1.47260523e-02f, + 1.65487963e-02f, 3.37180525e-02f, -9.87716440e-03f, 3.41747370e-02f, + 1.59197971e-02f, -1.72707724e-02f, 1.24481019e-02f, -2.10437300e-02f, + 2.14516862e-02f, -4.16782363e-02f, 1.08292480e-01f, 1.10092309e-01f, + -3.84993842e-02f, 1.76705272e-02f, -1.67766573e-02f, 7.42389629e-03f, + -1.06637436e-02f, 3.31166222e-03f, -7.83233002e-03f, 2.30525669e-03f, + 8.27273186e-02f, -1.06267440e-02f, 1.71500107e-02f, 3.04255951e-02f, + -1.29040329e-02f, 3.14119172e-03f, -6.89970189e-03f, 2.58446786e-05f, + -4.76788736e-03f, -1.67322244e-03f, -3.26918502e-03f, -3.11146451e-03f, + -1.78119815e-03f, -4.78193677e-03f, 2.71317758e-04f, -7.61517467e-03f, + 4.87679224e-03f, -1.76385092e-02f, 8.41807416e-02f, 2.87785558e-02f, + -1.62073406e-02f, 5.81977452e-03f, -9.30268239e-03f, 2.36875800e-03f, + -7.21869141e-03f, 9.80749733e-04f, -6.24474148e-03f, 2.76390153e-04f, + -5.73085076e-03f, -1.02739557e-04f, -5.43858904e-03f, -4.02150728e-04f, + -4.74398795e-03f, 3.87029138e-02f, -7.66450845e-03f, 1.98239812e-03f, + -8.40059958e-03f, 4.45974576e-03f, -1.50446568e-02f, 6.97863853e-02f, + 1.13756803e-02f, -8.33129468e-03f, -2.50160898e-05f, -4.15574292e-03f, + -2.76720102e-03f, -1.35046215e-03f, -7.61096924e-03f, 1.73791185e-01f, + 1.19975993e-02f, -1.02483968e-02f, 2.71785174e-03f, -7.71506736e-03f, + 1.93759865e-03f, -8.20370081e-03f, 5.30659279e-03f, 6.60718548e-02f, + -5.84391568e-03f, -2.05893424e-03f, -2.95414454e-03f, -2.93654314e-03f, + -2.85230879e-03f, -2.23200931e-03f, -5.64992162e-03f, 2.59555104e-02f, + 1.04681841e-02f, -1.17922507e-02f, 5.80276618e-03f, -1.25455936e-02f, + 9.46598555e-03f, -2.14441211e-02f, 4.43988001e-02f, 3.35316541e-02f, + 8.73570576e-03f, 6.50797022e-02f, -2.69682755e-02f, 1.49823052e-02f, + -6.45192897e-03f, 3.29346822e-02f, 4.64754542e-02f, -9.44465912e-03f, + -1.69338834e-03f, -1.50450859e-03f, -7.02071172e-03f, 2.88509524e-02f, + 3.70307483e-03f, 2.81135877e-02f, -2.76566418e-03f, -2.74137397e-03f, + -3.11692546e-03f, -2.53270565e-03f, -2.93813987e-03f, -3.63162157e-03f, + 1.91445466e-03f, 6.48610668e-02f, -1.49476806e-02f, 7.38160553e-03f, + -1.38202110e-02f, 1.07650082e-02f, -2.32735371e-02f, 5.60125007e-02f, + 5.07429277e-02f, 9.29364625e-03f, 1.85741062e-02f, -1.24204826e-02f, + 2.87828806e-03f, -6.33625317e-03f, -9.96331345e-04f, -3.23061576e-03f, + -4.00760952e-03f, 3.75302475e-04f, -9.87692197e-03f, 2.77516027e-02f, + 2.10860163e-02f, -3.35964405e-03f, 3.05991013e-02f, -1.15895198e-02f, + 2.58588534e-03f, -6.65338348e-03f, -9.92410308e-05f, -4.76129054e-03f, + -1.63490870e-03f, -3.37217067e-03f, -3.02889016e-03f, -1.78299894e-03f, + -5.29549151e-03f, 1.32929445e-02f, 3.99639995e-03f, 2.40605323e-02f, + 4.63126597e-02f, -1.50276700e-02f, 3.44535193e-02f, -9.33396791e-03f, + 2.81344929e-03f, -9.09721828e-03f, 2.88443117e-02f, -2.19764701e-03f, + 2.08456957e-02f, 7.91401375e-03f, 6.92112027e-03f, 8.90646874e-04f, + 2.72500903e-02f, -1.18314244e-02f, 6.03275380e-02f, -6.73453612e-03f, + 2.05906729e-03f, -8.90936212e-03f, 5.87058157e-03f, 1.52312126e-02f, + 3.11255265e-02f, 4.31822300e-02f, -9.12236132e-03f, 5.83401307e-04f, + -4.83898416e-03f, -1.68000358e-03f, -3.47077287e-03f, -2.41490889e-03f, + -3.76018807e-03f, 4.18661511e-03f, 8.71091870e-03f, -9.91923459e-03f, + 2.09600962e-02f, 1.93663179e-02f, -3.15590807e-03f, -7.30999549e-03f, + 1.30378281e-02f, -5.57381899e-03f, 1.85275679e-02f, 2.39368428e-02f, + -6.91844779e-03f, -3.42361205e-03f, 2.07206358e-03f, 1.34769468e-02f, + 3.49171591e-02f, 5.44972234e-02f, -1.46320012e-02f, 4.08725587e-03f, + -6.65721172e-03f, -2.58924345e-03f, 1.26683807e-02f, 1.47473038e-02f, + -1.31830011e-02f, 1.11776302e-02f, 1.35690756e-03f, -3.32222083e-03f, + 8.37419716e-03f, 6.61166193e-04f, -4.98705526e-03f, 2.52335283e-02f, + -4.83141430e-03f, -1.50321968e-03f, 2.75589897e-02f, -8.84052829e-05f, + -5.19648563e-03f, -8.62039939e-05f, 1.90762062e-03f, -2.43919923e-03f, + 2.62525158e-03f, -1.73671452e-03f, -1.37057386e-03f, 7.28466321e-03f, + 5.76232355e-03f, -6.33041929e-03f, 1.01476436e-02f, 2.92884243e-02f, + 8.57760470e-03f, 5.33042175e-03f, 8.28695349e-04f, 1.18057887e-02f, + 3.76629845e-02f, 1.24546241e-02f, 8.33349103e-03f, -8.71241625e-03f, + 8.29163488e-04f, 5.53288309e-03f, 1.79616342e-03f, -6.45551560e-03f, + 4.92534234e-04f, -6.10151397e-03f, 7.54234030e-04f, 3.68114326e-03f, + 1.97963306e-02f, 8.07662733e-03f, -6.31486547e-03f, -4.72893382e-04f, + 7.85070678e-03f, -2.01210510e-03f, -3.78300737e-03f, -1.70603556e-03f, + 4.03511966e-04f, 1.39920331e-02f, 1.61592430e-03f, -4.45808714e-03f, + -1.66392825e-03f, 2.60943527e-03f, -2.76701103e-03f, 3.18296389e-03f, + -3.08508089e-03f, -2.45834097e-03f, -3.35219367e-03f, -1.70440123e-03f, + 1.45652574e-02f, -3.51290108e-03f, -2.60829284e-03f, -2.74951665e-03f, + -3.10179740e-03f, -2.14520300e-03f, -4.34315573e-03f, 7.54216660e-03f, + 4.94509126e-04f, 1.20793233e-03f, -1.35434097e-03f, -4.00900292e-03f, + -1.68128921e-03f, -3.90716288e-03f, -1.64663340e-03f, -4.06022003e-03f, + -1.36927031e-03f, -3.75851627e-03f, 6.94473411e-03f, 2.61899791e-03f, + 1.49982610e-03f, -2.26330466e-03f, 1.73247417e-03f, -1.00370804e-03f, + -3.95736151e-03f, -9.36301181e-04f, 3.42811466e-03f, 2.01077785e-02f, + -2.28099750e-03f, -3.50899268e-03f, 8.57492326e-04f, 1.68716804e-03f, + 1.75047353e-02f, -3.28252480e-03f, -1.99070235e-03f, -4.12929547e-03f, + 7.05701159e-04f, 6.50903236e-03f, 1.91128074e-03f, -3.82135599e-03f, + 2.51839541e-03f, 2.39891607e-02f, 2.25050208e-03f, 8.75345908e-03f, + -5.98441731e-03f, 5.19770167e-03f, 4.75079275e-03f, 1.89833731e-04f, + -3.92577057e-03f, -2.33360986e-04f, 1.32906261e-03f, -2.74333792e-03f, + 3.51283117e-04f, -5.14904769e-03f, 9.18482625e-04f, 1.53048830e-02f, + -3.93678821e-04f, -1.66208692e-03f, -2.64876243e-03f, -3.62046891e-03f, + 2.10034433e-03f, -1.53668203e-03f, -2.63461016e-03f, 2.63436723e-03f, + -3.52257695e-03f, 1.15314342e-03f, 6.02959029e-03f, 3.81869850e-03f, + 2.15049901e-03f, 2.22834423e-04f, -4.01889171e-03f, 5.38579953e-03f, + 9.52671604e-06f, -2.82376071e-03f, -2.99717057e-03f, -2.62876425e-05f, + -2.53226625e-03f, -1.29822904e-03f, -3.53402755e-03f, -2.01602765e-03f, + 1.64274337e-03f, -2.04434665e-03f, -3.68956308e-03f, 2.91969510e-04f, + -9.57792814e-04f, 3.51238063e-03f, -4.09710594e-03f, 6.53652738e-04f, + 4.09610903e-03f, 4.84901420e-03f, 1.56353620e-03f, 5.14465356e-03f, + -1.17566539e-03f, -2.74311713e-03f, 3.22824778e-03f, -5.43919359e-03f, + -4.80255913e-04f, -4.90419355e-03f, -5.53508641e-04f, -5.08298748e-03f, + -9.92017323e-05f, -6.04904996e-03f, 3.37215109e-03f, -1.33450724e-03f, + -1.01830151e-03f, -5.77642000e-03f, 1.98348464e-03f, -8.16589537e-03f, + 1.98250253e-02f, 2.96908895e-02f, -8.44343152e-03f, 4.72628633e-03f, + -2.66638464e-03f, 1.85977811e-02f, -5.16056182e-03f, 7.59138638e-03f, + -8.55244833e-03f, 2.37161995e-03f, -6.91251294e-03f, 1.09184914e-02f, + -3.86753215e-03f, 1.51113035e-02f, 8.68218589e-03f, -3.83717573e-03f, + 4.38663607e-04f, 7.96443527e-03f, 1.24509545e-02f, -8.76894021e-03f, + 4.48113486e-03f, 7.08429831e-03f, 5.93418013e-03f, -4.69041506e-03f, + 4.86324584e-03f, -3.78128193e-04f, 2.96255173e-03f, -6.76778520e-03f, + 1.58133135e-02f, 4.71986325e-03f, 8.29658250e-03f, 6.34694026e-04f, + 3.77657440e-03f, 4.71269237e-03f, -2.77117841e-03f, -3.01674504e-03f, + -1.66883810e-03f, 1.02054559e-03f, -1.93088277e-03f, -4.70469373e-03f, + 3.42623990e-03f, 5.50766536e-03f, -4.85520579e-03f, -1.72406203e-03f, + -3.04816368e-03f, -2.90812061e-03f, -1.38372982e-03f, 1.87523515e-02f, + 8.76883573e-04f, -4.77793201e-03f, 6.31334590e-03f, 1.01385323e-02f, + 5.38491059e-04f, 8.30851171e-04f, 1.01157242e-03f, -1.16020814e-03f, + 1.82462065e-03f, 6.34970574e-04f, -2.09577287e-03f, 6.94820035e-03f, + -4.61727853e-03f, -1.84296062e-03f, 4.50176247e-04f, 8.50246007e-04f, + -4.57828703e-03f, 3.84617629e-03f, 2.14219176e-03f, -6.29882732e-04f, + 3.75099393e-04f, -3.85342292e-04f, -4.52315129e-04f, -1.41495356e-03f, + -1.27092189e-03f, -9.02826644e-04f, -1.83812794e-03f, -2.06271168e-03f, + -3.40832686e-03f, -4.64164907e-04f, -9.84247423e-04f, -1.96480149e-03f, + 1.36716764e-03f, -1.11731201e-03f, 4.94699241e-04f, -4.52653783e-03f, + 1.47391902e-03f, 5.35544183e-03f, -3.34068507e-03f, -2.17711317e-03f, + -2.58238111e-03f, -1.37038521e-03f, -3.53915189e-03f, -1.78026449e-03f, + -3.60175292e-03f, -1.59703435e-03f, -3.27445566e-03f, 1.17767290e-02f, + -4.20419777e-03f, 1.17537619e-02f, 1.48049316e-02f, 4.25577978e-03f, + 3.29273166e-03f, 6.47661632e-03f, 2.77804154e-03f, -5.40488302e-03f, + 1.22137895e-03f, -4.45992641e-03f, 2.20144116e-03f, -1.67481833e-03f, + 4.36029064e-03f, 9.12626536e-03f, -1.20551470e-03f, -4.62347410e-03f, + 5.17465791e-03f, 3.85288382e-03f, -2.76755352e-03f, 5.23004212e-03f, + 1.02226291e-03f, -2.64639119e-03f, -2.00322208e-03f, -8.40286735e-04f, + -2.66777611e-03f, 3.52765763e-03f, -2.30081690e-03f, 4.40445059e-03f, + -2.25232881e-03f, -1.29805048e-03f, 2.82684665e-03f, -3.10295038e-03f, + -2.60069609e-03f, 2.08780610e-04f, 6.63130488e-04f, -2.75197926e-03f, + -2.00757127e-03f, -2.25244005e-03f, -1.89468895e-03f, -1.83925167e-03f, + -8.93750170e-05f, -3.68862283e-03f, 1.05927476e-02f, 5.49823453e-03f, + 3.31817708e-03f, 1.59852207e-03f, 3.85010068e-03f, 4.64334230e-04f, + 3.20876247e-03f, 8.92783438e-04f, 1.09070148e-03f, -3.91716333e-03f, + 1.35404482e-03f, 5.56598837e-03f, -1.14628195e-04f, 8.39302832e-04f, + -3.65041407e-03f, -2.16268599e-03f, -2.15418782e-03f, 1.51255047e-03f, + -6.75503268e-04f, 2.35661227e-03f, -3.62471406e-04f, -1.93365061e-03f, + 2.02082792e-04f, -1.56972020e-06f, -2.52805095e-03f, -1.13494606e-03f, + -2.90090684e-03f, -1.39169777e-03f, -2.03512482e-03f, -7.75106597e-04f, + -1.78614447e-03f, -8.70464662e-04f, -1.67635198e-03f, -6.79899831e-04f, + 2.06417101e-03f, -3.05968846e-03f, -1.32683019e-03f, -2.45370827e-03f, + -1.60639722e-03f, -2.69590645e-03f, -1.92012918e-03f, -2.22315542e-03f, + -2.45902933e-03f, 5.64023151e-04f, 1.92883683e-04f, -2.26645589e-03f, + 1.36289458e-03f, 4.01347345e-04f, -1.85132689e-03f, -2.00721375e-03f, + -2.87953414e-03f, -2.07415625e-03f, -2.01350019e-03f, -7.24333821e-04f, + -1.94054916e-03f, -2.85287975e-03f, -2.31968081e-03f, -2.60338823e-03f, + -1.22655901e-03f, -1.79125349e-03f, 1.46996045e-03f, -1.92344836e-03f, + -2.34299126e-03f, -9.19258499e-04f, -4.03765625e-04f, -2.39408285e-03f, + 4.34688415e-04f, -2.62783408e-03f, -1.74108976e-03f, -2.75284296e-03f, + 5.37087310e-04f, 4.12444141e-03f, -1.41593284e-03f, -1.34628578e-03f, + -1.32306132e-03f, -1.31649898e-03f, -1.65519816e-03f, -2.69353765e-03f, + -6.23127106e-04f, -2.15871203e-03f, -2.55250031e-04f, -9.25737480e-04f, + -2.67442102e-03f, 6.25596248e-03f, 6.42773502e-03f, 9.05284919e-03f, + 5.20629879e-05f, 2.05935602e-03f, 3.88327058e-03f, -1.40380693e-03f, + -2.55602044e-03f, -2.65648567e-03f, -9.68577513e-04f, 2.14240606e-03f, + 2.42247712e-03f, 1.42042029e-03f, -4.97617877e-03f, 4.06548562e-03f, + 2.08200879e-03f, -2.08459387e-03f, 5.45656298e-03f, 1.66086164e-03f, + -2.21305349e-03f, 1.37301975e-03f, -8.74420082e-04f, -2.55846891e-03f, + 9.86741250e-04f, 8.24584181e-04f, -1.05511888e-03f, -2.02578911e-03f, + -1.42930672e-05f, -1.89648558e-03f, -4.19611959e-04f, -1.34633833e-03f, + -2.82310553e-03f, -7.12681069e-04f, -2.25623250e-03f, -1.52970419e-03f, + -1.99290377e-03f, 4.26303442e-04f, 4.50251070e-03f, -4.21258477e-03f, + 2.23501787e-04f, -8.31412310e-05f, -2.19158533e-03f, -1.38897671e-03f, + -2.83510707e-04f, -2.26421239e-03f, -1.94194320e-03f, 9.21230023e-04f, + -2.86059848e-03f, -2.21558651e-03f, -2.29390859e-03f, -1.94551852e-03f, + -9.68350208e-04f, -1.89726440e-03f, -1.24930598e-03f, -5.32689256e-04f, + 3.61860488e-03f, -2.07567488e-03f, -7.58935867e-04f, 4.19440733e-04f, + -1.09063156e-03f, -2.00594721e-03f, -2.62778744e-03f, -2.04901089e-03f, + -1.41449916e-03f, 3.37685818e-03f, -3.42078556e-04f, 1.28200956e-03f, + -1.96747748e-03f, -2.40083902e-03f, -5.76804691e-04f, -1.96589892e-03f, + -2.52375908e-03f, -1.08952322e-03f, -1.23258868e-03f, -2.21793047e-05f, + -1.57954266e-04f, -1.79046748e-03f, 1.76928709e-03f, 2.18406488e-04f, + -2.88290704e-03f, -1.52755961e-03f, -1.52170794e-03f, -2.24578486e-03f, + -1.66625909e-04f, -2.26210080e-03f, -1.77021286e-03f, -2.12663864e-03f, + -2.40295836e-03f, -1.18043302e-03f, -1.54658586e-03f, -2.35125320e-03f, + -1.92073413e-03f, -1.97188465e-03f, -1.11665320e-03f, 1.61061918e-03f, + 2.64706765e-04f, -2.02175068e-03f, -1.41896260e-03f, -2.48229956e-03f, + 4.98666543e-03f, -1.30283472e-03f, -2.63991430e-03f, 1.36499902e-03f, + -1.60967976e-03f, -2.29158829e-03f, -1.07336363e-03f, -1.05357466e-03f, + -4.80102499e-04f, 1.53156340e-03f, -2.08110400e-03f, 4.29553339e-03f, + 2.32141353e-03f, -1.49261101e-03f, 2.57343675e-03f, -7.73783408e-04f, + -2.00019551e-03f, -5.30104519e-04f, -2.57479339e-03f, -9.08898011e-04f, + 1.26604465e-03f, -1.83981199e-03f, -1.93062559e-03f, -1.84355015e-03f, + -1.37687962e-03f, -2.59840699e-04f, -1.88810406e-03f, 2.45595497e-03f, + -1.55418343e-03f, -8.99732871e-04f, -1.47250761e-03f, -1.07828557e-03f, + 8.02109208e-04f, -3.38639812e-03f, -3.60314932e-04f, 4.06655454e-04f, + -1.93077328e-03f, -2.05328440e-03f, -2.41624951e-03f, -9.11038189e-04f, + 1.13952911e-03f, -2.61813351e-03f, -8.96826173e-04f, -1.44024762e-03f, + -1.25435408e-03f, -8.30494593e-04f, -1.94072818e-03f, -1.73548410e-03f, + -1.52283465e-03f, -2.22951913e-03f, -2.27154188e-03f, -2.21064885e-03f, + -1.83265410e-03f, -1.87952320e-03f, -1.56398972e-03f, -2.43142994e-03f, + -1.35193484e-03f, -2.72909433e-03f, -7.97691258e-04f, -1.98042052e-03f, + -1.59576261e-03f, -4.62595619e-04f, -2.28686335e-03f, -1.01887978e-03f, + -2.23820506e-03f, -1.91753145e-03f, -8.17152560e-04f, -1.43364682e-03f, + 1.66986966e-05f, 7.95986173e-04f, -1.68941292e-03f, -1.87337374e-03f, + -2.39777256e-03f, -1.01380436e-03f, -1.33390624e-03f, -1.41925724e-03f, + -1.79644443e-03f, -2.41842885e-03f, -1.57172209e-03f, -8.13474627e-04f, + -1.72365301e-03f, -2.16932716e-03f, -2.02558094e-03f, -2.12632642e-03f, + -1.01771036e-03f, -1.91522969e-03f, -2.21525426e-03f, -2.00171878e-03f, + -1.45081109e-03f, -2.17746179e-03f, -2.28068742e-03f, -2.05269182e-03f, + -1.97164801e-03f, -1.91219661e-03f, -1.35159168e-03f, -8.87179831e-04f, + -9.64196369e-05f, -2.41923003e-03f, -5.54750632e-04f, -1.32549826e-03f, + -2.46575672e-03f, -1.04157265e-03f, -2.33954814e-03f, -1.99711757e-03f, + -1.59220139e-03f, -4.06419724e-04f, -3.77426563e-04f, -1.21324734e-03f, + -1.47333519e-03f, 1.40355026e-03f, -2.13444611e-03f, -8.72299218e-04f, + -6.52279568e-04f, -1.17809981e-03f, -1.85477300e-03f, -2.17849120e-03f, + -1.49433104e-03f, -5.22312747e-04f, -2.31003231e-03f, -1.93275776e-03f, + -1.92577518e-03f, -7.57396904e-04f, -2.23334233e-03f, 4.57172809e-04f, + -1.35428392e-03f, -9.42922345e-04f, -7.98282391e-04f, -2.38559210e-03f, + -1.90190724e-03f, -2.36379282e-03f, -1.63572030e-03f, -7.95265884e-04f, + -2.00129937e-03f, -2.10724521e-03f, -2.19891900e-03f, -1.38888109e-03f, + -1.90748400e-03f, -1.97337816e-03f, -1.74376618e-03f, -2.02185504e-03f, + -1.66687276e-03f, -1.91154620e-03f, -1.97920806e-03f, -2.15528873e-03f, + -2.15363335e-03f, -1.94003302e-03f, -1.91607353e-03f, -2.01374754e-03f, + -1.87016170e-03f, -1.91880402e-03f, -1.65264138e-03f, -1.34119288e-03f, + -2.31269374e-03f, -5.33150258e-04f, -1.49623485e-03f, -1.95179010e-03f, + -7.80020748e-04f, -1.95864385e-03f, -1.15607898e-03f, -2.30058919e-03f, + -1.85248634e-03f, -1.05467665e-03f, -1.48158391e-03f, -2.27222747e-03f, + -1.88154296e-03f, -1.87242356e-03f, -1.16321819e-03f, -1.71473484e-03f, + -2.05570149e-03f, -1.79122796e-03f, -1.96773158e-03f, -1.74162332e-03f, + -2.16258928e-03f, -1.74388617e-03f, -1.90491484e-03f, -1.29154265e-03f, + -1.92360821e-03f, -1.81160334e-03f, -1.79782343e-03f, -2.19923834e-03f, + -1.95146087e-03f, -1.89416094e-03f, -1.92485790e-03f, -1.81652841e-03f, + -1.67167501e-03f, -1.69203156e-03f, -8.44839607e-04f, -1.83768291e-03f, + -1.76736379e-03f, -1.88361601e-03f, -1.78130083e-03f, -2.04880372e-03f, + -1.83884575e-03f, -1.70828197e-03f, -1.74187827e-03f, -1.41381633e-03f, + -1.79985429e-03f, -8.94335012e-04f, -1.99363544e-03f, -1.17596019e-03f, + -2.00827236e-03f, -1.68741653e-03f, -1.46286776e-03f, -1.09928469e-03f, + -1.58706951e-03f, -1.37097690e-03f, -2.23076869e-03f, -1.29392480e-03f, + -3.00197580e-03f, 3.09335812e-03f, -2.92604139e-05f, -1.85363820e-03f, + 1.24792811e-03f, -3.07021677e-03f, -7.14235447e-04f, -3.37031650e-03f, + 1.29741564e-03f, -1.47867529e-03f, -5.89207908e-04f, -2.79768492e-04f, + -2.53039177e-04f, 5.25857975e-04f, -2.46881787e-03f, -8.95241419e-04f, + -2.79587640e-03f, -6.31436431e-04f, -1.29990303e-03f, -1.09012529e-03f, + -2.10177209e-03f, -1.38945978e-03f, -1.71965103e-03f, -1.48012445e-03f, + -1.95301418e-03f, -8.22418799e-04f, -2.56065226e-03f, 9.01509304e-04f, + -1.20848350e-03f, -1.67556045e-03f, -6.74937925e-04f, -2.27655217e-03f, + -1.14829380e-03f, -2.32409718e-03f, -5.49085718e-04f, -1.47242013e-03f, + -1.67544291e-03f, -1.95770989e-03f, -1.16019437e-03f, -1.98779504e-03f, + -1.90744554e-03f, -1.85945773e-03f, -1.98482816e-03f, -1.83629300e-03f, + -1.30899150e-03f, -1.57618215e-03f, -1.68025559e-03f, -1.60436580e-03f, + -2.13473093e-03f, -1.04360018e-03f, -9.52848398e-04f, -1.84620158e-03f, + -1.11083112e-03f, -1.51165009e-03f, -1.89778959e-03f, -1.06878326e-03f, + -8.65119080e-04f, -1.99203843e-03f, -4.67650733e-05f, -1.35317371e-03f, + -1.33628688e-03f, -1.71128996e-03f, -1.16123120e-03f, -1.20452512e-03f, + -1.77823768e-03f, -1.83662614e-03f, -1.56456980e-03f, -1.47328823e-03f, + -1.78088424e-03f, -1.70733464e-03f, -2.15923080e-03f, -9.14833385e-04f, + -1.06812065e-03f, -1.99794315e-03f, -1.09694075e-03f, -1.45496376e-03f, + -1.91957859e-03f, -1.69606415e-03f, -1.68223067e-03f, -1.70829539e-03f, + -1.57725205e-03f, -1.29953287e-03f, -1.49765055e-03f, -2.51654740e-04f, + -1.85231169e-03f, -1.28181160e-03f, -1.66948644e-03f, -1.85221580e-03f, + -1.95605322e-03f, -1.37394672e-03f, -1.20559450e-03f, -1.47751369e-03f, + -1.95547747e-03f, -1.43832425e-03f, -1.91713941e-03f, -1.26177497e-03f, + -6.30182467e-04f, -2.02801090e-03f, -1.05926404e-03f, 8.97527793e-04f, + -2.06060198e-03f, -4.60574414e-04f, -1.09140004e-03f, -1.44010641e-03f, + -2.24516346e-03f, -6.32870474e-04f, -1.10454340e-03f, -7.94496350e-04f, + -6.99237753e-04f, -1.40108695e-03f, -4.86823286e-04f, -2.22404888e-03f, + -1.41710860e-03f, -1.91258872e-03f, -8.40091398e-04f, -1.53657318e-03f, + -1.71595941e-03f, -1.53375356e-03f, -1.27437032e-03f, -1.98678203e-03f, + -1.64760738e-03f, -1.84424290e-03f, -1.59890856e-03f, -5.21132592e-04f, + -1.73099909e-03f, -6.34636219e-04f, -1.72742530e-03f, -1.12313754e-03f, + -1.34227206e-03f, -1.12398992e-03f, -1.26304502e-03f, -1.70444813e-03f, + -1.65425233e-03f, -9.84557859e-04f, -1.16043717e-03f, -1.71982177e-03f, + -1.34366180e-03f, -1.72532680e-03f, -1.60022074e-03f, -1.86094788e-03f, + -1.20817247e-03f, -1.64120676e-03f, -1.81990702e-03f, -1.37057955e-03f, + -1.26591143e-03f, -1.93549505e-03f, -1.74409597e-03f, -1.74446531e-03f, + -1.68532874e-03f, -1.15865177e-03f, -1.44179619e-03f, -1.12871165e-03f, + -1.04245704e-03f, -1.93680875e-03f, -1.74596955e-03f, -1.70930614e-03f, + -1.43911100e-03f, -1.85173194e-03f, -1.64176170e-03f, -1.37788407e-03f, + -1.44285663e-03f, -1.56634297e-03f, -1.54522107e-03f, -1.78052020e-03f, + -1.11003060e-03f, -1.97648235e-03f, -1.53146121e-03f, -1.56265133e-03f, + -1.28029654e-03f, -1.63798706e-03f, -1.52094184e-03f, -1.62019977e-03f, + -9.98452511e-04f, -1.27964559e-03f, -1.32585806e-03f, -7.64176111e-04f, + -1.80620178e-03f, -1.26883949e-03f, -1.63283024e-03f, -1.34618823e-03f, + -1.80242489e-03f, -1.31974963e-03f, -1.56040458e-03f, -1.77412785e-03f, + -1.53551291e-03f, -1.49841587e-03f, -1.77878028e-03f, -1.49849375e-03f, + -1.72233651e-03f, -1.56941033e-03f, -1.76141914e-03f, -1.65746130e-03f, + -1.44857421e-03f, -1.52171724e-03f, -1.73793602e-03f, -1.61486331e-03f, + -1.67932325e-03f, -1.58819761e-03f, -1.74045686e-03f, -1.38736509e-03f, + -1.37993231e-03f, -1.68774403e-03f, -1.53268939e-03f, -1.73658585e-03f, + -1.57043014e-03f, -1.69367812e-03f, -1.49254717e-03f, -1.11986840e-03f, + -1.60321987e-03f, -1.38975030e-03f, -1.62251034e-03f, -1.67661274e-03f, + -1.45377471e-03f, -1.55149723e-03f, -1.46831534e-03f, -1.69461950e-03f, + -1.21135732e-03f, -1.49714002e-03f, -9.99180003e-04f, -1.82962521e-03f, + -1.22823742e-03f, -1.98366835e-03f, -1.05650511e-03f, -2.17100962e-03f, + 7.76901383e-05f, -3.26095573e-04f, -1.23846267e-03f, -7.80587130e-04f, + -1.75025376e-03f, -1.80398972e-03f, -8.75584317e-04f, -8.32186878e-04f, + -1.07487581e-03f, -7.78376424e-04f, -9.55850360e-04f, -1.17205623e-03f, + -1.74695568e-03f, -1.36394876e-03f, -1.27623405e-03f, -1.24183174e-03f, + -1.83217094e-03f, -1.32002467e-03f, -1.11810308e-03f, -1.42823609e-03f, + -1.40836700e-03f, -1.67991615e-03f, -8.36255812e-04f, -9.30735727e-04f, + -1.15611812e-03f, -1.04665820e-03f, -1.78721649e-03f, -1.43629017e-03f, + -1.27757637e-03f, -1.20973063e-03f, -1.87869937e-03f, -1.29824069e-03f, + -1.43362482e-03f, -1.56956271e-03f, -1.40924812e-03f, -1.27969525e-03f, + -1.54449664e-03f, -1.43527305e-03f, -1.72261613e-03f, -1.39653984e-03f, + -1.51277512e-03f, -1.00985006e-03f, -1.35080094e-03f, -1.58069848e-03f, + -1.29244153e-03f, -1.63333805e-03f, -1.11430684e-03f, -1.28809656e-03f, + -1.18856464e-03f, -9.49155981e-04f, -1.63492232e-03f, -1.52741818e-03f, + -1.33729903e-03f, -1.39651146e-03f, -1.43651164e-03f, -1.30500072e-03f, + -1.33238893e-03f, -1.43822356e-03f, -1.56952683e-03f, -1.42653775e-03f, + -1.16729486e-03f, -1.53410650e-03f, -1.45177466e-03f, -1.31202515e-03f, + -1.51614117e-03f, -1.35630071e-03f, -1.43602510e-03f, -1.38070232e-03f, + -1.35053418e-03f, -1.45056121e-03f, -8.28797047e-04f, -1.47395356e-03f, + -1.23195645e-03f, -1.56839869e-03f, -1.43947050e-03f, -1.48389080e-03f, + -1.17200018e-03f, -1.59856217e-03f, -1.37323356e-03f, -1.56180228e-03f, + -1.14966396e-03f, -1.09257076e-03f, -1.38825250e-03f, -1.31930639e-03f, + -1.56871481e-03f, -1.51509143e-03f, -1.14691630e-03f, -1.44680547e-03f, + -1.60147646e-03f, -1.28198685e-03f, -1.25291262e-03f, -1.30517014e-03f, + -1.40285078e-03f, -1.33669906e-03f, -1.44148246e-03f, -1.50056940e-03f, + -1.31270708e-03f, -1.64148235e-03f, -6.63876163e-04f, -1.04628256e-03f, + -1.19922998e-03f, -1.15480944e-03f, -1.72851952e-03f, -1.24012374e-03f, + -1.08689739e-03f, -1.17468512e-03f, -1.17261299e-03f, -1.14106228e-03f, + -1.02738085e-03f, -1.39385722e-03f, -1.36012656e-03f, -1.25517875e-03f, + -1.32530635e-03f, -1.20748854e-03f, -1.19415442e-03f, -1.40257252e-03f, + -1.36623491e-03f, -1.51738821e-03f, -1.32173534e-03f, -7.07152837e-04f, + -1.34245705e-03f, -1.14429266e-03f, -1.42555895e-03f, -1.38664402e-03f, + -1.16467709e-03f, -1.21503580e-03f, -1.41988948e-03f, -1.30744986e-03f, + -1.19759890e-03f, -1.33733582e-03f, -1.40849448e-03f, -1.47664659e-03f, + -1.37651513e-03f, -1.34934702e-03f, -1.36139414e-03f, -1.22911788e-03f, + -1.27386430e-03f, -1.07372880e-03f, -1.47454688e-03f, -1.26775249e-03f, + -1.43455401e-03f, -1.20559449e-03f, -1.34264936e-03f, -1.10104773e-03f, + -1.25909416e-03f, -1.44065290e-03f, -1.27950898e-03f, -1.09283251e-03f, + -1.29353388e-03f, -1.31914762e-03f, -1.27216041e-03f, -1.38692423e-03f, + -1.35338592e-03f, -1.29250573e-03f, -1.34884808e-03f, -1.35455500e-03f, + -1.29088731e-03f, -1.27029282e-03f, -1.40406369e-03f, -1.38132875e-03f, + -1.41980117e-03f, -1.28434695e-03f, -1.40049359e-03f, -1.08129284e-03f, + -1.21431359e-03f, -1.30656193e-03f, -1.33995683e-03f, -1.46231487e-03f, + -1.25656690e-03f, -1.26422510e-03f, -1.34432757e-03f, -1.32484834e-03f, + -1.30336840e-03f, -1.38543540e-03f, -1.30918977e-03f, -1.37752745e-03f, + -1.37573161e-03f, -1.33892351e-03f, -1.30382031e-03f, -1.34382887e-03f, + -1.41997261e-03f, -1.33978324e-03f, -1.35621352e-03f, -1.39648005e-03f, + -1.32903994e-03f, -1.31588958e-03f, -1.40254264e-03f, -1.23866578e-03f, + -1.32858797e-03f, -1.29955525e-03f, -1.27446869e-03f, -1.34510688e-03f, + -1.05366847e-03f, -1.26887419e-03f, -1.28779325e-03f, -1.30164779e-03f, + -1.33272326e-03f, -1.25852491e-03f, -1.21810323e-03f, -1.18849816e-03f, + -1.10696054e-03f, -1.17562269e-03f, -1.22571913e-03f, -1.30537510e-03f, + -1.20079686e-03f, -1.37034832e-03f, -1.23356996e-03f, -1.28216170e-03f, + -1.26911030e-03f, -1.23724627e-03f, -1.28237522e-03f, -1.30315528e-03f, + -1.33855704e-03f, -1.31595183e-03f, -1.28222850e-03f, -1.36014124e-03f, + -1.30375187e-03f, -1.28943945e-03f, -1.26616226e-03f, -1.33135196e-03f, + -1.30871855e-03f, -1.34207883e-03f, -1.23093405e-03f, -1.24921249e-03f, + -1.25773886e-03f, -1.27411040e-03f, -1.28147481e-03f, -1.22711174e-03f, + -1.20634855e-03f, -1.29149196e-03f, -1.26789413e-03f, -1.28514419e-03f, + -1.27219581e-03f, -1.32073839e-03f, -1.23650817e-03f, -1.26874558e-03f, + -1.19146750e-03f, -1.22068935e-03f, -1.21857827e-03f, -1.30916973e-03f, + -1.19956044e-03f, -1.16863282e-03f, -1.21291527e-03f, -1.26238037e-03f, + -1.23194073e-03f, -1.17246465e-03f, -1.21986660e-03f, -1.25988811e-03f, + -1.24896532e-03f, -1.27192357e-03f, -1.17845967e-03f, -1.22389949e-03f, + -1.23124237e-03f, -1.23814729e-03f, -1.24063886e-03f, -1.24666085e-03f, + -1.27917380e-03f, -1.26726359e-03f, -1.19674975e-03f, -1.27409902e-03f, + -1.22313615e-03f, -1.18346697e-03f, -1.24241441e-03f, -1.23171031e-03f, + -1.21799489e-03f, -1.19369878e-03f, -1.22947804e-03f, -1.22881983e-03f, + -1.25647294e-03f, -1.18776849e-03f, -1.25740286e-03f, -1.21541962e-03f, + -1.24343828e-03f, -1.21671262e-03f, -1.27664718e-03f, -1.13206975e-03f, + -1.04665768e-03f, -1.19099030e-03f, -1.12643465e-03f, -1.29275225e-03f, + -1.12962020e-03f, -1.13470990e-03f, -1.21453892e-03f, -1.22673282e-03f, + -1.10942044e-03f, -1.08425606e-03f, -1.17591035e-03f, -1.16335803e-03f, + -1.23758376e-03f, -1.16057420e-03f, -1.16902795e-03f, -1.21497256e-03f, + -1.17570169e-03f, -1.18176595e-03f, -1.22970372e-03f, -1.18627203e-03f, + -1.22412808e-03f, -1.19247344e-03f, -1.22675401e-03f, -1.16633001e-03f, + -1.23354953e-03f, -1.14276932e-03f, -1.18392676e-03f, -1.16591501e-03f, + -1.17107087e-03f, -1.05641834e-03f, -1.22791703e-03f, -9.84694158e-04f, + -4.03673824e-04f, -9.43553737e-04f, -6.85300185e-04f, -1.35953818e-03f, + -8.43103796e-04f, -8.65962511e-04f, -8.51862352e-04f, -7.94437836e-04f, + -8.47558317e-04f, -1.16141941e-03f, -1.19177499e-03f, -9.18644196e-04f, + -1.13348246e-03f, -1.16436723e-03f, -1.05014730e-03f, -1.17457565e-03f, + -1.16632474e-03f, -9.90449781e-04f, -6.64353019e-04f, -1.01474803e-03f, + -9.86678822e-04f, -1.22622409e-03f, -1.01929226e-03f, -9.39937798e-04f, + -1.18565733e-03f, -1.03617055e-03f, -1.07702204e-03f, -1.11958432e-03f, + -1.15337347e-03f, -1.11398085e-03f, -1.14728663e-03f, -1.10500563e-03f, + -1.20280080e-03f, -9.53115206e-04f, -1.04857072e-03f, -1.13927214e-03f, + -1.13193532e-03f, -1.07250533e-03f, -9.57084353e-04f, -9.67453141e-04f, + -9.10356965e-04f, -1.23358757e-03f, -1.01144471e-03f, -1.03130166e-03f, + -1.14026705e-03f, -1.05062776e-03f, -1.05516207e-03f, -1.14168346e-03f, + -1.09260598e-03f, -1.02406349e-03f, -1.10230384e-03f, -9.34152793e-04f, + -1.08374206e-03f, -1.07242081e-03f, -1.11867786e-03f, -1.02854162e-03f, + -1.03531773e-03f, -8.96961799e-04f, -9.78983731e-04f, -1.03557035e-03f, + -1.08946152e-03f, -1.11443459e-03f, -9.48742053e-04f, -1.12508244e-03f, + -1.06822952e-03f, -1.05966847e-03f, -1.04265451e-03f, -1.06912785e-03f, + -1.10813082e-03f, -1.09681344e-03f, -1.08331504e-03f, -1.04022464e-03f, + -1.10746113e-03f, -1.04932636e-03f, -1.09071807e-03f, -1.04161374e-03f, + -1.06357832e-03f, -1.04571476e-03f, -1.11965220e-03f, -9.74181488e-04f, + -1.03529479e-03f, -1.02105011e-03f, -1.03317027e-03f, -1.04972374e-03f, + -9.92053167e-04f, -1.04596740e-03f, -1.00827447e-03f, -1.00233159e-03f, + -1.05126270e-03f, -9.06420743e-04f, -9.66736006e-04f, -1.03480379e-03f, + -1.06057734e-03f, -9.89721432e-04f, -1.05470036e-03f, -9.94649606e-04f, + -1.09093152e-03f, -8.84043305e-04f, -7.07877294e-04f, -9.30169758e-04f, + -9.04069984e-04f, -1.10570038e-03f, -8.31940345e-04f, -9.34964800e-04f, + -8.42436033e-04f, -8.55951135e-04f, -8.81336650e-04f, -1.06101744e-03f, + -9.07924090e-04f, -1.00236771e-03f, -1.04299628e-03f, -9.31631841e-04f, + -9.76441001e-04f, -1.06032662e-03f, -9.45343168e-04f, -8.42290651e-04f, + -9.64258513e-04f, -9.45532961e-04f, -1.08370787e-03f, -8.77266076e-04f, + -9.76294482e-04f, -9.60153971e-04f, -8.38497942e-04f, -9.53975817e-04f, + -9.75770538e-04f, -1.03175762e-03f, -9.42164052e-04f, -9.37512674e-04f, + -1.04090922e-03f, -8.84356034e-04f, -9.39158809e-04f, -9.62901604e-04f, + -9.91200009e-04f, -9.44534009e-04f, -9.16454645e-04f, -8.75986038e-04f, + -9.35713706e-04f, -1.01273874e-03f, -9.13961521e-04f, -1.00867209e-03f, + -9.87729672e-04f, -9.38135384e-04f, -9.72817606e-04f, -1.00406701e-03f, + -9.30453297e-04f, -9.99749703e-04f, -9.37297001e-04f, -9.62195817e-04f, + -9.61822541e-04f, -9.90992058e-04f, -9.40675296e-04f, -9.50809095e-04f, + -8.59336180e-04f, -9.11573780e-04f, -9.28606878e-04f, -1.00219598e-03f, + -9.25043733e-04f, -9.35584633e-04f, -9.69508734e-04f, -9.25533939e-04f, + -9.55019949e-04f, -9.37985397e-04f, -9.80374551e-04f, -9.59256459e-04f, + -9.69127552e-04f, -8.87566855e-04f, -9.28610095e-04f, -9.17977911e-04f, + -9.51749886e-04f, -9.54678918e-04f, -9.10819362e-04f, -9.63437624e-04f, + -9.37136893e-04f, -9.37024510e-04f, -9.25210862e-04f, -9.53672451e-04f, + -9.02354335e-04f, -8.27715136e-04f, -8.80270353e-04f, -9.00263333e-04f, + -9.48696254e-04f, -8.78489497e-04f, -8.75250365e-04f, -8.86383968e-04f, + -8.77996341e-04f, -8.95050484e-04f, -8.93170495e-04f, -8.78338492e-04f, + -9.34572624e-04f, -8.81910536e-04f, -9.20157233e-04f, -9.13809355e-04f, + -9.16947821e-04f, -9.21816477e-04f, -9.24560559e-04f, -9.16401957e-04f, + -9.11854745e-04f, -8.99278768e-04f, -8.95961294e-04f, -9.01486036e-04f, + -9.32090623e-04f, -8.66407769e-04f, -8.68104450e-04f, -8.48714436e-04f, + -8.80841003e-04f, -8.89896084e-04f, -8.99917928e-04f, -8.40586414e-04f, + -8.83457034e-04f, -8.92486620e-04f, -8.92005394e-04f, -9.00455649e-04f, + -8.99053647e-04f, -8.28104690e-04f, -8.69105320e-04f, -8.50428650e-04f, + -9.02190356e-04f, -8.72867883e-04f, -8.73899396e-04f, -8.68213459e-04f, + -9.11315127e-04f, -7.98290511e-04f, -9.19756681e-04f, -6.05372669e-04f, + -6.08482846e-04f, -7.53591166e-04f, -8.51827951e-04f, -8.34749263e-04f, + -6.71956387e-04f, -7.42221679e-04f, -6.74215700e-04f, -7.85368856e-04f, + -8.85263566e-04f, -7.87676718e-04f, -8.23930303e-04f, -8.79634272e-04f, + -8.18953508e-04f, -8.57429146e-04f, -8.78421814e-04f, -7.27656410e-04f, + -7.32442409e-04f, -7.99976083e-04f, -8.59953133e-04f, -8.30856485e-04f, + -7.52705792e-04f, -8.87980753e-04f, -7.71920063e-04f, -8.61403756e-04f, + -8.43905132e-04f, -8.55977924e-04f, -8.32144622e-04f, -8.43733163e-04f, + -8.39167950e-04f, -7.60123758e-04f, -7.76925770e-04f, -8.25848008e-04f, + -8.14191873e-04f, -7.61768054e-04f, -7.37135720e-04f, -7.20333827e-04f, + -8.66633103e-04f, -7.77333097e-04f, -8.16950017e-04f, -8.34212576e-04f, + -7.77779209e-04f, -8.34050554e-04f, -8.10960533e-04f, -7.92375739e-04f, + -8.21736350e-04f, -7.80846447e-04f, -8.20909982e-04f, -8.34161068e-04f, + -7.97691131e-04f, -7.89716592e-04f, -7.16335111e-04f, -7.59448442e-04f, + -7.85761503e-04f, -8.27094385e-04f, -7.85740954e-04f, -7.42636170e-04f, + -8.13155757e-04f, -7.76537168e-04f, -8.00314497e-04f, -7.74561011e-04f, + -8.03195729e-04f, -8.09528197e-04f, -7.80589958e-04f, -8.02106529e-04f, + -7.89623166e-04f, -7.25996641e-04f, -7.81014914e-04f, -7.76359080e-04f, + -7.99122005e-04f, -7.63219187e-04f, -7.93778622e-04f, -7.88589617e-04f, + -7.59345222e-04f, -7.74216240e-04f, -7.81362127e-04f, -7.94881820e-04f, + -7.63431711e-04f, -7.88992757e-04f, -7.72790822e-04f, -7.19397963e-04f, + -7.41686949e-04f, -7.65352929e-04f, -7.64310721e-04f, -7.60500922e-04f, + -7.60723990e-04f, -7.52188421e-04f, -7.83090439e-04f, -7.68944819e-04f, + -7.78481567e-04f, -7.29598838e-04f, -7.69666763e-04f, -7.53558571e-04f, + -7.79268399e-04f, -7.14079623e-04f, -7.44857229e-04f, -7.45043426e-04f, + -7.89660551e-04f, -6.20958740e-04f, -6.36430818e-04f, -6.76543275e-04f, + -7.56641503e-04f, -6.94166487e-04f, -6.63425812e-04f, -6.75679953e-04f, + -6.60623353e-04f, -7.61615446e-04f, -7.32551083e-04f, -6.88345818e-04f, + -6.89956933e-04f, -6.81854058e-04f, -7.15635033e-04f, -7.70250142e-04f, + -6.62415023e-04f, -6.57936930e-04f, -7.03607403e-04f, -7.30595480e-04f, + -7.06267101e-04f, -6.83197559e-04f, -7.46851710e-04f, -7.06366842e-04f, + -7.37553961e-04f, -7.20624587e-04f, -7.30839776e-04f, -7.18641148e-04f, + -7.45789445e-04f, -6.99228052e-04f, -6.85466598e-04f, -7.31816207e-04f, + -7.25836027e-04f, -6.97727492e-04f, -6.78968536e-04f, -6.59848164e-04f, + -7.31497515e-04f, -7.02020782e-04f, -7.07465226e-04f, -7.19004693e-04f, + -6.81274909e-04f, -7.17654276e-04f, -6.94178276e-04f, -6.95219673e-04f, + -7.00677937e-04f, -6.81644447e-04f, -6.93133426e-04f, -7.00066866e-04f, + -6.94784258e-04f, -6.80980934e-04f, -6.52152803e-04f, -6.73512166e-04f, + -6.52661609e-04f, -6.57762802e-04f, -6.57214870e-04f, -6.93372642e-04f, + -6.77119791e-04f, -6.70102539e-04f, -6.94471980e-04f, -6.72140386e-04f, + -6.74974481e-04f, -6.68470341e-04f, -6.93782893e-04f, -6.85092322e-04f, + -6.79373167e-04f, -6.85868815e-04f, -6.69297726e-04f, -6.82150569e-04f, + -6.73588270e-04f, -6.72100166e-04f, -6.79794922e-04f, -6.74181751e-04f, + -6.67251272e-04f, -6.75671183e-04f, -6.67837657e-04f, -6.66603396e-04f, + -6.53085327e-04f, -6.39351319e-04f, -6.52170614e-04f, -6.66916219e-04f, + -6.47781419e-04f, -6.60639344e-04f, -6.60512132e-04f, -6.48341253e-04f, + -6.45818093e-04f, -6.45659577e-04f, -6.58094748e-04f, -6.54511263e-04f, + -6.50142215e-04f, -6.62656132e-04f, -6.49068492e-04f, -6.46836083e-04f, + -6.46578113e-04f, -6.45901282e-04f, -6.38325513e-04f, -6.40869989e-04f, + -6.44428559e-04f, -6.39952411e-04f, -6.42835421e-04f, -6.35261122e-04f, + -6.41166203e-04f, -6.43727577e-04f, -6.45602047e-04f, -6.40263893e-04f, + -6.38645453e-04f, -6.14311215e-04f, -6.18435794e-04f, -6.38981035e-04f, + -6.36343899e-04f, -6.22998297e-04f, -6.36044852e-04f, -6.23857263e-04f, + -6.31239718e-04f, -6.30685949e-04f, -6.33221374e-04f, -6.31201211e-04f, + -6.26751747e-04f, -6.28371009e-04f, -6.26842081e-04f, -6.30732178e-04f, + -6.26085528e-04f, -6.23340016e-04f, -6.16833141e-04f, -6.22844599e-04f, + -6.17129816e-04f, -6.19457475e-04f, -6.20401716e-04f, -6.10568704e-04f, + -6.18186956e-04f, -6.14285572e-04f, -6.16264511e-04f, -6.06527632e-04f, + -6.00044720e-04f, -6.07002680e-04f, -6.11980887e-04f, -6.08583852e-04f, + -6.05364625e-04f, -6.04267713e-04f, -6.02469588e-04f, -6.07514019e-04f, + -6.01863311e-04f, -6.05495605e-04f, -5.95886216e-04f, -5.94842544e-04f, + -5.95562284e-04f, -5.88854717e-04f, -5.85634595e-04f, -5.93604282e-04f, + -5.94237382e-04f, -5.85683491e-04f, -5.89473003e-04f, -5.88862807e-04f, + -5.88865374e-04f, -5.88801299e-04f, -5.88385872e-04f, -5.88651310e-04f, + -5.86645070e-04f, -5.90477671e-04f, -5.81684764e-04f, -5.85764232e-04f, + -5.83699282e-04f, -5.81516191e-04f, -5.80167627e-04f, -5.76260419e-04f, + -5.58444045e-04f, -5.64690272e-04f, -5.73387280e-04f, -5.74811558e-04f, + -5.64014528e-04f, -5.71347787e-04f, -5.67869127e-04f, -5.56793424e-04f, + -5.67429221e-04f, -5.62083370e-04f, -5.56825957e-04f, -5.56662650e-04f, + -5.62015361e-04f, -5.46761301e-04f, -5.52400799e-04f, -5.62915945e-04f, + -5.55946955e-04f, -5.57607945e-04f, -5.59766863e-04f, -5.55751848e-04f, + -5.54723149e-04f, -5.59078750e-04f, -5.47234430e-04f, -5.49785971e-04f, + -5.44835019e-04f, -5.50432047e-04f, -5.42534999e-04f, -5.46155417e-04f, + -5.47365815e-04f, -5.48656392e-04f, -5.47050433e-04f, -5.44446450e-04f, + -5.47883324e-04f, -5.43651688e-04f, -5.43748170e-04f, -5.44312825e-04f, + -5.36974465e-04f, -5.44821855e-04f, -5.34680990e-04f, -5.33853227e-04f, + -5.32461254e-04f, -5.39282808e-04f, -5.34414087e-04f, -5.36110661e-04f, + -5.29629690e-04f, -5.35753738e-04f, -5.28851320e-04f, -3.76084649e-04f, + -4.35218503e-04f, -5.09961619e-04f, -5.14811427e-04f, -4.33279967e-04f, + -4.60084569e-04f, -4.27740924e-04f, -5.31755906e-04f, -5.00343056e-04f, + -4.83670579e-04f, -5.23212014e-04f, -4.86587153e-04f, -5.33097355e-04f, + -4.90679516e-04f, -4.39002361e-04f, -4.71769560e-04f, -5.16557391e-04f, + -4.88751366e-04f, -4.83517243e-04f, -5.10729050e-04f, -4.88456644e-04f, + -5.18808669e-04f, -5.01263136e-04f, -5.06989428e-04f, -5.07891004e-04f, + -4.95490722e-04f, -4.58042503e-04f, -5.18499288e-04f, -4.92156366e-04f, + -4.74154739e-04f, -4.38805202e-04f, -4.76170882e-04f, -5.01449781e-04f, + -4.73759206e-04f, -5.02967897e-04f, -4.67694549e-04f, -5.02586734e-04f, + -4.78564670e-04f, -4.84565349e-04f, -4.78140289e-04f, -4.81748034e-04f, + -4.93259469e-04f, -4.76829153e-04f, -4.70016615e-04f, -4.42840568e-04f, + -4.60159181e-04f, -4.81467717e-04f, -4.79181128e-04f, -4.55875136e-04f, + -4.88189904e-04f, -4.64322928e-04f, -4.56915020e-04f, -4.58671857e-04f, + -4.79641350e-04f, -4.62321761e-04f, -4.65161141e-04f, -4.71885391e-04f, + -4.61360825e-04f, -4.66066066e-04f, -4.63308514e-04f, -4.74421397e-04f, + -4.67343945e-04f, -4.70441969e-04f, -4.68674622e-04f, -4.67416289e-04f, + -4.69704814e-04f, -4.60700699e-04f, -4.62329907e-04f, -4.56496373e-04f, + -4.35363103e-04f, -4.52481650e-04f, -4.58307581e-04f, -4.40873127e-04f, + -4.45765377e-04f, -4.50375020e-04f, -4.54124894e-04f, -4.48980196e-04f, + -4.53500190e-04f, -4.53244551e-04f, -4.54132033e-04f, -4.54252114e-04f, + -4.44010365e-04f, -4.42420576e-04f, -4.50180717e-04f, -4.50921809e-04f, + -4.49671438e-04f, -4.45204037e-04f, -4.38078142e-04f, -4.44269956e-04f, + -4.34465805e-04f, -4.38730333e-04f, -4.40685716e-04f, -4.40086475e-04f, + -4.37342415e-04f, -4.22844299e-04f, -4.13960500e-04f, -4.38080732e-04f, + -4.25451672e-04f, -3.46946175e-04f, -3.97127233e-04f, -4.29914843e-04f, + -4.11748071e-04f, -3.85715526e-04f, -3.91519364e-04f, -3.96145343e-04f, + -4.41557365e-04f, -3.98707137e-04f, -4.28311457e-04f, -4.15572256e-04f, + -4.24897108e-04f, -4.19365436e-04f, -3.91387904e-04f, -3.96678790e-04f, + -4.23980299e-04f, -4.08032995e-04f, -4.01917253e-04f, -4.22220328e-04f, + -4.07220417e-04f, -4.21863668e-04f, -4.11439016e-04f, -4.16905162e-04f, + -4.19127674e-04f, -4.05798030e-04f, -3.95323950e-04f, -4.17534979e-04f, + -4.02183232e-04f, -3.95454839e-04f, -3.81634866e-04f, -4.07906026e-04f, + -3.88594605e-04f, -4.02462750e-04f, -3.93646075e-04f, -3.96772187e-04f, + -4.04683855e-04f, -3.93389400e-04f, -3.97549834e-04f, -3.88844301e-04f, + -4.03687397e-04f, -3.96631788e-04f, -3.90176267e-04f, -3.77545482e-04f, + -3.85242734e-04f, -3.97083407e-04f, -3.91776874e-04f, -3.85140572e-04f, + -3.95574512e-04f, -3.86013641e-04f, -3.89582116e-04f, -3.87821469e-04f, + -3.91528302e-04f, -3.81396059e-04f, -3.87832433e-04f, -3.83143287e-04f, + -3.85715556e-04f, -3.84363402e-04f, -3.84634733e-04f, -3.85555364e-04f, + -3.76403752e-04f, -3.75926370e-04f, -3.82919427e-04f, -3.78855676e-04f, + -3.77412966e-04f, -3.75732997e-04f, -3.65587273e-04f, -3.56764333e-04f, + -3.71654680e-04f, -3.69844641e-04f, -3.67542443e-04f, -3.71089724e-04f, + -3.64153935e-04f, -3.70054882e-04f, -3.70812835e-04f, -3.70828809e-04f, + -3.68894140e-04f, -3.69359913e-04f, -3.68254246e-04f, -3.62101847e-04f, + -3.65235161e-04f, -3.68069867e-04f, -3.64871981e-04f, -3.64956744e-04f, + -3.57635902e-04f, -3.63764887e-04f, -3.57240096e-04f, -3.57706865e-04f, + -3.61369276e-04f, -3.56121010e-04f, -3.56979190e-04f, -3.49076417e-04f, + -3.43001072e-04f, -3.54546641e-04f, -3.54359143e-04f, -3.46946540e-04f, + -3.50259170e-04f, -3.51042286e-04f, -3.48582733e-04f, -3.51107836e-04f, + -3.48023899e-04f, -3.47433923e-04f, -3.42511534e-04f, -3.43618198e-04f, + -3.46570163e-04f, -3.46773062e-04f, -3.40698767e-04f, -3.42857845e-04f, + -3.42362728e-04f, -3.40846640e-04f, -3.41046369e-04f, -3.40384132e-04f, + -3.40188801e-04f, -3.40728690e-04f, -3.36726378e-04f, -3.37562425e-04f, + -3.35391519e-04f, -3.38885243e-04f, -3.34607660e-04f, -3.36584603e-04f, + -3.29959795e-04f, -3.35763651e-04f, -3.28409814e-04f, -3.37471708e-04f, + -3.21928542e-04f, -3.34825495e-04f, -3.06196664e-04f, -2.51314753e-04f, + -2.98144643e-04f, -3.29032670e-04f, -2.90810275e-04f, -2.87045272e-04f, + -2.79457288e-04f, -3.19918536e-04f, -3.15713347e-04f, -3.07600994e-04f, + -3.21191669e-04f, -3.08530326e-04f, -3.28925576e-04f, -2.88273905e-04f, + -2.89792582e-04f, -3.16771550e-04f, -3.07770959e-04f, -2.96237721e-04f, + -3.11414022e-04f, -3.05155325e-04f, -3.14433835e-04f, -3.06313234e-04f, + -3.10796402e-04f, -3.08011573e-04f, -2.81305290e-04f, -3.04639098e-04f, + -3.04585898e-04f, -2.88691352e-04f, -2.79441265e-04f, -2.91653174e-04f, + -2.98141463e-04f, -2.96735874e-04f, -3.01058661e-04f, -2.94156513e-04f, + -3.04437682e-04f, -2.89031818e-04f, -2.97393714e-04f, -2.92972532e-04f, + -3.03325148e-04f, -2.94186650e-04f, -2.86339556e-04f, -2.73912240e-04f, + -2.89733417e-04f, -2.91868333e-04f, -2.79522032e-04f, -2.90245809e-04f, + -2.90124562e-04f, -2.82877303e-04f, -2.89727036e-04f, -2.89871654e-04f, + -2.87657310e-04f, -2.85693089e-04f, -2.88542032e-04f, -2.85144772e-04f, + -2.87754769e-04f, -2.84677626e-04f, -2.88501418e-04f, -2.82526624e-04f, + -2.82837267e-04f, -2.82386268e-04f, -2.83363238e-04f, -2.78611125e-04f, + -2.83027149e-04f, -2.73010537e-04f, -2.67118620e-04f, -2.80160147e-04f, + -2.73173635e-04f, -2.70395356e-04f, -2.71905742e-04f, -2.74763918e-04f, + -2.73952100e-04f, -2.73781624e-04f, -2.74130234e-04f, -2.72497795e-04f, + -2.72809469e-04f, -2.66404619e-04f, -2.69065819e-04f, -2.70730149e-04f, + -2.70296661e-04f, -2.67578034e-04f, -2.65778124e-04f, -2.68826855e-04f, + -2.64682725e-04f, -2.66796204e-04f, -2.65509611e-04f, -2.66154956e-04f, + -2.60742640e-04f, -2.51594403e-04f, -2.56501145e-04f, -2.62115628e-04f, + -2.53683904e-04f, -2.59366014e-04f, -2.57389056e-04f, -2.57450036e-04f, + -2.56069919e-04f, -2.58824695e-04f, -2.54335684e-04f, -2.58465448e-04f, + -2.41875738e-04f, -2.16318473e-04f, -2.45691023e-04f, -2.47915293e-04f, + -2.32536337e-04f, -2.30525091e-04f, -2.33997805e-04f, -2.49596127e-04f, + -2.37862975e-04f, -2.44585159e-04f, -2.41002746e-04f, -2.46571256e-04f, + -2.39760126e-04f, -2.25078530e-04f, -2.41125449e-04f, -2.41799888e-04f, + -2.35239010e-04f, -2.41407079e-04f, -2.39510523e-04f, -2.42441594e-04f, + -2.38368383e-04f, -2.36460566e-04f, -2.41242781e-04f, -2.27251692e-04f, + -2.37097801e-04f, -2.37086723e-04f, -2.29550609e-04f, -2.21772042e-04f, + -2.34365824e-04f, -2.32018628e-04f, -2.31765690e-04f, -2.29601031e-04f, + -2.31864244e-04f, -2.30841425e-04f, -2.27446556e-04f, -2.28201098e-04f, + -2.28543943e-04f, -2.28286421e-04f, -2.19938997e-04f, -2.20096307e-04f, + -2.18074587e-04f, -2.27072129e-04f, -2.20018857e-04f, -2.20452164e-04f, + -2.22674051e-04f, -2.22042728e-04f, -2.19044260e-04f, -2.18263045e-04f, + -2.20350411e-04f, -2.19758375e-04f, -2.19089570e-04f, -2.20182682e-04f, + -2.18226206e-04f, -2.18675322e-04f, -2.19027620e-04f, -2.16230171e-04f, + -2.14044111e-04f, -2.14037867e-04f, -2.16062203e-04f, -2.11212932e-04f, + -2.14075400e-04f, -2.06167291e-04f, -2.09637490e-04f, -2.12309865e-04f, + -2.08925378e-04f, -2.09796142e-04f, -2.06203161e-04f, -2.09102053e-04f, + -2.07766914e-04f, -2.05846726e-04f, -2.06237976e-04f, -2.06269706e-04f, + -2.03561704e-04f, -2.04589562e-04f, -2.05261222e-04f, -2.04690450e-04f, + -2.02809245e-04f, -2.02436868e-04f, -2.02536873e-04f, -1.99459229e-04f, + -2.01559709e-04f, -2.00538749e-04f, -2.00615920e-04f, -1.96019830e-04f, + -1.93259456e-04f, -1.96339232e-04f, -1.94822753e-04f, -1.94736634e-04f, + -1.94665347e-04f, -1.93797279e-04f, -1.93821308e-04f, -1.93214294e-04f, + -1.93561801e-04f, -1.92111864e-04f, -1.92193913e-04f, -1.90830841e-04f, + -1.91162665e-04f, -1.89730750e-04f, -1.89002819e-04f, -1.89513877e-04f, + -1.88964807e-04f, -1.87441137e-04f, -1.86835351e-04f, -1.86491243e-04f, + -1.86467535e-04f, -1.84880939e-04f, -1.84577605e-04f, -1.84304096e-04f, + -1.83565802e-04f, -1.82389193e-04f, -1.81681778e-04f, -1.82086345e-04f, + -1.80813166e-04f, -1.79293029e-04f, -1.77301195e-04f, -1.78459199e-04f, + -1.77867035e-04f, -1.76615128e-04f, -1.77119977e-04f, -1.75131687e-04f, + -1.76173938e-04f, -1.75714256e-04f, -1.74139186e-04f, -1.72199421e-04f, + -1.73332904e-04f, -1.73338817e-04f, -1.71045287e-04f, -1.71222944e-04f, + -1.71477791e-04f, -1.71052347e-04f, -1.70516591e-04f, -1.69389045e-04f, + -1.69384862e-04f, -1.68100557e-04f, -1.67757223e-04f, -1.63638266e-04f, + -1.62823566e-04f, -1.66434456e-04f, -1.62702510e-04f, -1.62131910e-04f, + -1.61374679e-04f, -1.61110064e-04f, -1.61739872e-04f, -1.62125846e-04f, + -1.60140814e-04f, -1.60967046e-04f, -1.60691185e-04f, -1.60015765e-04f, + -1.59182008e-04f, -1.59493743e-04f, -1.57764490e-04f, -1.57660261e-04f, + -1.57566468e-04f, -1.54997862e-04f, -1.53497282e-04f, -1.55902352e-04f, + -1.53060095e-04f, -1.53369479e-04f, -1.53459283e-04f, -1.53053583e-04f, + -1.51843470e-04f, -1.51673987e-04f, -1.51458931e-04f, -1.50961213e-04f, + -1.50444578e-04f, -1.49877729e-04f, -1.48955149e-04f, -1.47226604e-04f, + -1.47818686e-04f, -1.46599763e-04f, -1.45608332e-04f, -1.45345052e-04f, + -1.44748785e-04f, -1.45635228e-04f, -1.43796621e-04f, -1.43114473e-04f, + -1.43563532e-04f, -1.41617846e-04f, -1.42183636e-04f, -1.41583437e-04f, + -1.41051575e-04f, -1.40485828e-04f, -1.39346823e-04f, -1.39728669e-04f, + -1.38871808e-04f, -1.37811410e-04f, -1.37824429e-04f, -1.37387898e-04f, + -1.36469800e-04f, -1.36025128e-04f, -1.35394699e-04f, -1.35132647e-04f, + -1.34451199e-04f, -1.34190112e-04f, -1.33525035e-04f, -1.33025014e-04f, + -1.32610046e-04f, -1.32001734e-04f, -1.31039054e-04f, -1.30984229e-04f, + -1.30099146e-04f, -1.29453958e-04f, -1.28720415e-04f, -1.28900962e-04f, + -1.27035830e-04f, -1.27996377e-04f, -1.25566829e-04f, -1.25554011e-04f, + -1.22705410e-04f, -1.29105984e-04f, -1.04275971e-04f, -8.92290507e-05f, + -1.24045708e-04f, -1.09781874e-04f, -1.03773749e-04f, -9.87625990e-05f, + -1.19339783e-04f, -1.15118116e-04f, -1.15996473e-04f, -1.17203076e-04f, + -1.19372417e-04f, -1.13309652e-04f, -9.86063986e-05f, -1.18260375e-04f, + -1.11492099e-04f, -1.12108588e-04f, -1.13777999e-04f, -1.13671421e-04f, + -1.15949343e-04f, -1.13663918e-04f, -1.16039113e-04f, -1.04926884e-04f, + -1.09797753e-04f, -1.13662058e-04f, -1.01429068e-04f, -1.00032083e-04f, + -1.09501618e-04f, -1.07326274e-04f, -1.07987003e-04f, -1.06754957e-04f, + -1.08764941e-04f, -1.04999499e-04f, -1.04797799e-04f, -1.05876060e-04f, + -1.07505479e-04f, -1.02442861e-04f, -9.64097289e-05f, -9.75581172e-05f, + -1.04355981e-04f, -9.92243607e-05f, -1.01901202e-04f, -1.01587885e-04f, + -9.95902527e-05f, -1.02160054e-04f, -1.00758979e-04f, -9.98248398e-05f, + -1.00025575e-04f, -9.99642188e-05f, -9.85801565e-05f, -9.87454709e-05f, + -9.85758258e-05f, -9.84738482e-05f, -9.72446055e-05f, -9.76303356e-05f, + -9.48922363e-05f, -9.60119064e-05f, -9.16043826e-05f, -8.96156836e-05f, + -9.40740999e-05f, -9.20304141e-05f, -9.27100136e-05f, -9.18322317e-05f, + -9.33134229e-05f, -9.19727629e-05f, -9.18630319e-05f, -9.15250546e-05f, + -9.00094701e-05f, -8.74876495e-05f, -8.97596274e-05f, -8.93567399e-05f, + -8.84855815e-05f, -8.68930452e-05f, -8.83622104e-05f, -8.62835849e-05f, + -8.72617806e-05f, -8.63623137e-05f, -8.63145313e-05f, -8.04075853e-05f, + -8.05146487e-05f, -8.49523276e-05f, -8.17291455e-05f, -8.28765638e-05f, + -8.21753189e-05f, -8.18686078e-05f, -8.10860132e-05f, -8.18332999e-05f, + -8.07671347e-05f, -8.01766562e-05f, -8.04026601e-05f, -7.95782456e-05f, + -7.79862936e-05f, -7.92524800e-05f, -7.82759247e-05f, -7.82718895e-05f, + -7.65111376e-05f, -7.81383704e-05f, -7.55816022e-05f, -7.80433204e-05f, + -6.28351761e-05f, -6.01380694e-05f, -7.53301556e-05f, -6.61423422e-05f, + -6.32740304e-05f, -6.37918931e-05f, -7.36395845e-05f, -6.66026573e-05f, + -6.93881433e-05f, -6.85685730e-05f, -7.10998981e-05f, -6.17801846e-05f, + -6.49234173e-05f, -6.95500569e-05f, -6.53272989e-05f, -6.80946767e-05f, + -6.66677304e-05f, -6.88672116e-05f, -6.70890172e-05f, -6.81420266e-05f, + -6.32265934e-05f, -6.37447504e-05f, -6.68982776e-05f, -5.82382313e-05f, + -5.81619208e-05f, -6.32760373e-05f, -6.17669292e-05f, -6.18611415e-05f, + -6.03488120e-05f, -6.16155737e-05f, -6.00127443e-05f, -5.72621907e-05f, + -5.97085604e-05f, -6.02596273e-05f, -5.66595113e-05f, -5.47616180e-05f, + -5.78572476e-05f, -5.83383702e-05f, -5.57348213e-05f, -5.79850827e-05f, + -5.47671661e-05f, -5.73828646e-05f, -5.60601004e-05f, -5.49530046e-05f, + -5.52245372e-05f, -5.56277736e-05f, -5.46504370e-05f, -5.43788435e-05f, + -5.40706364e-05f, -5.38435146e-05f, -5.31215875e-05f, -5.27974623e-05f, + -5.14343824e-05f, -5.19721382e-05f, -4.93751049e-05f, -4.86928962e-05f, + -5.08461399e-05f, -4.89585189e-05f, -4.95109761e-05f, -4.88678807e-05f, + -4.85249373e-05f, -4.86847799e-05f, -4.83443226e-05f, -4.80787223e-05f, + -4.63545489e-05f, -4.65019866e-05f, -4.55384197e-05f, -4.59052283e-05f, + -4.49670346e-05f, -4.43071041e-05f, -4.48452555e-05f, -4.37057069e-05f, + -4.42625073e-05f, -4.35245919e-05f, -4.22245670e-05f, -4.00025516e-05f, + -4.27280250e-05f, -4.11725254e-05f, -4.10764474e-05f, -4.10869791e-05f, + -4.04313009e-05f, -4.02498345e-05f, -4.01633721e-05f, -3.95463953e-05f, + -3.91442666e-05f, -3.87334279e-05f, -3.81776818e-05f, -3.75200751e-05f, + -3.76123897e-05f, -3.73924414e-05f, -3.65113970e-05f, -3.58326981e-05f, + -3.60703324e-05f, -3.55096265e-05f, -3.47073875e-05f, -3.45646793e-05f, + -3.47987383e-05f, -3.37485175e-05f, -3.34949112e-05f, -3.29331904e-05f, + -3.18843190e-05f, -3.23146823e-05f, -3.05437916e-05f, -3.12566513e-05f, + -3.07286096e-05f, -3.06746044e-05f, -3.02684899e-05f, -3.01836609e-05f, + -2.96698387e-05f, -2.93138251e-05f, -2.88606287e-05f, -2.88157391e-05f, + -2.81979169e-05f, -2.77963145e-05f, -2.69987305e-05f, -2.75340181e-05f, + -2.63062752e-05f, -2.66878702e-05f, -2.55138871e-05f, -2.59334257e-05f, + -2.46262879e-05f, -2.54418203e-05f, -2.34667224e-05f, -2.50850174e-05f, + -2.18725638e-05f, -2.46575883e-05f, -8.53248875e-06f, -1.01759170e-05f, + -2.18811058e-05f, -1.33563051e-05f, -9.88987901e-06f, -1.55024070e-05f, + -1.96485551e-05f, -1.67153592e-05f, -1.88762751e-05f, -1.77562991e-05f, + -1.63701416e-05f, -8.94267316e-06f, -1.90171801e-05f, -1.38321995e-05f, + -1.59476902e-05f, -1.50801638e-05f, -1.66008391e-05f, -1.56308165e-05f, + -1.66447010e-05f, -1.29679421e-05f, -1.29514642e-05f, -1.58477157e-05f, + -9.76445313e-06f, -9.16810435e-06f, -1.32627810e-05f, -1.17306895e-05f, + -1.19749623e-05f, -1.16516413e-05f, -1.15437097e-05f, -1.02183431e-05f, + -1.08903742e-05f, -1.14455062e-05f, -9.91725729e-06f, -5.50019707e-06f, + -7.39333889e-06f, -9.87475314e-06f, -7.07374927e-06f, -8.62224102e-06f, + -7.56099939e-06f, -8.06853997e-06f, -8.43160016e-06f, -7.04287685e-06f, + -7.24337207e-06f, -7.07220205e-06f, -6.44495318e-06f, -6.31467321e-06f, + -6.35688939e-06f, -5.84259024e-06f, -5.59968811e-06f, -5.00482378e-06f, + -3.84243320e-06f, -4.62096801e-06f, -9.08155590e-07f, -2.66046992e-06f, + -3.16051512e-06f, -2.09848402e-06f, -2.40681188e-06f, -2.09296696e-06f, + -2.42223821e-06f, -1.69053045e-06f, -1.66840440e-06f, -1.91173363e-07f, + 2.84606811e-08f, -4.99408955e-07f, -3.31019313e-07f, 1.30534562e-06f, + 1.03567163e-06f, 9.18286097e-07f, 1.82045206e-06f, 1.53782250e-06f, + 1.75662154e-06f, 3.91547194e-06f, 5.05017231e-06f, 2.62647402e-06f, + 4.70857836e-06f, 3.83412670e-06f, 4.47202900e-06f, 4.71136393e-06f, + 4.68621235e-06f, 4.73811490e-06f, 5.55675535e-06f, 5.35969967e-06f, + 5.78648808e-06f, 6.51353985e-06f, 6.87084691e-06f, 6.59266195e-06f, + 7.35541260e-06f, 7.53611358e-06f, 7.86912100e-06f, 7.84846625e-06f, + 8.91040247e-06f, 8.51459599e-06f, 9.18031787e-06f, 9.30422742e-06f, + 1.03107371e-05f, 9.52919653e-06f, 1.08814180e-05f, 1.00656276e-05f, + 2.02233979e-05f, 1.61499494e-05f, 1.25493254e-05f, 1.65100255e-05f, + 1.81124697e-05f, 1.39674147e-05f, 1.38530324e-05f, 1.42768161e-05f, + 1.45762957e-05f, 1.47180748e-05f, 1.77365238e-05f, 1.74121343e-05f, + 1.49546514e-05f, 1.72877192e-05f, 1.60561550e-05f, 1.63025836e-05f, + 1.56093223e-05f, 1.64805905e-05f, 1.69681269e-05f, 1.89238678e-05f, + 1.61404275e-05f, 1.99137041e-05f, 2.16300520e-05f, 1.85482369e-05f, + 1.96431739e-05f, 1.99397201e-05f, 1.96120180e-05f, 2.01414202e-05f, + 2.08194184e-05f, 2.05017977e-05f, 2.02402568e-05f, 2.12204268e-05f, + 2.33862253e-05f, 2.22216169e-05f, 2.15050956e-05f, 2.27401822e-05f, + 2.24342700e-05f, 2.30512394e-05f, 2.24437817e-05f, 2.31011103e-05f, + 2.38457144e-05f, 2.37486483e-05f, 2.37383821e-05f, 2.42748188e-05f, + 2.45406002e-05f, 2.45445473e-05f, 2.49265534e-05f, 2.49728191e-05f, + 2.57807664e-05f, 2.57360359e-05f, 2.69579637e-05f, 2.73082154e-05f, + 2.65538995e-05f, 2.73695721e-05f, 2.77563377e-05f, 2.78507159e-05f, + 2.73922207e-05f, 2.82909710e-05f, 2.80755494e-05f, 2.91130765e-05f, + 2.91161058e-05f, 2.90378933e-05f, 2.91621055e-05f, 3.00967976e-05f, + 2.97705255e-05f, 3.03155596e-05f, 3.04688483e-05f, 3.07179451e-05f, + 3.09919044e-05f, 3.25597965e-05f, 3.21471511e-05f, 3.18666503e-05f, + 3.29515437e-05f, 3.24690182e-05f, 3.30534982e-05f, 3.29841262e-05f, + 3.32454351e-05f, 3.34235885e-05f, 3.38643796e-05f, 3.37560073e-05f, + 3.44103473e-05f, 3.47363188e-05f, 3.46435817e-05f, 3.51086167e-05f, + 3.53516513e-05f, 3.58322212e-05f, 3.63227395e-05f, 3.62741360e-05f, + 3.67816765e-05f, 3.66055320e-05f, 3.71632381e-05f, 3.72316539e-05f, + 3.74420974e-05f, 3.76529202e-05f, 3.83389726e-05f, 3.86806501e-05f, + 3.85911484e-05f, 3.89396682e-05f, 3.90905447e-05f, 3.93991582e-05f, + 3.94306512e-05f, 3.98077068e-05f, 3.99075486e-05f, 4.02910596e-05f, + 4.05203004e-05f, 4.07730889e-05f, 4.10987019e-05f, 4.12655090e-05f, + 4.15046566e-05f, 4.18088946e-05f, 4.19895269e-05f, 4.22355647e-05f, + 4.26880751e-05f, 4.28212447e-05f, 4.30217627e-05f, 4.34102368e-05f, + 4.41944029e-05f, 4.37886373e-05f, 4.42416919e-05f, 4.42755770e-05f, + 4.48452989e-05f, 4.52396644e-05f, 4.50147156e-05f, 4.55642135e-05f, + 4.56371038e-05f, 4.64652256e-05f, 4.61214912e-05f, 4.65034074e-05f, + 4.66457956e-05f, 4.68637224e-05f, 4.70028402e-05f, 4.73354716e-05f, + 4.74837917e-05f, 4.77789590e-05f, 4.80431503e-05f, 4.81694864e-05f, + 4.86748288e-05f, 4.86106745e-05f, 4.90175473e-05f, 4.91814553e-05f, + 4.93964416e-05f, 4.96884304e-05f, 5.00313844e-05f, 5.02433945e-05f, + 5.02828012e-05f, 5.05602355e-05f, 5.08007886e-05f, 5.13200081e-05f, + 5.14768695e-05f, 5.14501330e-05f, 5.19286347e-05f, 5.20487409e-05f, + 5.22802920e-05f, 5.23946947e-05f, 5.26815186e-05f, 5.27756778e-05f, + 5.31873778e-05f, 5.35217007e-05f, 5.35006269e-05f, 5.38518674e-05f, + 5.39973564e-05f, 5.42174801e-05f, 5.44246766e-05f, 5.46180031e-05f, + 5.48153001e-05f, 5.51599363e-05f, 5.53306627e-05f, 5.54958784e-05f, + 5.57709346e-05f, 5.59433449e-05f, 5.61906447e-05f, 5.64067776e-05f, + 5.65904828e-05f, 5.68919811e-05f, 5.71230049e-05f, 5.72870512e-05f, + 5.74729148e-05f, 5.77458433e-05f, 5.82437404e-05f, 5.82108251e-05f, + 5.83872934e-05f, 5.87229894e-05f, 5.89548021e-05f, 5.90466192e-05f, + 5.93280410e-05f, 5.94332290e-05f, 5.96950349e-05f, 5.98949954e-05f, + 6.00885865e-05f, 6.03128656e-05f, 6.04987728e-05f, 6.06927711e-05f, + 6.09303110e-05f, 6.11258679e-05f, 6.13196810e-05f, 6.15363482e-05f, + 6.18074800e-05f, 6.19106556e-05f, 6.22013940e-05f, 6.23965315e-05f, + 6.26697040e-05f, 6.28327200e-05f, 6.32898933e-05f, 6.31704303e-05f, + 6.38638679e-05f, 6.40878394e-05f, 6.38503657e-05f, 6.42296258e-05f, + 6.43076138e-05f, 6.46996633e-05f, 7.29535554e-05f, 6.79277943e-05f, + 6.60563291e-05f, 7.13629471e-05f, 6.89759062e-05f, 6.65079100e-05f, + 6.70538634e-05f, 6.72548299e-05f, 6.57593238e-05f, 6.97984915e-05f, + 6.97894021e-05f, 6.70860329e-05f, 6.90089539e-05f, 6.76860108e-05f, + 6.78572741e-05f, 6.75116141e-05f, 6.77580581e-05f, 6.91032834e-05f, + 6.93790118e-05f, 6.79386541e-05f, 7.21774789e-05f, 7.01210966e-05f, + 6.95316824e-05f, 6.98174089e-05f, 7.00551970e-05f, 6.97550308e-05f, + 7.08091848e-05f, 7.03900095e-05f, 7.01361829e-05f, 7.10921186e-05f, + 7.31443304e-05f, 7.10839996e-05f, 7.15373938e-05f, 7.17489065e-05f, + 7.16344076e-05f, 7.19140670e-05f, 7.14558169e-05f, 7.23807998e-05f, + 7.21357952e-05f, 7.23146309e-05f, 7.24624044e-05f, 7.26029774e-05f, + 7.25499317e-05f, 7.29142428e-05f, 7.29710418e-05f, 7.35099636e-05f, + 7.33638464e-05f, 7.50831017e-05f, 7.41441366e-05f, 7.42666364e-05f, + 7.45904261e-05f, 7.45696208e-05f, 7.43952223e-05f, 7.46779563e-05f, + 7.49006194e-05f, 7.52345557e-05f, 7.57565327e-05f, 7.52780155e-05f, + 7.55332356e-05f, 7.59609810e-05f, 7.59004821e-05f, 7.61542430e-05f, + 7.63342620e-05f, 7.61964071e-05f, 7.71369089e-05f, 7.80595057e-05f, + 7.69382742e-05f, 7.75785920e-05f, 7.73915826e-05f, 7.76291149e-05f, + 7.77647762e-05f, 7.77397910e-05f, 7.80055715e-05f, 7.82216022e-05f, + 7.82326922e-05f, 7.86000031e-05f, 7.87368013e-05f, 7.86378206e-05f, + 7.90064467e-05f, 7.91465441e-05f, 7.92013973e-05f, 7.95308282e-05f, + 7.97571514e-05f, 7.96497209e-05f, 7.99946112e-05f, 8.02605248e-05f, + 8.02606935e-05f, 8.02727418e-05f, 8.08563291e-05f, 8.11502027e-05f, + 8.09561188e-05f, 8.12617359e-05f, 8.11680979e-05f, 8.14258222e-05f, + 8.14383139e-05f, 8.16918766e-05f, 8.17228340e-05f, 8.21485579e-05f, + 8.63405175e-05f, 8.33875012e-05f, 8.32812283e-05f, 8.56959464e-05f, + 8.41519875e-05f, 8.32973607e-05f, 8.37736225e-05f, 8.35533983e-05f, + 8.36727529e-05f, 8.56313757e-05f, 8.46944914e-05f, 8.48308547e-05f, + 8.46749228e-05f, 8.46592244e-05f, 8.43682231e-05f, 8.44735789e-05f, + 8.47158998e-05f, 8.57843862e-05f, 8.45841423e-05f, 8.61656129e-05f, + 8.64434139e-05f, 8.54710731e-05f, 8.59040875e-05f, 8.60083867e-05f, + 8.60106037e-05f, 8.64640155e-05f, 8.64739652e-05f, 8.64079518e-05f, + 8.67771441e-05f, 8.77794197e-05f, 8.70026144e-05f, 8.71233287e-05f, + 8.72599333e-05f, 8.73172189e-05f, 8.74499500e-05f, 8.73904228e-05f, + 8.78299980e-05f, 8.76225257e-05f, 8.78744150e-05f, 8.79763061e-05f, + 8.82585275e-05f, 8.83341379e-05f, 8.83000555e-05f, 8.86428487e-05f, + 8.86615704e-05f, 8.90443369e-05f, 8.95365962e-05f, 8.90180294e-05f, + 8.94157661e-05f, 8.93948195e-05f, 8.94927183e-05f, 8.94982923e-05f, + 8.97281988e-05f, 8.98118927e-05f, 9.02366270e-05f, 9.01238016e-05f, + 9.01612666e-05f, 9.05198172e-05f, 9.05307264e-05f, 9.06556684e-05f, + 9.08794526e-05f, 9.07777671e-05f, 9.12473181e-05f, 9.18223473e-05f, + 9.13363685e-05f, 9.16901876e-05f, 9.16512288e-05f, 9.17877962e-05f, + 9.18772151e-05f, 9.21753100e-05f, 9.22026577e-05f, 9.22468062e-05f, + 9.23538737e-05f, 9.25756901e-05f, 9.25926734e-05f, 9.26296318e-05f, + 9.28847057e-05f, 9.29443777e-05f, 9.30422697e-05f, 9.32467224e-05f, + 9.33487375e-05f, 9.33722137e-05f, 9.36361763e-05f, 9.37560799e-05f, + 9.37483715e-05f, 9.39939821e-05f, 9.43674823e-05f, 9.42240608e-05f, + 9.44123343e-05f, 9.44536319e-05f, 9.45635449e-05f, 9.46412307e-05f, + 9.47450472e-05f, 9.48799869e-05f, 9.50166691e-05f, 9.51157068e-05f, + 9.52673683e-05f, 9.53595127e-05f, 9.54605596e-05f, 9.56320257e-05f, + 9.57002583e-05f, 9.58072265e-05f, 9.59721745e-05f, 9.60641184e-05f, + 9.61302600e-05f, 9.65618391e-05f, 9.68354616e-05f, 9.66531927e-05f, + 9.67898352e-05f, 9.68163848e-05f, 9.69619360e-05f, 9.70519667e-05f, + 9.71168957e-05f, 9.72459308e-05f, 9.73453120e-05f, 9.74122539e-05f, + 9.75229899e-05f, 9.76079046e-05f, 9.77246421e-05f, 9.78542525e-05f, + 9.80429190e-05f, 9.81471018e-05f, 9.82594072e-05f, 9.83772511e-05f, + 9.82474207e-05f, 9.89885051e-05f, 1.02835121e-04f, 9.92444103e-05f, + 1.00341769e-04f, 1.01822633e-04f, 1.00128520e-04f, 9.94906718e-05f, + 1.00036785e-04f, 9.91671972e-05f, 1.00634399e-04f, 1.01452362e-04f, + 9.98590413e-05f, 1.00640740e-04f, 1.00197845e-04f, 1.00120967e-04f, + 1.00033424e-04f, 1.00069076e-04f, 1.01090474e-04f, 1.00358003e-04f, + 1.01045158e-04f, 1.02078922e-04f, 1.00793388e-04f, 1.01157165e-04f, + 1.01080518e-04f, 1.01128870e-04f, 1.01442936e-04f, 1.01545310e-04f, + 1.01146425e-04f, 1.01856159e-04f, 1.02649595e-04f, 1.01687924e-04f, + 1.02034846e-04f, 1.01945488e-04f, 1.02088891e-04f, 1.01986145e-04f, + 1.02028518e-04f, 1.02277335e-04f, 1.02324077e-04f, 1.02519359e-04f, + 1.02403102e-04f, 1.02535257e-04f, 1.02548611e-04f, 1.02667030e-04f, + 1.02792134e-04f, 1.02906844e-04f, 1.03605419e-04f, 1.03138814e-04f, + 1.03288737e-04f, 1.03391530e-04f, 1.03294359e-04f, 1.03366848e-04f, + 1.03509861e-04f, 1.03549031e-04f, 1.03967061e-04f, 1.03781207e-04f, + 1.03771921e-04f, 1.04067052e-04f, 1.04031405e-04f, 1.04115781e-04f, + 1.04234546e-04f, 1.04121354e-04f, 1.04814685e-04f, 1.04919839e-04f, + 1.04524333e-04f, 1.04842857e-04f, 1.04705605e-04f, 1.04929453e-04f, + 1.04838952e-04f, 1.04945749e-04f, 1.05077468e-04f, 1.05064381e-04f, + 1.05216015e-04f, 1.05385297e-04f, 1.05309142e-04f, 1.05474794e-04f, + 1.05549796e-04f, 1.05552933e-04f, 1.05734832e-04f, 1.05779310e-04f, + 1.05770783e-04f, 1.05964230e-04f, 1.06037895e-04f, 1.05998861e-04f, + 1.06171984e-04f, 1.06491267e-04f, 1.06355337e-04f, 1.06477889e-04f, + 1.06452762e-04f, 1.06545193e-04f, 1.06635004e-04f, 1.06707110e-04f, + 1.06720306e-04f, 1.06854995e-04f, 1.06990472e-04f, 1.07063330e-04f, + 1.07007260e-04f, 1.07225802e-04f, 1.07114272e-04f, 1.07672450e-04f, + 1.09410061e-04f, 1.07624691e-04f, 1.08457914e-04f, 1.09019567e-04f, + 1.08202703e-04f, 1.07943839e-04f, 1.08177704e-04f, 1.07776963e-04f, + 1.08785719e-04f, 1.08589031e-04f, 1.08269970e-04f, 1.08510259e-04f, + 1.08249632e-04f, 1.08355891e-04f, 1.08229753e-04f, 1.08612487e-04f, + 1.08748944e-04f, 1.08538552e-04f, 1.09417670e-04f, 1.09030650e-04f, + 1.08860956e-04f, 1.08984744e-04f, 1.08947801e-04f, 1.09105460e-04f, + 1.09194888e-04f, 1.09094130e-04f, 1.09247406e-04f, 1.09882377e-04f, + 1.09388821e-04f, 1.09484387e-04f, 1.09521926e-04f, 1.09585798e-04f, + 1.09665624e-04f, 1.09572149e-04f, 1.09799225e-04f, 1.09691600e-04f, + 1.09840435e-04f, 1.09812150e-04f, 1.09921403e-04f, 1.09879038e-04f, + 1.10044188e-04f, 1.10042910e-04f, 1.10276203e-04f, 1.10490832e-04f, + 1.10262664e-04f, 1.10431944e-04f, 1.10410221e-04f, 1.10408359e-04f, + 1.10497565e-04f, 1.10510515e-04f, 1.10661248e-04f, 1.10745996e-04f, + 1.10664719e-04f, 1.10794396e-04f, 1.10871145e-04f, 1.10883042e-04f, + 1.10963178e-04f, 1.10935113e-04f, 1.11168459e-04f, 1.11536439e-04f, + 1.11180810e-04f, 1.11358120e-04f, 1.11296552e-04f, 1.11371017e-04f, + 1.11374077e-04f, 1.11405775e-04f, 1.11510709e-04f, 1.11506937e-04f, + 1.11601636e-04f, 1.11660647e-04f, 1.11653400e-04f, 1.11751748e-04f, + 1.11795405e-04f, 1.11804509e-04f, 1.11948880e-04f, 1.11976530e-04f, + 1.11954562e-04f, 1.12087492e-04f, 1.12227484e-04f, 1.12118175e-04f, + 1.12304191e-04f, 1.12368875e-04f, 1.12393850e-04f, 1.12406171e-04f, + 1.12389533e-04f, 1.12456604e-04f, 1.12462517e-04f, 1.12511018e-04f, + 1.12535742e-04f, 1.12606081e-04f, 1.12647639e-04f, 1.12749424e-04f, + 1.12770346e-04f, 1.12896100e-04f, 1.12873821e-04f, 1.12903509e-04f, + 1.12972849e-04f, 1.12961638e-04f, 1.13040780e-04f, 1.13174817e-04f, + 1.13119903e-04f, 1.13216610e-04f, 1.13200622e-04f, 1.13247034e-04f, + 1.13278971e-04f, 1.13336857e-04f, 1.13348796e-04f, 1.13401418e-04f, + 1.13442119e-04f, 1.13494216e-04f, 1.13505577e-04f, 1.13558270e-04f, + 1.13591271e-04f, 1.13635113e-04f, 1.13706750e-04f, 1.13715850e-04f, + 1.13745044e-04f, 1.13804535e-04f, 1.13827109e-04f, 1.13861606e-04f, + 1.13961110e-04f, 1.13973330e-04f, 1.14015053e-04f, 1.14017074e-04f, + 1.14060828e-04f, 1.14080134e-04f, 1.14202286e-04f, 1.14192656e-04f, + 1.14212854e-04f, 1.14261069e-04f, 1.14276445e-04f, 1.14337136e-04f, + 1.14341803e-04f, 1.14381745e-04f, 1.14397445e-04f, 1.14448344e-04f, + 1.14470921e-04f, 1.14499695e-04f, 1.14540738e-04f, 1.14567455e-04f, + 1.14600315e-04f, 1.14650582e-04f, 1.14684261e-04f, 1.14699328e-04f, + 1.14738514e-04f, 1.14757810e-04f, 1.14804388e-04f, 1.14822022e-04f, + 1.14873477e-04f, 1.14908969e-04f, 1.14916470e-04f, 1.14942003e-04f, + 1.15002435e-04f, 1.15064479e-04f, 1.15032900e-04f, 1.15087465e-04f, + 1.15093329e-04f, 1.15122652e-04f, 1.15134593e-04f, 1.15198847e-04f, + 1.15216625e-04f, 1.15233136e-04f, 1.15285675e-04f, 1.15295879e-04f, + 1.15312918e-04f, 1.15341045e-04f, 1.15361127e-04f, 1.15395435e-04f, + 1.15423490e-04f, 1.15447648e-04f, 1.15471899e-04f, 1.15499490e-04f, + 1.15512835e-04f, 1.15542083e-04f, 1.15582806e-04f, 1.15611179e-04f, + 1.15630016e-04f, 1.15658005e-04f, 1.15664864e-04f, 1.15690189e-04f, + 1.15708376e-04f, 1.15730545e-04f, 1.15748033e-04f, 1.15773031e-04f, + 1.15795429e-04f, 1.15841925e-04f, 1.15856205e-04f, 1.15873787e-04f, + 1.15881804e-04f, 1.15919495e-04f, 1.15972422e-04f, 1.15960058e-04f, + 1.15974406e-04f, 1.16012462e-04f, 1.16019722e-04f, 1.16035858e-04f, + 1.16066473e-04f, 1.16085151e-04f, 1.16070555e-04f, 1.16129457e-04f, + 1.16089794e-04f, 1.16169926e-04f, 1.16124471e-04f, 1.16238022e-04f, + 1.16126127e-04f, 1.16291869e-04f, 1.16120155e-04f, 1.16375595e-04f, + 1.16018258e-04f, 1.17024939e-04f, 1.18103541e-04f, 1.16321729e-04f, + 1.17716141e-04f, 1.17326731e-04f, 1.16518982e-04f, 1.16757107e-04f, + 1.16389588e-04f, 1.16717277e-04f, 1.17318747e-04f, 1.16483566e-04f, + 1.16857835e-04f, 1.16506405e-04f, 1.16559816e-04f, 1.16338426e-04f, + 1.16724161e-04f, 1.16743263e-04f, 1.16540029e-04f, 1.17318116e-04f, + 1.16718220e-04f, 1.16693867e-04f, 1.16701939e-04f, 1.16665112e-04f, + 1.16780024e-04f, 1.16730647e-04f, 1.16563096e-04f, 1.17140805e-04f, + 1.16953512e-04f, 1.16722331e-04f, 1.16841179e-04f, 1.16718356e-04f, + 1.16745246e-04f, 1.16679991e-04f, 1.16801716e-04f, 1.16668854e-04f, + 1.16767773e-04f, 1.16671911e-04f, 1.16724938e-04f, 1.16669796e-04f, + 1.16773348e-04f, 1.16705384e-04f, 1.17030552e-04f, 1.16898259e-04f, + 1.16805004e-04f, 1.16883206e-04f, 1.16752661e-04f, 1.16781372e-04f, + 1.16746817e-04f, 1.16840667e-04f, 1.16890798e-04f, 1.16774792e-04f, + 1.16827640e-04f, 1.16852752e-04f, 1.16800503e-04f, 1.16867094e-04f, + 1.16735951e-04f, 1.17052157e-04f, 1.17031890e-04f, 1.16850697e-04f, + 1.16929641e-04f, 1.16844809e-04f, 1.16896133e-04f, 1.16807059e-04f, + 1.16892009e-04f, 1.16822521e-04f, 1.16864234e-04f, 1.16893378e-04f, + 1.16837717e-04f, 1.16864623e-04f, 1.16868103e-04f, 1.16834682e-04f, + 1.16890221e-04f, 1.16848841e-04f, 1.16841036e-04f, 1.16891785e-04f, + 1.16847186e-04f, 1.16846718e-04f, 1.16962674e-04f, 1.16941277e-04f, + 1.16946140e-04f, 1.16891412e-04f, 1.16867282e-04f, 1.16874643e-04f, + 1.16851452e-04f, 1.16845610e-04f, 1.16827261e-04f, 1.16853837e-04f, + 1.16809300e-04f, 1.16839449e-04f, 1.16811066e-04f, 1.16833744e-04f, + 1.16823582e-04f, 1.16884161e-04f, 1.16763300e-04f, 1.16958613e-04f, + 1.16822078e-04f, 1.16899156e-04f, 1.16695723e-04f, 1.17264948e-04f, + 1.17626091e-04f, 1.16833643e-04f, 1.17540223e-04f, 1.17143769e-04f, + 1.16873455e-04f, 1.16945459e-04f, 1.16722876e-04f, 1.17069801e-04f, + 1.17090789e-04f, 1.16782019e-04f, 1.16974635e-04f, 1.16696578e-04f, + 1.16770473e-04f, 1.16638935e-04f, 1.16931465e-04f, 1.16657968e-04f, + 1.16944971e-04f, 1.16989125e-04f, 1.16693635e-04f, 1.16766928e-04f, + 1.16688311e-04f, 1.16770835e-04f, 1.16782059e-04f, 1.16613220e-04f, + 1.16818218e-04f, 1.16868154e-04f, 1.16636650e-04f, 1.16702516e-04f, + 1.16612594e-04f, 1.16616507e-04f, 1.16564641e-04f, 1.16609004e-04f, + 1.16537354e-04f, 1.16556169e-04f, 1.16504712e-04f, 1.16503942e-04f, + 1.16486633e-04f, 1.16496463e-04f, 1.16469546e-04f, 1.16603368e-04f, + 1.16502466e-04f, 1.16459544e-04f, 1.16482977e-04f, 1.16398599e-04f, + 1.16401035e-04f, 1.16353237e-04f, 1.16454268e-04f, 1.16437631e-04f, + 1.16326788e-04f, 1.16386379e-04f, 1.16319163e-04f, 1.16318122e-04f, + 1.16277268e-04f, 1.16272538e-04f, 1.16412581e-04f, 1.16274337e-04f, + 1.16276918e-04f, 1.16236274e-04f, 1.16222895e-04f, 1.16186146e-04f, + 1.16168759e-04f, 1.16173789e-04f, 1.16124297e-04f, 1.16150207e-04f, + 1.16096592e-04f, 1.16085286e-04f, 1.16075974e-04f, 1.16045908e-04f, + 1.16057487e-04f, 1.16026196e-04f, 1.15992060e-04f, 1.16005520e-04f, + 1.15973469e-04f, 1.15939367e-04f, 1.15982297e-04f, 1.15941020e-04f, + 1.15909140e-04f, 1.15895090e-04f, 1.15882050e-04f, 1.15841146e-04f, + 1.15822843e-04f, 1.15797194e-04f, 1.15776136e-04f, 1.15760380e-04f, + 1.15732005e-04f, 1.15722099e-04f, 1.15699453e-04f, 1.15673492e-04f, + 1.15662507e-04f, 1.15643895e-04f, 1.15608196e-04f, 1.15665634e-04f, + 1.15624567e-04f, 1.15577974e-04f, 1.15557626e-04f, 1.15529511e-04f, + 1.15505514e-04f, 1.15478201e-04f, 1.15449933e-04f, 1.15432874e-04f, + 1.15397606e-04f, 1.15384862e-04f, 1.15349710e-04f, 1.15368545e-04f, + 1.15338955e-04f, 1.15317473e-04f, 1.15285037e-04f, 1.15246285e-04f, + 1.15221257e-04f, 1.15201562e-04f, 1.15166608e-04f, 1.15152692e-04f, + 1.15129615e-04f, 1.15121034e-04f, 1.15058928e-04f, 1.15073336e-04f, + 1.15030810e-04f, 1.15045862e-04f, 1.14958380e-04f, 1.14997152e-04f, + 1.14891509e-04f, 1.14953552e-04f, 1.14806036e-04f, 1.14941507e-04f, + 1.14664094e-04f, 1.15362544e-04f, 1.15487201e-04f, 1.14818430e-04f, + 1.15512828e-04f, 1.14928150e-04f, 1.14803369e-04f, 1.14769408e-04f, + 1.14603742e-04f, 1.15029777e-04f, 1.14714220e-04f, 1.14667303e-04f, + 1.14610820e-04f, 1.14502449e-04f, 1.14412888e-04f, 1.14513106e-04f, + 1.14542551e-04f, 1.14441401e-04f, 1.14743738e-04f, 1.14365681e-04f, + 1.14384891e-04f, 1.14292618e-04f, 1.14288090e-04f, 1.14303542e-04f, + 1.14159858e-04f, 1.14256163e-04f, 1.14386152e-04f, 1.14111573e-04f, + 1.14150895e-04f, 1.14057169e-04f, 1.14034518e-04f, 1.13955821e-04f, + 1.13976013e-04f, 1.13896817e-04f, 1.13893375e-04f, 1.13824824e-04f, + 1.13801144e-04f, 1.13767273e-04f, 1.13750949e-04f, 1.13744283e-04f, + 1.13830122e-04f, 1.13662588e-04f, 1.13678071e-04f, 1.13596433e-04f, + 1.13545777e-04f, 1.13507773e-04f, 1.13489423e-04f, 1.13521043e-04f, + 1.13417991e-04f, 1.13403857e-04f, 1.13393065e-04f, 1.13334377e-04f, + 1.13338132e-04f, 1.13227475e-04f, 1.13376428e-04f, 1.13267227e-04f, + 1.13192053e-04f, 1.13157312e-04f, 1.13112701e-04f, 1.13064951e-04f, + 1.13018081e-04f, 1.13002003e-04f, 1.12938620e-04f, 1.12954766e-04f, + 1.12881339e-04f, 1.12853609e-04f, 1.12828451e-04f, 1.12768706e-04f, + 1.12763453e-04f, 1.12704920e-04f, 1.12668592e-04f, 1.12654951e-04f, + 1.12604144e-04f, 1.12593529e-04f, 1.12583193e-04f, 1.12519839e-04f, + 1.12470711e-04f, 1.12423929e-04f, 1.12383284e-04f, 1.12342900e-04f, + 1.12303069e-04f, 1.12265549e-04f, 1.12230849e-04f, 1.12195265e-04f, + 1.12151607e-04f, 1.12125070e-04f, 1.12076121e-04f, 1.12056183e-04f, + 1.12007337e-04f, 1.11970341e-04f, 1.11974070e-04f, 1.11935441e-04f, + 1.11856269e-04f, 1.11852759e-04f, 1.11759197e-04f, 1.11775247e-04f, + 1.11672399e-04f, 1.11709814e-04f, 1.11543098e-04f, 1.11905522e-04f, + 1.11868117e-04f, 1.11566767e-04f, 1.11875824e-04f, 1.11495153e-04f, + 1.11499078e-04f, 1.11365987e-04f, 1.11359907e-04f, 1.11484922e-04f, + 1.11277326e-04f, 1.11275050e-04f, 1.11177328e-04f, 1.11132086e-04f, + 1.11037988e-04f, 1.11123554e-04f, 1.10993545e-04f, 1.11096613e-04f, + 1.11040175e-04f, 1.10882597e-04f, 1.10886426e-04f, 1.10793303e-04f, + 1.10799738e-04f, 1.10716222e-04f, 1.10665290e-04f, 1.10749599e-04f, + 1.10632379e-04f, 1.10563042e-04f, 1.10527937e-04f, 1.10459136e-04f, + 1.10412388e-04f, 1.10379370e-04f, 1.10325149e-04f, 1.10279540e-04f, + 1.10237108e-04f, 1.10182352e-04f, 1.10148076e-04f, 1.10107245e-04f, + }; + +} // namespace mutap_test::fixtures diff --git a/tests/support/echo_scenario.h b/tests/support/echo_scenario.h index 7953eb4..0c3ae50 100644 --- a/tests/support/echo_scenario.h +++ b/tests/support/echo_scenario.h @@ -131,6 +131,14 @@ namespace mutap_test { const std::vector& error_block() const { return m_e; } const std::vector& echo_block() const { return m_d; } + /// Replace the echo path with one of the SAME length (keeps the + /// input history), for time-variant-path scenarios (ITU Stage 1: + /// the rotating-reflector analogue rebuilds the path per block). + void set_echo_path(const Sample* path, size_t n) { + assert(n == m_cfg.echo_path.size()); + std::copy(path, path + n, m_cfg.echo_path.begin()); + } + private: config m_cfg; std::vector m_x_work; ///< x history + current block, for the F convolution diff --git a/tests/support/itu_levels.h b/tests/support/itu_levels.h new file mode 100644 index 0000000..ebcb6b9 --- /dev/null +++ b/tests/support/itu_levels.h @@ -0,0 +1,287 @@ +// SPDX-License-Identifier: MIT +// Copyright 2026 MuTap contributors +// Level calibration and measurement for the ITU compliance suite +// (docs/itu-compliance.md, Stage 1). The recommendations speak in dBm0 +// (electrical, at the network reference point), dBPa (acoustic, at the +// mouth reference point) and dBov (digital, relative to overload); the +// simulation runs in linear float. This header pins ONE documented +// mapping between those planes and provides the meters the test +// procedures specify. +// +// Conventions (the simulation's calibration plane): +// - Digital overload is |x| = 1.0. dBov follows ITU-T G.100.1: the +// level of a signal relative to a full-scale SQUARE wave, so +// L_dBov = 20 log10(rms) and a full-scale sine reads -3.01 dBov. +// - dBm0 uses the A-law relationship between the overload point and +// the transmission plane: overload = +3.14 dBm0, i.e. +// L_dBm0 = L_dBov + 3.14. (Nominal receive -16 dBm0 = -19.14 dBov.) +// - dBPa maps through the alignment the P-series uses for hands-free +// testing: the nominal acoustic speech level -4.7 dBPa at the MRP is +// aligned with the nominal digital active speech level -26 dBov +// (P.501/P.56 normalization), giving L_dBov = L_dBPa - 21.3. +// Any consistent mapping proves the same algorithmic facts; this one is +// recorded so every number in the compliance suite is traceable. + +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace mutap_test::itu { + + inline constexpr double k_dbov_per_dbm0 = -3.14; ///< L_dBov = L_dBm0 + this + inline constexpr double k_dbov_per_dbpa = -21.3; ///< L_dBov = L_dBPa + this + + inline double rms_of(const double* x, size_t n) { + double acc = 0.0; + for (size_t i = 0; i < n; ++i) { + acc += x[i] * x[i]; + } + return std::sqrt(acc / static_cast(n)); + } + + inline double level_dbov(const double* x, size_t n) { + return 20.0 * std::log10(rms_of(x, n)); + } + + inline double dbm0_to_rms(double dbm0) { + return std::pow(10.0, (dbm0 + k_dbov_per_dbm0) / 20.0); + } + inline double rms_to_dbm0(double rms) { + return 20.0 * std::log10(rms) - k_dbov_per_dbm0; + } + inline double dbpa_to_rms(double dbpa) { + return std::pow(10.0, (dbpa + k_dbov_per_dbpa) / 20.0); + } + + /// Scale a signal in place to the given total-RMS level in dBm0 + /// (CSS levels are defined over the WHOLE cycled sequence including + /// pauses — P.501 7.2.1.1 b). + inline void set_level_dbm0(std::vector& x, double dbm0) { + const double r = rms_of(x.data(), x.size()); + const double g = dbm0_to_rms(dbm0) / r; + for (auto& v : x) { + v *= g; + } + } + + /// Crest factor in dB: peak over RMS. + inline double crest_factor_db(const double* x, size_t n) { + double peak = 0.0; + for (size_t i = 0; i < n; ++i) { + peak = std::max(peak, std::abs(x[i])); + } + return 20.0 * std::log10(peak / rms_of(x, n)); + } + + // ------------------------------------------------------------- A-weighting + + /// IEC 61672 A-weighting as a cascade of bilinear-transformed biquads, + /// normalized to 0 dB at 1 kHz for the given sample rate. The analog + /// prototype: four zeros at s = 0, double poles at 20.598997 Hz and + /// 12194.217 Hz, single poles at 107.65265 Hz and 737.86223 Hz. + class a_weighting { + public: + explicit a_weighting(double fs) { + const double pi = std::numbers::pi; + // Bilinear transform of each first-order section 1/(s + w) and + // zeros s^4 distributed as (1 - z^-1)^4. + const double w1 = 2.0 * pi * 20.598997; + const double w2 = 2.0 * pi * 107.65265; + const double w3 = 2.0 * pi * 737.86223; + const double w4 = 2.0 * pi * 12194.217; + + // First-order pole sections: H(z) = (1 + z^-1) / (a0 + a1 z^-1) + // from 1/(s + w), bilinear with PER-POLE frequency prewarping + // (k_w = w / tan(w / 2fs)) so each pole lands at its analog + // frequency — the plain transform shades the 12.2 kHz pole + // pair by ~1.5 dB at 10 kHz at audio rates. + auto pole = [&](double w) { + const double kw = w / std::tan(w / (2.0 * fs)); + return std::pair{kw + w, w - kw}; // a0, a1 + }; + const auto [p1a0, p1a1] = pole(w1); + const auto [p2a0, p2a1] = pole(w2); + const auto [p3a0, p3a1] = pole(w3); + const auto [p4a0, p4a1] = pole(w4); + + // Assemble three biquads: {zero^2/(p1^2)}, {zero^2/(p4^2)}, + // {1/(p2 p3)} — zeros as (1 - z^-1)^2 pairs. + m_sections[0] = {1.0, -2.0, 1.0, p1a0 * p1a0, 2.0 * p1a0 * p1a1, p1a1 * p1a1}; + m_sections[1] = {1.0, -2.0, 1.0, p4a0 * p4a0, 2.0 * p4a0 * p4a1, p4a1 * p4a1}; + m_sections[2] = {1.0, 2.0, 1.0, p2a0 * p3a0, p2a0 * p3a1 + p2a1 * p3a0, p2a1 * p3a1}; + // NOTE the third section carries the (1 + z^-1)^2 numerator that + // the two pole-only bilinear sections contribute. + + // Normalize to unity gain at 1 kHz. + m_gain = 1.0; + const double g = magnitude_at(1000.0, fs); + m_gain = 1.0 / g; + } + + /// Filter a whole buffer (offline use; resets state first). + std::vector apply(const std::vector& x) const { + std::vector y = x; + for (const auto& s : m_sections) { + double x1 = 0.0; + double x2 = 0.0; + double y1 = 0.0; + double y2 = 0.0; + for (auto& v : y) { + const double in = v; + const double out = (s.b0 * in + s.b1 * x1 + s.b2 * x2 - s.a1 * y1 - s.a2 * y2) / s.a0; + x2 = x1; + x1 = in; + y2 = y1; + y1 = out; + v = out; + } + } + for (auto& v : y) { + v *= m_gain; + } + return y; + } + + /// Magnitude response at frequency f (for validation). + double magnitude_at(double f, double fs) const { + const double w = 2.0 * std::numbers::pi * f / fs; + const double c1 = std::cos(w); + const double s1 = std::sin(w); + const double c2 = std::cos(2.0 * w); + const double s2 = std::sin(2.0 * w); + double re = 1.0; + double im = 0.0; + for (const auto& s : m_sections) { + const double nre = s.b0 + s.b1 * c1 + s.b2 * c2; + const double nim = -s.b1 * s1 - s.b2 * s2; + const double dre = s.a0 + s.a1 * c1 + s.a2 * c2; + const double dim = -s.a1 * s1 - s.a2 * s2; + const double den = dre * dre + dim * dim; + const double hre = (nre * dre + nim * dim) / den; + const double him = (nim * dre - nre * dim) / den; + const double ore = re * hre - im * him; + const double oim = re * him + im * hre; + re = ore; + im = oim; + } + return std::hypot(re, im) * m_gain; + } + + /// A-weighted level of a buffer in dBm0(A). + double level_dbm0a(const std::vector& x) const { + const auto y = apply(x); + return rms_to_dbm0(rms_of(y.data(), y.size())); + } + + private: + struct biquad { + double b0, b1, b2, a0, a1, a2; + }; + biquad m_sections[3]{}; + double m_gain = 1.0; + }; + + // ------------------------------------------------------------ level meters + + /// One-pole exponential mean-square level meter (the 35 ms / 5 ms + /// integrators the P.111x test procedures specify). Emits the level + /// trace in dBm0 per sample. + class exp_level_meter { + public: + exp_level_meter(double fs, double tau_seconds) + : m_alpha(1.0 - std::exp(-1.0 / (fs * tau_seconds))) {} + + std::vector trace_dbm0(const std::vector& x) { + std::vector out(x.size()); + double ms = 0.0; + for (size_t i = 0; i < x.size(); ++i) { + ms += m_alpha * (x[i] * x[i] - ms); + out[i] = rms_to_dbm0(std::sqrt(std::max(ms, 1e-30))); + } + return out; + } + + private: + double m_alpha; + }; + + /// Peak of the sliding-window RMS (G.168's 35 ms rectangular window). + inline double peak_windowed_rms_dbm0(const std::vector& x, double fs, double window_seconds = 0.035) { + const size_t n = static_cast(fs * window_seconds); + assert(x.size() >= n && n > 0); + double acc = 0.0; + for (size_t i = 0; i < n; ++i) { + acc += x[i] * x[i]; + } + double best = acc; + for (size_t i = n; i < x.size(); ++i) { + acc += x[i] * x[i] - x[i - n] * x[i - n]; + best = std::max(best, acc); + } + return rms_to_dbm0(std::sqrt(std::max(best, 1e-30) / static_cast(n))); + } + + /// Active speech level after the method of ITU-T P.56: a 30 ms + /// two-stage exponential envelope, a 200 ms hangover, and the + /// threshold at which the measured active level sits 15.9 dB above + /// it (found by scanning candidate thresholds downward from the + /// envelope peak in 0.5 dB steps). Returns the ACTIVE level in dBm0 + /// and, optionally, the activity factor. + inline double active_speech_level_dbm0(const std::vector& x, double fs, double* activity = nullptr) { + const double g = std::exp(-1.0 / (fs * 0.03)); + // Two cascaded one-poles on |x| (P.56's p and q). + std::vector env(x.size()); + double p = 0.0; + double q = 0.0; + double env_peak = 0.0; + double sq = 0.0; + for (size_t i = 0; i < x.size(); ++i) { + sq += x[i] * x[i]; + p = g * p + (1.0 - g) * std::abs(x[i]); + q = g * q + (1.0 - g) * p; + env[i] = q; + env_peak = std::max(env_peak, q); + } + const size_t hangover = static_cast(fs * 0.2); + const double margin_db = 15.9; + + double best_level = rms_to_dbm0(std::sqrt(sq / static_cast(x.size()))); + double best_act = 1.0; + for (double thr_db = 20.0 * std::log10(env_peak); thr_db > 20.0 * std::log10(env_peak) - 60.0; thr_db -= 0.5) { + const double thr = std::pow(10.0, thr_db / 20.0); + size_t active = 0; + size_t hang = 0; + for (size_t i = 0; i < env.size(); ++i) { + if (env[i] >= thr) { + hang = hangover; + } + if (hang > 0) { + ++active; + --hang; + } + } + if (active == 0) { + continue; + } + const double level_db = 20.0 * std::log10(std::sqrt(sq / static_cast(active))); + // P.56: as the threshold drops the margin (active level minus + // threshold) GROWS; the active level is read where the margin + // first reaches 15.9 dB. + if (level_db - thr_db >= margin_db) { + best_level = level_db - k_dbov_per_dbm0; + best_act = static_cast(active) / static_cast(env.size()); + break; + } + } + if (activity != nullptr) { + *activity = best_act; + } + return best_level; + } + +} // namespace mutap_test::itu diff --git a/tests/support/itu_signals.h b/tests/support/itu_signals.h new file mode 100644 index 0000000..398b5d8 --- /dev/null +++ b/tests/support/itu_signals.h @@ -0,0 +1,508 @@ +// SPDX-License-Identifier: MIT +// Copyright 2026 MuTap contributors +// ITU-T P.501 (04/2025) test-signal generators for the compliance suite +// (docs/itu-compliance.md, Stage 1). Everything here is GENERATED from +// the recommendation's algorithmic descriptions — no ITU signal files +// are redistributed. The layer runs natively at 44.1 kHz, the CSS's own +// sampling rate: P.501's segment framing is sample-exact only there +// (350 ms period = 15435 samples), and P.501 7.2.1.1 b lists 44.1 kHz +// as a preferred calibration rate. Signals for other rates would need +// the >60 dB stopband interpolation of P.501 NOTE 2 (not implemented). +// +// What is spec-exact vs method-equivalent (recorded per the matrix): +// - CSS voiced segments: EXACT — the literal sample tables 7-1/7-2 of +// P.501 transcribed below (134/229 values, column-major). +// - CSS PN segment: compliant-by-construction (flat magnitude, random +// conjugate-symmetric 0/pi phases, 8192-point adaptive-systems +// variant per 7.2.1.3) but not bit-exact with ITU reference files — +// the phase vector is "random" by specification; ours is a fixed +// mt19937 seed so every run is reproducible. +// - Real-speech sequences (P.501 7.3.x) are recordings and cannot be +// generated; the tests that need them are marked in the matrix. +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#include "mutap/fft.h" + +namespace mutap_test::itu { + + inline constexpr double k_fs = 44100.0; ///< native CSS rate (see header) + + // P.501 Table 7-1: the single-talk voiced segment, 3.04 ms at + // 44.1 kHz, repeated 16x for 48.62 ms. 16-bit sample values. + inline constexpr int k_css_voiced_st[134] = { + -76, 112, 298, 472, 628, 776, 916, 1068, 1234, 1398, 1572, 1752, 1932, 2098, 2244, + 2360, 2456, 2538, 2626, 2730, 2824, 2904, 2964, 2996, 3032, 3072, 3116, 3158, 3180, 3180, + 3168, 3146, 3132, 3122, 3108, 3096, 3076, 3038, 2992, 2930, 2866, 2808, 2764, 2728, 2686, + 2632, 2572, 2496, 2432, 2382, 2362, 2368, 2392, 2410, 2430, 2444, 2460, 2472, 2452, 2398, + 2300, 2178, 2068, 1976, 1892, 1824, 1772, 1742, 1750, 1760, 1762, 1736, 1684, 1624, 1572, + 1516, 1460, 1390, 1306, 1170, 968, 702, 394, 76, -244, -594, -968, -1384, -1846, -2356, + -2898, -3462, -4024, -4590, -5154, -5716, -6298, -6912, -7556, -8194, -8719, -8998, -8898, -8378, -7492, + -6414, -5334, -4428, -3772, -3360, -3128, -3002, -2924, -2870, -2830, -2800, -2792, -2806, -2844, -2888, + -2898, -2846, -2698, -2460, -2166, -1846, -1544, -1274, -1032, -818, -626, -456, -298, -130}; + + // P.501 Table 7-2: the double-talk voiced segment, 5.19 ms at + // 44.1 kHz, repeated 14x for 72.69 ms; a different pitch from the + // single-talk segment so the two stay decorrelated. + inline constexpr int k_css_voiced_dt[229] = { + -64, 148, 341, 502, 637, 750, 856, 973, 1095, 1230, 1380, 1486, 1591, 1681, 1763, 1844, + 1927, 2014, 2097, 2170, 2242, 2310, 2364, 2413, 2450, 2474, 2485, 2474, 2446, 2408, 2363, 2322, + 2287, 2243, 2185, 2109, 2009, 1906, 1806, 1709, 1614, 1515, 1416, 1316, 1212, 1118, 1023, 935, + 852, 762, 686, 615, 540, 477, 416, 364, 316, 271, 231, 197, 166, 139, 121, 104, + 96, 88, 88, 96, 97, 109, 124, 139, 158, 178, 206, 227, 255, 291, 323, 357, + 391, 429, 462, 500, 534, 568, 606, 640, 676, 706, 735, 762, 789, 814, 835, 856, + 875, 890, 905, 911, 926, 930, 935, 939, 935, 940, 935, 926, 925, 911, 901, 887, + 875, 857, 845, 826, 812, 789, 766, 751, 727, 709, 690, 660, 645, 626, 604, 588, + 571, 555, 538, 513, 500, 483, 470, 456, 441, 428, 419, 409, 406, 397, 388, 386, + 379, 377, 377, 368, 367, 413, 422, 413, 422, 426, 429, 432, 443, 456, 479, 512, + 561, 618, 686, 770, 856, 959, 1073, 1190, 1319, 1458, 1598, 1749, 1894, 2039, 2179, 2310, + 2413, 2477, 2488, 2461, 2395, 2299, 2174, 2033, 1864, 1663, 1439, 1188, 905, 588, 255, -73, + -457, -852, -1263, -1693, -2153, -2643, -3152, -3687, -4239, -4797, -5381, -5974, -6571, -7170, -7779, -8382, + -8968, -9478, -9826, -9925, -9752, -9318, -8667, -7903, -7087, -6287, -5541, -4849, -4202, -3601, -3033, -2506, + -2015, -1553, -1120, -726, -364}; + + // ------------------------------------------------------------ FIR helpers + + /// Windowed-sinc linear-phase low-pass (Kaiser window), designed for + /// >= 80 dB stopband. Offline test tooling — not RT code. + inline std::vector design_lowpass(double fs, double cutoff_hz, size_t taps) { + assert(taps % 2 == 1); + std::vector h(taps); + const double fc = cutoff_hz / fs; + const long mid = static_cast(taps / 2); + const double beta = 7.857; // Kaiser beta for ~80 dB + auto bessel_i0 = [](double v) { + double sum = 1.0; + double term = 1.0; + for (int i = 1; i < 32; ++i) { + term *= (v / (2.0 * i)) * (v / (2.0 * i)); + sum += term; + } + return sum; + }; + const double i0b = bessel_i0(beta); + for (long i = 0; i < static_cast(taps); ++i) { + const long m = i - mid; + const double s = (m == 0) ? 2.0 * fc + : std::sin(2.0 * std::numbers::pi * fc * static_cast(m)) + / (std::numbers::pi * static_cast(m)); + const double r = static_cast(m) / static_cast(mid); + h[static_cast(i)] = s * bessel_i0(beta * std::sqrt(std::max(0.0, 1.0 - r * r))) / i0b; + } + return h; + } + + /// Linear-phase FIR from a magnitude response given as corner points + /// (log-frequency straight-line interpolation in dB — the form + /// P.501's Figures 7-10/7-11 and Hoth-style spectra use), via + /// frequency sampling. `corners` = {Hz, dB} pairs, ascending. + inline std::vector design_from_corners(double fs, const std::vector>& corners, + size_t fft_size = 4096) { + auto gain_at = [&](double f) { + if (f <= corners.front().first) { + return corners.front().second; + } + if (f >= corners.back().first) { + return corners.back().second; + } + for (size_t i = 1; i < corners.size(); ++i) { + if (f <= corners[i].first) { + const double lf0 = std::log10(corners[i - 1].first); + const double lf1 = std::log10(corners[i].first); + const double t = (std::log10(f) - lf0) / (lf1 - lf0); + return corners[i - 1].second + t * (corners[i].second - corners[i - 1].second); + } + } + return corners.back().second; + }; + // Zero-phase magnitude sampling, then a real IFFT and circular + // shift to make it causal linear-phase. + mutap::real_fft fft(fft_size); + std::vector spec(fft_size, 0.0); + const double df = fs / static_cast(fft_size); + spec[0] = std::pow(10.0, gain_at(1e-3) / 20.0); + spec[1] = std::pow(10.0, gain_at(fs / 2.0) / 20.0); // packed Nyquist + for (size_t k = 1; k < fft_size / 2; ++k) { + spec[2 * k] = std::pow(10.0, gain_at(df * static_cast(k)) / 20.0); + spec[2 * k + 1] = 0.0; + } + std::vector h(fft_size); + fft.inverse(spec.data(), h.data()); + std::rotate(h.begin(), h.begin() + static_cast(fft_size / 2), h.end()); + // Hann-window the centre half to bound leakage, keep odd length. + const size_t taps = fft_size / 2 + 1; + std::vector out(taps); + for (size_t i = 0; i < taps; ++i) { + const double w = + 0.5 - 0.5 * std::cos(2.0 * std::numbers::pi * static_cast(i) / static_cast(taps - 1)); + out[i] = h[fft_size / 2 - taps / 2 + i] * w; + } + return out; + } + + inline std::vector fir_apply(const std::vector& x, const std::vector& h) { + std::vector y(x.size(), 0.0); + const size_t half = h.size() / 2; // compensate linear-phase delay + for (size_t n = 0; n < x.size(); ++n) { + double acc = 0.0; + for (size_t k = 0; k < h.size(); ++k) { + const long idx = static_cast(n + half) - static_cast(k); + if (idx >= 0 && idx < static_cast(x.size())) { + acc += h[k] * x[static_cast(idx)]; + } + } + y[n] = acc; + } + return y; + } + + /// P.501 Figure 7-10: the speech-shaping response for the fullband + /// CSS PN segment (5 dB/octave tilt, corner-point table). + inline std::vector> speech_shaping_corners() { + return {{50.0, -0.8}, {100.0, 9.2}, {200.0, 19.6}, {215.0, 18.8}, {500.0, 13.1}, {1000.0, 8.0}, + {2850.0, 0.4}, {3600.0, -1.3}, {5000.0, -3.5}, {7690.0, -6.6}, {7800.0, -7.8}, {8700.0, -20.0}}; + } + + /// P.501 Figure 7-11: the narrow-band CSS band-limiting/shaping + /// response (200 Hz - 3.6 kHz, speech tilt, steep upper skirt). + inline std::vector> narrowband_shaping_corners() { + return {{50.0, -25.8}, {100.0, -12.8}, {200.0, 17.4}, {215.0, 17.8}, {500.0, 12.2}, + {1000.0, 7.2}, {2850.0, 0.0}, {3600.0, -2.0}, {3660.0, -20.0}, {3680.0, -30.0}}; + } + + // ------------------------------------------------------------------- CSS + + enum class css_kind { single_talk, double_talk }; + + struct css_config { + css_kind kind = css_kind::single_talk; + size_t periods = 4; ///< periods to emit (polarity alternates) + bool shaped = false; ///< apply the Figure 7-10 speech shaping to the PN part + unsigned seed = 501; ///< PN phase / noise seed (fixed = reproducible) + }; + + /// One CSS stream per P.501 7.2.1.2/7.2.1.3/7.2.1.4 at 44.1 kHz. + /// Single talk: voiced 2144 (134 x 16) + PN 8820 (8192-point block + /// cycled) + pause 4471 = 15435 samples (350 ms). Double talk: + /// voiced 3206 (229 x 14) + Gaussian noise 8820 + pause 5614 = + /// 17640 samples (400 ms). Unit-agnostic amplitude — scale with + /// itu::set_level_dbm0 afterwards. + inline std::vector make_css(const css_config& cfg) { + const bool st = cfg.kind == css_kind::single_talk; + const int* tab = st ? k_css_voiced_st : k_css_voiced_dt; + const size_t tab_n = st ? 134 : 229; + const size_t reps = st ? 16 : 14; + const size_t noise_n = 8820; + const size_t period_n = st ? 15435 : 17640; + const size_t voiced_n = tab_n * reps; + const size_t pause_n = period_n - voiced_n - noise_n; + + // Voiced part, normalized to unit RMS. + std::vector voiced(voiced_n); + double vsq = 0.0; + for (size_t i = 0; i < voiced_n; ++i) { + voiced[i] = static_cast(tab[i % tab_n]) / 32768.0; + vsq += voiced[i] * voiced[i]; + } + const double vrms = std::sqrt(vsq / static_cast(voiced_n)); + for (auto& v : voiced) { + v /= vrms; + } + + // Measurement segment: PN (single talk) or Gaussian (double talk), + // RMS-matched to the voiced part (i.e. unity). + std::vector meas(noise_n); + std::mt19937 gen(cfg.seed); + if (st) { + constexpr size_t n_fft = 8192; + mutap::real_fft fft(n_fft); + std::vector spec(n_fft, 0.0); + std::bernoulli_distribution bit(0.5); + spec[0] = 0.0; + spec[1] = 0.0; // DC and Nyquist zero + for (size_t k = 1; k < n_fft / 2; ++k) { + spec[2 * k] = bit(gen) ? 1.0 : -1.0; // exp(j pi i_k) with i_k in {0,1} + spec[2 * k + 1] = 0.0; + } + std::vector block(n_fft); + fft.inverse(spec.data(), block.data()); + if (cfg.shaped) { + const auto h = design_from_corners(k_fs, speech_shaping_corners()); + block = fir_apply(block, h); + } + double msq = 0.0; + for (const double v : block) { + msq += v * v; + } + const double mrms = std::sqrt(msq / static_cast(n_fft)); + for (size_t i = 0; i < noise_n; ++i) { + meas[i] = block[i % n_fft] / mrms; // cycled to 200 ms per 7.2.1.2 + } + } + else { + std::normal_distribution dist(0.0, 1.0); + for (auto& v : meas) { + v = dist(gen); + } + double msq = 0.0; + for (const double v : meas) { + msq += v * v; + } + const double mrms = std::sqrt(msq / static_cast(noise_n)); + for (auto& v : meas) { + v /= mrms; + } + } + + std::vector out; + out.reserve(period_n * cfg.periods); + for (size_t p = 0; p < cfg.periods; ++p) { + const double sign = (p % 2 == 0) ? 1.0 : -1.0; // polarity inversion per period + for (const double v : voiced) { + out.push_back(sign * v); + } + for (const double v : meas) { + out.push_back(sign * v); + } + for (size_t i = 0; i < pause_n; ++i) { + out.push_back(0.0); + } + } + return out; + } + + /// Band-limiting per P.501 Table 7-7 (values in Hz: -3 dB point / + /// cutoff). NB 3600/4000, WB 7200/8000, SWB 14400/16000. At the + /// 44.1 kHz native rate fullband needs no filter. + enum class bandwidth { narrowband, wideband, super_wideband, fullband }; + + inline std::vector band_limit(const std::vector& x, bandwidth bw) { + double cutoff = 0.0; + switch (bw) { + case bandwidth::narrowband: + cutoff = 3800.0; + break; // -3 dB ~3.6k, deep by 4k + case bandwidth::wideband: + cutoff = 7600.0; + break; // -3 dB ~7.2k, deep by 8k + case bandwidth::super_wideband: + cutoff = 15200.0; + break; // -3 dB ~14.4k, deep by 16k + case bandwidth::fullband: + return x; + } + return fir_apply(x, design_lowpass(k_fs, cutoff, 1023)); + } + + // ------------------------------------------- AM-FM orthogonal double talk + + /// One channel of the P.501 7.2.4 AM-FM modulated multi-sine: + /// s(t) = [1 + (2/3) cos(2 pi 3 t)] * sum_n A(n) cos(2 pi f0(n) t + + /// (df(n)/1 Hz) sin(2 pi t)), with A(n) following the 250 Hz-corner + /// 5 dB/octave shaping. The two channels' frequency plans interleave + /// (P.501 Table 7-6, wideband) and never overlap once each component + /// stays within f0 +- df — that disjointness is what the comb-filter + /// analysis of the double-talk echo tests relies on. + struct amfm_plan { + std::vector f0; + std::vector df; + }; + + inline amfm_plan amfm_send_plan() { + amfm_plan p; + const double base[] = {125, 250, 500, 750, 1000, 1250, 1500, 1750}; + const double dev[] = {2.5, 5, 10, 15, 20, 25, 30, 35}; + for (size_t i = 0; i < 8; ++i) { + p.f0.push_back(base[i]); + p.df.push_back(dev[i]); + } + for (double f = 2000.0; f <= 7000.0; f += 250.0) { + p.f0.push_back(f); + p.df.push_back(40.0); + } + return p; + } + + inline amfm_plan amfm_receive_plan() { + amfm_plan p; + const double base[] = {180, 270, 540, 810, 1080, 1350, 1620, 1890}; + const double dev[] = {2.5, 5, 10, 15, 20, 25, 30, 35}; + for (size_t i = 0; i < 8; ++i) { + p.f0.push_back(base[i]); + p.df.push_back(dev[i]); + } + for (double f = 2160.0; f <= 6900.0; f += 250.0) { + p.f0.push_back(f); + p.df.push_back(35.0); + } + return p; + } + + inline std::vector make_amfm(const amfm_plan& plan, size_t samples) { + std::vector out(samples, 0.0); + const double pi = std::numbers::pi; + for (size_t c = 0; c < plan.f0.size(); ++c) { + // 5 dB/octave rolloff above the 250 Hz corner (P.501 7.2.4). + const double a = (plan.f0[c] <= 250.0) ? 1.0 : std::pow(10.0, -5.0 * std::log2(plan.f0[c] / 250.0) / 20.0); + for (size_t n = 0; n < samples; ++n) { + const double t = static_cast(n) / k_fs; + out[n] += a * std::cos(2.0 * pi * plan.f0[c] * t + plan.df[c] * std::sin(2.0 * pi * t)); + } + } + const double am_f = 3.0; + const double am_mu = 2.0 / 3.0; + for (size_t n = 0; n < samples; ++n) { + const double t = static_cast(n) / k_fs; + out[n] *= 1.0 + am_mu * std::cos(2.0 * pi * am_f * t); + } + return out; + } + + /// Energy (dB) of a signal inside the comb bands f0 +- (df + guard), + /// via one long Hann-windowed FFT — the analysis half of the AM-FM + /// method. P.501 7.2.4.1 sets the comb edges at exactly f0 +- df + /// (guard 0); widening the guard reaches across the plans' designed + /// interleave gaps (e.g. send 250+-5 vs receive 270+-5, 10 Hz apart) + /// and destroys the separation floor. + inline double comb_band_level_db(const std::vector& x, const amfm_plan& plan, double guard_hz = 0.0) { + size_t n_fft = 1; + while (n_fft < x.size()) { + n_fft *= 2; + } + mutap::real_fft fft(n_fft); + std::vector buf(n_fft, 0.0); + // Hann window: the components are not FFT-periodic, and the comb + // separation the double-talk analysis needs lives or dies on + // spectral leakage. + for (size_t i = 0; i < x.size(); ++i) { + const double w = + 0.5 + - 0.5 * std::cos(2.0 * std::numbers::pi * static_cast(i) / static_cast(x.size() - 1)); + buf[i] = x[i] * w; + } + fft.forward_inplace(buf.data()); + const double df_bin = k_fs / static_cast(n_fft); + double acc = 0.0; + for (size_t c = 0; c < plan.f0.size(); ++c) { + const size_t k0 = static_cast((plan.f0[c] - plan.df[c] - guard_hz) / df_bin); + const size_t k1 = static_cast((plan.f0[c] + plan.df[c] + guard_hz) / df_bin) + 1; + for (size_t k = std::max(1, k0); k <= std::min(n_fft / 2 - 1, k1); ++k) { + acc += buf[2 * k] * buf[2 * k] + buf[2 * k + 1] * buf[2 * k + 1]; + } + } + return 10.0 * std::log10(std::max(acc, 1e-30)); + } + + // --------------------------------------------------- activation sequence + + /// P.501 7.3.4-style activation sequence built on the CSS voiced + /// sound (which is also P.340's activation signal): a 500 ms voiced + /// token, 500 ms pause, level rising 1 dB per repetition across + /// `steps` repetitions. Returns the sequence and the sample index at + /// which each token starts (for build-up timing analysis). + inline std::vector make_activation_sequence(size_t steps, double start_gain_db, + std::vector* token_starts = nullptr) { + const size_t token_n = static_cast(0.5 * k_fs); + const size_t pause_n = token_n; + std::vector token(token_n); + double sq = 0.0; + for (size_t i = 0; i < token_n; ++i) { + token[i] = static_cast(k_css_voiced_st[i % 134]) / 32768.0; + sq += token[i] * token[i]; + } + const double rms = std::sqrt(sq / static_cast(token_n)); + for (auto& v : token) { + v /= rms; + } + std::vector out; + out.reserve((token_n + pause_n) * steps); + for (size_t s = 0; s < steps; ++s) { + const double g = std::pow(10.0, (start_gain_db + static_cast(s)) / 20.0); + if (token_starts != nullptr) { + token_starts->push_back(out.size()); + } + for (const double v : token) { + out.push_back(g * v); + } + out.insert(out.end(), pause_n, 0.0); + } + return out; + } + + // ------------------------------------------------------------ noise fields + + /// Hoth noise (the P.800/P.340 room-noise spectrum): white noise + /// shaped by the standard Hoth density corners (relative dB). + inline std::vector make_hoth_noise(size_t samples, unsigned seed) { + static const std::vector> k_corners = { + {100.0, 0.0}, {200.0, -1.7}, {400.0, -5.7}, {800.0, -12.4}, + {1000.0, -14.7}, {2000.0, -22.6}, {4000.0, -30.5}, {8000.0, -39.0}}; + std::mt19937 gen(seed); + std::normal_distribution dist(0.0, 1.0); + std::vector x(samples); + for (auto& v : x) { + v = dist(gen); + } + return fir_apply(x, design_from_corners(k_fs, k_corners)); + } + + /// Synthetic driving-noise analogue (labeled as such in the matrix: + /// the automotive recs use vehicle-specific recordings; this is the + /// documented stand-in): low-frequency-dominated noise, -12 dB/oct + /// above 120 Hz with a mild shelf, non-stationary +-2 dB slow + /// amplitude wander. + inline std::vector make_driving_noise(size_t samples, unsigned seed) { + static const std::vector> k_corners = { + {50.0, 0.0}, {120.0, 0.0}, {240.0, -12.0}, {480.0, -22.0}, + {1000.0, -30.0}, {4000.0, -42.0}, {12000.0, -54.0}}; + std::mt19937 gen(seed); + std::normal_distribution dist(0.0, 1.0); + std::vector x(samples); + for (auto& v : x) { + v = dist(gen); + } + auto y = fir_apply(x, design_from_corners(k_fs, k_corners)); + const double pi = std::numbers::pi; + for (size_t n = 0; n < y.size(); ++n) { + const double t = static_cast(n) / k_fs; + y[n] *= std::pow(10.0, 2.0 * std::sin(2.0 * pi * 0.13 * t) / 20.0); + } + return y; + } + + // ----------------------------------------------- time-variant echo paths + + /// The rotating-reflector analogue of P.1110 11.11.6 / P.1120 + /// 11.11.6: a base impulse response plus one early reflection whose + /// delay sweeps sinusoidally (a moving surface changes a path + /// length) and whose amplitude follows the rotation. path(t) is + /// rebuilt per block by the caller via fill(). + struct moving_reflector { + std::vector base; ///< the static room/cabin IR + double tap_gain = 0.1; ///< reflector strength vs unit-energy base + double delay0_s = 0.004; ///< mean extra path delay + double sweep_s = 0.0008; ///< delay sweep amplitude (+- ~27 cm) + double rate_hz = 0.25; ///< rotation rate (15 rpm = 0.25 Hz) + + void fill(double t_seconds, std::vector& path) const { + path.assign(base.begin(), base.end()); + const double d = delay0_s + sweep_s * std::sin(2.0 * std::numbers::pi * rate_hz * t_seconds); + const double g = tap_gain * std::abs(std::cos(2.0 * std::numbers::pi * rate_hz * t_seconds)); + const double ds = d * k_fs; + const size_t i0 = static_cast(ds); + const double fr = ds - static_cast(i0); + if (i0 + 1 < path.size()) { // linear-interpolated fractional tap + path[i0] += g * (1.0 - fr); + path[i0 + 1] += g * fr; + } + } + }; + +} // namespace mutap_test::itu diff --git a/tests/test_itu_signals.cpp b/tests/test_itu_signals.cpp new file mode 100644 index 0000000..737d5f1 --- /dev/null +++ b/tests/test_itu_signals.cpp @@ -0,0 +1,263 @@ +// SPDX-License-Identifier: MIT +// Copyright 2026 MuTap contributors +// +// Validation of the ITU signal layer (docs/itu-compliance.md, Stage 1): +// the generated signals must match the properties P.501 publishes and +// the instruments must read known signals correctly, or every number the +// compliance suite later produces is untrustworthy. Thresholds follow +// the house workflow — measured first, asserted with margin: +// +// CSS ST period 15435 samples exact; voiced/PN RMS ratio 1.0000/1.0003; +// PN crest 10.97 dB (spec 11 +- 1); PN bin-power stddev 0.000 dB; +// level calibration error 0.00 dB; DT noise crest 12.09 (spec 12 +- 1); +// shaped-PN crest 9.82 dB; A-weighting 100 Hz -19.18 / 1 kHz 0.00 / +// 10 kHz -1.76 dB (analog nominals -19.1 / 0 / -2.5; the 10 kHz point +// documents the prewarped-bilinear residual, IEC class-1 tolerance is +// +2.6/-3.6 dB there); NB band-limit 0.0 dB at 3.4 kHz, -85.2 dB at +// 4 kHz, -106.5 at 5 kHz; AM-FM comb separation 94.3 dB with the +// spec's exact band edges (guard 0 — an 8 Hz guard collapses it to +// 19 dB by reaching across the plans' 10 Hz interleave gaps); Hoth +// octave decline 100-200 -> 4k-8k measured 18.1 dB; driving-noise LF +// dominance 27.6 dB; cabin fixture RT60 66.6 ms (G.167 car figure: +// ~60 ms typical); P.56 meter on sparse bursts: activity 0.312 with +// level delta +5.06 dB (= 10 log10(1/activity), exact), and on CSS +// activity ~1 (the 101 ms pause is inside P.56's 200 ms hangover — +// the G.168 active-part corrections are the separate arithmetic +// constants +1.49/+1.66 dB, reproduced by our exact segment sizes). + +#include +#include +#include +#include + +#include + +#include "fixtures/rir_cabin.h" +#include "support/itu_levels.h" +#include "support/itu_signals.h" + +namespace { + + using namespace mutap_test; + + TEST(ItuCss, SingleTalkStructureIsSpecExact) { + itu::css_config cfg; + cfg.periods = 4; + const auto css = itu::make_css(cfg); + ASSERT_EQ(css.size(), 4U * 15435U) << "350 ms at 44.1 kHz, sample-exact"; + + // Segment levels: voiced and PN parts RMS-matched (P.501 requires + // equal levels), pause silent. + const double vr = itu::rms_of(css.data(), 2144); + const double pr = itu::rms_of(css.data() + 2144, 8820); + EXPECT_NEAR(20.0 * std::log10(vr / pr), 0.0, 0.05) << "measured 0.003 dB"; + EXPECT_EQ(itu::rms_of(css.data() + 10964, 4471), 0.0); + + // Polarity inversion between periods (offset-free long sequence). + for (size_t i = 0; i < 2144; ++i) { + ASSERT_EQ(css[i], -css[15435 + i]); + } + } + + TEST(ItuCss, PnSegmentCrestAndFlatness) { + const auto css = itu::make_css({}); + EXPECT_NEAR(itu::crest_factor_db(css.data() + 2144, 8820), 11.0, 1.0) + << "P.501 spec 11 +- 1 dB; measured 10.97"; + + // Flat magnitude by construction: every FFT bin of the 8192-point + // block has identical power (measured stddev 0.000 dB). + mutap::real_fft fft(8192); + std::vector b(css.begin() + 2144, css.begin() + 2144 + 8192); + fft.forward_inplace(b.data()); + double sum = 0.0; + double sum2 = 0.0; + int n = 0; + for (size_t k = 16; k < 3700; ++k) { + const double d = 10.0 * std::log10(b[2 * k] * b[2 * k] + b[2 * k + 1] * b[2 * k + 1]); + sum += d; + sum2 += d * d; + ++n; + } + const double mean = sum / n; + EXPECT_LT(std::sqrt(std::max(0.0, sum2 / n - mean * mean)), 0.1); + } + + TEST(ItuCss, DoubleTalkStructureAndCrest) { + itu::css_config cfg; + cfg.kind = itu::css_kind::double_talk; + cfg.periods = 4; + const auto css = itu::make_css(cfg); + ASSERT_EQ(css.size(), 4U * 17640U) << "400 ms at 44.1 kHz, sample-exact"; + EXPECT_NEAR(itu::crest_factor_db(css.data() + 3206, 8820), 12.0, 1.0) + << "P.501 spec 12 +- 1 dB; measured 12.09"; + } + + TEST(ItuCss, LevelCalibrationIsExact) { + auto css = itu::make_css({}); + itu::set_level_dbm0(css, -16.0); + EXPECT_NEAR(itu::rms_to_dbm0(itu::rms_of(css.data(), css.size())), -16.0, 0.01); + // G.168's active-part corrections fall out of the exact segment + // sizes: 10 log10(15435/10964) and 10 log10(17640/12026). + EXPECT_NEAR(10.0 * std::log10(15435.0 / 10964.0), 1.485, 0.01); + EXPECT_NEAR(10.0 * std::log10(17640.0 / 12026.0), 1.664, 0.01); + } + + TEST(ItuLevels, AWeightingSpotGains) { + const itu::a_weighting aw(itu::k_fs); + const auto db = [&](double f) { return 20.0 * std::log10(aw.magnitude_at(f, itu::k_fs)); }; + EXPECT_NEAR(db(100.0), -19.1, 0.5) << "measured -19.18"; + EXPECT_NEAR(db(1000.0), 0.0, 0.05); + // Prewarped-bilinear residual at 10 kHz: measured -1.76 vs the + // analog -2.5; IEC 61672 class-1 tolerance there is +2.6/-3.6. + EXPECT_NEAR(db(10000.0), -2.5, 2.0); + } + + TEST(ItuSignals, NarrowbandLimiterMeetsMask) { + auto probe = [&](double f) { + std::vector s(static_cast(itu::k_fs)); + for (size_t i = 0; i < s.size(); ++i) { + s[i] = std::sin(2.0 * std::numbers::pi * f * static_cast(i) / itu::k_fs); + } + const auto y = itu::band_limit(s, itu::bandwidth::narrowband); + return 20.0 + * std::log10(itu::rms_of(y.data() + 8000, y.size() - 16000) + / itu::rms_of(s.data() + 8000, s.size() - 16000)); + }; + EXPECT_GT(probe(3400.0), -1.0) << "passband (measured 0.0 dB)"; + EXPECT_LT(probe(4000.0), -70.0) << "P.501 Table 7-7 cutoff (measured -85.2 dB)"; + EXPECT_LT(probe(5000.0), -80.0) << "measured -106.5 dB"; + } + + // THE PROPERTY THE DOUBLE-TALK ECHO TESTS STAND ON: the send and + // receive AM-FM plans are orthogonal under the spec's own comb + // analysis. Measured separation 94.3 dB with exact band edges — the + // measurable echo-loss floor is far beyond the >= 33 dB margin + // targets. (Guard discipline matters: +8 Hz of guard collapses this + // to 19 dB via the send-250/receive-270 adjacency.) + TEST(ItuSignals, AmFmPlansAreOrthogonal) { + const auto sp = itu::amfm_send_plan(); + const auto rp = itu::amfm_receive_plan(); + const auto snd = itu::make_amfm(sp, static_cast(4 * itu::k_fs)); + const double own = itu::comb_band_level_db(snd, sp); + const double cross = itu::comb_band_level_db(snd, rp); + EXPECT_GT(own - cross, 60.0) << "measured 94.3 dB"; + } + + TEST(ItuSignals, NoiseFieldsHaveTheirSpectra) { + auto octave_db = [&](const std::vector& x, double f0, double f1) { + constexpr size_t n_fft = 65536; + mutap::real_fft fft(n_fft); + std::vector b(x.begin(), x.begin() + n_fft); + fft.forward_inplace(b.data()); + double acc = 0.0; + for (size_t k = static_cast(f0 * n_fft / itu::k_fs); + k < static_cast(f1 * n_fft / itu::k_fs); ++k) { + acc += b[2 * k] * b[2 * k] + b[2 * k + 1] * b[2 * k + 1]; + } + return 10.0 * std::log10(acc); + }; + const auto hoth = itu::make_hoth_noise(static_cast(4 * itu::k_fs), 7); + const double h_lo = octave_db(hoth, 100.0, 200.0); + const double h_mid = octave_db(hoth, 800.0, 1600.0); + const double h_hi = octave_db(hoth, 4000.0, 8000.0); + EXPECT_GT(h_lo, h_mid); + EXPECT_GT(h_mid, h_hi); + EXPECT_NEAR(h_lo - h_hi, 18.1, 4.0) << "Hoth decline, measured 18.1 dB"; + + const auto drv = itu::make_driving_noise(static_cast(4 * itu::k_fs), 7); + EXPECT_GT(octave_db(drv, 60.0, 120.0) - octave_db(drv, 4000.0, 8000.0), 20.0) + << "LF dominance, measured 27.6 dB"; + } + + // The cabin fixture is the automotive echo path of the compliance + // suite; G.167 5.2.3.1 gives the car figure as RT ~60 ms typical. + TEST(ItuSignals, CabinFixtureReverbTime) { + const float* r = fixtures::k_rir_cabin; + const size_t n = fixtures::k_rir_cabin_taps; + std::vector edc(n); + double acc = 0.0; + for (size_t i = n; i-- > 0;) { + acc += static_cast(r[i]) * static_cast(r[i]); + edc[i] = acc; + } + double t5 = 0.0; + double t35 = 0.0; + for (size_t i = 0; i < n; ++i) { + const double d = 10.0 * std::log10(edc[i] / edc[0]); + if (t5 == 0.0 && d <= -5.0) { + t5 = static_cast(i) / 48000.0; + } + if (t35 == 0.0 && d <= -35.0) { + t35 = static_cast(i) / 48000.0; + break; + } + } + const double rt60_ms = 2.0 * (t35 - t5) * 1000.0; + EXPECT_GT(rt60_ms, 50.0) << "measured 66.6 ms"; + EXPECT_LT(rt60_ms, 80.0) << "measured 66.6 ms"; + } + + TEST(ItuLevels, ActiveSpeechLevelMeter) { + // Sparse bursts: 0.5 s voiced + 2.0 s silence. P.56 activity = + // (burst + 200 ms hangover + envelope tail) / period; measured + // 0.312 with the level delta the definition demands. + std::vector x; + for (int b = 0; b < 4; ++b) { + for (size_t i = 0; i < static_cast(0.5 * itu::k_fs); ++i) { + x.push_back(static_cast(itu::k_css_voiced_st[i % 134]) / 3000.0); + } + x.insert(x.end(), static_cast(2.0 * itu::k_fs), 0.0); + } + double act = 0.0; + const double asl = itu::active_speech_level_dbm0(x, itu::k_fs, &act); + const double tot = itu::rms_to_dbm0(itu::rms_of(x.data(), x.size())); + EXPECT_NEAR(act, 0.312, 0.05); + EXPECT_NEAR(asl - tot, 10.0 * std::log10(1.0 / act), 0.1) << "definitionally consistent"; + + // On CSS the 101 ms pause sits inside the 200 ms hangover, so + // activity is ~1 and ASL ~ total level (measured -15.93 at -16). + auto css = itu::make_css({}); + itu::set_level_dbm0(css, -16.0); + double css_act = 0.0; + const double css_asl = itu::active_speech_level_dbm0(css, itu::k_fs, &css_act); + EXPECT_GT(css_act, 0.9); + EXPECT_NEAR(css_asl, -16.0, 0.5) << "measured -15.93 dBm0"; + } + + TEST(ItuSignals, ActivationSequenceGeometry) { + std::vector starts; + const auto seq = itu::make_activation_sequence(5, -40.0, &starts); + ASSERT_EQ(starts.size(), 5U); + EXPECT_EQ(starts[1] - starts[0], static_cast(itu::k_fs)) << "500 ms token + 500 ms pause"; + // +1 dB per step. + const size_t tn = static_cast(0.5 * itu::k_fs); + const double l0 = 20.0 * std::log10(itu::rms_of(seq.data() + starts[0], tn)); + const double l4 = 20.0 * std::log10(itu::rms_of(seq.data() + starts[4], tn)); + EXPECT_NEAR(l4 - l0, 4.0, 0.01); + } + + TEST(ItuSignals, MovingReflectorPathStaysSane) { + itu::moving_reflector mr; + mr.base.assign(256, 0.0); + mr.base[32] = 1.0; + std::vector path; + double tap_min = 1e9; + double tap_max = -1e9; + for (double t = 0.0; t < 4.0; t += 0.05) { + mr.fill(t, path); + ASSERT_EQ(path.size(), mr.base.size()); + EXPECT_EQ(path[32], 1.0) << "base path untouched"; + double extra = 0.0; + for (size_t i = 0; i < path.size(); ++i) { + if (i != 32) { + extra += path[i]; + } + } + tap_min = std::min(tap_min, extra); + tap_max = std::max(tap_max, extra); + } + EXPECT_NEAR(tap_max, mr.tap_gain, 0.01) << "reflector reaches full strength"; + EXPECT_LT(tap_min, 0.01) << "and vanishes at the rotation nulls"; + } + +} // namespace diff --git a/tools/fixtures/make_rir_fixtures.py b/tools/fixtures/make_rir_fixtures.py index 42bc224..139db38 100644 --- a/tools/fixtures/make_rir_fixtures.py +++ b/tools/fixtures/make_rir_fixtures.py @@ -72,6 +72,18 @@ mic=[9.5, 4.2, 1.6], blurb="reverberant hall, mic 5.6 m out — the PA scenario", ), + # The automotive scenario for the ITU compliance suite (Stage 1): + # ~2.6 m^3 enclosure, heavy absorption, RT ~60 ms — the car-interior + # figures G.167 5.2.3.1 specifies for mobile echo paths. Speaker in + # the footwell, mic at the mirror position. + "cabin": dict( + dims=[1.9, 1.45, 0.95], + absorption=0.75, + max_order=40, + speaker=[0.35, 0.4, 0.25], + mic=[1.1, 0.7, 0.85], + blurb="car cabin, mic at the mirror, speaker in the footwell", + ), } @@ -122,10 +134,12 @@ def emit_header(name: str, rir: np.ndarray, provenance: str) -> None: print(f"wrote {path} ({len(rir)} taps)") -def generate_modeled() -> None: +def generate_modeled(only: str | None = None) -> None: import pyroomacoustics as pra for name, spec in ROOMS.items(): + if only is not None and name != only: + continue room = pra.ShoeBox( spec["dims"], fs=FS, @@ -188,11 +202,13 @@ def from_wav(wav_path: str, name: str, source: str) -> None: def main() -> None: ap = argparse.ArgumentParser(description=__doc__) ap.add_argument("--generate", action="store_true", help="rebuild the modeled rooms") + ap.add_argument("--only", default=None, help="with --generate: rebuild a single room " + "(committed fixtures are baselines — never regenerate rooms you are not changing)") ap.add_argument("--from-wav", nargs=2, metavar=("WAV", "NAME"), help="import a measured RIR") ap.add_argument("--source", default="", help="provenance + license text for --from-wav") args = ap.parse_args() if args.generate: - generate_modeled() + generate_modeled(args.only) elif args.from_wav: if not args.source: raise SystemExit("--from-wav requires --source (provenance/license is not optional)") From a223fb4898205b55ca6d49c12ee196df0126166e Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 16 Jul 2026 10:36:31 +0000 Subject: [PATCH 2/2] ITU signal layer: 48 kHz and 16 kHz become required operating rates Per Tim's directive the compliance matrix now REQUIRES 48 kHz (MuTap's rate, the automotive recs' specified analysis rate, and where the RIR fixtures are exact) and 16 kHz (the wideband telephony rate) alongside the 44.1 kHz P.501-native reference. The bridge is the P.501 NOTE 2 resampler, built and measured: passband ripple <= 0.014 dB (spec < 0.2), alias rejection 101 dB at 16 kHz output (spec > 60). The CSS period stays sample-exact at every required rate (15435 / 16800 / 5600 samples per 350 ms); make_css_at() emits per-rate CSS, and the formula-based generators (AM-FM, noise, activation, band limits, moving reflector) take fs directly. Measured at the new rates: PN crest 11.86 / 11.44 dB (spec 11 +- 1), AM-FM comb separation 94.0 / 92.6 dB. Three new ItuRates tests; matrix + HANDOFF updated. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01TLE2rvptWxV8catE8vTvgx --- HANDOFF.md | 7 +- docs/itu-compliance.md | 31 ++++++--- tests/support/itu_signals.h | 134 +++++++++++++++++++++++++++++------- tests/test_itu_signals.cpp | 66 ++++++++++++++++++ 4 files changed, 202 insertions(+), 36 deletions(-) diff --git a/HANDOFF.md b/HANDOFF.md index f520acf..88e1713 100644 --- a/HANDOFF.md +++ b/HANDOFF.md @@ -280,7 +280,12 @@ collapses to 19 dB if any guard band is added (recorded in the test). Existing fixtures verified bit-reproducible with pyroomacoustics 0.10.1 before generating the cabin (--only flag added to the generator). Still open from this stage: the ITU real-speech attachment WAVs -(tests/data/itu/, git-ignored) for the three signal-exact rows.* +(tests/data/itu/, git-ignored) for the three signal-exact rows. +AMENDED (Tim's directive): 48 kHz and 16 kHz are REQUIRED operating +rates (44.1 kHz stays the P.501-native reference) — the NOTE 2 +resampler was built (ripple <= 0.014 dB, alias rejection 101 dB), the +formula generators take fs directly, and make_css_at() emits +sample-exact periods at every required rate; matrix policy updated.* **Stage 2 — Residual-echo post-filter + comfort noise.** The big DSP item. New header (working name `mutap/postfilter.h`): coherence-based diff --git a/docs/itu-compliance.md b/docs/itu-compliance.md index b95fd3a..e16573c 100644 --- a/docs/itu-compliance.md +++ b/docs/itu-compliance.md @@ -67,16 +67,23 @@ approach: narrowband (P.1100) variants run as band-limited configurations of the same tests, with P.501-specified band-limiting of the receive-direction signals (NB 3.6/4 kHz, WB 7.2/8 kHz, SWB 14.4/16 kHz). -- **Sample rate: the compliance suite runs at 44.1 kHz** (revised in - Stage 1 from the original 48 kHz intent): P.501's CSS framing is - sample-exact only at its native 44.1 kHz (350 ms period = 15435 - samples), and P.501 7.2.1.1 b lists 44.1 kHz as a preferred - calibration rate — running natively avoids the >60 dB-stopband - resampler P.501 NOTE 2 would otherwise require. Consequence, - documented: the RIR fixtures are 48 kHz tap sequences; played at - 44.1 kHz they represent a proportionally stretched room (times +6.6%, - e.g. the cabin's measured RT60 66.6 ms reads as ~71 ms), which stays - inside every RT envelope the recs specify. +- **Sample rates (revised twice; current policy per Tim's directive): + the compliance suite RUNS AT — and every Tier A/B row must pass at — + 48 kHz and 16 kHz, with 44.1 kHz kept as the P.501-native reference + rate.** Rationale per rate: + - **48 kHz (required)**: MuTap's operating rate, the automotive recs' + specified analysis rate (8k FFT @ 48 kHz), and the rate at which + the RIR fixtures are exact. + - **16 kHz (required)**: the wideband telephony rate (AMR-WB/P.1110 + world). SWB/FB-only clauses are exempt at 16 kHz (they exceed its + 8 kHz Nyquist); the AM-FM plans (<= 7.04 kHz) fit. + - **44.1 kHz (reference)**: P.501's native rate, where the CSS + framing is sample-exact without conversion; used to validate the + signal layer itself. + The bridge is the P.501 NOTE 2 resampler (Stage 1): measured passband + ripple <= 0.014 dB (spec < 0.2) and alias rejection 101 dB (spec + > 60); the CSS period stays sample-exact at every required rate + (15435 / 16800 / 5600 samples per 350 ms at 44.1 / 48 / 16 kHz). - **The simulated echo paths**: the three committed image-source rooms (fixtures) + a new car-cabin family (small volume ~2.5 m^3, RT ~60 ms per G.167 5.2.3.1's car figures) + the P.1110/P.1120 time-variant-path @@ -256,7 +263,9 @@ Instrument floors that bound what the compliance suite can measure: - CSS single/double-talk: sample-exact framing, PN crest 10.97 dB (spec 11 +- 1), bin-flat PN, level calibration exact, voiced segments - transcribed from P.501 Tables 7-1/7-2. + transcribed from P.501 Tables 7-1/7-2. Available at every required + rate via `make_css_at` (PN crest 11.86 dB at 48 kHz / 11.44 at + 16 kHz; AM-FM separation 94.0 / 92.6 dB at 48 / 16 kHz). - AM-FM orthogonal pair: **94.3 dB comb separation** at the spec's exact band edges — the double-talk echo-loss measurement floor sits far beyond the >= 33 dB margin targets. (Analysis discipline recorded in diff --git a/tests/support/itu_signals.h b/tests/support/itu_signals.h index 398b5d8..33b3a8a 100644 --- a/tests/support/itu_signals.h +++ b/tests/support/itu_signals.h @@ -6,8 +6,13 @@ // are redistributed. The layer runs natively at 44.1 kHz, the CSS's own // sampling rate: P.501's segment framing is sample-exact only there // (350 ms period = 15435 samples), and P.501 7.2.1.1 b lists 44.1 kHz -// as a preferred calibration rate. Signals for other rates would need -// the >60 dB stopband interpolation of P.501 NOTE 2 (not implemented). +// as a preferred calibration rate. The REQUIRED operating rates of the +// compliance matrix — 48 kHz (MuTap's rate, P.1120's analysis rate) and +// 16 kHz (the wideband telephony rate) — are served by resample()/ +// make_css_at(): the NOTE 2 interpolation (>60 dB stopband, <0.2 dB +// ripple), with the CSS period staying sample-exact at every required +// rate (350 ms = 15435 / 16800 / 5600 samples at 44.1 / 48 / 16 kHz). +// Formula-based generators (AM-FM, noise, activation) take fs directly. // // What is spec-exact vs method-equivalent (recorded per the matrix): // - CSS voiced segments: EXACT — the literal sample tables 7-1/7-2 of @@ -163,6 +168,61 @@ namespace mutap_test::itu { return y; } + /// The sample-rate converter of P.501 7.2.1.2 NOTE 2: "the + /// interpolation filter used for up- and down-sampling should be + /// close to an ideal rectangular filter. The stopband attenuation + /// should be >60 dB, the passband ripple <0.2 dB." Windowed-sinc + /// (Kaiser, ~80 dB design) evaluated per output sample; `out_len` + /// pins the exact output length where the spec's framing demands it + /// (350 ms = 16800 samples at 48 kHz, 5600 at 16 kHz). Offline + /// tooling, not RT code. + inline std::vector resample(const std::vector& x, double fs_in, double fs_out, size_t out_len = 0) { + if (fs_in == fs_out) { + return x; + } + const double ratio = fs_out / fs_in; + const size_t n_out = + out_len != 0 ? out_len : static_cast(std::llround(static_cast(x.size()) * ratio)); + const int half = 192; // kernel half-width, sized for a sharp transition at 16 kHz output + const double cutoff = 0.5 * std::min(1.0, ratio) * 0.985; // cycles per INPUT sample, transition guard + const double beta = 7.857; // Kaiser, ~80 dB stopband + auto bessel_i0 = [](double v) { + double sum = 1.0; + double term = 1.0; + for (int i = 1; i < 32; ++i) { + term *= (v / (2.0 * i)) * (v / (2.0 * i)); + sum += term; + } + return sum; + }; + const double i0b = bessel_i0(beta); + std::vector y(n_out, 0.0); + for (size_t n = 0; n < n_out; ++n) { + const double t = static_cast(n) / ratio; + const long k0 = static_cast(std::floor(t)) - half + 1; + double acc = 0.0; + for (long k = k0; k < k0 + 2 * half; ++k) { + if (k < 0 || k >= static_cast(x.size())) { + continue; + } + const double u = t - static_cast(k); + const double s = + (u == 0.0) ? 2.0 * cutoff : std::sin(2.0 * std::numbers::pi * cutoff * u) / (std::numbers::pi * u); + const double r = u / static_cast(half); + if (std::abs(r) >= 1.0) { + continue; + } + acc += x[static_cast(k)] * s * bessel_i0(beta * std::sqrt(1.0 - r * r)) / i0b; + } + y[n] = acc; + } + // No gain normalization: the 2*cutoff-scaled sinc kernel sampled + // at unit input spacing already sums to ~1 (measured passband + // error < 0.14 dB before this was understood — a 1/(2 cutoff) + // "correction" here produces a flat +8.9 dB at 16 kHz). + return y; + } + /// P.501 Figure 7-10: the speech-shaping response for the fullband /// CSS PN segment (5 dB/octave tilt, corner-point table). inline std::vector> speech_shaping_corners() { @@ -278,12 +338,29 @@ namespace mutap_test::itu { return out; } + /// CSS at one of the matrix's required operating rates: generated + /// at the native 44.1 kHz (where the voiced tables live), then + /// converted with the NOTE 2 resampler, output length pinned to the + /// sample-exact period count (16800 per period at 48 kHz, 5600 at + /// 16 kHz — 350 ms exactly; double-talk 19200 / 6400 for 400 ms). + /// At 16 kHz the resampler's anti-alias filter inherently limits + /// the CSS to the 8 kHz Nyquist (the wideband condition). + inline std::vector make_css_at(const css_config& cfg, double fs_out) { + const auto native = make_css(cfg); + if (fs_out == k_fs) { + return native; + } + const double period_s = (cfg.kind == css_kind::single_talk) ? 0.350 : 0.400; + const auto n_out = static_cast(std::llround(period_s * fs_out)) * cfg.periods; + return resample(native, k_fs, fs_out, n_out); + } + /// Band-limiting per P.501 Table 7-7 (values in Hz: -3 dB point / /// cutoff). NB 3600/4000, WB 7200/8000, SWB 14400/16000. At the /// 44.1 kHz native rate fullband needs no filter. enum class bandwidth { narrowband, wideband, super_wideband, fullband }; - inline std::vector band_limit(const std::vector& x, bandwidth bw) { + inline std::vector band_limit(const std::vector& x, bandwidth bw, double fs = k_fs) { double cutoff = 0.0; switch (bw) { case bandwidth::narrowband: @@ -298,7 +375,10 @@ namespace mutap_test::itu { case bandwidth::fullband: return x; } - return fir_apply(x, design_lowpass(k_fs, cutoff, 1023)); + if (cutoff >= fs / 2.0) { + return x; // band edge at or above Nyquist: nothing to remove + } + return fir_apply(x, design_lowpass(fs, cutoff, 1023)); } // ------------------------------------------- AM-FM orthogonal double talk @@ -345,21 +425,21 @@ namespace mutap_test::itu { return p; } - inline std::vector make_amfm(const amfm_plan& plan, size_t samples) { + inline std::vector make_amfm(const amfm_plan& plan, size_t samples, double fs = k_fs) { std::vector out(samples, 0.0); const double pi = std::numbers::pi; for (size_t c = 0; c < plan.f0.size(); ++c) { // 5 dB/octave rolloff above the 250 Hz corner (P.501 7.2.4). const double a = (plan.f0[c] <= 250.0) ? 1.0 : std::pow(10.0, -5.0 * std::log2(plan.f0[c] / 250.0) / 20.0); for (size_t n = 0; n < samples; ++n) { - const double t = static_cast(n) / k_fs; + const double t = static_cast(n) / fs; out[n] += a * std::cos(2.0 * pi * plan.f0[c] * t + plan.df[c] * std::sin(2.0 * pi * t)); } } const double am_f = 3.0; const double am_mu = 2.0 / 3.0; for (size_t n = 0; n < samples; ++n) { - const double t = static_cast(n) / k_fs; + const double t = static_cast(n) / fs; out[n] *= 1.0 + am_mu * std::cos(2.0 * pi * am_f * t); } return out; @@ -371,7 +451,8 @@ namespace mutap_test::itu { /// (guard 0); widening the guard reaches across the plans' designed /// interleave gaps (e.g. send 250+-5 vs receive 270+-5, 10 Hz apart) /// and destroys the separation floor. - inline double comb_band_level_db(const std::vector& x, const amfm_plan& plan, double guard_hz = 0.0) { + inline double comb_band_level_db(const std::vector& x, const amfm_plan& plan, double guard_hz = 0.0, + double fs = k_fs) { size_t n_fft = 1; while (n_fft < x.size()) { n_fft *= 2; @@ -388,7 +469,7 @@ namespace mutap_test::itu { buf[i] = x[i] * w; } fft.forward_inplace(buf.data()); - const double df_bin = k_fs / static_cast(n_fft); + const double df_bin = fs / static_cast(n_fft); double acc = 0.0; for (size_t c = 0; c < plan.f0.size(); ++c) { const size_t k0 = static_cast((plan.f0[c] - plan.df[c] - guard_hz) / df_bin); @@ -408,9 +489,8 @@ namespace mutap_test::itu { /// `steps` repetitions. Returns the sequence and the sample index at /// which each token starts (for build-up timing analysis). inline std::vector make_activation_sequence(size_t steps, double start_gain_db, - std::vector* token_starts = nullptr) { + std::vector* token_starts = nullptr, double fs = k_fs) { const size_t token_n = static_cast(0.5 * k_fs); - const size_t pause_n = token_n; std::vector token(token_n); double sq = 0.0; for (size_t i = 0; i < token_n; ++i) { @@ -421,8 +501,13 @@ namespace mutap_test::itu { for (auto& v : token) { v /= rms; } + if (fs != k_fs) { // other required rates: NOTE 2 resampling of the token + token = resample(token, k_fs, fs, static_cast(0.5 * fs)); + } + const size_t tok_n = token.size(); + const size_t pau_n = tok_n; std::vector out; - out.reserve((token_n + pause_n) * steps); + out.reserve((tok_n + pau_n) * steps); for (size_t s = 0; s < steps; ++s) { const double g = std::pow(10.0, (start_gain_db + static_cast(s)) / 20.0); if (token_starts != nullptr) { @@ -431,7 +516,7 @@ namespace mutap_test::itu { for (const double v : token) { out.push_back(g * v); } - out.insert(out.end(), pause_n, 0.0); + out.insert(out.end(), pau_n, 0.0); } return out; } @@ -440,7 +525,7 @@ namespace mutap_test::itu { /// Hoth noise (the P.800/P.340 room-noise spectrum): white noise /// shaped by the standard Hoth density corners (relative dB). - inline std::vector make_hoth_noise(size_t samples, unsigned seed) { + inline std::vector make_hoth_noise(size_t samples, unsigned seed, double fs = k_fs) { static const std::vector> k_corners = { {100.0, 0.0}, {200.0, -1.7}, {400.0, -5.7}, {800.0, -12.4}, {1000.0, -14.7}, {2000.0, -22.6}, {4000.0, -30.5}, {8000.0, -39.0}}; @@ -450,7 +535,7 @@ namespace mutap_test::itu { for (auto& v : x) { v = dist(gen); } - return fir_apply(x, design_from_corners(k_fs, k_corners)); + return fir_apply(x, design_from_corners(fs, k_corners)); } /// Synthetic driving-noise analogue (labeled as such in the matrix: @@ -458,7 +543,7 @@ namespace mutap_test::itu { /// documented stand-in): low-frequency-dominated noise, -12 dB/oct /// above 120 Hz with a mild shelf, non-stationary +-2 dB slow /// amplitude wander. - inline std::vector make_driving_noise(size_t samples, unsigned seed) { + inline std::vector make_driving_noise(size_t samples, unsigned seed, double fs = k_fs) { static const std::vector> k_corners = { {50.0, 0.0}, {120.0, 0.0}, {240.0, -12.0}, {480.0, -22.0}, {1000.0, -30.0}, {4000.0, -42.0}, {12000.0, -54.0}}; @@ -468,10 +553,10 @@ namespace mutap_test::itu { for (auto& v : x) { v = dist(gen); } - auto y = fir_apply(x, design_from_corners(k_fs, k_corners)); + auto y = fir_apply(x, design_from_corners(fs, k_corners)); const double pi = std::numbers::pi; for (size_t n = 0; n < y.size(); ++n) { - const double t = static_cast(n) / k_fs; + const double t = static_cast(n) / fs; y[n] *= std::pow(10.0, 2.0 * std::sin(2.0 * pi * 0.13 * t) / 20.0); } return y; @@ -485,17 +570,18 @@ namespace mutap_test::itu { /// length) and whose amplitude follows the rotation. path(t) is /// rebuilt per block by the caller via fill(). struct moving_reflector { - std::vector base; ///< the static room/cabin IR - double tap_gain = 0.1; ///< reflector strength vs unit-energy base - double delay0_s = 0.004; ///< mean extra path delay - double sweep_s = 0.0008; ///< delay sweep amplitude (+- ~27 cm) - double rate_hz = 0.25; ///< rotation rate (15 rpm = 0.25 Hz) + std::vector base; ///< the static room/cabin IR + double tap_gain = 0.1; ///< reflector strength vs unit-energy base + double delay0_s = 0.004; ///< mean extra path delay + double sweep_s = 0.0008; ///< delay sweep amplitude (+- ~27 cm) + double rate_hz = 0.25; ///< rotation rate (15 rpm = 0.25 Hz) + double fs = 48000.0; ///< the simulation rate the path runs at void fill(double t_seconds, std::vector& path) const { path.assign(base.begin(), base.end()); const double d = delay0_s + sweep_s * std::sin(2.0 * std::numbers::pi * rate_hz * t_seconds); const double g = tap_gain * std::abs(std::cos(2.0 * std::numbers::pi * rate_hz * t_seconds)); - const double ds = d * k_fs; + const double ds = d * fs; const size_t i0 = static_cast(ds); const double fr = ds - static_cast(i0); if (i0 + 1 < path.size()) { // linear-interpolated fractional tap diff --git a/tests/test_itu_signals.cpp b/tests/test_itu_signals.cpp index 737d5f1..f3ef483 100644 --- a/tests/test_itu_signals.cpp +++ b/tests/test_itu_signals.cpp @@ -236,6 +236,72 @@ namespace { EXPECT_NEAR(l4 - l0, 4.0, 0.01); } + // ---------------------------------------- the required operating rates + // The matrix requires 48 kHz (MuTap's rate, P.1120's analysis rate) + // and 16 kHz (the wideband telephony rate) alongside the 44.1 kHz + // P.501 reference. Measured: resampler passband ripple <= 0.014 dB + // (NOTE 2 allows 0.2), alias rejection 101 dB at 16 kHz output + // (NOTE 2 wants > 60); CSS periods sample-exact at every rate + // (16800 / 5600 per 350 ms); PN crest 11.86 dB at 48 kHz and + // 11.44 dB at 16 kHz (spec 11 +- 1); AM-FM comb separation 94.0 dB + // at 48 kHz and 92.6 dB at 16 kHz. + + TEST(ItuRates, ResamplerMeetsNote2) { + auto tone = [](double f, double fs, size_t n) { + std::vector s(n); + for (size_t i = 0; i < n; ++i) { + s[i] = std::sin(2.0 * std::numbers::pi * f * static_cast(i) / fs); + } + return s; + }; + auto through = [&](double f, double fs_out) { + const auto x = tone(f, 44100.0, 44100); + const auto y = itu::resample(x, 44100.0, fs_out); + const double in = itu::rms_of(x.data() + 4000, x.size() - 8000); + const double out = itu::rms_of(y.data() + 2000, y.size() - 4000); + return 20.0 * std::log10(out / in); + }; + // Passband ripple < 0.2 dB (measured <= 0.014 dB). + for (const double f : {100.0, 1000.0, 6800.0, 19000.0}) { + EXPECT_NEAR(through(f, 48000.0), 0.0, 0.2) << f << " Hz"; + } + for (const double f : {100.0, 1000.0, 7400.0}) { + EXPECT_NEAR(through(f, 16000.0), 0.0, 0.2) << f << " Hz"; + } + // Alias rejection > 60 dB (measured ~101 dB). + EXPECT_LT(through(10000.0, 16000.0), -60.0) << "measured -101.6 dB"; + EXPECT_LT(through(12000.0, 16000.0), -60.0) << "measured -102.1 dB"; + } + + TEST(ItuRates, CssIsSampleExactAtRequiredRates) { + for (const double fs : {48000.0, 16000.0}) { + itu::css_config cfg; + cfg.periods = 4; + const auto css = itu::make_css_at(cfg, fs); + ASSERT_EQ(css.size(), 4U * static_cast(0.35 * fs)) << fs; + // PN crest survives the conversion (spec 11 +- 1; measured + // 11.86 at 48 kHz, 11.44 at 16 kHz). + const size_t v_n = static_cast(2144.0 * fs / 44100.0); + const size_t p_n = static_cast(8820.0 * fs / 44100.0); + EXPECT_NEAR(itu::crest_factor_db(css.data() + v_n, p_n), 11.0, 1.0) << fs; + + cfg.kind = itu::css_kind::double_talk; + const auto dt = itu::make_css_at(cfg, fs); + ASSERT_EQ(dt.size(), 4U * static_cast(0.4 * fs)) << fs; + } + } + + TEST(ItuRates, AmFmOrthogonalityHoldsAtRequiredRates) { + const auto sp = itu::amfm_send_plan(); + const auto rp = itu::amfm_receive_plan(); + for (const double fs : {48000.0, 16000.0}) { + const auto snd = itu::make_amfm(sp, static_cast(4 * fs), fs); + const double own = itu::comb_band_level_db(snd, sp, 0.0, fs); + const double xr = itu::comb_band_level_db(snd, rp, 0.0, fs); + EXPECT_GT(own - xr, 60.0) << fs << " Hz (measured 94.0 / 92.6 dB)"; + } + } + TEST(ItuSignals, MovingReflectorPathStaysSane) { itu::moving_reflector mr; mr.base.assign(256, 0.0);