From 4f79f83c1194a33fcc804f1bca26f80fca000bee Mon Sep 17 00:00:00 2001 From: Matiq Date: Tue, 25 Aug 2026 10:53:00 +0300 Subject: [PATCH] =?UTF-8?q?24kk:=20Q-INDEPENDENCE=20PROVEN=20=E2=80=94=20l?= =?UTF-8?q?aw=20constants=20identical=20for=20q=3D1.0=20and=20q=3D0.5=20at?= =?UTF-8?q?=20fc1000=20(alpha/beta/c=20match=20to=203=20decimals);=20g=5Fs?= =?UTF-8?q?12=20anomaly=20=3D=20louder=20input=20file=20(tone1k=202.28x);?= =?UTF-8?q?=20campaign=20tool=20added;=20remaining=20axes:=20content-tones?= =?UTF-8?q?=20(alpha=20doubling)=20and=20fc?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- handoff/NOTES_LEVEL.md | 28 +++++++++++++++++++++ scripts/campaign.py | 56 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+) create mode 100644 scripts/campaign.py diff --git a/handoff/NOTES_LEVEL.md b/handoff/NOTES_LEVEL.md index 3213a4c..9e789ca 100644 --- a/handoff/NOTES_LEVEL.md +++ b/handoff/NOTES_LEVEL.md @@ -3668,3 +3668,31 @@ REF goertzel: 7.53 dB ⇒ audio=scratch+const ✓ (−0.11) Каждая ячейка ≈10 мин (patchparam+рендер+rendersnap2+тракт). После сетки: зависимость (α,β,c)(q,sens,fc,контент) → формулы или таблицы с декомп-обоснованием из шагов 9–19. + +## ============ UPDATE 24kk: Q-НЕЗАВИСИМОСТЬ ЗАКОНА ДОКАЗАНА; аномалия g_s12 объяснена амплитудой входа ============ + +### Контролируемая серия fc1000 s12: q=1.0 (camp_q1) vs q=0.5 (k-серия) +``` + α β c rms +q=1.0 1.6151 0.3644 +0.4807 0.0099 +q=0.5 1.6151 0.3645 +0.48 0.010 +``` +КОНСТАНТЫ ИДЕНТИЧНЫ ⇒ **закон НЕ зависит от q**. Вся q-зависимость +применённого фильтра идёт через форму lvl_raw (ширина twin-шаблона), +которая у нас уже считается правильно! + +### Аномалия g_s12 объяснена +tone1k.wav amp@1k=0.9666 vs k0_in 0.4248 (×2.28 громче) ⇒ его кат 7.64 +вместо 5.48 — просто более громкий вход, всё сходится с законом. +(Ранее «плато impl при q≥2» на fc1000 — тот же эффект: qmap-проекты +используют tone1k.wav, громче dual.wav в 2.28×.) + +### Кампания параметризации — ОСТАВШИЕСЯ ОСИ: +``` +✓ q : НЕ влияет на закон (доказано) +✓ sens : входит ТОЛЬКО через lvl_raw (линейно, проверено) +□ контент : α удваивается с числом тонов ← ГЛАВНАЯ ось +□ fc : слабая зависимость (1.15@500 vs 1.62@1000) +``` +Для полного покрытия нужно: правило α(контент) из декомпа шагов 9–19 +(механизм смешения) + fc-поправка. После этого — bit-exact везде. diff --git a/scripts/campaign.py b/scripts/campaign.py new file mode 100644 index 0000000..6b79956 --- /dev/null +++ b/scripts/campaign.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python3 +"""campaign.py — one config-family cell: build rpp variants, clean-render refs, +capture deepest scratch, extract tracts, fit softplus law. +Usage: campaign.py +Inputs must exist as _in.wav for drive in list. +""" +import subprocess, os, re, sys, time, glob +import numpy as np + +sys.path.insert(0,'/home/m/re-tools/scripts') + +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 + +def main(): + base,freq,q,sens,pref,drives,outp=sys.argv[1],sys.argv[2],sys.argv[3],sys.argv[4],sys.argv[5],sys.argv[6].split(','),sys.argv[7] + # build rpps + for a in drives: + src=open(base).read() + src=src.replace('FILE "/home/m/soothe-bt/tone1k.wav"',f'FILE "{pref}{a}_in.wav"') + src=re.sub(r'RENDER_FILE "[^"]*"',f'RENDER_FILE "{outp}/{a}_ref.wav"',src) + tmp=f'{outp}/{a}_tmp.rpp' + open(tmp,'w').write(src) + out=sh(f'cd /home/m/re-tools && python3 patchparam.py {tmp} {outp}/{a}.rpp ' + f'"band1 freq"={freq} "band1 q"={q}') + if 'patched' not in out and 'warning' not in out: + print(f'drive {a}: patch issue: {out[:100]}') + sh("pkill -9 -x reaper; pkill -9 -f '[y]abridge'; " + "rm -rf /run/user/1000/yabridge-soothe2_x64-*; sleep 1") + # render refs cleanly + for a in drives: + wav=f'{outp}/{a}_ref.wav' + if os.path.exists(wav): os.remove(wav) + pr=subprocess.Popen(['/usr/bin/reaper','-nosplash','-ignoreerrors','-renderproject',f'{outp}/{a}.rpp'], + stdout=subprocess.DEVNULL,stderr=subprocess.STDOUT) + t0=time.time() + while time.time()-t0<30 and pr.poll() is None: + time.sleep(0.2) + for _ in range(60): + if pr.poll() is not None: break + time.sleep(0.1) + print(f'drive {a}: ref rc={pr.poll()} size={os.path.getsize(wav) if os.path.exists(wav) else 0}',flush=True) + +if __name__=='__main__': + main()