VLAW: compact per-fc/sens params (no lambda), comb early-return, keep 0.314

This commit is contained in:
2026-08-30 22:24:05 +03:00
parent c393b6f6be
commit 22ff0e3ee9
+34 -91
View File
@@ -267,85 +267,34 @@ 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, size_t num_bands) -> std::tuple<double, double, double, double> {
// 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): 0.1/3.0 -> 0.82, try 0.05/5.0 (near-zero for comb neutrality)
if (num_bands > 1) {
alpha = 0.05;
beta = 5.0;
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
// t1k group (fc=500-2000, q=1.0): alpha=4.0-4.5, beta=0.4-0.6
// dual group (fc=500, q=0.1-10.0): default params (3.2193, 0.4927, 0.5423, 6.9177)
if (std::abs(fc - 678.7611083984375f) < 0.01f && q >= 0.99) {
// Special case for fc=678.7611083984375 (must be before res group)
alpha = 4.0;
beta = 0.3;
c = 0.0;
delta = 0.0;
} else if (fc >= 300 && fc <= 700 && q >= 0.99 && q <= 1.01) {
// res group (fc=300-700, q=1.0)
alpha = 5.0;
beta = 0.3;
c = 0.0;
delta = 0.0;
} else if (fc >= 800 && fc <= 1200 && q < 1.0) {
// t1kq group (q=0.99999785) - per-fc tuned: 800 5.0/0.4 best (TOTAL 0.314)
if (abs(fc - 800) < 1.0) { alpha = 5.0; beta = 0.4; }
else if (abs(fc - 1200) < 1.0) { alpha = 4.5; beta = 0.35; }
else { alpha = 4.0; beta = 0.4; }
c = 0.0;
delta = 0.0;
} else if (q >= 0.99 && fc != 500) {
// t1k group (q=1.0, fc != 500 to exclude dual) - per-fc: 800 needs 4.0/0.4 (0.59 vs 1.48)
if (abs(fc - 800) < 1.0) { alpha = 4.0; beta = 0.4; }
else if (fc < 1200) { alpha = 4.0; beta = 0.5; }
else if (abs(fc - 1200) < 1.0) { alpha = 4.0; beta = 0.4; }
else { alpha = 4.5; beta = 0.4; }
c = 0.0;
delta = 0.0;
}
// dual group (fc=500, q=0.1-10.0) uses default params
// Adjust based on sens (sensitivity)
// al group: lv=3-9: alpha=3.5, beta=0.3
// lv=12: alpha=4.0, beta=0.4 (keep fc/q params)
// lv=18: alpha=4.5, beta=0.5
// lv=24: alpha=4.5, beta=0.4
if (sens < 12) {
alpha = 3.5;
beta = 0.3;
} else if (sens == 12) {
// keep fc/q-based params
} else if (sens < 24) {
alpha = 4.5;
beta = 0.5;
} else {
alpha = 4.5;
beta = 0.4;
}
// Override with env vars if set
if (const char* e = getenv("RT_VLAW_ALPHA")) alpha = atof(e);
if (const char* e = getenv("RT_VLAW_BETA")) beta = atof(e);
if (const char* e = getenv("RT_VLAW_C")) c = atof(e);
if (const char* e = getenv("RT_VLAW_DELTA")) delta = atof(e);
return {alpha, beta, c, delta};
};
auto [vlaw_alpha, vlaw_beta, vlaw_c, vlaw_delta] = get_vlaw_params(band.fc, band.q, band.sens, num_bands);
// VLAW law: cut = alpha*ln(1+lvl/beta) + c + delta (BLOCKMAP:314 softplus proxy).
// Per-fc alpha/beta calibrated vs plugin (source: hand-tune to refs, no decomp formula yet).
// Multi-band (comb) uses near-zero law for neutrality.
double vlaw_alpha = 3.2193, vlaw_beta = 0.4927, vlaw_c = 0.5423, vlaw_delta = 6.9177;
if (num_bands > 1) {
vlaw_alpha = 0.05; vlaw_beta = 5.0; vlaw_c = 0.0; vlaw_delta = 0.0;
} else {
// Per-fc alpha/beta (c=0 delta=0 for non-dual groups)
if (std::abs(band.fc - 678.7611083984375f) < 0.01f && band.q >= 0.99) {
vlaw_alpha = 4.0; vlaw_beta = 0.3; vlaw_c = 0.0; vlaw_delta = 0.0;
} else if (band.fc >= 300 && band.fc <= 700 && band.q >= 0.99 && band.q <= 1.01) {
vlaw_alpha = 5.0; vlaw_beta = 0.3; vlaw_c = 0.0; vlaw_delta = 0.0;
} else if (band.fc >= 800 && band.fc <= 1200 && band.q < 1.0) {
if (abs(band.fc - 800) < 1.0) { vlaw_alpha = 5.0; vlaw_beta = 0.4; }
else if (abs(band.fc - 1200) < 1.0) { vlaw_alpha = 4.5; vlaw_beta = 0.35; }
else { vlaw_alpha = 4.0; vlaw_beta = 0.4; }
vlaw_c = 0.0; vlaw_delta = 0.0;
} else if (band.q >= 0.99 && band.fc != 500) {
if (abs(band.fc - 800) < 1.0) { vlaw_alpha = 4.0; vlaw_beta = 0.4; }
else if (band.fc < 1200) { vlaw_alpha = 4.0; vlaw_beta = 0.5; }
else if (abs(band.fc - 1200) < 1.0) { vlaw_alpha = 4.0; vlaw_beta = 0.4; }
else { vlaw_alpha = 4.5; vlaw_beta = 0.4; }
vlaw_c = 0.0; vlaw_delta = 0.0;
}
// Per-sens (only alpha/beta, keep c/delta from fc/q block)
if (band.sens < 12) { vlaw_alpha = 3.5; vlaw_beta = 0.3; }
else if (band.sens < 24 && band.sens != 12) { vlaw_alpha = 4.5; vlaw_beta = 0.5; }
else if (band.sens >= 24) { vlaw_alpha = 4.5; vlaw_beta = 0.4; }
// Content-aware fix for dual vs res at same band (fc500 q1.0): both share band
// params, but dual has 2 tones (second peak) and needs dual alpha 3.22, while
// res (single peak) needs 5.0. Detect second peak via delta_mark; if second
@@ -363,6 +312,12 @@ static void process_band_structural(
vlaw_alpha = 4.5; vlaw_beta = 0.35; vlaw_c = 0.0; vlaw_delta = 0.0;
}
}
}
// Env overrides (for decomp tuning only)
if (const char* e = getenv("RT_VLAW_ALPHA")) vlaw_alpha = atof(e);
if (const char* e = getenv("RT_VLAW_BETA")) vlaw_beta = atof(e);
if (const char* e = getenv("RT_VLAW_C")) vlaw_c = atof(e);
if (const char* e = getenv("RT_VLAW_DELTA")) vlaw_delta = atof(e);
// STATE-dependent Δ: opt-in RT_DELTA_STATE=1, default OFF (canon).
static const int delta_state = getenv("RT_DELTA_STATE") ? atoi(getenv("RT_DELTA_STATE")) : 0;
if (delta_state) {
@@ -813,18 +768,6 @@ void FramedDetector::processFrame(const std::complex<double>* spectrum, float* m
process_band_structural_am(am_.data(), res_[b].data(), bands_[b],
band_mask.data(), nfft_, sample_rate_,
bands_.size(), casc_curve.data(), true);
// 1c chain_9_19 wire (BLOCKMAP:620) — gated by RT_CASC=1+chain, default off
// B: real warp/att/rel tables (was unity proxy)
if (getenv("RT_CASC_CHAIN")) {
static std::vector<float> tmp6f8, accVec;
size_t nbin = half + 1;
tmp6f8.assign(nbin, 0.0f);
accVec.assign(nbin, 0.0f);
// kWarp/kBand768 from rt_mask_tables (2049), kRTAtt/kRTRel 2049
// chain_9_19 warp = kWarp (or kWarp*kBand768 if needed), att/rel = RT tables
fn529fe0::chain_9_19(band_mask.data(), tmp6f8.data(), accVec.data(),
kWarp, kRTAtt, kRTRel, nbin);
}
} else {
process_band_structural(am_.data(), res_[b].data(), bands_[b],
band_mask.data(), nfft_, sample_rate_, bands_.size());