Files
MAG160C/analysis/history/handoff_20260810.md
T

417 lines
21 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# MAG160C 项目交接文档 (2026-08-10)
> **2026-08-10 晚更新(本会话)**:FFC 停帧问题已解决并多次实机验证;
> 坏点/对比度/标定管线已按开源方案重做并合入 csdk。详见第 10 节。
## 1. 项目目标
对 Elo/Magnity MAG160C USB 热成像相机进行完整逆向,实现一个独立、可用的
Linux/Windows C SDK + Windows GUI Demo。已完成的逆向依据:
- `analysis/protocol_spec.md`(协议全谱)
- `analysis/findings.md`(证据链)
- `analysis/captures/libusb0_trace.txt`(官方 demo 完整 USB 流量,26092 行)
- `analysis/captures/official_hand.pcap`(官方 demo 手掌遮挡抓包)
- `analysis/captures/csdk_verified.pcap`(csdk 抓包)
## 2. 硬件事实(实机确认)
- 设备名:Magnity Thermal Camera,VID 0x833C PID 0x0001,序列号 160043865
- 分辨率 160x120,帧率 ~15fps,每帧 38456 字节
- USB:config 值 1(仅一个配置),interface 0,端点:0x03 OUT、0x81/0x82/0x84 IN
- 设备只有 config 1——Linux SDK 逆向中的 set_configuration(2) 在这台机器上失败,
会回退到 1(逆向代码 0x1865b 分支)
## 3. 已验证协议(权威,实机+官方流量双重确认)
### 3.1 命令(4 字节魔数,无参数;仅 FFC 用 8 字节 {magic,param})
| 命令 | 字节 | 响应 |
|---|---|---|
| 0x6bb6b66b 信息查询 | 4 | 0x5bb5b55b(60B:pid@+4,width=160@+0x14,height=120@+0x18,fps=15@+0x1c) |
| 0x6bb6b66c | 4 | 0x5bb5b55c(60B,另一数据块,勿当 info 解析) |
| 0x6bb6b66f | 4 | 0x5bb5b55e(20B) |
| 0x6bb6b672 FFC | 8 | 0x5bb5b55f(4B OK) |
| 0x6bb6b673 START | 4 | 0x5bb5b55f |
| 0x6bb6b674 STOP | 4 | 0x5bb5b55f(需先 clear_halt 0x03/0x82) |
注意:帧头字段偏移以"帧内"为准:marker@0、cnt@4、len@8、type@0xc、shutter@0x10
### 3.2 启动序列(官方一致)
```
open(config 1, claim iface 0)
66b → 66c → 66f (各 4B)
FFC(0) → 100ms → FFC(0) → 300ms → START(4B) → 700ms
```
### 3.3 FFC 语义(关键难点)
- FFC(1) 使流切换为 **type=0 帧(温度数据,avg ~11720,手掌遮挡 +1200 counts)**
- FFC(0) 使流切换为 type=1 帧(avg ~16000,手掌遮挡变化小 <100)
- **官方 demo 在 type=0 下每 ~10 帧发一次 FFC(0/1 交替)维持推流**
- FFC 必须在"完整帧(头+数据)之后"发送
- 问题:在 libusb-1.0(TI DLL)或 libusb0 下,FFC(1) 切换后设备经常停帧;
`csdk/tools/thermal_viewer.c`(单线程、frames==3 时 FFC(1)+Sleep(400))
能稳定工作(已验证多次,显示 type=0 帧 100+)
- `csdk/tools/mag160c_demo2.c` 基于 viewer 核心,但被强杀/反复运行后设备
进入坏状态需 libusb_reset_device 重试(已加 4 次重试)
### 3.4 帧格式
```
+0x00 u32 0x1bb1b11b
+0x04 u32 frame counter
+0x08 u32 0x9600 (38400 data length)
+0x0c u32 type (0=温度/response, 1=raw)
+0x10 u32 shutter
+0x14..0x1b 保留
+0x1c .. 38400 字节像素 (u16 LE)
+0x1c+38400 u32 0x1bb1b11c (尾标记)
之后 24 字节尾字段(含 0x6cf0 类统计值)
```
## 4. 温度数据(实测)
- type=0 帧:背景 avg≈11720,手掌遮挡(整个 FOV)+1200 counts
- 线性标定:约 **147 counts/°C**(假设手掌 34°C vs 背景 25°C,未精确标定)
- demo 温度显示:25 + (v - reference)/147
- 官方 Android SDK 有 T2E 表(0x112 项,已 dump 到 analysis/t2e_table.json)
和 E2TAccQ10 表(逆向的 ReviseTemperature/CorrectTemperature 用)
## 5. 当前 Demo 状态(csdk/tools/)
| 文件 | 状态 |
|---|---|
| `thermal_viewer.c` | ✅ 稳定工作:单线程循环、frames==3 时 FFC(1)、percentile 2%-98% 渲染、type=0 显示 |
| `mag160c_demo2.c` | 🔶 基于 viewer 核心,加面板/按钮/温度/坏点检测;有设备状态残留问题(需 reset 重试) |
| `mag160c_demo.c` | ❌ 弃用(自行写的 init/FFC 逻辑设备会停帧) |
| `mag160c_demo_usb0.c` | ❌ 弃用(libusb0 API 版,同样停帧——问题不在传输层) |
### 已知显示问题(需参考开源实现解决)
1. **坏点(红蓝固定点)**:type=0 帧存在固定坏像素,显示为红/蓝点。
已在 demo2 加"参考采集时 min-max 波动 >400 标记坏点、邻居平均替换",
但用户反馈仍可见(阈值/方法需优化,或坏点表应在 FFC 后重新采集)
2. **对比度**:diff 模式(当前-参考,deadband±70,span 1500)手掌轮廓可见但偏弱;
absolute 模式 percentile 拉伸对比度差
3. **FFC 后设备停帧**:不稳定,与官方 demo(持续工作)行为不一致,
差异可能在于官方 FFC 的精确时序/频率
## 6. 环境与工具
- Windows 11,MinGW gcc 14.2 (C:\mingw64)
- 设备驱动:**libusb-win32 v1.2.6.0**(Zadig 安装;WinUSB 也可但 TI libusb DLL 的
FFC 写失败;官方 libusb-1.0.27 在两种驱动下都崩溃)
- 传输库:**TI libusb-1.0.dll**(C:\ti\ccs2050\ccs\ccs_base\common\bin\,
支持 libusb0 后端,有无害的 monotonic clock 警告)
+ dlltool 生成的导入库 csdk/third_party/libusb/win64/
- USBPcap 1.5.4 + Wireshark(重启后可用,设备在 \\\\.\USBPcap4)
- 抓包 pcap 解析脚本:analysis/captures/ 下(参考之前会话)
## 7. 开源热成像 SDK 参考(下一轮调研目标)
网络在部分时段可用,建议用 webfetch 搜索:
- **FLIR Lepton SDK**(github: groupgets/LeptonModule 或 purethermal1):展示了
raw→radiance→温度、AGC(自动增益控制)、伪彩色流程;坏点补偿思路
- **Seek Thermal 开源驱动**(github: ThermalScope/seek-thermal-camera 或
fnoop/seek-thermal-linux):EEPROM 坏点表、NUC(非均匀性校正)
- **MLX90640 库**(github: intergatedcircuits/Pico-MLX90640):插值+显示
- **AMG8833/MLX90640 的 Adafruit 库**:显示映射方法
- 关键要学习:①坏点检测与补偿算法 ②AGC/显示拉伸(直方图均衡 vs percentile)
③NUC/FFC 后的温度图管线 ④伪彩色 LUT 设计
## 8. 下一步工作
1. 调研开源热成像显示管线,改进 demo2 的:坏点补偿、AGC(显示拉伸)、伪彩色
2. 稳定 FFC:对照官方 trace 精确复刻 FFC 时序(包括周期性),解决停帧
3. 温度标定:用已知温度(冰水/热水)做两点标定,替代 147 counts/°C 假设
4. 把验证过的协议与显示管线合并回 csdk 的 mag160c_ir 实现
5. Linux 移植(最终目标)
## 9. 快速启动命令
```powershell
# 设备恢复(设备停帧时)
.\build-artifacts\usb_hardreset.exe
# 运行 demo(能看手掌的稳定版)
.\build-artifacts\thermal_viewer.exe
# 功能完整版(重试+坏点+新 FFC 调度)
.\build-artifacts\mag160c_demo2.exe
# 无头 FFC 稳定性验证(1400 帧 type=0,~95s)
.\build-artifacts\mag160c_ffc_test.exe
# csdk 线程管线验证(reader thread + FFC scheduler)
.\build-artifacts\csdk_stream_test.exe
# csdk CLI 综合(显示管线自检 / 流验证)
.\build-artifacts\csdk_cli_libusb.exe display-test
.\build-artifacts\csdk_cli_libusb.exe ffc-test 1000
# 抓包
& "C:\Program Files\USBPcap\USBPcapCMD.exe" -d \\.\USBPcap4 -o out.pcap -A -s 65535
```
## 10. 2026-08-10 晚:FFC 停帧解决 + 显示管线重做(本会话)
### 10.1 官方 FFC 时序(从 libusb0_trace.txt 精确解码)
逐行统计 26092 行官方流量,每帧 = 28B 头 + 38428B 数据。FFC 事件与帧计数:
```
init: 66b 66c 66f -> FFC(0) -> START -> [frame 1] -> FFC(0)
frame 10: FFC(1) -> 流切换 type=0(第 11 帧起)
然后周期循环: FFC(0) --9 帧--> FFC(1) --N 帧--> FFC(0) ...
```
- **FFC(1) 总是在 FFC(0) 后恰 9~10 帧**发出(0.6s@15fps,即快门闭合→恢复)。
- FFC(1) 后到下一个 FFC(0) 的间隔 N 不固定:34, 48, 66, 101, 166, 373, 346,
103, 1383, 381, 48, 1006, 317, 171, 158, 189, 219, 294, 425, 628, 723,
1012, 1450, 1804, 2680, 403, 105 …(用户/定时器驱动,非固定周期)。
- 全程 10898 帧持续推送,type=0 占 10519 帧(96.5%),type=1 只出现在每个
FFC(0)→FFC(1) 的 9 帧窗口。
- **FFC 必须在一整帧(头+数据)读完之后发送**(trace 中 FFC 行紧跟帧数据行)。
- **教训**:demo2 旧版只发一次 FFC(1) 且周期 44 帧过密 → 设备停帧或 type=1
占比过高(17.7%)、fps 下滑。官方式 **周期 400 帧 + 9 帧间隔** 完美工作。
### 10.2 实机验证结果(全部 PASS)
| 验证项 | 工具 | 结果 |
|---|---|---|
| FFC 周期 400 + gap 9 | `mag160c_ffc_test.exe` | 1400 type=0 帧 / 95s / 15.1fps / 0 停帧(2 次) |
| csdk 线程管线(reader thread + scheduler) | `csdk_stream_test.exe` | 1030 type=0 帧 / 70s / 14.7fps / 0 停帧 |
| csdk CLI `ffc-test` | `csdk_cli_libusb.exe` | 同上,PASS |
| 显示管线单测 | `csdk_test_display.exe` | 20/20 通过 |
| GUI demo2 | `mag160c_demo2.exe` | 窗口实时显示 type=0,坏点红蓝占比 0.02%,无饱和坏点 |
| 回归(旧 4 套) | csdk test_* | 全部通过 |
### 10.3 显示管线(按开源方案重做,已合入 csdk)
新增 `csdk/src/mag160c_display.c` + `csdk/include/mag160c/mag160c_display.h`,
纯 C 无平台依赖(Linux 可直接编):
1. **坏点检测**(参考 OpenThermal/libseek-thermal SeekCam.cpp + MLX90640):
- 时域:参考帧 min-max 波动 > 400 → 坏点(保留旧法)
- 直方图峰偏离(Seek 法):`thr = histPeak - (frameMax - histPeak)`,
并加 `histPeak + 200` 下界防孤立极值误杀全图
- **拓扑序填充**:坏簇从边缘向中心迭代,存填充顺序;参考图与每帧
都按该顺序用 4 邻域均值替换(坏簇逐层内缩)
2. **AGC/显示拉伸**:
- 绝对模式:2%~98% percentile 拉伸 + **ironbow LUT**(FLIR 风格 7 锚点)
- diff 模式:自适应 span = 2×mean|diff|,clamp [120, 4000],
deadband = span/20(轮廓对比度显著提升)
3. **FFC 调度器** `mag160c_ffc_scheduler_t`:tick(帧后)返回应发的 FFC
参数(0/1/-1);`mag160c_ir_set_ffc_scheduler()` 挂到 reader thread,
Linux 线程模型直接可用。
4. **两点线性标定** `mag160c_temp_calibrate_linear(counts0,temp0,counts1,temp1)`
→ a/b;demo2 有 Cal Cold(0°C)/Cal Hot(90°C) 按钮,CLI 有 `calibrate` 占位。
### 10.4 遗留事项(下一步)
- **物理两点标定**:需实际操作(冰水 0°C / 开水 90°C+ 充满 FOV),用 demo2
的 Cal Cold/Cal Hot 按钮或记录 counts 代入 `mag160c_temp_calibrate_linear`
当前仍是 147 counts/°C 假设(参考背景 ~11720 counts @ 25°C)。
- demo2 内联的坏点/AGC 逻辑与 csdk 模块功能重复,后续可让 demo2 直接调
csdk 模块(现 demo2 已用 csdk 的 FFC scheduler)。
- Linux 移植:csdk 侧已就绪(纯 C + pthread + libusb);GUI demo 的 Win32
部分需换 SDL/GTK。
### 10.5 后续小 bug 修复(2026-08-10 深夜)
用户反馈两个现象,均已修复并实机验证:
1. **鬼影**:旧参考帧用逐像素 EMA(`(r*199+v)/200`)持续吸收当前画面,
静止物体 ~13s 就被"吃进"参考帧,移开后留下反向残影。改为**漂移跟随**:
仅当场景安静(mean|diff| < 40)时,把参考帧整体平移全局均值差
(clamp ±400),不再吸收任何空间内容 —— 跟温度漂移/FFC 基线,不跟场景。
2. **FFC 响应红黄闪烁 + 卡顿**:FFC(0) 后设备输出 ~9 帧 type=1(avg ~16000,
与 type=0 基线差 +4300),旧 demo 照常渲染 → 全屏红黄;手动 FFC 按钮在
UI 线程 `Sleep(300)` 阻塞。修复:
- 主循环**跳过非 type=0 帧的渲染**(冻结画面,与官方 app 一致)—— 实测
218s/3744 帧/~8 次自动 FFC 周期标题栏从未出现 type=1,闪烁消除。
- 手动 FFC 改**异步排队**:按钮只置 `g_manual_ffc` 标志,主循环在下一
完整帧后经 `mag160c_ffc_scheduler_trigger()` 发 FFC(0),9 帧后自动
发 FFC(1),UI 不再阻塞。
- csdk 新增 `mag160c_ffc_scheduler_trigger()`(test_display 22/22 通过)。
### 10.6 二次修复:鬼影根因 + FFC 残闪(2026-08-10 深夜,实机验证)
用户复测:鬼影仍存在,且高温物体进入鬼影区会被"遮住"成低温色;
红黄帧不再卡住但偶尔闪过。根因分析 + 修复(参考 OpenCV MOG 背景建模
与 Seek 挡片校准思路):
1. **鬼影根因**(两层):
- 旧参考更新用"全局 mean drift":物体占 FOV 比例小时 mean|d| < 40
误判安静,全局偏移把**小物体逐步吸收进参考帧**(数秒~数十秒),
移开后留下高温残影;真实高温物体移到该位置时 diff=live-ref 变负
→ 显示成低温,即"被遮住"。
- 初始参考采集是 30 帧**均值**:采集窗口内若有物体在动,均值会把
物体烘焙进参考,永久鬼影。
- 修复:
a. **MOG 逐像素背景模型**(`mag160c_display_ref_track`):背景像素
(|d| < 60)慢速 EMA 跟踪漂移;前景像素(|d| >= 60)**完全冻结**,
永不吸收(之前是 clamp+漏吸收,约 112 counts/s 泄漏)。
b. **安静门控的初始采集**:每帧与上一帧 mean|Δ| < 25 才入样本,
30 帧逐像素取**中位数**(物体短暂进入窗口不会污染参考);
场景一直不静则参考一直不落(可手动 Set reference)。
c. 合成测试 `MOG_GHOST_TEST`:静态 +1200 热块 4500 帧(模拟 5 分钟)
吸收 0 像素;移开后 diff≈0 无鬼影;慢漂移仍可跟踪 → PASS。
2. **FFC 残闪**:FFC(1) 后 type=0 基线跳变(官方 trace 实测最大 +1000
counts),旧重对齐 ±400 clamp 不够,残余偏移需 MOG 数秒才消化 →
短暂偏红。修复:重对齐 clamp 放宽到 ±2000(中位数本身抗 >50% FOV
物体),FFC(1) 后跳过前 2 帧渲染(`g_skip_ffc`)。
实测连续 3+ 个 FFC 周期(period 400)红色占比前后无跳变(11.1% →
11.1%),蓝色始终 0.01%,type=1 帧从不渲染,流不断(1500+ 帧)。
证据:`analysis/demo2_v3_mog_verified_20260810.png`;单测 28/28 通过
(`csdk_test_display.exe`),旧 4 套回归全绿。
### 10.7 三次修复:开机乱图 + 残余鬼影(2026-08-10 深夜,实机验证)
用户复测:FFC 红黄闪帧已解决,但(1) 刚开软件画面有红黄点乱分布,
且不会消失、叠加到正常画面上;(2) 鬼影仍存在。
**根因**(两层,均为 MOG"永久冻结"缺陷):
1. **开机乱图**:参考帧首次采集在 nread>=150(~10s,第一个自动 FFC 周期
之前)进行。设备刚完成启动 FFC(1),type=0 基线/坏点尚未稳定,启动
噪声(红黄点)被中位数采入参考;之后 live 已正常,这些像素
|d| >= 60 被 MOG **永久冻结** → 乱图叠加且永不消失。
2. **鬼影**:同上——参考一旦采错(含物体/含噪声),MOG 冻结使其无法自愈;
FFC 后一次性 median rebase 只平移全局,修不掉逐像素错误。
**修复**:
1. **首次参考采集提前到启动 FFC(1) 稳定之后**(nread >= 40 + 跳过 2 帧
过渡),不在第一个自动 FFC 周期前采集 → 启动噪声不再进入参考。
2. **每次 FFC(1) 后重新采集参考**(REF_REINIT_AFTER_FFC):FFC 校准后
设备输出最干净的 type=0 帧,用它重建参考(安静帧中位数,30 帧,
沿用坏点表填充),取代一次性 rebase。每 ~27s 自动刷新一次,任何
残留错误最长一个周期内被清除。
3. **MOG 自愈**(`mag160c_display_ref_track_heal`):孤立像素(8 邻域前景
< 2)连续前景 >= 30 帧 → 判定为参考错误(启动噪声/坏点)而非物体
(物体是连片的),重置 ref = live。乱图/残点最长 ~2s 内自愈。
**验证**:
- 合成测试 `SELFHEAL_TEST` / csdk `test_display` 30/30:40 个孤立噪声点
全被治愈;60x40 连片热块 200 帧吸收 0 像素、不被误治;移开后无鬼影。
- 实机:开机 t=4s 孤立噪声 0.12%,t=34s(参考+FFC 后)0.11%,t=90s
(5+ FFC 周期)0.10% —— 乱图不出现、不叠加、不增长;红色像素全部为
真实场景连片目标(45~71 个大 blob);FFC 周期红%无跳变(6.4~8.6%),
蓝%恒 0.01%;流持续 2157+ 帧无停帧。
证据:`analysis/demo2_v4_selfheal_verified_20260810.png`
### 10.8 四次修复:根因定位(传感器 mura)+ NUC 平场校正(2026-08-10 深夜,数据驱动)
用户复测:开机乱图和鬼影依然存在。本次用数据驱动定位**真正根因**,并
采用开源(Seek/FLIR 挡片帧)同款方案修复。
**实测数据(mag160c_frame_dump 抓 60 帧 type=0 分析)**:
- 每像素时域噪声 std ~248 counts(99.9% 像素"波动")→ diff 模式自适应
span≈400、deadband≈20 把噪声全部放大成可见红蓝点 = **开机乱图**
- 固定传感器 mura:行剖面跨度 15594(row1 恒定 +5000,25418 vs row98 9824)、
列剖面 8714;FFT 行/列轴能量占比 ~10%
- mura 会话内漂移 ~350 counts,FFC 后突变 → diff 参考帧跟不上 = **鬼影**
- flat-field 校正验证:`live - (ref - mean(ref))` 把 mura std 3557→379
(行跨度 15704→401),中值滤波后噪声 ~80
**为什么官方 app 没有乱图/鬼影**:Android 官方管线是 raw→温度→**绝对
温度窗口显示(25~40°C)**,不用场景参考帧做 diff,天然免疫噪声放大与
参考漂移。
**修复(推翻 diff 方案,改 NUC 平场 + 绝对温度显示)**:
1. **flat-field(NUC)校正**(`mag160c_display_nuc`,csdk):`nuc = live -
(ref - mean(ref))`,消除固定 mura;显示绝对温度级别,median 居中
±1500 窗口 + ironbow。
2. **3x3 中值平滑**:把 248-count 时域噪声降 ~3 倍,画面平滑无噪点。
3. 参考帧只做**固定图案**,不跟踪场景:采集时 5% 像素偏离阈值即拒帧
(持久物体永不进参考)+ MOG 冻结 + FFC 后重采集 → 无鬼影。
4. diff 模式降级为可选(默认 absolute)。
**实机验证**:speckle residual 2.2~2.7(平滑)、纯蓝 0%、红色均为真实场景
连片目标(1~1.4%);连续 5+ FFC 周期无闪帧、无图案出现、无噪声增长;
流持续 2268+ 帧。csdk 单测 32/32,旧回归全绿。
证据:`analysis/demo2_v5_nuc_verified_20260810.png`。
工具:`csdk/tools/mag160c_frame_dump.c`、`mag160c_frame_stats.c`。
### 10.9 五次修复:数据驱动根因 + 官方 DLL 活体对比(2026-08-10 深夜)
用户复测:画面更混乱。本次彻底转向**官方实现对比**:
**逆向成果(活体官方管线)**:
1. 反汇编 Windows 官方 CoreSDKLib.dll + ThermalSDK.dll(65 个 MAG 导出,
精确 RVA 全部解析),确认官方渲染管线:
- `MAG_GetOutputBMPdataRGB24`:8-bit 灰度 `[dev+0xb00]` → 调色板查表
(256x4 BGR),输出 320x240 RGB
- `MAG_GetTemperatureData`:逐像素 counts→temp,T2E 表(646 项,已从
`.rdata 0x5cde0` 提取)+ 斜率表,公式:
`temp = slope[i]*diff>>12 + (i<<12) - 0x249f0`
- Windows 调用序列:NewChannel(chan) → EnumCameras(chan) →
LinkCamera(chan,pid) → StartProcessImage(chan)
2. **用官方 ThermalSDK.dll 活体驱动设备成功**(tsdk_debug/tsdk_capture3):
- 官方渲染帧 320x240,**紫红调色板(G=0,R/B 渐变),极平滑
(speckle 0.00%,仅 106 色),无 mura 无噪点**
- 官方温度:背景 26.7~27.4°C(ReadTemperatureAtPoint)
3. **数据对比锁定根因**:
- counts 有大尺度固定 mura:空间 std 3560、行跨度 15000+、
row0 17318 → row120 7954(固定,会话间一致,row1 漂移 1535/FFC)
- **官方图像完全无此 mura** → 官方用 per-pixel 校正(baseline/DDT)
消除了它
- **NUC 验证**:`live - (ref - mean(ref))` 把 mura std 3560→29
(行跨度 15000→23~49),mura 消除 99%
4. **demo2 的 bug**:参考采集的 quiet-gate(要求 mean|d|<25)在用户
观看时永不满足 → **NUC 从未激活** → 显示 raw counts 乱图。
**修复(最终方案)**:
1. 参考采集**去掉 quiet-gate**,直接取 30 帧逐像素**修剪中位数**
(中间 50% 均值,抗物体/死点)
2. **NUC 平场校正**为默认显示(绝对温度),消除 mura
3. **自适应窄窗口**:NUC 值 median ± 4*mean|d|(实测 std~29 → span~120,
手掌 +1200 清晰弹出),替代过宽的 ±1500 固定窗口
4. 3x3 中值平滑 + MOG 冻结/自愈 + FFC 后重采集(保留)
**实机验证**:unique colors 22260(高对比)、纯蓝 0%、孤立噪点 0.62%、
310 个大 blob(真实场景)、speckle 2.3、6+ FFC 周期无闪帧无鬼影累积、
流持续 2621+ 帧。csdk 单测 32/32 通过。
证据:`analysis/demo2_v6_nuc_final_20260810.png`。
工具:`csdk/tools/tsdk_debug.c`、`tsdk_capture3.c`、`official_harness.c`、
`analysis/temp/official_t2e.txt`(官方 646 项 T2E 表)。
### 10.10 六次修复:逐像素复刻官方显示管线(2026-08-10 深夜)
用户指出显示效果与官方不一致。通过**官方 DLL 活体驱动 + 逐层提取**,
完整复刻了官方的显示管线:
**逆向提取(全部来自官方活体)**:
1. **官方温度公式**(CoreSDKLib 0x180016290):counts → 646 项 T2E 表
二分查找 + 斜率插值:
`temp_mc = slope[i]*diff>>12 + (i<<12) - 0x249f0`
T2E 表已从 .rdata 0x5cde0 提取(646 int32,单调递增)。
**shift=6 验证**:counts 11224 → 24.8°C(与官方探针 26.7-27.4 一致,
差异来自 NUC/offset)。
2. **官方调色板**(从 8 帧官方渲染提取 115 色 + 插值到 256 项):
**品红/紫红系**:深红(74,0,0)→ 红 → 品红(145,0,145)→ 紫 →
蓝紫(115,32,210)→ 紫(154,0,188)。G 通道中段有小值。
3. **官方显示特征**:背景落在**调色板中段(品红)**,不是黑/深红——
因为显示窗口围绕背景温度(自适应),背景 ~25°C 映射到灰度 ~128。
**demo2 复刻(最终显示管线)**:
```
counts → NUC 平场(live - (ref - mean(ref)),消除 mura)
→ T2E 官方温度(shift=6)
→ 自适应窄窗口(背景温度 ± 2°C)
→ 官方品红调色板查表
```
**两个关键 bug 修复**:
1. 窗口单位 bug:temp_mc 是毫°C,窗口却用 °C 比较 → 全图灰度 255。
2. NUC 参考被 MOG 更新吸收背景 → NUC 失效(参考只 FFC 后重采集,
MOG 仅用于可选 diff 模式)。
**实机验证**:画面 mean RGB 139/25/144 vs 官方 141/1/130(几乎一致);
背景品红(139,0,117)与官方(145,0,145)同色系;黑色 0.1% vs 0.0%;
4+ FFC 周期无闪帧、稳定。csdk 单测 32/32。
证据:`analysis/demo2_v7_official_look_20260810.png`。
新增:`csdk/src/mag160c_official_palette.h`(256 项官方调色板)、
`csdk/src/mag160c_official_t2e.h`(646 项官方 T2E 表)、
`csdk/tools/tsdk_pair.c`、`tsdk_gray.c`、`tsdk_palette.c`。