Files
orisys-sdk/docs/field-gain-model.zh.md
T
ykcheungab dc8a630df3 发布 SDK 0.6.0 并补充场标定使用说明
支持不带前缀的版本标签,保留 Finger 资产随 wheel 交付。发布工具 97 项回归及 SDK 自带资产的场标定录像验证通过。
2026-10-19 20:56:00 +08:00

130 lines
7.9 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.
# 场加权力标定模型契约
用途:reference。范围:SDK schema 3 `field_gain/1` 的输入、映射、空载基线、诊断与兼容边界。
[统一力标定模型契约](calibration-model-contract.zh.md)负责文件选择、身份与逐帧生命周期;
本文只补充场加权模型特有语义。状态:2026-10-19 已实现并有回归测试,离线录像对照见
[实施计划](../../docs/workflow/field-weighted-calibration-plan.zh.md)。
## 定位与边界
从现有多点增益生成空间图,对 HHD 无旋向量场做加权求和,作为 FN 的实验估计。
不依赖深度、接触中心、最大光流点或单接触判定。SDK 的 `FingerRuntime` 可直接加载模型、
声明加权空载窗口并逐帧推断;处理来源可以是录像或相机。尚未接入的是 Studio 实时采集界面,
其应用入口仍显式拒绝场模型,不是 SDK 的来源限制。
现有增益对应各加载位置的整场响应,不是已验证的局部系数。交付证明软件契约与可复现估计,
不宣称局部压力、多接触力可加性或精度改善。负的基线差保留;显示阈值只由显示层决定。
SDK 使用示例(配置、资产、模型和设备身份须匹配):
```python
from orisys.finger import FingerRuntime
runtime = FingerRuntime.open(
config="sensor.json", export_dir="assets", video="input.mp4",
cal_path="force_calibration.field.json", device_id="YOUR-SENSOR-SN",
)
try:
# 仅在传感器无载时声明;video 也可以传相机编号。
runtime.declare_unloaded_reference("unloaded-1")
with runtime.pipeline(contact=False, include=()) as pipe:
while (snapshot := pipe.wait()) is not None:
if snapshot.calibration_status.get("fn") == "ok":
print(snapshot.normal_force)
finally:
runtime.close()
```
模型前 30 个有效处理帧用于建立零点;订阅者可能跳过中间快照,不能以收到的快照数判断就绪。
运行中换模型必须由调用方在处理线程的帧边界执行,随后重新声明空载窗口;不能与运行中的
pipeline 并发调用切换接口。当前独立验证覆盖录像的同步处理和 pipeline 软件链,
不等于已验证相机实机精度、吞吐或延迟。
## 文件字段
`model.type` 为 `field_gain/1`,`input_profile` 为 `hhd_normal_l1_field/1`,`outputs` 仅 `["fn"]`。
`pipeline` 沿用 schema 3 的测量身份,并增加闭合的 `pipeline.field`(由 SDK
`FIELD_IDENTITY` 生成):`grid`、`shape`、`mask_shape`、`vector`、`reduction`、`dtype`、
`unit`、`mask`、`lifecycle`、`area_compensation`。它们进入特征签名;改变任一值即需升级 profile。
`params` 必需键:
| 键 | 规则 |
|---|---|
| `points_uv`、`gains_N_per_raw`、`triangles` | 沿用空间增益的完整凸包三角网校验;点数由数组决定 |
| `valid_force_range_N` | 必填 `[low, high]`;超范围保留数值并标 `out_of_range` |
| `mapping` | 固定 `{"inside": "barycentric", "outside": "boundary_projection", "tie_break": "boundary_edge_order"}` |
| `baseline` | 固定 `{"frames": 30, "statistic": "median"}`,仅实现这一策略 |
`artifacts` 必须有且仅有一个 `role="coordinate_map"` 附件;`map_sha256` 必须等于附件字节摘要。
附件提供输出分辨率 `uv_by_output_px` 与 `valid_mask`,SDK 打开模型时校验形状与有限性。
## 增益图与加权求和
先把支撑点增益映射到 HHD 向量场的计算网格,再逐帧归约;缓存身份包含模型指纹、坐标附件、
HHD 网格形状与物理有效掩膜,任一变化都重建。映射规则:
- 三角网内按重心插值取增益;查询落在共享边时按文件中的三角顺序取第一个命中的三角形。
- 凸包外投影到最近边界线段,再按投影参数插值两端增益;距离相同时取边界边排序中靠前者。
- 输出网格内只在物理有效像素上统计;有效掩膜内缺坐标或增益是模型映射错误,报
`coordinate_unmapped`,不当作零或域外增益。
- 按块面积降采样到 HHD 网格:增益取覆盖有效像素的均值;`coverage` 是覆盖面积比,
`inside` 是凸包内面积比;混合覆盖格点保留比例,不平均无效坐标。
逐帧对同一帧的 HHD 无旋向量场 `d` 计算
`P = A * sum_{HHD 激活格点}(gain * (|d_x| + |d_y|))`。HHD raw 汇总正是
`A * sum_{激活格点}(|d_x|+|d_y|)`,所以常增益必须精确等于 `gain * raw`;`coverage` 只用于
外推比例与诊断,不得再乘进 `P`,否则掩膜边缘的部分覆盖格点会被重复折扣。
HHD 激活但 `coverage=0`(没有任何有效像素映射到该格点)是模型映射错误,报
`coordinate_unmapped`,不得静默记零。`A` 取自 `hhd/api.py` 现有的
参考网格面积补偿(参考网格像素数/当前网格像素数),调用方不得再乘一次或重复归一化。
不得改变 FN raw、HHD 分解或剪切分量。空场时 `P=0` 且外推比例为 0;
负的 `FN = P - B0` 保留为有效数值(可能超量程)。
## 空载基线与生命周期
用户先声明无载窗口,SDK 才对后续帧累计加权 `P`:
- `Sensor.declare_unloaded_reference(reference_id=...)`(`FingerRuntime` 同名转发)开始窗口;
`reference_id` 必填并记录。窗口要求连续 30 个有效帧;任一无效输入或映射错误会中断连续计数,
向前 30 帧零点未就绪。
- `B0` 为这 30 个 `P` 的中位数;就绪前的帧状态为 `zero_unavailable`,不输出牛顿值。
就绪后 `FN = P - B0`。
- 空载确认不以接触定位为门槛,但要求输入有限;换模型、重置、倒播或新会话使基线失效。
- 场模型拒绝旧标量零点:`Sensor.set_calibration_reference()` 对 `hhd_normal_l1_field/1`
抛 `CalibrationError`,调用方必须使用加权窗口接口,不能把旧 FN raw 零点当作 `B0`。
## 结果诊断
`CalibrationResult.diagnostics` 逐帧携带版本化诊断;旧结果或缺字段时按未知处理,不得补零:
| 键 | 含义 |
|---|---|
| `model_fingerprint` | 模型文档与附件的内容指纹 |
| `mapping` | 生效的边界策略 |
| `baseline_N`、`reference_id` | 已就绪基线及其声明标识;未就绪为 `None` |
| `pending_reference_frames` | 当前连续窗口已累计的有效帧数 |
| `extrapolated_fraction`、`coverage_fraction` | 按 `q` 加权的凸包外比例与覆盖比例 |
| `area_scale`、`frame_id` | 本帧面积补偿与帧标识 |
`extrapolated_fraction` 是估计质量,不是有效性:它不改变 `status`,也不得让上层丢弃牛顿值。
零点缺失、输入错误仍无效;超量程沿用现有显式状态。
## 兼容与实现位置
旧 `spatial_gain/1`、`global_gain/1` 与旧文件语义不变;schema 3 按声明轴校验,旧 SDK 遇
`field_gain/1` 必须拒绝。`hhd_downsample` 仍按既有兼容例外处理:只允许该键数值不同,
其余处理参数、几何、展开域、SN 与传感器类型仍须匹配,不能借此跳过签名校验。
| 位置 | 责任 |
|---|---|
| `src/orisys/field_calibration.py` | profile/策略常量、增益图构建、加权归约 |
| `src/orisys/calibration_models.py` | 类型注册、参数校验、基线状态与诊断 |
| `src/orisys/hhd/api.py` | 同帧 `get_field()`:`d` 拷贝、物理掩膜、面积补偿 |
| `src/orisys/sensor.py`、`src/orisys/finger/runtime.py` | 同帧场推断、加权零点声明、上下文绑定 |
| 工作区 `scripts/finger_multical/export_field.py` | 现有空间模型只读导出为实验文件,不重训、不改排除点 |
回归证据:`tests/test_field_calibration.py` 覆盖常增益等价、两区域贡献、重叠向量先合成再 L1、
边界投影、掩膜/NaN/空场、映射错误与 30 帧基线生命周期;`tests/test_model_runtime.py` 覆盖
HHD 同帧场接线、加权零点声明与无接触推断。命令与 run_id 记录在实施计划的执行结果中。
实验导出文件不覆盖原件,provenance 声明来源哈希、边界/基线策略和实验假设。