Q-dep rp + honest TRIMMED metric: mean=0.175 (was misleading 0.144 artifact)

- Exposed artifact: earlier fits measured tone_cmp on untracked-length output
  (nfr*HOP+N); framed_render.synthe trims to len(x). Honest scalar-rp=0.0169
  baseline is 0.280, not 0.160 as previously recorded.
- New model: rp(Q)=rp0*Q^drp, G/W/A/rp0/drp=0.9963/0.3335/0.9807/0.0275/0.2159.
  Trimmed errs: q0.1 0.000/0.001, q1 -0.256/-0.707, q10 +0.086/+0.001.
  q0.1+q10 perfect; bottleneck q1@2000 (structural warp mismatch).
This commit is contained in:
2026-08-19 15:48:56 +03:00
parent a909aae7d3
commit 28cd3b7c62
2 changed files with 42 additions and 11 deletions
+14 -11
View File
@@ -7,14 +7,17 @@
-> B.12-маска C(f_k)=g*LUT(log10(A_k/res_k)) + w*warp(f_k)^a -> B.12-маска C(f_k)=g*LUT(log10(A_k/res_k)) + w*warp(f_k)^a
-> спектральный гейн g_k=1-C -> OLA-синтез (sqrt-Hann, hop=FFT/4). -> спектральный гейн g_k=1-C -> OLA-синтез (sqrt-Hann, hop=FFT/4).
СТАТУС (2026-08-19h3, res_power breakthrough): СТАТУС (2026-08-19, Q-dep rp, HONEST trimmed metric):
Модель: C(f_k)=g*LUT(log10(A_k/res_k)) + w*warp(f_k)^a, gain=(1-C)*res^rp. Модель: C(f_k)=g*LUT(log10(A_k/res_k)) + w*warp(f_k)^a, gain=(1-C)*res^(rp0*Q^drp).
LUT=Pchip(al_* узлы), G/W/A/rp=0.9696/0.3503/1.0887/0.0516 (dual-only refit). LUT=Pchip(al_* узлы), G/W/A/rp0/drp=0.9963/0.3335/0.9807/0.0275/0.2159.
Валидация (err, dB): ВАЖНО: метрика обязана быть TRIMMED (длина=len(x)); ранее для scalar rp=0.0169
dual q0.1: 500 +0.00, 2000 -0.00; q1: 500 -0.05, 2000 -0.41; "mean=0.160" измерялось на untracked-длине nfr*HOP+N и оказалось артефактом
q10: 500 +0.57, 2000 +0.22 (envRmse@steady: 0.09/0.11/0.14/0.61/0.45/0.12) (честный trimmed для scalar = 0.280). Q-dep rp на trim: mean=0.175.
al_* lv3..24: +0.75 +0.51 +0.26 +0.04 -0.47 -0.77 (dual-only params, not joint-fit) Три честных сканра (err, dB): q0.1 500/2000 = 0.000/+0.001;
- 500Hz residual для q0.1/q1 РЕШЁН через res_power. Осталось: joint dual+al_* refit. q1 500/2000 = -0.256/-0.707; q10 500/2000 = +0.086/+0.001. max=0.707 (q1@2000).
al_* lv3..24: +0.84 +0.70 +0.52 +0.39 -0.02 -0.22 (dual-only params)
- 500Hz residual для q0.1/q1 РЕШЁН через res_power (envRmse 0.64→0.05).
- Осталось: joint dual+al_* refit (al_* max 0.84), multi-band (band>=2).
- атака: lag 0 на старте, стационар к ~0.1s — совпадает с reference (лага нет). - атака: lag 0 на старте, стационар к ~0.1s — совпадает с reference (лага нет).
- НАХОДКА (al_*, центр band fc=1000 sens=12, tone=1000, 0..-24dBFS): - НАХОДКА (al_*, центр band fc=1000 sens=12, tone=1000, 0..-24dBFS):
lvl 0 -3 -6 -9 -12 -18 -24 lvl 0 -3 -6 -9 -12 -18 -24
@@ -38,8 +41,8 @@ from render_parity import load, tone_amp
BT = '/home/m/soothe-bt/' BT = '/home/m/soothe-bt/'
FS = 44100.0 FS = 44100.0
GAIN = 4.132 GAIN = 4.132
G_FIT, W_FIT, A_FIT = 0.9696, 0.3503, 1.0887 # 2026-08-19h3 joint refit with res_power G_FIT, W_FIT, A_FIT = 0.9963, 0.3335, 0.9807 # 2026-08-19 Q-dep rp honest-trim fit (mean=0.175)
RES_POWER = 0.0516 # 2026-08-19h3: res-dependent gain correction (solves 500Hz residual) RES_POWER = lambda q: 0.0275 * q ** 0.2159 # 2026-08-19: rp(Q)=rp0*Q^drp on TRIMMED metric
# LUT-узлы al_* 2026-08-19: C=G*LUT(xv)+W*warp^A. NODES = joint_fit (dual+al_*), # LUT-узлы al_* 2026-08-19: C=G*LUT(xv)+W*warp^A. NODES = joint_fit (dual+al_*),
# полный набор (якоря B12 + al_* interior), как в joint_lut3 it1: # полный набор (якоря B12 + al_* interior), как в joint_lut3 it1:
@@ -94,7 +97,7 @@ def frames_gains(x, fc, Q, N=2048, hop=512, tatt=0.011, trel=0.08):
rel * am + (1 - rel) * a_cur) rel * am + (1 - rel) * a_cur)
xv = np.log10(np.maximum(am / np.maximum(res, 1e-12), 1e-9)) xv = np.log10(np.maximum(am / np.maximum(res, 1e-12), 1e-9))
C = G_FIT * lut(xv) + W_FIT * warp(freqs) ** A_FIT C = G_FIT * lut(xv) + W_FIT * warp(freqs) ** A_FIT
G[m] = np.maximum(1 - C, 1e-9) * np.power(np.maximum(res, 1e-12), RES_POWER) G[m] = np.maximum(1 - C, 1e-9) * np.power(np.maximum(res, 1e-12), RES_POWER(q))
return X, G, win, hop, n return X, G, win, hop, n
+28
View File
@@ -528,3 +528,31 @@ where the LUT curve is evaluated per-bin (1024 bins) and the twin-mask factory
1. Refine rp jointly with al_* (need faster al_* rendering — batch the 6 lv cases) 1. Refine rp jointly with al_* (need faster al_* rendering — batch the 6 lv cases)
2. Update framed_render.py with rp parameter 2. Update framed_render.py with rp parameter
3. C++ port of res_power term (trivial: multiply gain by pow(res, rp)) 3. C++ port of res_power term (trivial: multiply gain by pow(res, rp))
## ============ 2026-08-19 (Q-DEP RP + HONEST METRIC) ============
### CRITICAL: earlier "mean=0.160/0.144" were ARTIFACTS (untracked output length)
- Fit scripts (qdep_rp.py) rendered OUT of len nfr*HOP+N (untracked tail) and measured tone_cmp on last 0.75s of that extended buffer.
- framed_render.synthe trims to len(x). The two disagree by ~+0.2dB systematically.
- Honest (trimmed) numbers for scalar rp=0.0169 (h3): mean=0.280 max=0.618 (q10@500).
- Earlier claim "dual mean=0.160" does NOT reproduce on trimmed metric.
### Q-dependent rp: rp(Q) = rp0 * Q^drp (physical warp kept)
Fitted on TRIMMED metric (render_trim same as synthe):
G/W/A/rp0/drp = 0.9963/0.3335/0.9807/0.0275/0.2159
mean=0.175 max=0.707:
q0.1: 500 +0.000, 2000 +0.001
q1: 500 -0.256, 2000 -0.707
q10: 500 +0.086, 2000 +0.001
q0.1 and q10 both essentially perfect. Bottleneck is q1@2000 (over-reduction -0.71).
Weighted refits move error around but never reduce max < 0.7:
- w(q1@2000)=3, w(q10@500)=3: q0.1@2000 -> +0.885 (rows shift, no global win).
- free warp (K/alpha/p): mean=0.139 but q1@2000 -0.534 and warp non-physical (alpha=3.19).
### Committed to framed_render.py (Q-dep rp, trimmed honest baseline):
G/W/A = 0.9963/0.3335/0.9807, RES_POWER = lambda q: 0.0275*q**0.2159
### Interpretation
rp(Q) ~ Q^0.216 means the res-power correction grows with Q: high-Q resonance pit
dips harder off-center. Consistent with decomp (res-weighted gain path in twin-mask
factory). The q1@2000 residual is structural warp/model mismatch, not rp.