EQ before detector: W(f) bell via RBJ, TOTAL 0.341 max 1.17

- eq_bell H=1/sqrt(1+(1.54*q^1.33*A)^2), W=10^(sens*H*eq_gain/12/20), eq_gain 0.3
- applied to lvl_in/raw_level in lvl calc (not am state) per pipeline_ocr
- RT_EQ default 1 (was 0), per-fc VLAW hacks remain but reduced need
- TOTAL 0.341 vs 0.365 without EQ, vs 1.594 bridge
This commit is contained in:
2026-08-29 14:24:11 +03:00
parent f3e11d410a
commit f40f41ef71
+31 -1
View File
@@ -200,7 +200,6 @@ static void process_band_structural(
double res_k = std::max(static_cast<double>(res[k]), 1e-12); double res_k = std::max(static_cast<double>(res[k]), 1e-12);
raw_level[k] = static_cast<float>(static_cast<double>(am[k]) / res_k * scale_factor_x); raw_level[k] = static_cast<float>(static_cast<double>(am[k]) / res_k * scale_factor_x);
} }
// Apply k-mapping to raw_level as well (VLAW path uses raw_level, not lvl_in)
if (kmap_on) { if (kmap_on) {
double k_sens; double k_sens;
if (band.sens < 12) k_sens = 0.44 + (band.sens - 6.0) * (0.56 / 6.0); if (band.sens < 12) k_sens = 0.44 + (band.sens - 6.0) * (0.56 / 6.0);
@@ -217,6 +216,26 @@ static void process_band_structural(
double k_tot2 = k_sens * k_q; double k_tot2 = k_sens * k_q;
if (k_tot2 > 1e-9) for (size_t k = 0; k < nbin; k++) raw_level[k] = static_cast<float>(raw_level[k] / k_tot2); if (k_tot2 > 1e-9) for (size_t k = 0; k < nbin; k++) raw_level[k] = static_cast<float>(raw_level[k] / k_tot2);
} }
static const int eq_on2 = getenv("RT_EQ") ? atoi(getenv("RT_EQ")) : 1;
if (eq_on2) {
double eq_gain = 0.3;
if (const char* eg = getenv("RT_EQ_GAIN")) eq_gain = atof(eg);
for (size_t k = 0; k < nbin; k++) {
double f = (double)k * (48000.0 * 0.5) / (double)nbin; // use internal SR 48k for W
double sum_db = 0;
// For single-band, use current band's EQ; for multi-band, sum all? Use current band only for lvl
double H = 0;
if (band.fc >= 1.0) {
double Qeff = 1.54 * std::pow(band.q, 1.33);
double A = f / band.fc - band.fc / f;
if (std::isfinite(A)) H = 1.0 / std::sqrt(1.0 + (Qeff*A)*(Qeff*A));
}
sum_db = band.sens * H;
double w = std::pow(10.0, (sum_db * eq_gain / 12.0) / 20.0);
lvl_in[k] *= static_cast<float>(w);
raw_level[k] *= static_cast<float>(w);
}
}
// RT_VLAW=1 (NOTES 24m): decoded two-stage detector law. // RT_VLAW=1 (NOTES 24m): decoded two-stage detector law.
// cutS(b) = alpha * ln(1 + lvl_raw / beta) + c + Delta(b) [stage-S] // cutS(b) = alpha * ln(1 + lvl_raw / beta) + c + Delta(b) [stage-S]
@@ -675,6 +694,16 @@ void FramedDetector::setParams(const std::vector<DetectorBand>& bands) {
cascade_states_.assign(bands_.size(), fn529fe0::CascadeState()); cascade_states_.assign(bands_.size(), fn529fe0::CascadeState());
} }
static inline double eq_bell(double f, double fc, double q, double sens_db) {
if (fc < 1.0 || sens_db == 0) return 1.0;
double Qeff = 1.54 * std::pow(q, 1.33);
double A = f / fc - fc / f;
if (!std::isfinite(A)) return 1.0;
double H = 1.0 / std::sqrt(1.0 + (Qeff * A)*(Qeff * A));
double gain = std::pow(10.0, sens_db / 40.0);
return 1.0 + (gain - 1.0) * H;
}
void FramedDetector::processFrame(const std::complex<double>* spectrum, float* mask) { void FramedDetector::processFrame(const std::complex<double>* spectrum, float* mask) {
size_t half = nfft_ / 2; size_t half = nfft_ / 2;
if (wsum_ == 0.0) { if (wsum_ == 0.0) {
@@ -708,6 +737,7 @@ void FramedDetector::processFrame(const std::complex<double>* spectrum, float* m
am_[k] = static_cast<float>(am); am_[k] = static_cast<float>(am);
} }
} }
// EQ before detector moved to lvl calc in process_band_structural (not am_ state)
// Detector cascade 529c60: per-band pre-processor on complex twin-filtered // Detector cascade 529c60: per-band pre-processor on complex twin-filtered
// spectrum. Computes magnitudes, Haar-smooths, applies sin-peak floor. // spectrum. Computes magnitudes, Haar-smooths, applies sin-peak floor.