From 3c5e276fc5a6c52bba997bc7aaa64c04029a7a42 Mon Sep 17 00:00:00 2001 From: Matiq Date: Wed, 26 Aug 2026 11:49:48 +0300 Subject: [PATCH] 24mm9: FIR-chain decoded = min-phase cepstral sandwich; opB/opC are RFFT twins (plan@548), df0 = complex-mul dst=track; validated 0.0065 dB median over 60 clean frames; gamma = 1+s_F(q), q~0.8 source open --- handoff/BLOCKMAP_529fe0.md | 57 ++++++++++++++++++++++ handoff/NOTES_LEVEL.md | 62 ++++++++++++++++++++++++ scripts/cascade_sim.py | 98 ++++++++++++++++++++++++++++++++++++++ scripts/rendersnap2.py | 5 +- 4 files changed, 221 insertions(+), 1 deletion(-) diff --git a/handoff/BLOCKMAP_529fe0.md b/handoff/BLOCKMAP_529fe0.md index 521d838..b1acd15 100644 --- a/handoff/BLOCKMAP_529fe0.md +++ b/handoff/BLOCKMAP_529fe0.md @@ -733,3 +733,60 @@ df0: 18000df0→18000b3c0 ; f70→18000e360 ; финальный combine Все четыре микровопроса 24mm6 закрыты или локализованы до тел-обёрток. Следующий раунд: семантика 4ca80/1a0c0 (кандидаты источника γ=2k−масштаба), затем полный numpy-конвейер. + +## ДОПОЛНЕНИЕ 24mm9: opB/opC = RFFT-близнецы; df0 = complex-mul; цепь валидирована 0.0065 дБ + +### Слой вызовов FIR-секции (уточнение поверх 24l/24mm6) +``` +обёртки: th2180 impl=125e0, th1a90 impl=5560 — только перестановка аргументов: + воркер получает (rcx=data, rdx=data, r8=ПЛАН, r9=WORK), ин-плейс. +ПЛАН = [ctx+540548] (buf548!): tag=6 [+0], log2n=12 [+4], flag [+8]=0, + scale_flag=1 [+0xc], scale=2^-12 [+0x10], workbytes=16384 [+0x18]. +WORK = [ctx+540598] — рабочая область FFT (заметение «lane-mask» из 23b). +th2180 → воркер 4ca80(f)/1d160(d): INVERSE real-RFFT (голова: X[0]±X[Nyq]). +th1a90 → воркер 1a0c0(f)/18400(d): FORWARD real-RFFT (хвост: пакинг Nyq). +тела: импортные близнецы 181b853e0(inv)/181b81b80(fwd); константы только + ±0.707107; масштабов нет. ffe0 = ×scale pass (skip при scale∈{0,1}). +copy th2210 → 136e0 → 4d900(src,dst,n): pack re=v, im=0 (vunpcklps+zero). +df0 18000b3c0: ПОЭЛЕМЕНТНОЕ КОМПЛЕКСНОЕ УМНОЖЕНИЕ dst=[rdx]=arg2: + track_i := track_i ⊗ FIR (vfmaddsub213ps; f70/b560 — double версия). +EXP 140b30 → 1803831c0: полиномиальная комплексная exp (без таблиц значений): + magic 12582912 (=2^23·1.5), guard 87.33654, редукция 184.665≈128/ln2, + коэф. {−0.01604,−1.541667(=−37/24), 3.166e-05, 1.008329, −1.65777e-06, + −0.01932, 0.00134, 0.00541687, 10000, 4.19179}; AVX-512+FMA. + Численно = поточечный комплексный exp (flat-exp проигрывает 8 дБ). +``` + +### Полная последовательность (52b60c–52b893, все шаги, без пропусков) +``` +design 535a70(scratch@628 ← ln(bands_i)) ; 52b62f, своп аргументов +copy 2210(scratch → FIR, 2049 пар (re,im=0)) ; 52b644 +FIR[4096]=0 ; 52b685 Найквост ДО фолда +inv-RFFT opA ; 52b672 th2180 +fold: float[1..2047]*=2.0 (xmm13@1824c41e0) ; 52d920 + float[2049..4095]=0 ; 52db50 +fwd-RFFT opB ; 52b6e1 th1a90 +EXP in-place, аргумент×q (q≈0.80, источник ОТКРЫТ); 52b716 +inv-RFFT opC ; 52b74b th2180 +FIR[4096]=0 ; 52b76d +float[0..2047]*=WINfreq[2048..4095] ; 52d990 (падающий Hann) +float[2048..4095]=0 ; 52db50 +fwd-RFFT opD ; 52b7ba th1a90 +FIR[0]=1.0f; FIR[1]=0 ; 52b7cd +(flag f890≠0: pair-scalars 1880/ca0 — live мертво) +th2030(FIR, wet=s888, 2n float) ; 52b857, s888=1 no-op +df0(FIR, track_i, n): track_i := track_i ⊗ FIR ; 52b893 +``` +Смысл: классическое минимально-фазовое ядро через кепстр +(IDFT лога → фолдинг ×2 причинной части + усечение → exp → обратный ход). + +### Валидация и γ +mask_sim = trk·|F(q)|: 60 ультрачистых кадров, ВСЕ 2049 бина: +rms мед 0.0065 дБ / p90 0.0075 / max 0.035 при q=0.80 (порог 0.05 ✓). +γ = 1 + s_F(q), s_F = наклон log|F| по log trk в нотче: q=0.8 ⇒ γ_pred=1.7516 +(точный 1.760561). Открыто: место q в асме (внутренность 1803831c0); +unicorn не эмулирует FMA ⇒ нужен статдекод ядра или live-захват входа EXP. +Дизасмы: /tmp/opencode/cascade/{wrapA_125e0,wrapB_5560,opB_4ca80,opC_1a0c0, +df0_b3c0,h_ffe0,h_136e0*,imp_b8*3e0_full,bk_1803831c0}.dis +(*copy: python3 scripts/disasm_func.py 1800136e0 — ВАЖНО: полный VA, +короткая форма «125e0» даёт пустой файл!). diff --git a/handoff/NOTES_LEVEL.md b/handoff/NOTES_LEVEL.md index 2719f8e..e454c95 100644 --- a/handoff/NOTES_LEVEL.md +++ b/handoff/NOTES_LEVEL.md @@ -4040,3 +4040,65 @@ opB-воркер 18004ca80: пролог + тег [obj]==6 проверка (0xf Полный дизасм не сохранён (скрипт-глюк с редиректом), перегенерировать: `python3 scripts/disasm_func.py 18004ca80 0x300`. Цель: найти множитель γ=1.760561 внутри opB/opC/df0 → замкнуть конвейер. + +## ============ 24mm9: FIR-ЦЕПЬ ДЕКОДИРОВАНА = MIN-PHASE КЕПСТРАЛЬНЫЙ СЭНДВИЧ; ВАЛИДАЦИЯ 0.0065 дБ ============ + +### Структура опов (полные дизасмы в /tmp/opencode/cascade/*.dis) +``` +обёртки 125e0/5560: перестановка аргументов → воркер(rcx=data, rdx=data, + r8=ПЛАН, r9=WORK); всё ин-плейс над FIR +ПЛАН = buf548@540548 (!НЕ маски/твидлы): {tag=6, log2n=12 [+4], + [+8]=0, scale_flag=1 [+0xc], scale=2^-12 [+0x10], work=16384Б [+0x18]} +WORK = buf598@540598 (рабочая область FFT, ~1.0 мусор; «lane-mask» из + 23b — УСТАРЕЛО) +th2180(воркер 4ca80) = INVERSE real-FFT (голова: сумма/разность X[0]/X[Nyq]); +th1a90(воркер 1a0c0) = FORWARD real-FFT (хвост: пакинг Найквиста в слот n); +тела — импортные близнецы 181b853e0/181b81b80 (AVX, только ±1/√2 твидлы, +без внутренних масштабов); ffe0 = in-place ×scale (skip при 1/0); +copy th2210→136e0→4d900 = пак real→interleaved complex (re=v, im=0). +df0 18000b3c0 = ПОЭЛЕМЕНТНОЕ КОМПЛЕКСНОЕ УМНОЖЕНИЕ, dst=arg2: + track_i := track_i ⊗ FIR (vfmaddsub213ps; двойная версия b560+) +EXP-ядро 140b30→1803831c0: таблично-полиномиальная комплексная экспонента + (магия 12582912 expf-класса, guard 87.33654=maxarg−2ln2, + редукция 184.665≈128/ln2, диадич. {−37/24,15/8,31/24,11/1024}); + численно ведёт себя как КОМПЛЕКСНЫЙ exp (вариант flat проиграл 8 дБ). + Unicorn-эмуляция невозможна (нет FMA в TCG) — статический декод открыт. +``` + +### Цепь (все константы из асмa; fn529fe0.dis 52b60c–52b893) +``` +scr@628 → pack(re=scr,im=0) 2049 пар +→ FIR[n]=FIR[4096]=0 ; 52b685 (Найквост re:=0, ДО фолда!) +→ inv-RFFT ; opA th2180 +→ fold: y[1..2047]*=2.0 ; xmm13 @1824c41e0, 52d920 + y[2049..4095]=0 ; 52db50 (y[2048] НЕ трогается) +→ fwd-RFFT ; opB th1a90 +→ комплексная EXP аргумент ×q ; 52b716, q≈0.80 (см. ОТКРЫТО) +→ inv-RFFT ; opC th2180 +→ float[0..2047]*=WINfreq[2048..4095] (падающий Hann); хвост=0 ; 52d990/db50 +→ fwd-RFFT ; opD th1a90 +→ FIR[0]=1.0, FIR[1]=0 ; 52b7cd +→ df0: mask_i := track_i ⊗ FIR ; финальный combine +``` +Это классическое построение минимально-фазового ядра через кепстр +(IDFT лога → удвоение причинной части → exp → обратно). + +### Валидация (структурная фаза, критерий <0.05 дБ — ВЫПОЛНЕН) +60 ультрачистых кадров (|γ_fit−1.760561|<5e-4, fit-rms<1e-5, все sc_*): +по ВСЕМ 2049 бинам rms медиана **0.0065 дБ**, p90 0.0075, max 0.035 при q=0.80. +Инструмент: cascade_sim.py --mask / fir_probe.py. + +### γ выводится из цепи: γ = 1 + s_F(q), s_F = ∂log|F|/∂log trk в нотче +При q=0.8: s_F=0.7516 ⇒ γ_pred=1.7516 против точного 1.760561 (Δ 0.5%). +Остаточная структура та же, что даёт пер-бин модуляцию rms 0.0065 дБ. + +### ОТКРЫТО (следующий раунд) +1. **Источник q** на аргументе EXP: эмпирика 0.785–0.809 по подвыборкам; + главный подозреваемый — внутренность 1803831c0 (или xmm10=0.8 + @1824c3e28-класс константа вне прослеженного пути). Нужен статический + декод ядра (~5700 строк AVX-512+FMA) либо live-захват входа/выхода EXP. +2. Асинхронность снапшотов (cur может отставать от scr/trk) ограничивает + точность пер-кадрового фита — уйдёт с симуляцией детектора (Этап B). +3. Детекторный каскад lvl_raw→scr (шаги 9–17) не тронут; нужны ACC@7c8 + (+ WINfreq@658 для контроля окна) — обновить rendersnap2 SLOTS. + diff --git a/scripts/cascade_sim.py b/scripts/cascade_sim.py index 787832e..826252f 100644 --- a/scripts/cascade_sim.py +++ b/scripts/cascade_sim.py @@ -109,8 +109,106 @@ def validate_scr(sim_scr, cap_scr, tol_db=0.05): return float(np.sqrt(np.mean(err ** 2))), int(m.sum()) +def win_periodic_hann(N): + return 0.5 * (1.0 - np.cos(2.0 * np.pi * np.arange(N) / N)) + + +# ------------------------------------------------ FIR-цепь (24mm9) -------- +NFRAME = 4096 # n=[ctx+0x540534] +NBINS_FIR = NFRAME // 2 + 1 +Q_EXP = 0.80 # скаляр аргумента EXP; источник в 1803831c0 (ОТКРЫТО) + + +def winfreq_fall(): + """WINfreq@[ctx+0x540658]: периодический Hann(4096), падающая половина.""" + return win_periodic_hann(NFRAME)[NFRAME // 2:] + + +def fir_kernel(scr, q=Q_EXP): + """Полная FIR-цепь (BLOCKMAP 24mm9): min-phase кепстральный сэндвич. + + scr(2049) → pack(re=scr,im=0) → FIR[n]=0 (Найквост) + → inv-RFFT → fold(y[1..2047]*=2.0 @1824c41e0; y[2049..4095]=0) + → fwd-RFFT → комплексная EXP (1803831c0, аргумент ×q) + → inv-RFFT → ×падающий Hann → ноль хвоста → fwd-RFFT + → FIR[0]=1, FIR[1]=0. Возвращает |F| (2049). + """ + h = np.asarray(scr, dtype=np.complex128).copy() + h[-1] = 0.0 + y = np.fft.irfft(h, n=NFRAME) + y[1:NFRAME // 2] *= 2.0 + y[NFRAME // 2 + 1:] = 0.0 + w = np.fft.irfft(np.exp(q * np.fft.rfft(y, n=NFRAME)), n=NFRAME) + w[:NFRAME // 2] *= winfreq_fall() + w[NFRAME // 2:] = 0.0 + F = np.abs(np.fft.rfft(w, n=NFRAME)) + F[0] = 1.0 + return F + + +def mask_from_frame(S, q=Q_EXP): + """mask_sim из слотов кадра: cur ≈ trk · |F(scr)| (df0 complex-mul).""" + scr = S[0x540628][:NBINS_FIR].astype(np.float64) + trk = S[0x540688][:NBINS_FIR].astype(np.float64) + return trk * fir_kernel(scr, q) + + +def validate_mask_stage(ds, q=Q_EXP, cap=60): + """Валидация масочной ветви на чистых γ-кадрах (24mm9-протокол). + + Отбор: |γ_fit−1.760561|<5e-4 и fit-rms<1e-5 (жёстче pick_clean_frame). + Критерий: rms по ВСЕМ 2049 бинам < 0.05 дБ (структурная фаза). + """ + import glob + rmss, gpred = [], [] + for f in sorted(glob.glob(os.path.join(ds, 'ph*.npz'))): + try: + d = np.load(f) + except Exception: + continue + if '0x540628' not in d: + continue + scr = d['0x540628'][:NBINS_FIR].astype(np.float64) + trk = d['0x540688'][:NBINS_FIR].astype(np.float64) + cur = d['0x540678'][:NBINS_FIR].astype(np.float64) + ok = (trk > 1e-30) & (cur > 1e-30) & np.isfinite(scr) + if ok.sum() < 50: + continue + lt, lc = np.log(trk[ok]), np.log(cur[ok]) + sel = np.abs(lt) > 0.05 + if sel.sum() < 8: + continue + g = float(np.sum(lt[sel] * lc[sel]) / np.sum(lt[sel] ** 2)) + frms = float(np.sqrt(np.mean((lc[sel] - g * lt[sel]) ** 2))) + if not (abs(g - GAMMA) < 5e-4 and frms < 1e-5): + continue + F = fir_kernel(scr, q) + lf = np.log(F[sel]) + lt_s = np.log(trk[sel]) + sF = float(np.sum(lf * lt_s) / np.sum(lt_s ** 2)) + gpred.append(1.0 + sF) + m = trk * F + mm = (cur > 1e-12) & (m > 1e-12) + e = (np.log(m[mm]) - np.log(cur[mm])) * 20 / np.log(10) + rmss.append(float(np.sqrt(np.mean(e ** 2)))) + if len(rmss) >= cap: + break + if not rmss: + print('нет ультрачистых кадров в', ds) + return + rmss = np.array(rmss) + print('кадров=%d | rms медиана=%.4f дБ p90=%.4f max=%.4f | ' + 'gamma_pred(1+s_F)=%.6f' % + (len(rmss), np.median(rmss), np.percentile(rmss, 90), rmss.max(), + float(np.median(gpred)))) + + def main(): import sys + if len(sys.argv) > 1 and sys.argv[1] == '--mask': + validate_mask_stage(sys.argv[2] if len(sys.argv) > 2 + else '/tmp/opencode/sc_multi4b') + return 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' diff --git a/scripts/rendersnap2.py b/scripts/rendersnap2.py index 906d4f5..d454cd9 100644 --- a/scripts/rendersnap2.py +++ b/scripts/rendersnap2.py @@ -20,7 +20,10 @@ import numpy as np SLOTS = [0x540668, 0x540548, 0x540550, 0x540598, 0x540628, 0x5406f8, 0x540678, 0x540688, 0x5406c8, 0x5406e8, 0x540768, - 0x540788, 0x5407f8] + 0x540788, 0x5407f8, + # 24mm9: ACC-таблица указателей (шаг 10 combine) и WINfreq + # (окно FIR-цепи; падающий Hann — контроль формы) + 0x5407c8, 0x540658] NARR = 8194 SCAL_OFF = 0x540860 SCAL_N = 24 # floats -> 0x540860..0x5408c0