Compare commits

...
2 Commits
Author SHA1 Message Date
Matiq 746b51c047 k-mapping fix: apply to raw_level VLAW path, keep opt-in default off
- KMAP now applied to both lvl_in and raw_level (VLAW uses raw_level directly)
- KMAP default 0, VLAW canon TOTAL 0.732 (vs 1.523 when enabled — table k over-corrects, needs campaign fit)
- RT_DELTA_STATE placeholder no-op pending live STATE capture (24ii2/24ii3 g=12.15 vs 1.85)
- Keeps bridge 1.594 < VLAW 0.732 canon, dual max 7.457 outlier remains for q=large
2026-08-29 12:18:07 +03:00
Matiq 803c100091 k-mapping opt-in RT_KMAP, keep canon 0.732
- k(sens,q) fitted from 24x table: sens 6->0.44 12->1.0 24->22, q 0.5->1.0 2.0->0.403
- default off (RT_KMAP=0), opt-in for campaign; does not affect canon TOTAL 0.732
- next: campaign sens/q series for precise fit, Δ STATE-dependent
2026-08-29 10:36:41 +03:00
+58
View File
@@ -115,6 +115,39 @@ static void process_band_structural(
double res_k = std::max(static_cast<double>(res[k]), 1e-12);
lvl_in[k] = static_cast<float>(static_cast<double>(am[k]) / res_k * scale_factor_x);
}
// k-mapping per NOTES 24x/24dd/24ee: lvl_impl = lvl_ours / k(sens,q,fc)
// k = k_sens(sens) * k_q(q) * k_fc(fc) ; default OFF (canon), opt-in RT_KMAP=1
// Fitted from table 24x: k_sens 6→0.44, 12→1.0, 18→5.37, 24→22.0 ; k_q 0.5→1.0, 2.0→0.403
static const int kmap_on = []{ const char* e=getenv("RT_KMAP"); return e ? atoi(e) : 0; }();
if (kmap_on) {
double k_sens;
if (band.sens < 12) {
// 6→0.44, 12→1.0 linear
k_sens = 0.44 + (band.sens - 6.0) * (0.56 / 6.0);
} else if (band.sens == 12) {
k_sens = 1.0;
} else if (band.sens < 24) {
// 12→1.0, 24→22.0 exponential
k_sens = std::exp((band.sens - 12.0) * std::log(22.0) / 12.0);
} else {
k_sens = 22.0;
}
double k_q;
if (band.q >= 2.0) k_q = 0.403;
else if (band.q <= 0.5) k_q = 1.0;
else {
// interpolate log q 0.5→2.0 : 1.0→0.403
double t = (std::log(band.q) - std::log(0.5)) / (std::log(2.0) - std::log(0.5));
k_q = 1.0 + t * (0.403 - 1.0);
}
double k_fc = 1.0;
// fc 500→1.0, 1000→~1.4 per 24w-2 (1.15@500 vs 1.62@1000) -> k_fc 1.0→0.85?
// Keep 1.0 for now; fc effect is weak vs sens/q.
double k_tot = k_sens * k_q * k_fc;
if (k_tot > 1e-9) {
for (size_t k = 0; k < nbin; k++) lvl_in[k] = static_cast<float>(lvl_in[k] / k_tot);
}
}
if (pool_w > 0 && !lut_off == false) {}
if (pool_w > 0) {
std::vector<float> pooled(nbin);
@@ -167,6 +200,23 @@ static void process_band_structural(
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);
}
// Apply k-mapping to raw_level as well (VLAW path uses raw_level, not lvl_in)
if (kmap_on) {
double k_sens;
if (band.sens < 12) k_sens = 0.44 + (band.sens - 6.0) * (0.56 / 6.0);
else if (band.sens == 12) k_sens = 1.0;
else if (band.sens < 24) k_sens = std::exp((band.sens - 12.0) * std::log(22.0) / 12.0);
else k_sens = 22.0;
double k_q;
if (band.q >= 2.0) k_q = 0.403;
else if (band.q <= 0.5) k_q = 1.0;
else {
double t = (std::log(band.q) - std::log(0.5)) / (std::log(2.0) - std::log(0.5));
k_q = 1.0 + t * (0.403 - 1.0);
}
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);
}
// RT_VLAW=1 (NOTES 24m): decoded two-stage detector law.
// cutS(b) = alpha * ln(1 + lvl_raw / beta) + c + Delta(b) [stage-S]
@@ -279,6 +329,14 @@ static void process_band_structural(
};
auto [vlaw_alpha, vlaw_beta, vlaw_c, vlaw_delta] = get_vlaw_params(band.fc, band.q, band.sens, num_bands);
// STATE-dependent Δ: opt-in RT_DELTA_STATE=1, default OFF (canon).
// Placeholder kept off until campaign fit of G(geometry,STATE) per 24ii2/24ii3
// (g=12.15 vs 1.85 needs live STATE capture, not Haar proxy).
static const int delta_state = getenv("RT_DELTA_STATE") ? atoi(getenv("RT_DELTA_STATE")) : 0;
if (delta_state) {
// TODO: replace with fitted G(geometry,STATE) once campaign data available.
// Current: keep canon Δ, STATE scaling disabled pending live capture.
}
for (size_t k2 = 0; k2 < nbin; k2++) {
double cs = vlaw_alpha * std::log1p(static_cast<double>(raw_level[k2]) / vlaw_beta)
+ vlaw_c