Files
orisys-sdk/docs/force-workflow.zh.md
T
ykcheungab c256870ee2 fix: 按复位请求目标确认参考版本并隔离复位状态
防止在途旧帧提前触发归零,并保留旧 reset 用法。SDK 101 项针对性回归与 lint 通过。
2026-10-20 20:33:23 +08:00

112 lines
6.8 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.
# 力读数工作流(`ForceSession`)
用途:SDK 显式力读数会话(`studio-force/1`)的公共接口参考。状态:已实现并接入 Studio,2026-10-20;
硬件、真实相机与真实载荷精度未验证。需求与验收矩阵见
[流程规格](../../docs/workflow/studio-force-workflow.zh.md),实施状态见
[重写计划](../../docs/workflow/studio-force-rewrite-plan.zh.md)。
测量、标定模型、空载基线与输出后处理全部由本会话拥有;调用方只提供源帧与帧身份,
发送归零/换模型请求,并分发返回的 `ForceOutput`。这样同一帧只测量、推断、后处理各一次,
显示与记录拿到同一个不可变输出。
## 入口与版本
```python
from orisys import ForceSession, WORKFLOW_VERSION
```
`WORKFLOW_VERSION = "studio-force/1"` 是处理顺序与语义的稳定身份,随每个输出返回,
记录、缓存键与诊断引用它;改变顺序或语义时必须提升该版本。
构造显式启用测量源(`Sensor` 或 `FingerRuntime`)的会话接缝:
```python
session = ForceSession(
source=runtime, # 已打开、由调用方负责 close
sensor_family="finger", # box | mini | finger | finger-mems
device_id="FINGER-001", # 可选,用于标定身份校验
context=context, # schema 3 模型需要的实际管线身份
calibration=model, # Calibration(schema 1/2)、ModelCalibration(schema 3)或 None
settings=output_settings, # 可选;默认 OutputSettings(sample_rate_hz=30.0)
)
```
构造失败不会留下“半切换”的会话;旧 `Sensor.read_info` / `ForceReadout.apply` 路径在
未构造 `ForceSession` 时保持原语义,本模块不与旧路径并行运行。
## 主要方法与属性
| 成员 | 说明 |
|---|---|
| `process_frame(source_frame, stamp) -> ForceOutput` | 唯一逐帧入口:测量 → 归零状态 → 标定 → 后处理。同一 `(session_id, frame_id)` 重复调用返回同一缓存对象且不推进状态;乱序帧显式失败并清除完成标志 |
| `read_sdk_frame(source_frame, stamp) -> SdkReading` | 只做同帧测量(图像准备、光流/HHD、可选接触/场),不推断、不读数滤波 |
| `request_zero(*, reference_id, declared_unloaded, replay_window=None) -> ZeroProgress` | 启动唯一空载归零操作;`declared_unloaded` 必须为空载确认;拒绝带载相对置零 |
| `update_zero(reading) -> ZeroProgress` | 推进归零状态机并执行本帧一次模型推断;迟到代次的结果被忽略 |
| `invalidate(*, reason) -> ZeroProgress` | 断流、取消、换模型或测量配置变化时作废基线/完成状态与滤波历史 |
| `apply_calibration(reading, zero) -> CalibratedReading` | 不复用旧结果、不重复推断,给出未做读数滤波的 raw/N 与逐轴状态 |
| `apply_filter(measurement) -> ForceOutput` | 唯一后处理:raw 与 N 各自独立地 median → low-pass → 可关闭逐轴阈值 |
| `set_calibration(calibration, *, context=None)` | 帧边界原子换模型;校验失败保留原模型、基线与完成状态 |
| `zero`、`calibration_fingerprint`、`output_settings`、`last_output` | 只读状态/身份;`output_settings` 是实际生效参数 |
## 帧身份
`FrameStamp(session_id, frame_id, source_frame_id, signal_time_s, time_basis)`;后处理低通的
采样率来自信号时间,不取离线处理耗时。实时与顺序录像只替换源适配器,其余流程相同。
## 归零(空载基线)
1. `request_zero(declared_unloaded=True, reference_id=...)` 只登记请求并递增参考代次;
2. 处理线程在下一个帧边界重置 tracker,然后才测量该帧;
3. 采集重置后连续 30 个有效处理帧,按模型类型得到基线:标量模型取 raw 中位数,
场模型委托 `ModelCalibration` 用同一增益图加权后的 30 帧中位数;
4. 第 30 帧仍为基线帧;第 31 帧起 `phase="ready"`、`completed=True` 并输出 N,
`effective_from_frame_id` 指向该帧。
基线未完成、无效帧、窗口不足或已取消时 N 为 `NaN`、状态显式;窗口不足不越界补帧。
录像重算用 `replay_window=(start, end)` 在声明区间执行同一操作。
三级流水线已有同帧测量时,用 `process_measurement(row, stamp, tracker_reset_seq=...)`
传入快照自带的参考版本,不读流水线的实时计数。外部归零先调用
`target = pipeline.request_reset()`,再调用
`request_zero_external_reset(reference_id=..., declared_unloaded=True, target_reference_version=target)`。
`target` 为正整数,帧版本达到它才开始采样;较早复位后已在途的帧不能确认本次请求。
未被 flow 领取的请求合并为同一目标,领取后的新请求另分配目标;共用目标的复位与归零只确认一次。
该接缝尚未发布,本轮将原 `tracker_reset_seq` 请求参数改为明确的目标版本参数;
逐帧输入仍用 `tracker_reset_seq`。已发布 `Sensor.reset()` / `StreamPipeline.reset()` 用法不变。
实现见 `pipeline.py`、`force_session.py`,回归见 `tests/test_pipeline.py`、`tests/test_force_session.py`。
## 后处理与有效设置
`OutputSettings(sample_rate_hz, median_window=1, lowpass_hz=0.0, lowpass_order=2,
raw_threshold=0.0, newton_threshold=0.0)`。每阶段由自身值关闭(median=1、lowpass=0、
threshold=0),全关时对有效值严格直通(NaN 保留);无效轴不进入滤波历史。
`ForceOutput.settings` 返回实际生效的参数(例如截止频率达到 Nyquist 时解析为 off)。
## 离线重滤波
```python
from orisys.force_readout import process_output_sequence
raw_out, newton_out, effective = process_output_sequence(
settings, raw_samples, newton_samples,
raw_valid=None, newton_valid=None, signal_times_s=times,
)
```
该函数只重放输出级(带完整 warm-up),用于从已存未滤波序列生成新参数下的最终输出;
不重新测量、不打开模型链。
## 状态与诊断
逐轴状态:`ok`、`out_of_range`、`zero_unavailable`、`no_contact`、`coordinate_unmapped`、
`outside_coverage`、`invalid_input`、`uncalibrated`、`measurement_failed`、`frame_order`、
`signal_time_order`。仅 `ok`/`out_of_range` 携带可用牛顿值;模型不输出的轴(例如 FN-only
模型的 FX/FY)恒为 `NaN` + `uncalibrated`。缺失值与有效零分开。
`CalibratedReading.diagnostics` 提供 `reference_id`、`baseline_N`、`baseline_raw_fn/fx/fy`、
`model_fingerprint`、`mapping`、`extrapolated_fraction`、`coverage_fraction`、`area_scale`、
`pending_reference_frames` 等;调用方存储或展示,不据此改写逐轴有效性。
场模型质量(外推、覆盖)与 downsample 差异属于诊断,不替代有效性判断;
`hhd_downsample` 不同是唯一允许的管线身份差异,其余差异仍拒绝并报告。