Version 1.0: VLAW parameterization + detector cascade
- Implemented exact ln/exp2 infrastructure (log2_ln.hpp/cpp) - Parameterized VLAW α/β/c by (fc, q, sens) configuration - Implemented real RFFT for FIR construction - Fixed VLAW parameterization for dual group (3.455 → 0.764 dB) - Added detector cascade 529c60 (Haar smoothing, magnitude, peak processing) - TOTAL error: 0.870 dB (vs bridge baseline 1.594 dB) Results: - t1kq: 0.618 dB (bridge: 0.226 dB) - t1k: 0.938 dB (bridge: 1.801 dB) ✓ better - al: 0.727 dB (bridge: 0.638 dB) - res: 0.284 dB (bridge: 0.628 dB) ✓ better - dual: 0.764 dB (bridge: 0.726 dB) - comb: 3.000 dB (bridge: 10.149 dB) ✓ better
This commit is contained in:
@@ -12,6 +12,7 @@
|
||||
// - blend_exp2 : out == exp2(-x)*blend, blend = freqaxis*(1-mix)+mix*0.8
|
||||
// - combine_acc: subtract then add band/f6f8 contributions (exact)
|
||||
// - warp_mask : multiplies by kBand768*kWarp
|
||||
// - cascade : Haar, magnitudes, blend (529c60 decode)
|
||||
int main() {
|
||||
const size_t nbin = 2049; // internal N/2+1 grid used by the chain
|
||||
const size_t nfft = 4096;
|
||||
@@ -78,6 +79,122 @@ int main() {
|
||||
std::printf("live: kWarp[0]=%.3f kWarp[2048]=%.3f kBand768[0]=%.3f kBand768[2048]=%.3f\n",
|
||||
kWarp[0], kWarp[2048], k768[0], k768[2048]);
|
||||
|
||||
// === Cascade 529c60 tests ===
|
||||
|
||||
// --- haar_one_pass: kernel [0.25, 0.5, 0.25] ---
|
||||
{
|
||||
// Input: [1, 3, 5, 7, 9] (5 elements)
|
||||
// Expected: b[0]=0.5*(1+3)=2.0; b[1]=0.25*1+0.5*3+0.25*5=3.0;
|
||||
// b[2]=0.25*3+0.5*5+0.25*7=5.0; b[3]=0.25*5+0.5*7+0.25*9=7.0;
|
||||
// b[4]=0.25*7+0.75*9=8.5 (boundary)
|
||||
float data[] = {1.0f, 3.0f, 5.0f, 7.0f, 9.0f};
|
||||
float expected[] = {2.0f, 3.0f, 5.0f, 7.0f, 8.5f};
|
||||
fn529fe0::haar_one_pass(data, 5);
|
||||
double max_h = 0.0;
|
||||
for (int i = 0; i < 5; i++)
|
||||
max_h = std::fmax(max_h, std::fabs(data[i] - expected[i]));
|
||||
std::printf("haar_one_pass: max|d|=%.3e (%s)\n", max_h,
|
||||
max_h < 1e-6 ? "OK" : "MISMATCH");
|
||||
if (max_h >= 1e-6) fail = 1;
|
||||
}
|
||||
|
||||
// --- haar_smooth: 2 iterations on ramp ---
|
||||
{
|
||||
float data[] = {0.0f, 0.25f, 0.5f, 0.75f, 1.0f};
|
||||
fn529fe0::haar_smooth(data, 5, 2);
|
||||
// After 2 Haar passes, the ramp should be smoothed.
|
||||
// Just check monotonicity and bounds [0, 1].
|
||||
bool ok = true;
|
||||
for (int i = 0; i < 5; i++) {
|
||||
if (data[i] < -0.01f || data[i] > 1.01f) ok = false;
|
||||
}
|
||||
// Check output is smoother than input (less spread)
|
||||
float spread_in = 1.0f - 0.0f; // input range
|
||||
float spread_out = data[4] - data[0];
|
||||
if (spread_out >= spread_in) ok = false;
|
||||
std::printf("haar_smooth: spread %.3f→%.3f (%s)\n",
|
||||
spread_in, spread_out, ok ? "OK" : "MISMATCH");
|
||||
if (!ok) fail = 1;
|
||||
}
|
||||
|
||||
// --- compute_magnitudes: |z| from complex pairs ---
|
||||
{
|
||||
// Input: [3,4, 5,12, 0,0] → [5, 13, 0]
|
||||
float complex_state[] = {3.0f, 4.0f, 5.0f, 12.0f, 0.0f, 0.0f};
|
||||
float mag[3];
|
||||
fn529fe0::compute_magnitudes(complex_state, mag, 3);
|
||||
double max_m = 0.0;
|
||||
max_m = std::fmax(max_m, std::fabs(mag[0] - 5.0f));
|
||||
max_m = std::fmax(max_m, std::fabs(mag[1] - 13.0f));
|
||||
max_m = std::fmax(max_m, std::fabs(mag[2] - 0.0f));
|
||||
std::printf("compute_magnitudes: max|d|=%.3e (%s)\n", max_m,
|
||||
max_m < 1e-5 ? "OK" : "MISMATCH");
|
||||
if (max_m >= 1e-5) fail = 1;
|
||||
}
|
||||
|
||||
// --- cascade_detect: full pipeline smoke test ---
|
||||
{
|
||||
// Create test signal: DC=1 in all bins (complex: re=1, im=0)
|
||||
std::vector<float> complex_state(2 * nbin);
|
||||
for (size_t i = 0; i < nbin; i++) {
|
||||
complex_state[2 * i] = 1.0f; // re
|
||||
complex_state[2 * i + 1] = 0.0f; // im
|
||||
}
|
||||
std::vector<float> bands_curve(nbin, 0.0f);
|
||||
fn529fe0::CascadeState state;
|
||||
|
||||
// First call: accumulator is empty
|
||||
fn529fe0::cascade_detect(complex_state.data(), bands_curve.data(),
|
||||
state, nbin, 2,
|
||||
0.0f, // sin_peak_param=0 (disabled)
|
||||
10.0f, // ctx24
|
||||
1, // ctx1a0
|
||||
4); // ctx1ac
|
||||
|
||||
// All magnitudes are 1.0, Haar-smoothed should be ~1.0
|
||||
// Peak should be ~1.0, sin_peak disabled
|
||||
// Check output is in valid range
|
||||
bool ok = true;
|
||||
for (size_t i = 0; i < nbin; i++) {
|
||||
if (bands_curve[i] < -0.01f || bands_curve[i] > 2.0f) ok = false;
|
||||
}
|
||||
std::printf("cascade_detect DC: [0]=%.4f [mid]=%.4f [end]=%.4f (%s)\n",
|
||||
bands_curve[0], bands_curve[nbin/2], bands_curve[nbin-1],
|
||||
ok ? "OK" : "MISMATCH");
|
||||
if (!ok) fail = 1;
|
||||
|
||||
// Second call: accumulator should be non-zero
|
||||
fn529fe0::cascade_detect(complex_state.data(), bands_curve.data(),
|
||||
state, nbin, 2, 0.0f, 10.0f, 1, 4);
|
||||
std::printf("cascade_detect DC 2nd: acc[0]=%.6f out[0]=%.4f\n",
|
||||
state.accumulator[0], bands_curve[0]);
|
||||
}
|
||||
|
||||
// --- cascade_detect: alternating signal ---
|
||||
{
|
||||
std::vector<float> cs(2 * nbin);
|
||||
for (size_t i = 0; i < nbin; i++) {
|
||||
cs[2 * i] = (i % 2 == 0) ? 2.0f : 0.5f;
|
||||
cs[2 * i + 1] = 0.0f;
|
||||
}
|
||||
std::vector<float> bc(nbin, 0.0f);
|
||||
fn529fe0::CascadeState st;
|
||||
fn529fe0::cascade_detect(cs.data(), bc.data(), st, nbin, 2,
|
||||
0.0f, 10.0f, 1, 4);
|
||||
// Haar should smooth the alternating pattern
|
||||
float min_v = bc[0], max_v = bc[0];
|
||||
for (size_t i = 1; i < nbin; i++) {
|
||||
min_v = std::fmin(min_v, bc[i]);
|
||||
max_v = std::fmax(max_v, bc[i]);
|
||||
}
|
||||
float spread = max_v - min_v;
|
||||
// Original spread was 1.5, after 2 Haar passes should be much smaller
|
||||
bool ok = spread < 0.5f;
|
||||
std::printf("cascade_detect alt: spread=%.4f [0]=%.4f [1]=%.4f (%s)\n",
|
||||
spread, bc[0], bc[1], ok ? "OK" : "MISMATCH");
|
||||
if (!ok) fail = 1;
|
||||
}
|
||||
|
||||
std::printf("fn529fe0 check %s\n", fail ? "FAIL" : "PASS");
|
||||
return fail;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user