Files
MAG160C/analysis/handoff_20260812.md
T

6.6 KiB
Raw Blame History

MAG160C 逆向交接文档 v3(2026-08-12)

本文件是最新、最完整上下文快照。 上一版:handoff_20260811.md。 本轮(2026-08-11 晚)完成官方"读取→显示"完整管线逆向,全部实机 像素级验证(100.0% 精确),并交付 demo3(官方管线版)

1. 本轮成果(概览)

  1. 同帧配对 harness(tsdk_pair2.exe):同一帧抓官方 gray + RGB24 + raw counts + palette + per-pixel 温度(m°C)+ 窗口/LUT 字段。
  2. 完整显示管线逆向完毕(Windows CoreSDKLib.dll + 实机验证):
    USB counts → NUC: nuc[i] = clamp((counts[i]-ref[i])*3 + comp, 0, 65535)
    → 统计: mean/min/max(每帧)
    → 窗口: lo = min(max, mean-312), hi = max(min, mean+312)  (X=624)
    → 灰度: idx = (nuc[i]-lo) * (0xFFC00000/(hi-lo)) >> 22   (u32 截断!)
             gray = LUT1024[dev+0x4284c][idx]  (非线性对比度曲线)
    → 颜色: palette[dev+0xb18][gray]  (256×4 BGR,含 alpha=0)
    → 2x bilinear 放大 → 320x240 输出
    
  3. 像素级验证:raw→gray 重建 = 100.0% 精确(与官方同帧 gray 逐像素一致,mean|diff|=0.000);palette 渲染 vs 官方 RGB24 = 100.0% 精确
  4. 温度公式:temp_mC = T2E[3*raw - C],C≈5797(5784-5812 会话 漂移)。12 帧验证 mean|err| = 1.3 mC。
  5. demo3(mag160c_demo3.c,已编译运行):完整官方管线 + 修正了 像素偏移 bug(旧代码 +28 是错的,正确从 data[0] 开始,探针 验证:read1=28B 头,read2=38400 像素+28B 尾)。
  6. 鬼影结论:官方 NUC 参考帧只在 FFC 时更新(冻结),无时域滤波 → 无鬼影。demo3 沿用此机制(FFC 后重采集参考帧)。

2. 官方显示管线(权威,全部实机验证)

2.1 关键内存布局(Windows CoreSDKLib.dll 运行时对象 dev)

偏移 内容 说明
dev+0x220 灰度缓冲指针 8-bit,显示尺寸(此处 320x240)
dev+0x270 NUC 后帧指针 u16,160x120,NUC 输出
dev+0x2a0 (另一缓冲,MapTemperature 输出目标之一)
dev+0xaf0 显示结构 +4 w,+8 h(此处 320x240)
dev+0xb18 调色板 256×4 BGRα,与渲染 100% 一致
dev+0xf18 色彩条 128 级灰度渐变 RGBA
dev+0x42010 帧 min u32(0x1800108a0 统计输出)
dev+0x42014 帧 max u32
dev+0x42018 帧 mean u32
dev+0x4201c 帧 std u32
dev+0x4202c 窗口 hi u32(实测 ~10088-10116)
dev+0x42030 窗口 lo u32(实测 ~9464-9492)
dev+0x4204c 直方图 256×u32(灰度 idx>>2)
dev+0x4284c LUT1024 1024 字节,非线性对比度曲线
dev+0x41ef0 NUC 参考帧指针 dev+0x41f0c=是否有参考帧
dev+0x47938 像素数 19200
dev+0x47948/0x4794c comp 参数 comp=(0xc350-offset)>>shift
[0x18006ea60] NUC 增益(全局) 会话自适应,实测=3,饱和时 -1

2.2 帧处理流程(0x180017040 = NUC+增益)

nuc[i] = clamp((frame[i] - ref[i]) * gain + comp, 0, 0xffff)
frame = USB 原始帧(参数),ref = dev+0x41ef0 参考帧,
gain  = [0x18006ea60](饱和像素 >0x100 时减 1),
comp  = (0xc350 - dev+0x47948) >> dev+0x4794c (clamp>=0)
输出写 dev+0x270 指向的缓冲

之后 0x180017200 做 3x3 加权滤波(系数 1/3,1/6,1/7 等,写回 dev+0x270)。

2.3 灰度生成(0x180010e85 = Windows MapTemperature)

