From a79c8f4934aaa6a89a91edd33547e383c4226e7b Mon Sep 17 00:00:00 2001 From: Matiq Date: Wed, 26 Aug 2026 02:33:11 +0300 Subject: [PATCH] 24mm4: cascade_sim.py skeleton + clean-frame picker (gamma/identity phases), power law validated to 0.0006dB; pointwise detector laws refuted on 447 bins - scr is spectral-cascade product --- handoff/NOTES_LEVEL.md | 27 ++++++++ scripts/cascade_sim.py | 139 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 166 insertions(+) create mode 100644 scripts/cascade_sim.py diff --git a/handoff/NOTES_LEVEL.md b/handoff/NOTES_LEVEL.md index bd083a0..18a2649 100644 --- a/handoff/NOTES_LEVEL.md +++ b/handoff/NOTES_LEVEL.md @@ -3994,3 +3994,30 @@ mask(f) = exp(γ · scr(f)) ; γ вычисляется цепоч rendersnap-кадры полиморфны: отбирать только кадры где (а) trk==exp(scr), (б) fit γ имеет rms<1e-5, (в) нет нулей в 678. Критерий отбора встроен в scan-скрипты следующего раунда. + +## ============ 24mm4: ЦЕЛЬ СИМУЛЯТОРА = scr(f); ТОЧЕЧНЫЕ ЗАКОНЫ ОТВЕРГНУТЫ НА 447 БИНАХ; cascade_sim.py ============ + +### Сквозная валидация степенного закона (scripts/cascade_sim.py) +- multi4b/ph073: γ=1.760561 (fit rms 1.1e-07), закон mask=trk^γ: + rms 0.0064 дБ / 48 бинов | multi4b/ph065: 0.0006 дБ / 103 бина +- multi6: identity-фаза ph034 (γ=1, маска==trk, 499 бинов rms 0) даёт ВСЕ + шесть нотчей ±0.03 дБ; γ-фаза ph037: 0.0006 дБ. +- Отбор кадров формализован (pick_clean_frame): две фазы (γ*≈1.760561 и + identity γ=1), критерий fit-rms<1e-4. + +### Детекторный вход: точечные законы окончательно мертвы +На multi6/ph034 по всем 447 значимым бинам: corr(−scr, ln X) ≤ 0.36 для +X ∈ {lvl, am·S/res, am·S, S/res, am·res, S·lvl, am·S/√res}; лучший +двухпараметрический фит rms 0.20 (нужно <0.05 дБ). scr(f) зависит от +ОКРЕСТНОСТИ спектра ⇒ воспроизводится только спектральным каскадом +(частотные IIR шагов детектора, коэф. 533340). Это и есть остаток Задачи №1. + +### Состояние на закрытие сессии +1. Все 10 ядер резолвлены+опознаны; expf/divide декодированы до формул + (BLOCKMAP 24mm2). Каноническая C++ транскрипция ядер — после замыкания + структуры каскада. +2. Применение: mask=trk^1.760561, trk=exp(scr); γ вычисляется цепочкой — + источник γ в алгебре divide/add/exp шагов 9–19 (поиск в декоде). +3. Симулятор: scripts/cascade_sim.py (каркас + валидатор + отбор кадров). + Следующий раунд: оп-за-оп декод тела каскада между lvl_raw и scr + (частотные IIR с коэф. 24cc → vec6f8/bands_curve), затем C++ порт. diff --git a/scripts/cascade_sim.py b/scripts/cascade_sim.py new file mode 100644 index 0000000..787832e --- /dev/null +++ b/scripts/cascade_sim.py @@ -0,0 +1,139 @@ +#!/usr/bin/env python3 +"""cascade_sim.py — структурный симулятор тракта маски soothe2 (float-путь). + +Цель (24mm3): воспроизвести scr(f)=дизайн-сигнал детектора; применённая +маска = exp(γ·scr), γ=1.760561 (точно), trk@688=exp(scr@628) бит-в-бит. + +Структура канонической цепи (BLOCKMAP 24hh/24ii + 24mm2): + шаг 9a: vec698 *= (1 − [54087c]) ; zero при дефолтах + шаг 9b: vec6f8 += [54087c]·0.8 ; xmm10=0.8 @1824c3e28 + шаг 9c: bands_curve_i /= ... divide-ядро ; dst=678i, A/B уточняются + шаг 10: vec6f8 = bands_curve_i − ACC_i ; dc40, ACC @таблицы 0x5407c8 + шаг 11: fma att/rel (тройки re/im/coef) ; коэф @6c8/6e8 + шаг 12: COPY ; memcpy + шаг 13: зеркало 9 + шаг 14: expf(bands_curve); bands_curve += (−1) ; ПОРЯДОК исправлен 24mm2 + шаг 15: bands_curve *= track_i ; th2000 array-mul + шаг 16: bands_curve *= kWarp@[5406a8] + шаг 17: expf ещё раз ; call-site 52b32c + пост-17: exp-вариант(140a40) + pow?(140b00) + FIR-секция: кривая-float(140b30→1803831c0) + sincos-twiddle(140aa0) + +ЯДРА (структурная фаза — математически точные numpy-эквиваленты; +канонический C++ порт = инструкци-точная транскрипция, см. BLOCKMAP 24mm2): +""" +import numpy as np +import glob +import os + +GAMMA = 1.760561 # 24mm3: показатель степени, rms фита 0 на чистых кадрах +N = 2049 # число бинов полной сетки + + +# ---------------------------------------------------------------- ядра ---- +def k_exp(x): + """expf-ядро 180296c80. Структурная фаза: np.exp. + Каноническая формула (для C++ порта, FMA-точно): + n = fma(log2e_hi=1.4427f, x, 12582912.0f); k = n - MAGIC + r = (x - 0.693146f*k) - 1.42861e-06f*k + p = (((0.00829172f*r+0.0418735f)*r+0.166674f)*r+0.499994f)*r+1)*r+1 + out = bits((k<<23) + bits(p)); guard |x|>87.3365 -> slow path + """ + return np.exp(x) + + +def k_div(a, b): + """divide-ядро 1803a06a0: dst = B/A (~0.5 ulp, rcp+таблицы+полином). + Структурная фаза: точное деление.""" + return b / a + + +# ------------------------------------------------------------ данные ----- +def load_tract(path): + """tract_*.txt: k am res lvl_raw band_level prewarp w""" + t = np.loadtxt(path) + return {'am': t[:, 1], 'res': t[:, 2], 'lvl': t[:, 3]} + + +def load_frame(npz): + """Слоты кадра rendersnap2 → dict[int, np.ndarray].""" + d = np.load(npz) + out = {} + for k in d.keys(): + if k.startswith('0x'): + out[int(k[2:], 16)] = d[k] + return out, d['t_snap'] + + +def pick_clean_frame(ds_dir, min_bins=8): + """Отбор чистых стационарных кадров по фазам (24mm3): + возвращает лучший на фазе γ* (~1.7606, маска применена) + и лучший на фазе γ=1 (степень ещё не применена).""" + classes = {'gamma': None, 'identity': None} + for f in sorted(glob.glob(os.path.join(ds_dir, 'ph*.npz'))): + try: + S, ts = load_frame(f) + except Exception: + continue + if not all(x in S for x in (0x540628, 0x540688, 0x540678)): + continue + s = S[0x540628][:1025].astype(np.float64) + t = S[0x540688][:1025].astype(np.float64) + c = S[0x540678][:1025].astype(np.float64) + ok = (t > 1e-30) & (c > 1e-30) & np.isfinite(s) + if ok.sum() < 50: + continue + lt = np.log(t[ok]) + lc = np.log(c[ok]) + sel = np.abs(lt) > 0.05 + if sel.sum() < min_bins: + continue + g = float(np.sum(lt[sel] * lc[sel]) / np.sum(lt[sel] ** 2)) + rms = float(np.sqrt(np.mean((lc[sel] - g * lt[sel]) ** 2))) + depth = float(-lc.min()) + key = 'gamma' if abs(g - GAMMA) < 0.01 else \ + ('identity' if abs(g - 1.0) < 1e-4 else None) + if key is None or rms > 1e-4: + continue + cand = (depth, f, s, t, c, g, rms) + if classes[key] is None or depth > classes[key][0]: + classes[key] = cand + return classes + + +# ------------------------------------------------------- валидация ------- +def validate_scr(sim_scr, cap_scr, tol_db=0.05): + """rms в дБ между симулированным и захваченным scr.""" + m = np.abs(cap_scr) > 0.02 + err = (sim_scr[m] - cap_scr[m]) * (20 / np.log(10)) + return float(np.sqrt(np.mean(err ** 2))), int(m.sum()) + + +def main(): + import sys + ds = sys.argv[1] if len(sys.argv) > 1 else '/tmp/opencode/sc_multi6' + tract = sys.argv[2] if len(sys.argv) > 2 else '/tmp/opencode/tract_multi6.txt' + + classes = pick_clean_frame(ds) + ph_g = classes['gamma'] + ph_i = classes['identity'] + if not ph_g and not ph_i: + print('нет чистых кадров в', ds) + return + for lbl, best in (('γ-фаза', ph_g), ('identity', ph_i)): + if not best: + continue + _, f, scr, trk, cur, gamma_fit, grms = best + n = len(scr) + cut_meas = -20 / np.log(10) * np.log(np.maximum(cur, 1e-30)) + g_use = gamma_fit + cut_sim = g_use * (-scr) * 20 / np.log(10) + e = cut_sim - cut_meas + sel = np.abs(cut_meas) > 0.1 + rms_db = float(np.sqrt(np.mean(e[sel] ** 2))) if sel.any() else 0.0 + print(f'{lbl}: {os.path.basename(f)} γ={gamma_fit:.6f} (rms {grms:.1e}) ' + f'закон: rms={rms_db:.4f} дБ / {int(sel.sum())} бинов') + + +if __name__ == '__main__': + main()