chain: wire IIR4 generator (RT_IIR4_GEN) + add chain smoke test

- iir4_bidir: env-gated generate_iir4_coefs (C/tau/p/mult/sr) vs proxy kIIR
- fix exp sign: up=exp(-c*g*tau/mult) → down=1-up in 0..1 (was Inf)
- fn529fe0_check: chain_9_19 smoke + generate_iir4 smoke (down0=1 up0=0 ok)
- Gates: bridge 1.594, structural 2.689 (RT_CASC=0) unchanged
This commit is contained in:
2026-09-02 21:38:44 +03:00
parent f2cc0aeaa9
commit b41d7a40cb
2 changed files with 51 additions and 8 deletions
+29 -6
View File
@@ -196,13 +196,35 @@ void cascade_detect(
static inline void iir4_bidir_340510(float* x, size_t nbin) { static inline void iir4_bidir_340510(float* x, size_t nbin) {
// BLOCKMAP:52af09 IIR4×2 bidir log-domain base 0x340510 // BLOCKMAP:52af09 IIR4×2 bidir log-domain base 0x340510
// Uses DOUBLE precision (movsd/mulsd in disasm) // Uses DOUBLE precision (movsd/mulsd/cvtpd2ps in disasm 1191-1201)
// Coefficients from FUN_180533340 generator (frequency-dependent warp) // When RT_IIR4_GEN=1, generate via FUN_180533340 (freq-warp g=fc_norm/i|pow), else use proxy kIIR_A1/B1
// For now, use kIIR_A1/B1 as proxy (structure is correct) static std::vector<double> genDown, genUp;
static int genN = 0;
const double* A1;
const double* B1;
const double* A2;
const double* B2;
static const int useGen = getenv("RT_IIR4_GEN") ? atoi(getenv("RT_IIR4_GEN")) : 0;
if (useGen) {
if ((int)nbin != genN) {
genDown.assign(nbin, 0.0); genUp.assign(nbin, 0.0);
double C = getenv("RT_IIR4_C") ? atof(getenv("RT_IIR4_C")) : 1000.0;
double tau = getenv("RT_IIR4_TAU") ? atof(getenv("RT_IIR4_TAU")) : 1200.0;
double p = getenv("RT_IIR4_P") ? atof(getenv("RT_IIR4_P")) : 0.5;
double mult = getenv("RT_IIR4_MULT") ? atof(getenv("RT_IIR4_MULT")) : 360.0;
double sr = getenv("RT_IIR4_SR") ? atof(getenv("RT_IIR4_SR")) : 48000.0;
generate_iir4_coefs(genDown.data(), genUp.data(), (int)nbin, C, tau, sr, p, mult);
genN = (int)nbin;
}
// down=1-up, so A=down, B=up
A1 = genDown.data(); B1 = genUp.data();
A2 = genDown.data(); B2 = genUp.data();
} else {
extern const double kIIR_A1[]; extern const double kIIR_B1[]; extern const double kIIR_A1[]; extern const double kIIR_B1[];
extern const double kIIR_A2[]; extern const double kIIR_B2[]; extern const double kIIR_A2[]; extern const double kIIR_B2[];
const double* A1 = ::kIIR_A1; const double* B1 = ::kIIR_B1; A1 = ::kIIR_A1; B1 = ::kIIR_B1;
const double* A2 = ::kIIR_A2; const double* B2 = ::kIIR_B2; A2 = ::kIIR_A2; B2 = ::kIIR_B2;
}
double acc = 0.0; double acc = 0.0;
for (size_t i = 0; i < nbin; i++) { double y = A1[i]*acc + B1[i]*x[i]; acc = y; x[i] = static_cast<float>(y); } for (size_t i = 0; i < nbin; i++) { double y = A1[i]*acc + B1[i]*x[i]; acc = y; x[i] = static_cast<float>(y); }
acc = 0.0; acc = 0.0;
@@ -223,7 +245,8 @@ void generate_iir4_coefs(double* downCoef, double* upCoef,
for (int i = 1; i < n; i++) { for (int i = 1; i < n; i++) {
double g = (i <= fc_norm) ? (fc_norm / i) : std::pow(fc_norm / i, p); double g = (i <= fc_norm) ? (fc_norm / i) : std::pow(fc_norm / i, p);
double c = 1.0 / (g * tau / mult + 1.0); double c = 1.0 / (g * tau / mult + 1.0);
upCoef[i] = std::exp(c * g * tau * exp_scale); // state[2] ≈ mult per BLOCKMAP, so normalize: exp(-c*g*tau/state2) → 0..1
upCoef[i] = std::exp(-c * g * tau / mult * exp_scale);
downCoef[i] = 1.0 - upCoef[i]; downCoef[i] = 1.0 - upCoef[i];
} }
} }
+20
View File
@@ -195,6 +195,26 @@ int main() {
if (!ok) fail = 1; if (!ok) fail = 1;
} }
// --- chain_9_19: gated pipeline smoke (LOG#1→DIVIDE→dc40→FMA→EXP-1→*track→*warp→LOG#2→IIR4→FIR→EXP#2) ---
{
std::vector<float> bands(nbin, 0.5f), tmp(nbin, 0.1f), acc(nbin, 0.0f);
std::vector<float> warp(nbin, 1.0f), att(nbin, 0.0f), rel(nbin, 0.0f);
std::vector<float> bands0 = bands;
fn529fe0::chain_9_19(bands.data(), tmp.data(), acc.data(), nullptr, warp.data(), att.data(), rel.data(), nbin);
bool ok = true;
for (size_t i = 0; i < nbin; i++) if (!std::isfinite(bands[i]) || bands[i] < 0.0f || bands[i] > 5.0f) ok = false;
std::printf("chain_9_19 smoke: in0=%.3f out0=%.3f outmid=%.3f finite=%d (%s)\n",
bands0[0], bands[0], bands[nbin/2], ok, ok ? "OK" : "MISMATCH");
if (!ok) fail = 1;
// IIR4 generator smoke
std::vector<double> down(nbin), up(nbin);
fn529fe0::generate_iir4_coefs(down.data(), up.data(), (int)nbin, 1000.0, 1200.0, 48000.0, 0.5, 360.0);
bool gok = std::fabs(down[0]-1.0)<1e-9 && std::fabs(up[0])<1e-9 && down[1] < 1.0 && down[1] > 0.0;
std::printf("generate_iir4: down0=%.3f up0=%.3f down1=%.4f up1=%.4f (%s)\n",
down[0], up[0], down[1], up[1], gok ? "OK" : "MISMATCH");
if (!gok) fail = 1;
}
std::printf("fn529fe0 check %s\n", fail ? "FAIL" : "PASS"); std::printf("fn529fe0 check %s\n", fail ? "FAIL" : "PASS");
return fail; return fail;
} }