Session 2 reversed several of its own conclusions. The docs are append-only, so a reader could land on a superseded section and act on it. This pass makes the repo internally consistent. Defects found and fixed in STATUS.md: - claimed "Hybrid VQ with k=1024: no" as the answer to the linework question, directly contradicting FINDINGS 14, which rejected k=1024. Both profiles are k=256. - malformed profile table (six column separators, five columns). - next-steps list had two items numbered 3 and listed the full-disc survey twice. - the disk-benchmark section still read CRITICAL-PATH with "if SCSI sustains >=800 KB/s, ship pixel-exact". That was written while the bandwidth figure was misread as 4 MB/s. At 4 Mbps pixel-exact needs 92-97% of the pipe and is not available, and the ring-buffer result means the design no longer hangs on the benchmark at all. Rewritten with what it IS still worth doing: confirming the 4 Mbps provenance, and confirming DMA is used rather than PIO. FINDINGS now carries supersession blockquotes on 5, 8, 11, 17 and 18 pointing at the sections that correct them. 18 is the dangerous one -- its peak-vs- sustained test is reversed by 21 -- so it is marked DO NOT ACT ON THIS SECTION while noting the per-frame data itself remains valid. profile_gen.py had the same problem in code: it defaulted to the superseded peak sizing and returned lam=25 where the docs say lam=10. The buffered test is now the default and peak sizing is behind --size-for-peak as a bound only. A tool that contradicts the findings is worse than no tool. Also preserves the five measurement scripts that produced this session's numbers as tools/analysis/05-09, following the session 1 precedent, and adds an "explicitly abandoned -- do not re-propose" list to STATUS covering entropy coding, k=1024 codebooks and flat 4x4 VQ. Claude-Session: https://claude.ai/code/session_01194oWYW8DQXK1SZ2DnChW6
64 lines
2.6 KiB
Python
64 lines
2.6 KiB
Python
"""What does LOSSLESS (palettised-quality) delta coding actually cost at 12fps?
|
|
|
|
Session 1 measured only a hand-rolled row-span+RLE (3.2:1). The 68000 has ~12x
|
|
CPU headroom, so a real LZ decoder is affordable -- byte copies are what the
|
|
68000 is good at. This measures the achievable floor at zero extra quality loss.
|
|
"""
|
|
import sys, zlib, lzma; sys.path.insert(0,'tools/encoder')
|
|
import vq, numpy as np
|
|
S=sys.argv[1]
|
|
RAW=256*192
|
|
|
|
def rle_delta(a,b,gap=4):
|
|
"""session 1's row-span + RLE, reimplemented for comparison"""
|
|
t=0
|
|
for y in range(a.shape[0]):
|
|
d=np.nonzero(a[y]!=b[y])[0]
|
|
if not len(d): continue
|
|
sp=[];s=d[0];p=d[0]
|
|
for x in d[1:]:
|
|
if x-p>gap: sp.append((s,p)); s=x
|
|
p=x
|
|
sp.append((s,p)); t+=2
|
|
for s0,e0 in sp:
|
|
seg=b[y][s0:e0+1]; t+=2; i=0
|
|
while i<len(seg):
|
|
r=1
|
|
while i+r<len(seg) and seg[i+r]==seg[i] and r<127: r+=1
|
|
t += 2 if r>=3 else r; i+=r
|
|
return t
|
|
|
|
print(f'{"scene":8}{"frames":>7}{"raw KB/s":>9}{"rle":>8}{"xor+zl":>8}{"delta+zl":>9}{"lzma":>8}',flush=True)
|
|
tot={}
|
|
for s in ['00010','00020','00146','00181']:
|
|
rgb=vq.load_frames(f'{S}/fr_{s}')
|
|
ref,pal=vq.scene_palette(rgb)
|
|
idx=vq.palettise(rgb,ref)
|
|
n=len(idx)-1
|
|
r_rle=sum(rle_delta(idx[i-1],idx[i]) for i in range(1,len(idx)))/n
|
|
# XOR against previous frame then deflate -- unchanged pixels become 0 runs
|
|
r_xor=sum(len(zlib.compress((idx[i]^idx[i-1]).tobytes(),9)) for i in range(1,len(idx)))/n
|
|
# RLE-of-changed-spans payload, then deflate on top
|
|
def spans(a,b,gap=8):
|
|
out=bytearray()
|
|
for y in range(a.shape[0]):
|
|
d=np.nonzero(a[y]!=b[y])[0]
|
|
if not len(d): continue
|
|
sp=[];st=d[0];p=d[0]
|
|
for x in d[1:]:
|
|
if x-p>gap: sp.append((st,p)); st=x
|
|
p=x
|
|
sp.append((st,p))
|
|
for s0,e0 in sp:
|
|
out += bytes([y,s0,e0-s0]) + b[y][s0:e0+1].tobytes()
|
|
return bytes(out)
|
|
r_dz=sum(len(zlib.compress(spans(idx[i-1],idx[i]),9)) for i in range(1,len(idx)))/n
|
|
r_lz=sum(len(lzma.compress(spans(idx[i-1],idx[i]),preset=9))for i in range(1,len(idx)))/n
|
|
f=12/1024.0
|
|
print(f'{s:8}{len(idx):7}{RAW*f:9.0f}{r_rle*f:8.0f}{r_xor*f:8.0f}{r_dz*f:9.0f}{r_lz*f:8.0f}',flush=True)
|
|
for k,v in [('rle',r_rle),('xor',r_xor),('dz',r_dz),('lz',r_lz)]: tot.setdefault(k,[]).append(v)
|
|
print()
|
|
for k,v in tot.items():
|
|
m=np.mean(v)
|
|
print(f'{k:8} mean {m:7.0f} B/frame {m*12/1024:6.0f} KB/s {m*12*22*60/1048576:5.0f} MB/22min ratio {RAW/m:.1f}:1')
|