# 场加权力标定模型契约 用途: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 声明来源哈希、边界/基线策略和实验假设。