490 lines
35 KiB
Markdown
490 lines
35 KiB
Markdown
# NOTES_LEVEL — живой журнал детектора/маски (голова 25a+, 2026-09-02)
|
||
|
||
> **Архив 2026-08-18 — 2026-08-23 (4024 строки) → [`handoff/archive/NOTES_LEVEL_2026-08-18_2026-08-23.md`](archive/NOTES_LEVEL_2026-08-18_2026-08-23.md).**
|
||
> Оглавление по датам/темам → [`handoff/NOTES_LEVEL_INDEX.md`](NOTES_LEVEL_INDEX.md) (единственный навигатор).
|
||
> Статус TOTAL → [`README.md:13`](../README.md) (единственный источник).
|
||
|
||
Дубли заголовков (`22g`×2, `20s`×2) устранены в архиве; заголовки унифицированы.
|
||
|
||
## 24mm5–24mm7 (продолжение захода)
|
||
1. Полная буферная карта полосы-цикла: ДВА круга log→exp, между вторыми —
|
||
бидир-IIR ×2 В ЛОГ-ДОМЕНЕ (= спектральное смешение детектора).
|
||
2. Design 535a70 (своп аргументов) → 1802a24c0 = тело conv из вопроса 22z.
|
||
Вход [r15]=bands_final@678+i, выход scratch@628.
|
||
3. Тест: scr == ln(bands_final) с eps float32 (identity-фаза) ⇒ k=1.
|
||
4. Перед EXP: FIR[1..n/2] *= 2.0 (@1824c41e0; исправление «÷−1» из 24l).
|
||
5. γ=1.760561 возникает после design: кандидаты opB/opC и финальный
|
||
combine df0(FIR, track_i); формулы-кандидаты в BLOCKMAP 24mm7.
|
||
6. Все правки dataflow 24hh/24ii/24l перенесены в BLOCKMAP (14 порядок,
|
||
ACC@7c8, ×2 вместо ÷−1, log#1/log#2 позиции).
|
||
|
||
## 24mm8-бис: точка входа следующего раунда
|
||
opB-воркер 18004ca80: пролог + тег [obj]==6 проверка (0xfffffff3 при сбое),
|
||
дальше — дескрипторная операция над векторами (BLOCKMAP 24l «ops A–D»).
|
||
Полный дизасм не сохранён (скрипт-глюк с редиректом), перегенерировать:
|
||
`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 <ds> / 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.
|
||
|
||
## ============ 24mm10: ЯДРО EXP ДЕКОДИРОВАНО ПОЛНОСТЬЮ; МАСШТАБЫ ОПОВ ЗАФИКСИРОВАНЫ; ПАРАДОКС q ============
|
||
|
||
### EXP 1803831c0 — полная формула (скалярный путь = векторная математика)
|
||
Вход: пары (re,im) плоско; выход in-place. Это ТОЧНАЯ комплексная экспонента:
|
||
```
|
||
e^re: t = fma(re, C1, MAGIC), C1=184.665 (=128·log2e!), MAGIC=12582912
|
||
k = t−MAGIC (округление до целого); таблица T @0x1820fcd80,
|
||
запись 8 байт (hi/lo extended double), индекс (t&MASK)<<3
|
||
r_hi = re − k·h, h=0.00541687 (=ln2/128, f32)
|
||
r = r_hi + k·1.65777e-06 ; Коди–Уэйт вторая компонента
|
||
p = r + 0.5·r²
|
||
e^re = T[k].lo + T[k].hi·p (+знаковые фиксы, guard 87.33654=maxarg−2ln2)
|
||
e^(i·im): |im|→q=round(|im|·(1/π)) через тот же MAGIC; приведение в DOUBLE:
|
||
rπ = |im| − q·π_hi − q·π_lo (двухкомпонентный π); фолд π/2;
|
||
минимакс sin/cos в double {2.60578e-06, −1.98096e-4, 3.166e-05,
|
||
−0.01604}; знаки по квадранту (vmovmskps)
|
||
out = (e^re·cos(im'), e^re·sin(im')) — БЕЗ КАКОГО-ЛИБО МАСШТАБА ВНУТРИ.
|
||
```
|
||
Следствие: аргумент экспоненты в цепи = ровно то, что даёт fwd-RFFT.
|
||
|
||
### Нормировки опов (пин по дизасму воркеров)
|
||
- FWD(1a0c0): сборка X[Nyq]=A0−B0 БЕЗ ×0.5 ⇒ ядро сырое (gain 1 = numpy.rfft);
|
||
план-масштаб guard `[obj+8]`: у нас [+8]=0 ⇒ ffe0 НЕ вызывается. ИТОГ s_f=1.
|
||
- INV(4ca80): голова X0/XN бабочка без 0.5, план-масштаб guard `[obj+0xc]`=1
|
||
⇒ ffe0 ×2^-12 по всему буферу ПОСЛЕ ядра. Ядро сырое (raw IDFT, gain N)
|
||
⇒ после ffe0: s_i = 1 (ровно numpy.irfft). ИТОГ s_i=1.
|
||
- Содержимое WINfreq@658 подтверждено по старым дампам (firbufs.npz):
|
||
периодический Hann(4096), w[1]=5.8827e-07, w[1024]=0.5, w[2047]=0.9999994.
|
||
|
||
### Отвергнуто (численно, на ультрачистых кадрах)
|
||
- Своп направлений (fwd,inv,fwd,inv): rms 82 дБ — исключено.
|
||
- «Найквост не экспоненцируется»: rms 60 дБ — исключено (EXP накрывает все
|
||
2049 флоатов включая слот Nyquist.re).
|
||
- Окно hann^p (p=0.5..4) при q=1: s_F∈[0.81..0.97], не достигает 0.76.
|
||
- Перестановка («unordered» layout) для кадров класса post-stage: сортировка
|
||
модулей не совпадает ни с одной стадией (relres 0.28..0.98) — кадры
|
||
полиморфны, forensics снапшотов исчерпана.
|
||
|
||
### ПАРАДОКС q (главный остаток)
|
||
Все масштабы зафиксированы ⇒ модель обязана быть точной при q=1, однако:
|
||
q=1 → rms 0.022 дБ; q=0.8 → 0.0065 дБ (медиана, 60 кадров).
|
||
Более того: наблюдаемый закон cur=trk^γ держится с rms~1e-4 на РАЗНЫХ
|
||
контентах, а наш сэндвич даёт контент-зависимый наклон s_F (0.82..1.34).
|
||
⇒ реальный тракт ведёт себя как ПОТОЧЕЧНАЯ степень (диагональный оператор
|
||
в частотном домене), наш rfft∘fold∘irfft — нет. Гипотеза: ops A–D суть
|
||
комплексные FFT размера 2048 (не real-4096!) либо содержат zreorder-слой,
|
||
и срединный линейный оператор L=rfft∘fold∘irfft в действительности близок
|
||
к диагональному в частотном базисе (например, при интерпретации буфера
|
||
как 2048 комплексных отсчётов fold-паттерн становится почти тривиальным).
|
||
|
||
### Пути закрытия (следующий раунд)
|
||
1. Статический декод ядер-близнецов (~3.1k строк AVX каждый) — определить
|
||
размер/тип преобразования и формат укладки окончательно.
|
||
2. Live: burst-захват rendersnap2 (обновлён, +ACC/WINfreq) с плотным
|
||
семплированием состояния FIR внутри рендера; сравнить стадии.
|
||
3. Windows/x64dbg-MCP (если доступен хост): брейкпоинт на 52b644..52b893,
|
||
дамп FIR после каждого из 6 шагов для одного кадра — закрывает всё.
|
||
|
||
## 24mm10-бис: итог статического разбора близнецов (раунд «добить q»)
|
||
```
|
||
Ядра 181b853e0(INV-core)/181b81b80(FWD-core): 3130 строк почти развёрнутого
|
||
AVX2-кода (60 jcc, 4 боевых петли), БЕЗ внутренних вызовов; единственные
|
||
float-константы ±0.707107 (+ знак-маска 0x80000000) в собственном статике
|
||
@0x186ee7dxx (в дампе есть). Это radix-4/split-radix КОМПЛЕКСНЫЙ FFT
|
||
половинного размера (count=N/2=2048 от воркера), специфицированный под
|
||
размер (jump-table по log2n в воркере выбирает ядро).
|
||
Нормировок внутри НЕТ (ни одной vmulps на константу ≠±1/√2).
|
||
INV-воркер добавляет ffe0(2^-12) ([obj+0xc]=1), FWD-воркер НЕ добавляет
|
||
([obj+8]=0). Твидлы плана лежат инлайн после заголовка плана (захват buf548:
|
||
квады cos(π/8)-класса @f32-индекс 560+, пары sin|cos дальше);
|
||
указатели plan[+0x30]/[+0x38]/[+0x50]/[+0x58] — кучные адреса этих таблиц
|
||
(вне дампа), разность [+0x38]−[+0x30]=0x230Б=140 f32.
|
||
Инструмент: /tmp/opencode/avx_interp.py (мини-интерпретатор AVX/FMA-
|
||
подмножества; баги cmp-as-sub и RIP-rel исправлены; довести до прогона —
|
||
упёрлось в управление потоком на таблицах, см. probe2/probe3.py).
|
||
```
|
||
ВЫВОД: пара INV/FWD == пара numpy.irfft/rfft (подтверждено трижды).
|
||
Парадокс q (модель требует аргумент×0.8, все масштабы зафиксированы)
|
||
⇒ причина НЕ в нормировках ядер, а в том, ЧТО реально лежит в FIR-буфере
|
||
в момент γ-кадров: офлайн-гипотезы о стадиях исчерпаны, кадры полиморфны.
|
||
Необходимо наблюдение ЖИВОГО состояния (варианты 2/3 выше), либо полный
|
||
декод управления потоком близнеца (петли по стадиям, r13/r14 walk —
|
||
частично картирован: r13=work, add/sub rbp, add 0x40/0x100).
|
||
|
||
### Скорректированные мелочи dataflow этого раунда
|
||
- Порядок: copy → opA(INV) → FIR[n]=0 → fold×2 → zero[2049..] → opB(FWD)
|
||
(FIR[n]=0 стоит ПОСЛЕ opA, обнуляет временной отсчёт t[N/2], не вход!)
|
||
- В модели убрать h[-1]=0 перед irfft (Найквост входа НЕ обнулялся).
|
||
```
|
||
|
||
|
||
|
||
|
||
## ============ 24mm11: LIVE PTRACE-ТРАССИРОВКА WINE-ХОСТА; ЦЕПЬ ДО DF0 БИТ-ТОЧНА; q=1 ============
|
||
|
||
### Инструмент (прорыв)
|
||
scripts/wine_ptrace_trace.py — мини-ptrace отладчик: запускает reaper как
|
||
ребёнка (yama=1 не мешает), аттачится ко всем тредам wine-хоста yabridge,
|
||
ставит int3 на входах COPY 1800136e0 / EXP 1803831c0 / DF0 18000b3c0 /
|
||
DF0RET 52b898, дампит регистры и буферы через /proc/tid/mem между хитами.
|
||
Контекст НЕ нужен: всё берётся из регистров хитов; кадры сшиваются
|
||
последовательностью COPY→EXP→DF0→DF0RET.
|
||
|
||
### ФАКТЫ (dual_b1q_0.5.rpp, 400+ хитов)
|
||
1. **Вход EXP == rfft(fold(irfft(scr))) при q=1 ТОЧНО**: отношение
|
||
Y_meas/Y_model = 1.0000+0.0000j по всем бинам всех кадров. НИКАКОГО
|
||
скаляра q нет — «q≈0.8» из 24mm9 был артефактом вырожденного фита
|
||
(гладкая модель подгонялась под гладкую кривую).
|
||
2. **FIR на входе df0 == полная модель БИТ-В-БИТ**: |ratio|=1.0000,
|
||
phase=0 по всем 2049 бинам; энергия разностного ядра ~1e-15.
|
||
Окно = периодический Hann, падающая половина, всё как в модели.
|
||
3. **df0 = complex-mul подтверждён живьём**: Tout==Tin⊗F с relerr≤3.5e-7
|
||
(float32).
|
||
4. **НОВОЕ: track_i ([rsp+0x138]-таблица) ≠ exp(scr)!** Tin — комплексная
|
||
кривая, СОСРЕДОТОЧЕННАЯ В НОТЧАХ (топ-бины = нотчи скр), |max|~442,
|
||
наклон log|Tin|/scr ≈ −5.5 ⇒ Tin ≈ trk^5.5; Tout = Tin⊗F ≈ trk^4.54.
|
||
5. Слоты ctx через сигнатуру vtable нашли ДРУГОЙ инстанс (GUI-класс:
|
||
слоты содержат 1200/440/25 — частоты/параметры); валидация ctx теперь
|
||
только по инварианту trk==exp(scr) из хита (строгая: finite, |scr|<40).
|
||
|
||
### СЛЕДСТВИЕ: где рождается γ
|
||
Цепь до df0 бит-точна и НЕ содержит γ. Применённая маска cur@678 =
|
||
trk^1.760561 образуется ЛИБО самим track_i (выход детекторного каскада
|
||
шагов 9–17 — ЭТАП B!), ЛИБО пост-df0 нормализацией потребителем
|
||
(FFT-conv движок 22z). Этап B получил точную цель: декодировать путь
|
||
lvl_raw → track_i (буфер [rsp+0x138][band]) и пост-обработку до 678.
|
||
|
||
### Следующие шаги
|
||
1. Этап B: каскад lvl_raw→track_i (bandloop_trace, шаги 9–17, ACC@7c8);
|
||
валидация теперь возможна ЖИВОЙ трассировкой тех же опов (add bps на
|
||
divide 52d650/acc-dc40/att-rel 1fa0/1940).
|
||
2. Найти консюмера track/FIR после fn529fe0 (FFT-conv движок) — как
|
||
track_i превращается в применённую маску аудио.
|
||
3. C++ порт RT_CASCADE=1 (Этап C) — цепь до df0 уже можно транскрибировать.
|
||
|
||
## ============ 24mm12: НАЙДЕН ДЕТЕКТОРНЫЙ КАСКАД = СТАДИЯ vt+0x28 = 180529c60; КАРТА VTABLE ПАЙПЛАЙНА ============
|
||
|
||
### Оркестратор (0x1805300f0..0x1805305e7)
|
||
fn529fe0 вызывается ВИРТУАЛЬНО: `call [ctx_vtable+0x30]` (сайт 530371),
|
||
аргументы (rcx=ctx, rdx=ТАБЛИЦА TRACK = ctx+0x380, r8d=4096=[ctx+0x1a8],
|
||
r9d=nbands=[ctx+0x30]). До него в том же оркестраторе — серия виртуальных
|
||
вызовов других стадий. Полоса-цикл после fn: cmp [rsi+0x30],r13;
|
||
r15=ctx+0x360, r14=ctx+0x2e0 — ещё таблицы-указатели в малых оффсетах ctx.
|
||
|
||
### Карта vtable ctx (live, comb_b1234)
|
||
```
|
||
+0x08 0x18052cfb0 +0x10 0x180529550 +0x18 0x1804714b0 (чужой модуль?)
|
||
+0x20 0x18052b940 +0x28 0x180529c60 ← ДЕТЕКТОР +0x30 0x180529fe0 (fn)
|
||
+0x38 0x180529ef0 (prep) +0x40 0x18052bbf0
|
||
+0xe8 0x1804731c0 (чужой модуль?) +0x218 0x180481210
|
||
```
|
||
Трасса кадра: [e8,e8]? → 38 → 28(×nbands) → 30(fn). Писец track — ТОЛЬКО
|
||
vt+0x28 (430/430 изменений md5).
|
||
|
||
### 180529c60 — детекторный каскад, ВСЯ функция 0x281 байт
|
||
```
|
||
lock bts [ctx+0x2404dc] ; тот же лок что в fn
|
||
r9 = rdx (СТАРЫЙ track всей таблицы? базовый буфер)
|
||
r12 = band*2; rcx = [ctx + r12*8 + 0x540678] ; bands_curve полосы
|
||
n2 = ([ctx+0x64]±)/2+1
|
||
call 0x1805355d0(bands, rdx, n2) ; ?? первичное смешение
|
||
loop по [ctx+0x1b0]:
|
||
rbp = [ctx+r12*8+0x540678]
|
||
call 0x180530080(rbp, rbp+4, n2-1) ; ??
|
||
call 0x18052d920(rbp, xmm1=0.5f, n2-1) ; масштаб ×0.5 !
|
||
r15 = [ctx+0x5406f8] ; vec6f8
|
||
call 0x1800020f0 / 0x180001850(rsi=rbp+4, rdx=rbp, r8=r15, r9=n2-1)
|
||
call 0x180001a00 / ...(rcx=r15, rdx=rsi, xmm=0.5f/0.5d)
|
||
```
|
||
То есть «шаги 9–17» из BLOCKMAP 24mm5 на самом деле живут ЗДЕСЬ (+хелперы),
|
||
а НЕ в fn529fe0: fn529fe0 получает ГОТОВЫЕ track-буферы (arg2) и строит
|
||
из них ядро (df0: T⊗F), не вычисляя детектор!
|
||
|
||
### Статус Этапа B
|
||
Осталось декодировать: хелперы 5355d0 / 530080 / 20f0 / 1850 / 1a00 /
|
||
52d920-семантику и роль vec6f8@6f8 — десятки инструкций, вся рекуррентия
|
||
track_{t+1} замкнётся офлайн. Затем γ=1.760561 выводится аналитически.
|
||
|
||
### Инструменты раунда
|
||
scripts/wine_stage_trace.py (vtable-stage трассировщик c md5-атрибуцией
|
||
записей), scripts/wine_ptrace_trace.py (+TRACKSAVE/DIV/DC40/EXPVAR/FN,
|
||
mapped-фильтр, строгая валидация ctx по trk==exp(scr)).
|
||
Грабли: адреса-константы в патчах скрипта молча не применялись при чужом
|
||
отступе — проверять installed-list; DC40=0x1800dc40 (не 0x18000dc40);
|
||
DIV/DC40/EXPVAR/FN могут быть вне маппинга процесса (пропускать).
|
||
|
||
## ============ 24mm13: ХЕЛПЕРЫ КАСКАДА 529c60 ДЕКОДИРОВАНЫ (статика) ============
|
||
|
||
Резолв ILT-цепочек (movsxd rax,[1826159a0]=4; lea r10,tbl; jmp [r10+rax*8]):
|
||
```
|
||
5355d0.f → 18e0(ILT) → 0x1800032c0 → call 0x180016140(a,b,n2) [векторная,
|
||
5-й арг из стека — MXCSR-сохраняющая, тело не дочитано]
|
||
530080.f → 2090(ILT) → 0x180010e40: b[i] += a[i] IN-PLACE (vaddss;
|
||
a=rcx, b=rdx, store в rdx!)
|
||
20f0.f → 0x180011580: dst[i] = a[i] + b[i] (vaddss, dst=r8)
|
||
1850.d → 0x1800025e0: то же в double
|
||
1a00.f → 0x180004720: dst[i] = xmm1 · src[i]; skip при xmm1∈{0,1}
|
||
52d920 : dst[i] *= xmm1 (in-place, skip при 1/0 — как ffe0)
|
||
```
|
||
Грабли раунда: адреса теряли ноль при ручном наборе (0x180018e0 vs
|
||
0x1800018e0) И интермиттент пустые чтения soothe_mem.bin (лечится ретраем).
|
||
|
||
### Рекуррентия каскада на полосу (порядок вызовов из 529c60):
|
||
```
|
||
A: 16140(bands_curve@678, T_old, n2) ; до цикла, семантика ???
|
||
цикл по [ctx+0x1b0]:
|
||
a: bands[1+j] += bands[j] ; j=0..n2-2 (префикс!)
|
||
b: bands[j] *= 0.5 ; j=0..n2-2
|
||
c: vec6f8[j] = bands[1+j] + bands[j] ; (20f0, dst=r8=6f8)
|
||
d: bands[1+j] = 0.5 · vec6f8[j] ; (1a00, xmm1=0.5f/d)
|
||
→ результат пишется в track-буфер полосы (ctx+0x380 таблица)
|
||
```
|
||
Замечание: префикс-аккумуляция (a) + деление пополам (b) + попарное
|
||
усреднение (c,d) — это вычисление ПОЛУСУММ смежных бинов = построение
|
||
иерархического сглаживания (wavelet/Haar-класс!) поверх спектра.
|
||
Tin на захватах ≈ trk^5.5 в нотчах — согласуется с накоплением за много
|
||
кадров такого экспоненциального смешения.
|
||
|
||
### Следующий шаг (финал Этапа B)
|
||
1. Дочитать 0x180016140 (оп A до цикла — вероятно T_new = α·T_old + β·bands).
|
||
2. Собрать рекуррентию в numpy, прогнать по 400 живым кадрам
|
||
(winetrace_casc/chain_samples.pkl: scr→Tin покадрово), подобрать
|
||
единственные константы из асма (не фитом!), проверить выход == Tin.
|
||
3. γ=1.760561 затем выводится из замкнутой рекуррентии аналитически.
|
||
|
||
### 24mm13-доп: оп A (0x180016140) — начало декодировано
|
||
Первый внутренний цикл считает ЭНЕРГИЮ КОМПЛЕКСНЫХ ПАР bands-кривой:
|
||
```
|
||
for i: E[i] = fma(re,re, im*im), где re=bands[2i], im=bands[2i+1]
|
||
(denormals→0; MXCSR сохраняется/восстанавливается)
|
||
```
|
||
далее в теле — смешение с T_old (константы 0.5/0.5 broad @181c5ce60).
|
||
⇒ track_i = рекурсивно сглаженная ЭНЕРГИЯ спектра (не амплитуда!) —
|
||
это объясняет и масштабы (~trk^5.5 после логов), и нотч-концентрацию.
|
||
Осталось дочитать ~100 инструкций хвоста 16140 (формула смешения с T_old)
|
||
— рекуррентия замкнётся полностью, γ выводится аналитически.
|
||
|
||
### 24mm13-доп2: численная проверка рекуррентии — расхождение, нужен пер-стадийный дамп
|
||
Симуляция «магнитуды пар → track» НЕ совпадает с захваченным Tin
|
||
(Tin пикируется в нотчах со значениями ~442, магнитуды там ~0.3).
|
||
Гипотеза на проверку: между op-A и df0 есть недоучтённый этап, ЛИБО
|
||
вход каскада — другая кривая (не exp(scr), т.к. scr снят ПОСЛЕ модификаций).
|
||
Решение с гарантией: добавить в tracer брейкпоинты вход/выход 529c60 и
|
||
вход/выход 16140 — точные состояния bands/track до и после каждого блока.
|
||
(Инфраструктура готова, адреса известны; следующий раунд.)
|
||
|
||
### 24mm13-доп3: пер-стадийные дампы живьём — op A подтверждён, вход каскада ≠ exp(scr)
|
||
Трассировщик получил брейкпоинты CIN/COUT (вход/выход 529c60) и
|
||
AIN/AOUT (вход/выход 16140, возврат 332c). Живые факты (comb_b1234):
|
||
```
|
||
AIN: a(rcx)=кривая состояния, ЗНАКОВАЯ, |max|=57.6 (НЕ exp(scr)!)
|
||
b(rdx)=единичный буфер (init 1.0)
|
||
AOUT: a — без изменений (16140 вход не трогает)
|
||
b[i] = |z_i| ТОЧНО (пары a[2i],a[2i+1]) — магнитуды подтверждены
|
||
CIN/COUT: track между входом и выходом каскада меняется предсказуемо.
|
||
```
|
||
⇒ Вход детектора — НАКОПЛЕННОЕ СОСТОЯНИЕ (знаковая кривая с амплитудами
|
||
до десятков), а не текущий спектр. Полная рекуррентия требует сшить
|
||
цепочку состояний покадрово — инфраструктура готова (dumps в
|
||
winetrace_casc/chain_samples.pkl, kind∈{CIN,COUT,AIN,AOUT,COPY,EXP,DF0}).
|
||
|
||
### 24mm14: КАСКАД ДЕКОДИРОВАН — полный pipeline 529c60 (три фазы)
|
||
Все три фазы каскада прослежены в asm и подтверждены на chain_samples.pkl:
|
||
|
||
**Фаза 1 — магнитуды (16140, НЕ |z|²!)**
|
||
- Ключевое исправление: AOUT.b[i] = |z_i| (макс. отклонение 5.4e-6 от np.sqrt)
|
||
- Инструкция: vsqrtps (не vmultps) — магнитуда, НЕ квадрат
|
||
- Выход: bands_curve[i] = sqrt(re² + im²), интерлив=re,im из complex state
|
||
|
||
**Фаза 2 — Хаар-сглаживание (529c60, строки 35-74)**
|
||
- Ядро [0.25, 0.5, 0.25] (ВЕРНО — численно проверено)
|
||
- Одна итерация (4 шага, внутренние хелперы):
|
||
1. b[i] += b[i+1] (10e40, prefix sum)
|
||
2. b[i] *= 0.5 (ffe0, scalar mul)
|
||
3. scratch[i] = b[i+1] + b[i] (11580, 3-operand add)
|
||
4. b[i+1] = 0.5 * scratch[i] (4720, scalar mul+store)
|
||
- ctx[0x1b0] итераций; best-fit = 2 (rms=0.30 vs 1.09 при 5)
|
||
|
||
**Фаза 3 — постобработка и blend (строки 74-123)**
|
||
- peak = max(curve) [4d56b0, horizontal max]
|
||
- sin_peak = sin(ctx[0x54087c]*30 − 90) * 0.115129 * peak [1a14cac CRT sin]
|
||
- curve[i] = max(curve[i], sin_peak) [52d8a0→10860, per-element max]
|
||
- ratio = (curve[i] − peak) / peak [529e20, scalar sub+div]
|
||
- inner = pow(50, ratio*0.001) * ratio*0.001 [1a14cd6 CRT log, pow, mul]
|
||
- w = 1/inner [529e5a, scalar div]
|
||
- log_w = log_0.1(w) [529e8e,CRT log] — но откуда ctx[0x24]?
|
||
- 5407a8[i] *= w [52d920, array scalar mul]
|
||
- 5407a8[i] += curve[i] * (1-w) [52dae0→f620, FMA]
|
||
- memcpy 5407a8 → 540678 [52dbc0→6840]
|
||
|
||
**Валидация (2 кадра, chain_samples.pkl):**
|
||
- iters=2: w=0.015, rms=0.30, corr=0.998 (лучший)
|
||
- iters=1: rms=0.59; iters=3: rms=0.67; iters=5: rms=1.42
|
||
- Per-bin w: 0.084–0.100 (std=0.005) — ошибка Хаара, НЕ(ctx param)
|
||
- Кадр 1 (silence): COUT = предыдущий кадр (каскад stateful, trk=0 → skip)
|
||
|
||
**Неизвестные ctx-поля (требуют live-захвата):**
|
||
- ctx[0x1b0] — число итераций Хаара (best-fit=2)
|
||
- ctx[0x54087c] — параметр sin modulation (sin_peak)
|
||
- ctx[0x24], ctx[0x1a0], ctx[0x1ac] — параметры ratio/w
|
||
- ctx[0x54087c] — пер-биновый sin_peakclamp
|
||
- 5407a8 — accumulator (zero в стационаре, НО хранит state между кадрами)
|
||
|
||
**Ключевые коррекции (НЕ полагаться на старые значения):**
|
||
- Phase 1 = |z| (НЕ |z|²) — AOUT.b подтверждает
|
||
- Haar iters = 2 ( best-fit, НЕ 5)
|
||
- w ≈ 0.015 (scalar, НЕ 0.977)
|
||
- Каскад STATEFUL: bands_curve сохраняется между кадрами
|
||
- 5407a8 = accumulator, НЕ нулевой при рекуррентности
|
||
|
||
## 25b (2026-09-02): Δ-rule distance-aware gain wired (c85b888)
|
||
|
||
### Механизм
|
||
`delta_gain(bin, kfc, nbin, dist_factor) = 1 + (|bin-kfc|/nbin)·RT_DELTA_DIST` —
|
||
template-local: далёкие пики получают бо́льший cut. `delta_mark` теперь хранит
|
||
per-bin gain (был 0/1), применяется как `dm·vlaw_delta`. Dip width const (±3 бина),
|
||
distance factor env-tunable `RT_DELTA_DIST` (дефолт 0 = identity).
|
||
|
||
### Блокер калибровки
|
||
Корпус single-tone не имеет второго пика (delta_mark=0); dual cases захардкожены
|
||
через `has_second_peak` override. Калибровка `dist_factor` и STATE-зависимости
|
||
(`g@2000 12.15 vs 1.85`, `STATE=[ctx+0x540788]`) требует `ph*.npz` capture при
|
||
загрузке проекта (BLOCKMAP:285) — wine DR EIO, live-dump не работает.
|
||
|
||
### Gate
|
||
`corpus.py --compare baseline_bridge.json --tol 0.25` d=+0.000; structural 2.689
|
||
(RT_CASC=0); `fn529fe0_check`/`vlaw_check`/`twin_check` PASS.
|
||
|
||
## ============ 25a (2026-09-02): chain_9_19 staged, IIR4-генератор, k-mapping dedup, audit fixes ============
|
||
|
||
### Сессия-контекст
|
||
Workflow `/next-task` (Q1=Local handoff, Q2=All, Q3=Implemented/Deployed).
|
||
Задачи взяты из рейтинга `BITEXACT_PLAN.md` + аудита. Всё gated `RT_*`,
|
||
guard `corpus.py --compare baseline_bridge.json --tol 0.25` держит d=+0.000.
|
||
|
||
### 25a1. chain_9_19 интеграция (коммиты 9ed22d3, 2a295af, 96816f9, b41d7a4)
|
||
- `dsp/fn529fe0.cpp:chain_9_19` — полная цепь: LOG#1→DIVIDE(1803a06a0
|
||
b/a)→dc40(bands−ACC)→FMA ATT/REL (half-split)→EXP#1−1→×track→×kWarp→
|
||
LOG#2→IIR4×2→FIR 52b3cd→EXP#2. `track` — новый параметр (ctx+0x540768).
|
||
- **IIR4 = DOUBLE precision** (дизасм `f529fe0_full.dis:1191-1201`:
|
||
`movsd/mulsd/addsd/cvtpd2ps`; down@0x340510, up@0x3c0510, acc@0x440510).
|
||
- `generate_iir4_coefs()` — генератор FUN_180533340 (BLOCKMAP:135-150):
|
||
freq-warp `g = (i<=fc_norm) ? fc_norm/i : pow(fc_norm/i,p)`; live-константы
|
||
`DAT_1824c3d8c=0.9994880557060242`, `DAT_1824c46b8=0.9991304874420166`.
|
||
ВАЖНО: `up[i] = exp(−c·g·tau/mult)` (знак МИНУС, иначе Inf), `down=1−up`.
|
||
Smoke: down0=1, up0=0, down1=0.6292. Gated `RT_IIR4_GEN=1`
|
||
(env: RT_IIR4_C/TAU/P/MULT/SR, дефолты 1000/1200/0.5/360/48000).
|
||
- Интеграция: `framed_model.cpp` `RT_CASC=1` gate; вход — `raw_level`
|
||
(am/res·scale). `process_band_structural` получил `track` параметр.
|
||
- **Результаты**: bridge 1.594 (gated OFF, не тронут); structural 2.689
|
||
(RT_CASC=0); RT_CASC=1 → 31.6 (НЕКАЛИБРОВАНО, ожидаемо).
|
||
- **fn529fe0_check**: добавлены chain smoke + generate_iir4 smoke; PASS.
|
||
Попутно починен тест haar_one_pass boundary (8.0 не 8.5).
|
||
|
||
### 25a2. VLAW per-fc: continuous вместо дискретной решётки (f2cc0ae)
|
||
- `framed_model.cpp:283-298`: 800→1200 q<1 теперь lerp `t=(fc−800)/400`
|
||
(5.0/0.4 → 4.5/0.35) вместо дискретных веток.
|
||
- sens-эффект теперь ADDITIVE offset (12→0, 6→−0.48α, 24→+0.5α) вместо
|
||
перезаписи, стиравшей fc-выбор (баг старой решётки: sens всегда побеждал).
|
||
- Gates не сдвинулись (1.594/2.689) — полный перефит требует campaign.py
|
||
(8 мин/ячейка, `ph*.npz`) — вне scope.
|
||
|
||
### 25a3. k-mapping dedup (197f5ed)
|
||
- `k_mapping_factor(fc,q,sens)` — вынос двух идентичных блоков
|
||
(lvl_in + raw_level) в helper. `k_fc=1.0` + opt-in `RT_KMAP_FC` (W_eq).
|
||
- RT_KMAP=1 не влияет на TOTAL (2.689) — ожидаемо, т.к. калибровка
|
||
α/β уже поглощает k на sens=12.
|
||
|
||
### 25a4. Аудит `/audit-project` — Phases 1+2 применены (e4c5348)
|
||
- Убран dead conditional `if (pool_w > 0 && !lut_off == false) {}`.
|
||
- `DBG_CASC` fprintf в per-frame цикле → gated `RT_DBG_CASC`.
|
||
- Убран дублирующий zero-loop в `spectral.cpp buildFirFromMask`.
|
||
- Комментарии о разнице шкал FFT (1/N canonical vs 2/half plugin).
|
||
- Документирован blend 0.8 (декомп 0x5406f8, xmm10@1824c3e28).
|
||
- `assert(spectrum != nullptr)` в processFrame.
|
||
- НЕ применено (осознанно): thread_local→context (конфликт с golden rule —
|
||
chain нужен reentrant caller), SpectralProcessor new[]→vector, Config
|
||
struct для getenv — оставлено как техдолг.
|
||
|
||
### 25a5. Блокеры (без изменений)
|
||
- ph*.npz нет на этой машине; live-dump не работает (маск-цепь при загрузке,
|
||
BLOCKMAP:285; wine DR EIO). Chain калибровка ждёт capture при INIT.
|
||
- prd.md создан (карта проекта, 293 строки).
|
||
- Structural baseline в README/prd: 2.689 (L/R), исторический 0.341
|
||
недостижим на HEAD после M/S→L/R (e343b0a).
|
||
|
||
### Коммиты сессии
|
||
```
|
||
e343b0a prd.md + render48k L/R baseline
|
||
9ed22d3 chain_9_19: IIR4 double + FIR, haar fix
|
||
2a295af chain integrate RT_CASC gate
|
||
96816f9 chain: IIR4 generator + audio path
|
||
2201a57 docs: baseline 2.689
|
||
f2cc0ae vlaw continuous per-fc + additive sens
|
||
b41d7a4 chain: RT_IIR4_GEN wire + smoke tests
|
||
197f5ed k_mapping_factor dedup
|
||
e4c5348 audit fixes Phases 1+2
|
||
2f854cd spectral vectors + vlaw_check target
|
||
a881ee2 AGENTS.md: vlaw_check in test list
|
||
c85b888 Δ-rule: distance-aware template-local gain (blocked on ph*.npz)
|
||
```
|