S = 0xFFC00000 / (hi - lo)            ; u32 除法
idx = (nuc[i] - lo) * S >> 22         ; u32 截断乘法!
gray[i] = LUT1024[dev+0x4284c + idx]
直方图[dev+0x4204c + (idx>>2)]++

2.4 窗口自适应(0x1800109c0/0x180010b0d)

统计(0x1800108a0):min→0x42010, max→0x42014, mean→0x42018, std→0x4201c
half = X/2, X 来自积分时间×增益(0x1800108a0 内部,会话恒定,实测 624)
lo = min(max, mean - 312);  hi = max(min, mean + 312)
clamp lo>=0, hi<=0xffff

实测窗口中心 == 帧 mean(9804.8→9804 ✓),X=624 恒定。

2.5 温度(实测公式)

temp_mC = T2E[3*raw - C], C≈5797(5784-5812 逐帧漂移)
T2E:646 项 int32 表(analysis/official_t2e_table.txt,已转 C 头)
slope = (0x1000000 + span/2) / span;  temp = slope*diff>>12 + (i<<12) - 0x249f0
验证:12 帧 × 19200 像素 mean|err| = 1.3 mC

3. 已导出资源(csdk/src/)

  • mag160c_official_palette256.h:256×4 BGR(dev+0xb18,12 帧一致)
  • mag160c_official_lut1024.h:1024 字节(dev+0x4284c,非线性曲线)
  • mag160c_official_t2e.h:646 项(已有)
  • 验证脚本:analysis/temp/(Python)与本次新增:
    • tsdk_pair2.c(harness)→ build-artifacts/tsdk_pair2.exe
    • mag160c_demo3.cbuild-artifacts/mag160c_demo3.exe
    • 配对数据:analysis/pairs2/(12 帧 × gray/rgb/raw/pal/t32), analysis/pairs_win/(窗口/LUT/直方图字段), analysis/pairs_ffc/(FFC 前后)

4. 帧解码修正(重要 bug)

像素从第二次 bulk read 的 data[0] 开始(探针 mag160c_layout_probe2 实测:read1 恰 28B 头,read2 = 38400 像素 + 28B 尾,尾魔数 0x1bb1b11c @ offset 38400)。

  • mag160c_demo2.cdecode_live(+28)是错的 → demo3 已改为 +0。
  • mag160c_frame_dump.cfwrite(frame+28) 也是错的(错位 14 u16), 统计均值看似正常是因为行 mura 平滑,但像素错位。
  • 注意:这与官方 SDK 内部不同(官方 buf+0x1c 起拷像素,因为官方 的帧缓冲含 28B 头)。

5. 温度/窗口剩余问题(未完全确定)

  1. LUT 高端/低端形态:场景只有 26-28°C,只覆盖 LUT 部分 idx。 LUT 已直接从内存取全 1024 项,无需外推 ✓(这个已经解决了)。
  2. X=624 的来源:会话恒定,但可能随积分时间/增益模式变化。 已从 dev+0x4202c/0x42030 实测;demo3 硬编码 312 half。
  3. comp 绝对校准:官方 comp=(0xc350-offset)>>shift 自适应; demo3 简化为 ref 捕获时 comp=9804(官方 NUC 中心水平)。
  4. ref 捕获时机:官方在 FFC 后捕获;demo3 沿用"FFC(1)后 30 帧 中值"方案(已验证 mura std 3560→29)。

6. 下一步建议

  1. 实机对比 demo3 画面与官方 app(用户操作,目视确认)。
  2. 若需要长期稳定性:把 comp 校准改为跟随窗口中心 (mean±312 自动居中,comp 只影响绝对温度显示,画面自适应)。
  3. Linux 移植:管线纯 C 已在 csdk/src(display/t2e/palette/lut), 把 demo3 的 render 逻辑移植到 mag160c_display.c 官方版 API。
  4. 热源实验(可选):宽温度范围数据可验证 LUT 外推与窗口 clamp 行为(idx 溢出回绕)。

7. 环境与工具

  • 设备检测:Get-PnpDevice | ? InstanceId -match 833C
  • 官方 harness:build-artifacts\tsdk_pair2.exe <dir> <npairs> <delay_ms> (可选第 4-6 参数 SetTempBoundary)
  • 官方 SDK:IR_Camera_SDK-1.0.1\windows\windows\app\(ThermalSDK/ CoreSDKLib/CameraSDK + libusb0.dll)
  • 反汇编:objdump -d -Mintel;RVA 表见各 disasm_*.txt
  • Python 3.10 + numpy/scipy/PIL