Files
orisys-sdk/docs/force-stream-session.zh.md
T
ykcheungab 14e73d743c feat: 新增消费 MeasurementFrame 的力侧会话 ForceStreamSession(T06a)
新会话直接消费 ImageMeasurement:参考版本或 session 改变时,在 resetting、collecting、ready 任一阶段都作废旧零点;请求的目标版本到达时采用并开始同版本基线采样,目标前的在途帧标为 zero_pending;重复、迟到、同时间戳的帧只给诊断;max_gap_s/max_window_s 超限给出原因;每帧输出带帧头和参考版本的结果行。不提供旧的外部复位接口;旧 ForceSession 原样保留给 App。标量与无标定场景与旧会话逐位一致。回归 374 项、lint 通过。
2026-10-21 15:01:38 +08:00

72 lines
4.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.
# 新力侧会话(T06a)
本文件是单路 SensorStream 计划 T06a 的 SDK 合同:新的力侧会话直接消费 T05 的
`ImageMeasurement`(T03 `MeasurementFrame` 头 + 同帧 raw/field),参考版本取帧上的
`reference_generation`。旧 `ForceSession` 仍为 App 保留到 T09/T10 迁移,本会话不提供
`process_measurement`、`request_zero_external_reset`、`tracker_reset_seq` 等旧外部复位接口。
## 接口
- `ForceStreamSession(sensor_family=..., calibration=None, settings=None)`:构造;T06a 支持
无标定与 schema2 标量曲线,`settings` 为 `OutputSettings`(None 用旧默认)。
- `request_zero(reference_id=..., declared_unloaded=True, expected_reference_generation=版本, max_gap_s=None, max_window_s=None)`:
为指定参考版本确认无载归零;可选窗口上限。
- `process(measurement) -> ForceStreamOutput`:消费一个 T05 `ImageMeasurement`,返回逐帧结果
(`frame` 携带 T03 帧头与 `reference_generation`,以及 `raw/newton/status/quality/zero`)。
## 规则
- **版本/会话变化即废旧零点(K8.3)。** `reference_generation` 或 `session_id` 一旦变化,
resetting、collecting、ready 任一阶段的旧零点立即失败(`zero.phase == "failed"`),
必须对新的版本显式调用 `request_zero(expected_reference_generation=新版本)` 才能恢复有效 N。
正常顺序(会话在处理 v0 → 复位得到目标 v1 → v1 到达)中,等于**请求目标**的新版本会被采用
并开始/继续同版本窗口,不会作废这次请求;只有未请求的版本变化或版本超过目标才失败。
旧的 `generation` 在采样开始后不再检查的缺陷(阶段 0 P3-2)由本会话修复。
- **基线只取请求版本的帧(K8.3/K8.5)。** 归零请求绑定一个版本。目标到达前、仍属当前版本的
在途帧记为 `zero_pending`(不是迟到,也绝不进入窗口);比当前版本更旧的帧才是 `late`;
超过目标的版本使请求失败,而不是静默改绑。基线固定 30 帧无载输入;
可选 `max_gap_s`/`max_window_s` 超限时失败并把原因写进 `zero.failure_reason`。
- **重复、迟到、同时间戳(K4.2)。** 以 `sensor_id + session_id + source_frame_id`
(无源编号时用 `frame_id`)去重,凡是送入引擎的帧都会登记身份。重复帧只产生诊断结果;
旧版本和同时间戳/乱序帧只标记 `late`/`zero_pending`,不推进零点或滤波,也不作废旧零点。
不同源帧时间戳相同不算重复。
- **逐帧结果流(K6.1)。** 每个输入帧都返回一个冻结 `ForceStreamOutput`,携带 T03 帧头与
`reference_generation`;`quality` 为 `ok` / `uncalibrated` / `zero_pending` / `duplicate` /
`late` / `session_changed` / `version_changed` / `window_failed` / `invalid`。
迟到、无效和带质量标记的结果不会被丢弃;拒绝帧仍保留 raw 特征。
- **数值等价与滤波。** T06a 的零点/标定换算/读数滤波复用已发布算法;同一输入、无复位、
同一标定时与旧 `ForceSession` 逐帧相等(测试覆盖标量曲线、无标定、median+lowpass 滤波器)。
固定设计帧率与显式滤波切换属于 T07,不在本会话实现。
- **线程与只读。** 一个实例只属于一个力侧线程;输入数组只读,输出只含标量/状态/不可变进度。
T06b 在本合同上补充 field 模型、FN-only 全局增益模型与三类标定的完整等价测试。
## 示例
```python
from orisys.force_stream_session import ForceStreamSession
from orisys.image_pipeline import ImageMeasurement
from orisys.stream_contract import FrameStamp, MeasurementFrame
session = ForceStreamSession(sensor_family="box")
session.request_zero(reference_id="run-1", declared_unloaded=True,
expected_reference_generation=0)
frame = MeasurementFrame(
stamp=FrameStamp(sensor_id="BOX-001", session_id="run-1", frame_id=1,
source_frame_id=1, capture_time_ns=33_333_333,
clock_id="host", capture_time_basis="capture_monotonic"),
source_dt_s=None, reference_generation=0,
)
row = session.process(ImageMeasurement(frame=frame, force_raw=(0.0, 0.0, 0.0),
torque=0.0, flow=None))
assert row.frame.reference_generation == 0
assert row.zero.phase in ("resetting", "collecting")
```
## 后续
T06b:field(`hhd_normal_l1_field/1`)与 FN-only(schema3 `outputs=["fn"]`)标定、标定不匹配、
field 加权基线与标量力域基线的分离,以及对照旧 ForceSession 的完整五场景数值等价。
T07 才改变输出滤波的帧率与切换语义;T09/T10 迁移 App 后删除旧 `ForceSession`。
另一项后续任务:删除旧 `ForceSession` 之前,先把零点、标定、读数引擎从旧类中抽出来,
避免新会话依赖待删除的类型(T06b 或 T09 之前)。