Files

139 lines
6.6 KiB
Markdown
Raw Permalink 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 逆向交接文档 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.c` → `build-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.c` 的 `decode_live`(+28)是错的 → demo3 已改为 +0。
- `mag160c_frame_dump.c` 的 `fwrite(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