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..88e1713 100644 --- a/HANDOFF.md +++ b/HANDOFF.md @@ -263,13 +263,29 @@ 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. +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 8e14b37..e16573c 100644 --- a/docs/itu-compliance.md +++ b/docs/itu-compliance.md @@ -65,9 +65,25 @@ 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 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 @@ -238,7 +254,37 @@ 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. 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 + 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..33b3a8a --- /dev/null +++ b/tests/support/itu_signals.h @@ -0,0 +1,594 @@ +// 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. 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 +// 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; + } + + /// 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() { + 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; + } + + /// 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, double fs = k_fs) { + 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; + } + 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 + + /// 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, 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) / 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) / 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, + double fs = k_fs) { + 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 = 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, double fs = k_fs) { + const size_t token_n = static_cast(0.5 * k_fs); + 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; + } + 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((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) { + token_starts->push_back(out.size()); + } + for (const double v : token) { + out.push_back(g * v); + } + out.insert(out.end(), pau_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, 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}}; + 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(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, 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}}; + 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(fs, k_corners)); + const double pi = std::numbers::pi; + for (size_t n = 0; n < y.size(); ++n) { + 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; + } + + // ----------------------------------------------- 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) + 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 * 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..f3ef483 --- /dev/null +++ b/tests/test_itu_signals.cpp @@ -0,0 +1,329 @@ +// 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); + } + + // ---------------------------------------- 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); + 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)")