24nn: SESSION FINALE — per-peak softplus laws ultra-clean (pk2 rms 0.0006!), shared alpha~3.3, beta2 10x smaller than beta1, level-scale x11.6 const; CROSS-RUN absolute comparisons UNRELIABLE (state selection) — within-run series only; campaign tools complete

This commit is contained in:
2026-08-25 12:32:23 +03:00
parent f365fa8451
commit def7cea522
2 changed files with 90 additions and 0 deletions
+29
View File
@@ -3774,3 +3774,32 @@ bigkernel'ов из рантайм-адресов (24jj).
формулы применения с калибровкой rms 0.016; все инструменты/датасеты формулы применения с калибровкой rms 0.016; все инструменты/датасеты
сохранены. Полное кросс-конфиг замыкание = транскрипция каскада по сохранены. Полное кросс-конфиг замыкание = транскрипция каскада по
dataflow (связная задача следующей сессии, блокеров нет). dataflow (связная задача следующей сессии, блокеров нет).
## ============ ФИНАЛ СЕССИИ 24ll/24mm/24nn: пер-пиковые законы; кросс-ран сравнения ненадёжны ============
### Двухтоновая серия (tt, один прогон — оба пика согласованно):
```
PK1 (центр полосы): cut = 3.282·ln1p(lvl/0.5593)+0.768 rms 0.0037
PK2 (тон@2000): cut = 3.355·ln1p(lvl/0.0570)+1.091 rms 0.0006 (!!)
```
Общий α≈3.3; β₂ в 10 раз меньше β₁ (второй пик чувствительнее);
m-тест: pk2-закон = pk1-закон(уровень×11.6±0.1) — константный масштаб.
### Кросс-РАН сравнения абсолютных катов НЕНАДЁЖНЫ
Глубокое/мелкое состояние буфера выбирается по-разному между запусками
(d1500 дал 6.62 @pk2, tt-семейство 11.46 при том же контенте!) ⇒
валидны только ВНУТРИ-прогонные серии (один запуск = одно состояние).
Это объясняет все прошлые «немонотонности» и противоречия между сериями.
### Параметризация сведена к:
```
α ≈ 3.3 (общий наклон)
β_peak, c_peak — зависят от ПОЗИЦИИ пика относительно полосы
(шаблонная геометрия; источник — декомп шагов 9–19/LUT)
Δ-правило — из pre-combine
```
### ИНСТРУМЕНТЫ КАМПАНИИ ГОТОВЫ
campaign.py (ячейка семейства); tt_series.py (рецепт двухтоновой серии);
все датасеты sc_*/tract_*/*pkl сохранены. Следующая сессия: декод шагов
919 до конца (dataflow готов) + захват A/B/γ объектов банд → замыкание.
+61
View File
@@ -0,0 +1,61 @@
#!/usr/bin/env python3
"""two-tone drive series at fc500/q0.5/s12: renders+captures+fit."""
import subprocess, os, sys, time, glob
import numpy as np, wave
def sh(cmd): return subprocess.run(cmd,shell=True,capture_output=True,text=True).stdout
def find_host():
import glob as g
for p in g.glob('/proc/[0-9]*'):
pid=int(os.path.basename(p))
try:
cmd=open('/proc/%d/cmdline'%pid,'rb').read().replace(b'\0',b' ').decode('utf8','replace')
maps=open('/proc/%d/maps'%pid).read()
except Exception: continue
if 'soothe2' in maps and 'reaper' not in cmd: return pid
return None
# inputs: dual content (500+2000 equal) at drives 0/-6/-12/-18 with probes
sr=44100; T=4.0; n=int(sr*T); t=np.arange(n)/sr
ph=np.random.default_rng(41).uniform(0,2*np.pi,7)
drives=(0,6,12,18)
for att in drives:
A=0.4248*10**(-att/20)
y=A*np.sin(2*np.pi*500*t+ph[0])+A*np.sin(2*np.pi*2000*t+ph[1])
for i,f in enumerate((300.,700.,1400.,2800.,5000.)):
y+=A*10**(-30/20)*np.sin(2*np.pi*f*t+ph[i+2])
y=np.clip(y,-0.999,0.999)
nm='tt%d'%att
w=wave.open('/tmp/opencode/%s_in.wav'%nm,'wb'); w.setnchannels(1); w.setsampwidth(2); w.setframerate(sr)
w.writeframes((y*32767).astype(np.int16).tobytes()); w.close()
src=open('/tmp/opencode/multi.rpp').read()
import re
src=re.sub(r'RENDER_FILE "[^"]*"','RENDER_FILE "/tmp/opencode/%s_ref.wav"'%nm,src)
src=src.replace('FILE "/tmp/opencode/multi_in.wav"','FILE "/tmp/opencode/%s_in.wav"'%nm)
open('/tmp/opencode/%s.rpp'%nm,'w').write(src)
print('inputs+rpps ready')
sh("pkill -9 -x reaper; pkill -9 -f '[y]abridge'; rm -rf /run/user/1000/yabridge-soothe2_x64-*; sleep 1")
for att in drives:
wav='/tmp/opencode/tt%d_ref.wav'%att
if os.path.exists(wav): os.remove(wav)
pr=subprocess.Popen(['/usr/bin/reaper','-nosplash','-ignoreerrors','-renderproject','/tmp/opencode/tt%d.rpp'%att],
stdout=subprocess.DEVNULL,stderr=subprocess.STDOUT)
t0=time.time(); host=None
while time.time()-t0<30 and not host: host=find_host(); time.sleep(0.002)
for _ in range(240):
if pr.poll() is not None: break
time.sleep(0.1)
print('tt%d ref rc=%s'%(att,pr.poll()),flush=True)
# captures + tracts
for att in drives:
od='/tmp/opencode/sc_tt%d'%att
sh('rm -rf %s'%od)
sh('cd /home/m/re-tools && timeout 60 python3 scripts/rendersnap2.py /tmp/opencode/tt%d.rpp 400 %s'%(att,od))
tf='/tmp/opencode/tract_tt%d.txt'%att
if os.path.exists(tf): os.remove(tf)
env=dict(os.environ); env['RT_DUMP_BIN']=tf
subprocess.run(['/home/m/re-tools/dsp/build/render48k','/tmp/opencode/tt%d_in.wav'%att,
'/tmp/o48_tt.wav','500,0.5,12'],capture_output=True,env=env)
print('captures+tracts done')