归档分析脚本到 analysis/reverse_tools(compare_live/verify_nuc/verify_full/parse_ddt/parse_pcap),更新 session_state 引用路径

This commit is contained in:
ZXCLI
2026-08-19 15:55:21 +08:00
parent 0d83c625d1
commit dd52469377
6 changed files with 395 additions and 4 deletions
+53
View File
@@ -0,0 +1,53 @@
import struct, sys
# compare demo3 live capture vs official capture on the same static scene
b = open(r"C:\Project\MAG160C\build-artifacts\demo3_frame_capture.bin", "rb").read()
off = 0
live = struct.unpack_from("<19200H", b, off); off += 38400
ref = struct.unpack_from("<19200H", b, off); off += 38400
nuc = struct.unpack_from("<19200H", b, off); off += 38400
gray = b[off:off+19200]; off += 19200
lut = b[off:off+1024]; off += 1024
meta = struct.unpack_from("<8i", b, off)
print("demo3: win=[%d,%d] stats=(%d..%d m%d s%d) shutter=%d sel=%d" % meta)
print("demo3: live_mean=%.0f ref_mean=%.0f nuc_mean=%.0f" % (sum(live)/19200, sum(ref)/19200, sum(nuc)/19200))
d = r"C:\Project\MAG160C\analysis\pairs_final_20260813"
def load(path, fmt, n):
b = open(path, "rb").read()
return struct.unpack_from("<%d%s" % (n, fmt), b, 0)
win = open(d + r"\pair_000.win", "rb").read()
hi, lo, fmax, fmin, mean, std, axmax, axmin = struct.unpack_from("<8I", win, 0)
gray_o = load(d + r"\pair_000.gray", "B", 320*240)
raw_o = load(d + r"\pair_000.raw", "H", 19200)
lut_o = open(d + r"\pair_000.lut", "rb").read()
print("official: win=[%d,%d] stats=(%d..%d m%d s%d)" % (lo, hi, fmin, fmax, mean, std))
print("official: raw_mean=%.0f" % (sum(raw_o)/19200))
# gray comparison: demo3 gray160 vs official gray320 downsampled (2x parity)
g_o160 = [gray_o[y*320 + x] for y in range(0, 240, 2) for x in range(0, 320, 2)]
import collections
hd = collections.Counter(gray)
ho = collections.Counter(g_o160)
# histogram correlation
allk = set(hd) | set(ho)
n = sum(hd.values())
# compare histograms as distributions
import math
def corr(a, b):
ka = set(a); kb = set(b)
ks = ka | kb
ma = sum(a[k] for k in ks)/n
mb = sum(b[k] for k in ks)/n
num = sum((a.get(k,0)-ma)*(b.get(k,0)-mb) for k in ks)
da = math.sqrt(sum((a.get(k,0)-ma)**2 for k in ks))
db = math.sqrt(sum((b.get(k,0)-mb)**2 for k in ks))
return num/(da*db) if da and db else 0
print("gray histogram correlation: %.4f" % corr(hd, ho))
print("demo3 gray range: %d..%d, official: %d..%d" % (min(gray), max(gray), min(g_o160), max(g_o160)))
# LUT comparison
dl = sum(1 for i in range(1024) if lut[i] != lut_o[i])
print("demo3 lut vs official lut diff: %d/1024" % dl)
print("demo3 lut[0:8]:", list(lut[:8]), " official:", list(lut_o[:8]))
print("demo3 lut[1000:]:", list(lut[1000:]), " official:", list(lut_o[1000:]))
+85
View File
@@ -0,0 +1,85 @@
import struct, sys, os
path = r"C:\Project\MAG160C\analysis\ida\Core160043865.ddt"
b = open(path, "rb").read()
print(f"size: {len(b)}")
def u32(o): return struct.unpack_from("<I", b, o)[0]
def i32(o): return struct.unpack_from("<i", b, o)[0]
def u16(o): return struct.unpack_from("<H", b, o)[0]
def i16(o): return struct.unpack_from("<h", b, o)[0]
magic = u32(0)
w, h = u32(4), u32(8)
count = u32(12) # 0x41558 endpoint count
nsegs = u32(16) # 0x41554 segments
loc238 = u32(20) # v3: shift-related
loc230 = u32(24) # v3
c5c = u32(28) # 0x4155c
c60 = u32(32) # 0x41560
print(f"magic={magic:#x} w={w} h={h} endpoints={count} nsegs={nsegs} loc238={loc238} loc230={loc230:#x}({i32(24)}) 0x4155c={c5c} 0x41560={c60}")
o = 36
T = [u32(o + i*4) for i in range(count)]
print("T (0x41564):", T)
o += count*4
B = [u32(o + i*4) for i in range(count)]
print("B (0x415b4):", B)
o += count*4
C = [u32(o + i*4) for i in range(count)]
print("C (0x41604):", C)
o += count*4
D = [u32(o + i*4) for i in range(count-1)]
print("D (0x41654):", D)
o += (count-1)*4
print(f"table blocks start: 0x{o:x}")
npix = w * h
u26 = c60 + (3*nsegs - 1)*npix*2 + c5c
print(f"per-endpoint block: {u26} bytes")
blind_total = sum(d*40 for d in D)
trailer = count*0x10 + 0x24
total = count*u26 + blind_total + (count-1)*4 + 36 + 4*4 + trailer
print(f"blind_total={blind_total} trailer={trailer} computed_total={total} file={len(b)}")
# dump endpoint table structure: per endpoint:
# thr rows: (nsegs-1)*npix u16 (2 rows x 19200)
# gain/off rows: nsegs*npix*2 u16 (6 rows x 19200) [seg][pix] gain/off pairs
ep = o
for e in range(count):
thr_off = ep
g_off = thr_off + (nsegs-1)*npix*2 + (c5c>>1)*2 if False else thr_off + (nsegs-1)*npix*2 + (c5c//2)*2
print(f"EP{e}: thr@{thr_off:#x} gain@{g_off:#x} T={T[e]}")
t0 = i16(thr_off), i16(thr_off+2), i16(thr_off+4), i16(thr_off+19200*2)
g0 = u16(g_off), u16(g_off+2), u16(g_off+4), u16(g_off+19200*2), u16(g_off+2*19200*2)
print(f" thr[0..3]={t0} thr[1st pix row start]={t0[3]}")
print(f" gain seg0[0..3]={g0[0:4]} gain seg1[0]={g0[4]}")
ep += u26
# blind records: after all endpoint blocks
blind_off = ep
print(f"blind records at 0x{blind_off:x}, total {blind_total} bytes")
for e in range(count-1):
n = D[e]
print(f"EP{e} blind count={n}")
for i in range(min(n, 8)):
r = blind_off + e*0 + i*40
target, typ = u32(r), u32(r+4)
neigh = [u32(r + 8 + j*4) for j in range(8)]
print(f" rec[{i}]: target={target} type={typ} neigh={neigh[:typ-2 if typ>=3 else 8]}")
blind_off += n*40
# check: what's after blind records (trailer)
print(f"trailer at 0x{blind_off:x}:")
for i in range(8):
print(f" +{i*4}: {u32(blind_off+i*4):#010x}")
# compare with the captured working tables
gain = open(r"C:\Project\MAG160C\build-artifacts\mag160c_official_nuc_gain.bin", "rb").read()
thr = open(r"C:\Project\MAG160C\build-artifacts\mag160c_official_nuc_thr.bin", "rb").read()
print(f"\ncaptured working tables: gain={len(gain)} thr={len(thr)}")
print(f"thr[0:4]={[i16(i*2) for i in range(4)]} (from thr.bin)")
print(f"gain[0:4]={[u16(i*2) for i in range(4)]}")
print(f"gain[19200*2:19200*2+4]={[u16(19200*2+i*2) for i in range(4)]} (seg1)")
# find which endpoint the working table corresponds to: interpolate check later in C
+31
View File
@@ -0,0 +1,31 @@
import struct, sys
# parse usbpcap file, extract bulk transfer payloads on EP 0x81,
# find 0x1bb1b11b markers and dump tail words
path = r"C:\Project\MAG160C\analysis\captures\official_hand.pcap"
data = open(path, "rb").read()
magic = data[:4]
print("pcap magic:", magic.hex())
# USBPcap: linktype 249? global header 24 bytes: magic, vMaj, vMin, tz, sigfigs, snaplen, linktype
lt = struct.unpack_from("<I", data, 20)[0]
print("linktype:", lt)
# find all occurrences of the frame marker
idx = 0
count = 0
frames = []
while True:
i = data.find(b"\x1b\xb1\xb1\x1b", idx)
if i < 0: break
idx = i + 4
count += 1
if count <= 3 or count % 50 == 0:
if i + 0x9640 < len(data):
# header
hdr = struct.unpack_from("<8I", data, i)
# tail words
tail = struct.unpack_from("<8I", data, i + 0x1c + hdr[2])
frames.append((i, hdr, tail))
print(f"frame@{i:#x} hdr={[hex(x) for x in hdr[:5]]} tail[0:8]={[hex(x) for x in tail]}")
if count > 120: break
print("total markers scanned:", count)
+126
View File
@@ -0,0 +1,126 @@
import struct
d = r"C:\Project\MAG160C\analysis\pairs_verify_20260813"
npix = 19200
def load(path, fmt, n):
b = open(path, "rb").read()
return struct.unpack_from("<%d%s" % (n, fmt), b, 0)
# 1) verify interpolation: thrw vs interp(thr0, thr1, t)
thr0 = load(d + r"\pair_000.thr0", "h", 19200*2 + 512) # (nsegs-1)*npix + 1024/2
thr1 = load(d + r"\pair_000.thr1", "h", 19200*2 + 512)
thrw = load(d + r"\pair_000.thrw", "h", 19200*2)
T = [8304, 18390, 28495, 33637, 38730, 47664]
dev54 = 29289
sel = 2
t = ((dev54 - T[sel]) << 12) // (T[sel+1] - T[sel])
print("t =", t)
diff = 0
for i in range(19200*2):
a = thr0[i]
b = thr1[i]
w = thrw[i]
calc = a + ((b - a) * t >> 12)
# clamp to int16 (out-of-range branch)
if calc > 32767: calc = 32767
if calc < -32768: calc = -32768
calc16 = struct.unpack("<h", struct.pack("<H", calc & 0xFFFF))[0]
if calc16 != w:
diff += 1
if diff <= 5:
print(f" thr mismatch i={i} a={a} b={b} calc={calc16} w={w}")
print(f"thr interp: diff={diff}/38400")
g0 = load(d + r"\pair_000.g0", "H", 19200*3*2)
g1 = load(d + r"\pair_000.g1", "H", 19200*3*2)
gw = load(d + r"\pair_000.gw", "H", 19200*3*2)
diff = 0
for i in range(19200*3*2):
a = g0[i]; b = g1[i]; w = gw[i]
calc = a + ((b - a) * t >> 12)
if calc > 65535: calc = 65535
if calc < 0: calc = 0
if calc != w:
diff += 1
if diff <= 5:
print(f" gain mismatch i={i} a={a} b={b} calc={calc} w={w}")
print(f"gain interp: diff={diff}/115200")
# 2) NUC verify with working tables + blind
f20 = load(d + r"\pair_000.f20", "H", npix)
ref = load(d + r"\pair_000.ref", "H", npix)
raw = load(d + r"\pair_000.raw", "H", npix)
blind = open(d + r"\pair_000.blind", "rb").read()
recs = []
for i in range(len(blind)//40):
target, typ = struct.unpack_from("<II", blind, i*40)
neigh = struct.unpack_from("<8I", blind, i*40+8)
recs.append((target, typ, neigh))
nuc = [0]*npix
for i in range(npix):
d2 = (int(f20[i]) - int(ref[i])) >> 1
seg = 0
if d2 > thrw[i*2]: seg = 1
if seg == 1 and d2 > thrw[i*2+1]: seg = 2
p = (seg*npix + i)*2
v = gw[p+1] + ((gw[p] * d2) >> 12)
if v < 0: v = 0
if v > 65535: v = 65535
nuc[i] = v
out = list(nuc)
for (tgt, typ, ng) in recs:
if typ == 8:
out[tgt] = sum(out[ng[j]] for j in range(8)) >> 3
elif typ == 7:
out[tgt] = sum(out[ng[j]] for j in range(7)) // 7
elif typ == 6:
out[tgt] = sum(out[ng[j]] for j in range(6)) // 6
elif typ == 5:
out[tgt] = sum(out[ng[j]] for j in range(5)) // 5
elif typ == 4:
out[tgt] = sum(out[ng[j]] for j in range(4)) >> 2
elif typ == 3:
out[tgt] = sum(out[ng[j]] for j in range(3)) // 3
diff = sum(1 for i in range(npix) if out[i] != raw[i])
sad = sum(abs(out[i]-raw[i]) for i in range(npix))
print(f"NUC+blind vs official raw: diff={diff}/19200 MAE={sad/npix:.4f}")
# 3) window + gray: LUT1024 + idx
win = open(d + r"\pair_000.win", "rb").read()
hi, lo, fmax, fmin, mean, std, axmax, axmin = struct.unpack_from("<8I", win, 0)
print(f"win: hi={hi} lo={lo} fmax={fmax} fmin={fmin} mean={mean} std={std}")
lut = open(d + r"\pair_000.lut", "rb").read()
S = 0xFFC00000 // (hi - lo)
gray = []
for i in range(npix):
v = out[i]
if v <= lo: idx = 0
elif v >= hi: idx = 1023
else: idx = (v - lo) * S >> 22
if idx > 1023: idx = 1023
gray.append(lut[idx])
# compare with official gray (320x240) - downsample center? official gray is 2x
g320 = load(d + r"\pair_000.gray", "B", 320*240)
# check the 2x relation: gray320[2y][2x] should equal gray160[y][x] (or the interp)
match = 0
tot = 0
for y in range(0, 120):
for x in range(0, 160):
g2 = g320[y*2*320 + x*2]
if g2 == gray[y*160 + x]: match += 1
tot += 1
print(f"gray 2x top-left parity: {match}/{tot}")
# what mapping? try LUT1024 idx directly vs gray320[0..] offset scan
best = None
for dy in range(4):
for dx in range(4):
m = 0
for y in range(0, 120):
for x in range(0, 160):
yy = y*2+dy; xx = x*2+dx
if yy < 240 and xx < 320:
if g320[yy*320+xx] == gray[y*160+x]: m += 1
if best is None or m > best[0]:
best = (m, dy, dx)
print("best offset:", best)
+94
View File
@@ -0,0 +1,94 @@
import struct, os
d = r"C:\Project\MAG160C\analysis\pairs_recheck_20260811"
npix = 19200
nsegs = 3
def load16(name, n):
b = open(os.path.join(d, name), "rb").read()
return struct.unpack_from("<%dH" % n, b, 0)
def loadi16(name, n):
b = open(os.path.join(d, name), "rb").read()
return struct.unpack_from("<%dh" % n, b, 0)
f20 = load16("pair_000.f20", npix)
ref = load16("pair_000.ref", npix)
raw = load16("pair_000.raw", npix)
# working tables (from build-artifacts, verified = interp of EP2/EP3)
gain = load16(r"C:\Project\MAG160C\build-artifacts\mag160c_official_nuc_gain.bin", npix*nsegs*2)
thr = loadi16(r"C:\Project\MAG160C\build-artifacts\mag160c_official_nuc_thr.bin", npix*(nsegs-1))
# blind records from DDT (all endpoints identical; use EP2)
ddt = open(r"C:\Project\MAG160C\analysis\ida\Core160043865.ddt", "rb").read()
thr_ep0 = 0x80
block = (nsegs-1)*npix*2 + 1024 + nsegs*npix*4
blind_off = thr_ep0 + 6*block
recs = []
for i in range(32):
r = blind_off + i*40
target, typ = struct.unpack_from("<II", ddt, r)
neigh = struct.unpack_from("<8I", ddt, r+8)
recs.append((target, typ, neigh))
print("blind recs:", len(recs), "first:", recs[0])
def blind_apply(buf, recs):
out = list(buf)
for (t, typ, ng) in recs:
if typ == 3:
v = out[ng[0]] + out[ng[1]] + out[ng[2]]
out[t] = v // 3
elif typ == 4:
v = out[ng[0]] + out[ng[1]] + out[ng[2]] + out[ng[3]]
out[t] = v >> 2
elif typ == 5:
v = out[ng[0]] + out[ng[1]] + out[ng[2]] + out[ng[3]] + out[ng[4]]
out[t] = v // 5
elif typ == 6:
v = sum(out[ng[j]] for j in range(6))
out[t] = v // 6
elif typ == 7:
v = sum(out[ng[j]] for j in range(7))
out[t] = v // 7
elif typ == 8:
v = sum(out[ng[j]] for j in range(8))
out[t] = v >> 3
return out
# NUC with exact official math
nuc = [0]*npix
for i in range(npix):
d2 = (int(f20[i]) - int(ref[i])) >> 1
seg = 0
if d2 > thr[i*2]:
seg = 1
if d2 > thr[i*2+1]:
seg = 2
p = (seg*npix + i)*2
v = (gain[p] * d2) >> 12 + gain[p+1] # CAREFUL: precedence! official: off + ((gain*d2)>>12)
v = gain[p+1] + ((gain[p] * d2) >> 12)
if v < 0: v = 0
if v > 65535: v = 65535
nuc[i] = v
# stats before blind
diff = sum(1 for i in range(npix) if nuc[i] != raw[i])
sad = sum(abs(nuc[i]-raw[i]) for i in range(npix))
print(f"NUC only: diff={diff}/{npix} MAE={sad/npix:.4f}")
# apply blind comp
out = blind_apply(nuc, recs)
diff2 = sum(1 for i in range(npix) if out[i] != raw[i])
sad2 = sum(abs(out[i]-raw[i]) for i in range(npix))
print(f"NUC+blind: diff={diff2}/{npix} MAE={sad2/npix:.4f}")
# list mismatch pixels
mism = [(i, nuc[i], out[i], raw[i]) for i in range(npix) if out[i] != raw[i]]
print("mismatches:", len(mism))
for m in mism[:15]:
print(" pix", m)
# blind target pixels check
for (t, typ, ng) in recs:
print(f" rec target={t} type={typ} neigh={list(ng[:typ-2])}")
+6 -4
View File
@@ -67,10 +67,12 @@ Stop-Process -Name mag160c_demo3 -Force -ErrorAction SilentlyContinue
# 注意:tsdk_pair3 的 config.txt / pair_*.meta / pair_*.win 写在进程 CWD
# 跑完要把 C:\Project\MAG160C 下的 config.txt 和 pair_0*.meta/win 移回目录。
# 对比/复算脚本(Python
# C:\Users\ZXC\AppData\Local\Temp\opencode\compare_live.py demo3捕获 vs 官方同场景
# C:\Users\ZXC\AppData\Local\Temp\opencode\verify_nuc.py 官方抓帧重建验证
# C:\Users\ZXC\AppData\Local\Temp\opencode\verify_full.py 全链路验证
# 对比/复算脚本(Python,已归档到 analysis/reverse_tools/
# analysis/reverse_tools/compare_live.py demo3捕获 vs 官方同场景
# analysis/reverse_tools/verify_nuc.py 官方抓帧重建验证
# analysis/reverse_tools/verify_full.py 全链路验证
# analysis/reverse_tools/parse_ddt.py DDT 文件解析
# analysis/reverse_tools/parse_pcap.py pcap 抓包解析
# C:\Users\ZXC\AppData\Local\Temp\opencode\verify_c_pipeline.exe C实现离线复算
```