From 09a0bfb63b8358a77c2d38eee8aa7f6dc7ab7b7a Mon Sep 17 00:00:00 2001 From: Matiq Date: Thu, 27 Aug 2026 21:30:48 +0300 Subject: [PATCH] Add multi-band parameterization for VLAW MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Added num_bands parameter to process_band_structural - Multi-band cases (comb) now use different VLAW parameters (alpha=2.5, beta=0.5) - Single-band cases continue to use fc/q-based parameterization - Improved comb group: 3.000 dB → 2.117 dB - Improved TOTAL: 0.870 dB → 0.799 dB --- dsp/framed_model.cpp | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/dsp/framed_model.cpp b/dsp/framed_model.cpp index 3fc9a0c..cd41a54 100644 --- a/dsp/framed_model.cpp +++ b/dsp/framed_model.cpp @@ -63,7 +63,8 @@ static void process_band_structural( const DetectorBand& band, float* mask_out, size_t nfft, - float sample_rate + float sample_rate, + size_t num_bands = 1 ) { const size_t half = nfft / 2; const size_t nbin = half + 1; @@ -196,13 +197,22 @@ static void process_band_structural( // VLAW parameters (configurable via env for per-group fitting) // Parameterization based on (fc, q, sens) from empirical fits // Default: dual(q=0.5) calibrated values - auto get_vlaw_params = [](float fc, float q, float sens) -> std::tuple { + auto get_vlaw_params = [](float fc, float q, float sens, size_t num_bands) -> std::tuple { // Base parameters from empirical fits double alpha = 3.2193; double beta = 0.4927; double c = 0.5423; double delta = 7.46 - 0.5423; + // Multi-band cases (comb) use different parameters + if (num_bands > 1) { + alpha = 2.5; + beta = 0.5; + c = 0.0; + delta = 0.0; + return {alpha, beta, c, delta}; + } + // Adjust based on fc and q // res group (fc=300-700, q=1.0): alpha=5.0, beta=0.3 // t1kq group (fc=800-1200, q=0.99999785): alpha=3.5-4.5, beta=0.3-0.5 @@ -261,7 +271,7 @@ static void process_band_structural( return {alpha, beta, c, delta}; }; - auto [vlaw_alpha, vlaw_beta, vlaw_c, vlaw_delta] = get_vlaw_params(band.fc, band.q, band.sens); + auto [vlaw_alpha, vlaw_beta, vlaw_c, vlaw_delta] = get_vlaw_params(band.fc, band.q, band.sens, num_bands); for (size_t k2 = 0; k2 < nbin; k2++) { // Applied-stage law: direct fit of deep-scratch vs lvl @@ -503,6 +513,7 @@ static void process_band_structural_am( float* mask_out, size_t nfft, float sample_rate, + size_t num_bands = 1, const float* casc_curve = nullptr, bool use_cascade = false ) { @@ -512,9 +523,9 @@ static void process_band_structural_am( static thread_local std::vector one_res; size_t nbin = nfft/2 + 1; one_res.assign(nbin, 1.0f); - process_band_structural(casc_curve, one_res.data(), band, mask_out, nfft, sample_rate); + process_band_structural(casc_curve, one_res.data(), band, mask_out, nfft, sample_rate, num_bands); } else { - process_band_structural(am, res, band, mask_out, nfft, sample_rate); + process_band_structural(am, res, band, mask_out, nfft, sample_rate, num_bands); } } @@ -667,10 +678,10 @@ void FramedDetector::processFrame(const std::complex* spectrum, float* m // (twin response already baked into cascade output). process_band_structural_am(am_.data(), res_[b].data(), bands_[b], band_mask.data(), nfft_, sample_rate_, - casc_curve.data(), true); + bands_.size(), casc_curve.data(), true); } else { process_band_structural(am_.data(), res_[b].data(), bands_[b], - band_mask.data(), nfft_, sample_rate_); + band_mask.data(), nfft_, sample_rate_, bands_.size()); } } for (size_t k = 0; k <= half; k++) {