ykcheungab
26382b359f
feat: ForceStreamSession 使用固定设计帧率的输出滤波(T07)
...
新增 FixedRateOutputFilter:设计帧率在会话创建时固定,实测帧率漂移和长间隔只报告、不重新设计也不清历史;request_output_settings 可跨线程排队,在力线程帧边界切换,只重建滤波链、清空历史,不改零点和参考版本,并发出 output_filter_changed StreamEvent(设置、指纹、生效帧、预热)。结果行带滤波设置身份与预热状态。已发布 ForceReadout 和旧 ForceSession/ForceOutputFilter 默认行为不变;设计帧率下与旧会话逐位一致。回归 391 项、lint 通过。
2026-10-21 16:27:44 +08:00
ykcheungab
11f8dc93e5
feat: ForceStreamSession 覆盖 field 与 FN-only 标定(T06b)
...
新增 measurement_requirements,告知调用方 field 模型需要同帧场数据。补充标量、field、FN-only 三类标定与旧 ForceSession 的数值等价测试,以及标定与帧不匹配的情况:field 缺 context 时构造失败,基线帧缺 field 时零点失败,ready 后缺 field 的帧单独标为 invalid_input。与改动前的旧会话基线逐位一致。回归 381 项、lint 通过。
2026-10-21 15:46:01 +08:00
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
ykcheungab
e3b60f3d6d
feat: 将图像块拆分为可独立运行的 ImagePipeline
...
光流、HHD 和场从 Sensor 中抽到 ImageSettings/ImagePipeline,Sensor 与 FingerRuntime 改为委托,公开接口与数值不变(222 个基线数组逐位一致,含运行时 flow_ema_alpha 场景)。参考版本只有一个来源:StreamPipeline 在 flow 线程领取的版本逐帧交给图像块。对外数组为只读副本;输出带 stream-contract 的 MeasurementFrame 头。回归 357 项、lint 通过。
2026-10-21 13:35:02 +08:00
ykcheungab
474dbf5a64
feat: 为每个 Sensor 绑定只读 SensorContext
...
构造时一次绑定 SN、配置、资产和当前生效的标定:只接受显式给出的 SN,不做猜测;标定路径只取当前生效的标定,清除后为 None;换标定时整体替换。帧身份复用 stream-contract 的 FrameIdentity。load_config 改为复用 resolve_config_source,使记录的配置来源与实际读取的文件一致,并补一致性测试。已发布 Sensor 数值和资产包解析不变。回归 275 项、lint 通过。
2026-10-21 11:04:02 +08:00
ykcheungab
f6f3c45285
feat: 新增单路流类型合同 stream-contract/1
...
冻结逐帧身份、采集时钟、测量头和事件信封:FrameIdentity、FrameClock、FrameStamp、MeasurementFrame、StreamEvent,并从包根导出。采用严格读取:未知字段和未列出的版本一律拒绝,任何字段变更都升版本,读取方在 SUPPORTED_CONTRACT_VERSIONS 中列出可读版本;未知事件 kind 仍兼容。事件可哈希,kind 为 lower_snake。合同写入 docs/stream-contract.zh.md;不接入现有运行时。窄套件 139 项、lint 通过。
2026-10-21 11:03:53 +08:00
ykcheungab
cbccbd14b5
test: 覆盖暂停恢复时复位请求的合并与新目标分配
...
resume(reset=True) 与暂停中未领取的请求共享目标,领取后另分配;变异验证两项断言有效。SDK 窄套件 103 项通过。
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01CpCfJF6SvonMKmPZhzKZHb
2026-10-20 14:07:37 +00:00
ykcheungab
c256870ee2
fix: 按复位请求目标确认参考版本并隔离复位状态
...
防止在途旧帧提前触发归零,并保留旧 reset 用法。SDK 101 项针对性回归与 lint 通过。
2026-10-20 20:33:23 +08:00
ykcheungab
ee830d8505
新增统一力读数会话 ForceSession
...
把同帧测量、空载归零、模型推断与共用后处理收进一个 SDK 会话,Studio 显示与记录使用同一样本;旧 Sensor 读数接口保持兼容。以 force session 与受影响 SDK 套件、lint 与文档门禁验证,硬件与真实载荷精度未验证。
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01CpCfJF6SvonMKmPZhzKZHb
2026-10-20 07:07:22 +00:00
ykcheungab
dc8a630df3
发布 SDK 0.6.0 并补充场标定使用说明
...
支持不带前缀的版本标签,保留 Finger 资产随 wheel 交付。发布工具 97 项回归及 SDK 自带资产的场标定录像验证通过。
2026-10-19 20:56:00 +08:00
ykcheungab
0a042c7fbf
新增 HHD 场加权标定模型与加权空载基线
...
field_gain/1 用坐标增益图对无旋向量场做 L1 场加权,以连续 30 帧加权中位数替代旧 raw 零点,实时入口暂不支持。目标测试 102 项与 lint_gate 通过;契约见 orisys-sdk/docs/field-gain-model.zh.md。
2026-10-19 19:49:25 +08:00
ykcheungab
c78f7a304f
允许 HHD 下采样率不同的标定保持兼容
...
按实际运行上下文核对其余处理参数,保留文件指纹与设备身份校验。115 项标定及运行时检查通过。
2026-10-19 16:30:42 +08:00
ykcheungab
c0c91ad3f1
统一 Finger SDK 计算资源与 Studio 标定基准
...
同步完整计算资源并移除旧几何缓存。84 项测试通过,SDK 与 Studio 在同一录像的 150 帧 raw、力值和状态一致。
2026-10-19 09:58:01 +08:00
ykcheungab
fb72dabecd
补充 Finger 模型切换与逐帧接触状态
...
按实际几何和处理参数校验切换模型,并保留帧内接触状态。88 项相关测试通过。
2026-10-19 09:47:44 +08:00
ykcheungab
e9710e140b
精简 Finger 示例的标定启动参数
...
从配置包读取几何资源,并提供显式无载荷启动置零。30 项测试、静态检查及现有录像验证通过。
2026-10-18 13:10:45 +08:00
ykcheungab
ff7614a6a0
接入力标定 schema 3 与多点空间增益模型
...
保留旧格式和 cal_path,校验 SN、特征身份及坐标附件,按帧返回逐轴状态。相关测试 263 项通过,已核对存量预测并实测 180 帧录像。
2026-10-18 12:56:40 +08:00
ykcheungab
9c951e9d3c
fix: 将 ARM64 wheel 纳入发布校验和上传流程
...
补齐全部架构的运行证据、GitHub 发布说明和 PyPI 逐文件下载核验。已通过 161 项测试、代码和文档门禁、九个 wheel 的本地索引下载核验,以及 ARM 三个 ABI 的 40 帧 CPU 检查。
2026-10-15 21:39:31 +08:00
ykcheungab
bb15b750fb
feat: 添加 ARM64 manylinux wheel 构建选项
...
复用现有 Docker 和 Nuitka 流程,隔离架构镜像并支持 aarch64 标签。已通过 47 项测试、代码及文档门禁,并完成 Python 3.10 ARM64 wheel 构建、隔离导入与内容审计。
2026-10-14 16:08:54 +08:00
ykcheungab
120b8c2cf6
为采集帧绑定主机时间与来源信息
...
采集时间随图像穿过处理队列,并修正未读帧的丢帧计数。通过采集与流水线针对性测试。
2026-10-11 12:48:34 +08:00
ykcheungab
34cb83d4a4
修正示例中的三轴力单位显示
...
避免未标定读数被示例标成 N,并让 Finger 示例读取 SDK 的每轴单位。已通过相关测试和语法检查。
2026-10-05 13:10:58 +08:00
ykcheungab
38d3e67b00
固定 HHD 下采样并标记三轴力单位
...
避免运行中改变 HHD 测量配置,并明确部分标定时各轴单位。已通过 SDK 与共享层测试。
2026-10-05 12:56:29 +08:00
ykcheungab
80f7da5a20
添加按设备 ID 选择和校验标定文件
...
避免多台传感器误用默认标定,缺文件时保持 raw。已通过 SDK 回归测试和文档检查。
2026-10-05 12:21:04 +08:00
ykcheungab
230b04a79d
Add a sensor bundle contract separating family, backend and profile
...
Product name decided the pipeline: Mini worked live but replay refused it. A bundle descriptor now declares profile_id, product_family and processing_backend, with computational and visualization assets kept apart, and one resolver serves live and recorded input. Legacy bundles load through a documented adapter that never guesses a backend from a folder name.
2026-10-04 20:55:39 +08:00
ykcheungab
6e3d509239
Add pipeline pause and resume at two levels
...
Pause now holds the pipeline without tearing it down: CAPTURE_ONLY keeps the camera
streaming so a live sensor stays converged while the flow and HHD stages stop, and BOTH stops
the read as well. Resume rebases the tracker, because a held reference frame would otherwise
report the hold itself as deformation.
Verified with tests/test_pipeline_pause.py: 10 passed across three consecutive runs.
2026-10-04 20:55:35 +08:00
ykcheungab
333fa8fcff
added pause/wait functions for stream
2026-09-30 21:23:08 +08:00
ykcheungab
b5d7533e24
examples: make StreamPipeline the recommended entry, archive the manual loop
...
The two canonical examples taught the advanced path: they sequenced
get_img() -> compute_deformation() -> compute_contact() -> read_info() by hand
and unpacked a 13-element tuple positionally, which is what led developers to
reach for the compute backend, the capture queue and the stitch mode. The
managed alternative already existed and was documented nowhere.
Library (add-only, nothing removed):
- FrameSnapshot.image_size_raw carries the capture resolution, so a caller can
compare it with the processed frame instead of reaching into Sensor.
- StreamPipeline.reset() resets the tracker and force filters *safely*. It is
queued and applied by the flow stage before its next frame, never inline:
Sensor.reset rebases initial_img on the current Sensor.img, which the flow
stage is reading concurrently, so a caller-thread reset would capture a
half-written reference frame. Idempotent.
- TactileProcessor.pipeline(produce) and FingerRuntime.pipeline() build a
pipeline without the caller naming a backend concept; the latter is
`with runtime.pipeline(contact=True) as pipe`.
Examples:
- examples/basic_pipeline.py and examples/finger_pipeline.py rewritten onto
StreamPipeline + FrameSnapshot: one object, one call per frame, no tuple, and
no compute backend, queue or stitch setting in sight.
- examples/archive/basic_pipeline_manual.py and _finger_pipeline_manual.py keep
the previous versions byte-for-byte apart from a supersede header, so code
copied from them keeps working. The finger header also records the archived
--show defect (store_true with default=True, so it could never be disabled).
- examples/_display.py holds the shared display helpers, so an example no longer
hand-rolls depth normalisation and colormap application.
- examples/README.md leads with the recommended pair and documents the manual
form as still-supported, and states that examples/gui/ is moving to
orisys-studio.
Tests: three added to tests/test_pipeline.py, covering the reset queue (it must
not run on the caller's thread and must land before the first compute_flow),
image_size_raw, and the None case when a producer reports no size. Verified the
reset test fails when reset() is made inline, so it discriminates.
Verified end-to-end against real media: basic_pipeline on data/sample/s1_480p.mp4
(box) reaches ~113 FPS and exits 0; finger_pipeline on data/dd02-0703/1.mp4
(finger) reaches ~140 FPS with mask coverage 0.41 and exits 0. Both archived
manual versions still run. tests/test_pipeline.py: 20 passed. Full suite:
342 passed, 3 failed - all three failures reproduce on the pristine tree
(import precedence, longrun timing, and a stale ruff version literal in
docs/code-review.md) and are unrelated to this change.
2026-09-30 17:09:02 +08:00
ykcheungab
e2ac36269c
added ruff code reivew
2026-09-27 19:21:55 +08:00
ykcheungab
0e903792bd
fix test sample s1.mp4 missing
2026-09-20 11:46:03 +08:00
ykcheungab
153f51df11
change sample s1_480.mp4 to s1.mp4
2026-09-20 11:39:02 +08:00
ykcheungab
2e7b65298b
fixed test_signal_processing error
2026-09-20 11:36:30 +08:00
ykcheungab
e2b906a640
fix preflight config path check
2026-09-20 11:20:47 +08:00
ykcheungab
1cf78c9d71
fixed calibration data not loading due to path
2026-09-20 11:00:33 +08:00
ykcheungab
11962cdc34
配置没写的滤波键等于"关",不再回落到会滤波的默认值 - What: DEFAULT_FORCE_MEDIAN_WINDOW 3 -> 1、DEFAULT_FLOW_EMA_ALPHA 0.5 -> 1.0(DEFAULT_FORCE_LOWPASS_HZ 本就是 0.0),并把注释改成"配置文件没写的键就是关,而不是我们觉得合理的那一档"——原因写在注释里:否则设备会去滤一个没人要求滤的测量,而文件里没有任何线索;实测的延迟/降噪数据保留在注释中,作为 balanced/low_noise 预设的依据。docs/filters.md 第 2 节增加"缺省 = 关"这一条并说明没有 filters 段的配置什么都不滤,预设表里 balanced 的用途由"默认建议"改为"建议起步档"(它不再是默认值)。examples/filters/README.md 补一句"整段删掉等价于 off"。tests/test_filter_presets.py 新增 test_a_config_with_no_filters_block_filters_nothing:把 box bundle 的 filters 段整段删掉后构造真实 Sensor,断言 filters_state() 报 ema 1.0 / median 1 / cutoff 0.0 且 any_stage_applied 为 False。 - Why: 上一版只把"非法值"改成回落到关,但"键根本不写"仍会走 DEFAULT_* 从而把 EMA 0.5 + 中值 3 打开——这与"配置自描述、文件说什么就跑什么、出厂默认全关"矛盾,且现实里存在大量没有 filters 段的手写配置(例如 _perf/cfg_res_280x300.json),它们会在无人察觉的情况下继续滤波。缺省开是这条链上最后一个隐藏默认值。 - Verification: 删掉 filters 段后实测 filters_state() = (1.0, 1, 0.0) 且 any_stage_applied=False,出厂 box/mini/finger 三份同样为全关;pytest tests/test_filter_presets.py + tests/test_calibration.py → 33 passed;SDK 全量 336 passed / 15 skipped(唯一失败仍是需要 1200 帧而样例只有 577 帧的 longrun 测试);app 侧 studio 85 项与 shared 142 项测试、ui_check 554 项检查在升级后的 0.5.2 下全绿。 - Not in this change: 出厂 bundle 的三个显式值未动(本来就全关);_perf 的两个校验脚本不在仓库内,已就地补上显式 filters 段(balanced)以保持"开 vs 关"对照仍有意义;app 侧 wrapper/齿轮/CSV 17 列未动。
2026-09-14 10:53:33 +08:00
ykcheungab
7f8e5d0975
四个滤波预设落成机器可读的配置文件,并加上防漂移测试 - What: 新增 examples/filters/filters_{off,low_latency,balanced,low_noise}.json —— 每个都是完整可整块替换的 filters 段(五键齐全:flow_ema_alpha / force_median_window / force_lowpass_cutoff_hz / force_lowpass_order / force_lowpass_sample_rate_hz),数值即 FILTER_PRESETS 展开后的结果;examples/filters/README.md 说明这四份副本的存在与用途;新增 tests/test_filter_presets.py(12 项):预设名恰为四个、每个示例文件 == 默认块叠加该预设(改预设或改文件都会红)、每份都是含三个开关键的真实 filters 段、三个出厂 bundle(box/mini/finger)的 filters 段仍为全关、且用 external-frame 模式构造真实 Sensor 核对 filters_state() 报的也是全关(文件与设备必须一致)。 - Why: 之前的实现计划里写的是"四个 sensor_<preset>.json 整机配置",但整机配置要按传感器各复制一份、且必然随 bundle 漂移;README 里内嵌的 JSON 又无法被测试覆盖,等于把"建议用哪档滤波"这句话留在了一处会过时的散文里。改成"filters 片段 + 断言与 FILTER_PRESETS 逐值一致的测试",既不谎称是完整配置,也不会静默过时。 - Verification: pytest tests/test_filter_presets.py → 12 passed;SDK 全量 335 passed / 15 skipped(唯一失败仍是需要 1200 帧而样例只有 577 帧的 longrun 测试)。 - Not in this change: 未生成按传感器复制的整机配置;docs/filters.md 的预设表未纳入测试(只有这四个文件与代码常量对齐);app 侧未动。
2026-09-14 10:44:07 +08:00
ykcheungab
35190562e5
标定指纹改读生效值并按测量/读数分组 - What: calibration.py 新增 FILTER_MEASUREMENT_KEYS(flow_ema_alpha)与 FILTER_READOUT_KEYS(中值窗口、低通截止/阶数/采样率/rate_auto)、filters_fingerprint()(把 Sensor.filters_state() 归一化成 {measurement, readout, preset, source}:非法值丢弃、来源没写的键不出现而不是补默认、空映射返回 {} 表示"无记录")、filter_mismatches()(按组判读差异)与 _filters_from_config / _flat_filters_from(扁平旧格式与 preset 展开的兼容解析,显式键优先);pipeline_from_sensor_json() 新增 filters_state= 关键字——传了生效值就用生效值,否则读文件的 filters 段并标注 source="sensor.json.filters",返回结构化 filters 键,删除原先会凭空补出 0.5/3/10 的扁平键与 enabled 覆盖逻辑;Calibration.to_dict() 写 meta.filters(同时保留扁平键供旧读者按名取用);parse() 把 filters 读回 pipeline(此前 to_dict 写进 meta 的滤波键在读回时被整段丢弃,指纹实际是"只写不读");check() 改用 filter_mismatches 分开报告——measurement 组差异进 warnings 且措辞含 not comparable,readout 组差异进新增字段 CheckResult.notes(只记录、不拦截);build(extra_meta=…) 把 filters 与扁平滤波键折进结构化组。tests/test_calibration.py 新增 11 项测试(分组、preset 展开与显式键优先、enabled:false 全关、非法值为空而非默认、写入-读回往返、旧扁平文档读回、生效值压过文件、四个预设逐档核对)。docs/filters.md 新增第 7 节。 - Why: 用户决策 B 要求"Sensor.filters_state() 作为唯一生效值出口,calibration.py 指纹与 session.json 都读它、不读配置文件,指纹分 measurement/readout 两组";动手时确认旧实现三个问题叠加:来源错(读文件、被 filters.enabled 覆盖、文件没写就补默认 0.5/3/10),写进 meta 的指纹在读回时被丢弃,check() 因此永远比不出滤波差异——审计链是断的,不是不精确。 - Verification: SDK 全量 pytest 335 passed / 15 skipped,唯一失败 test_vnormal_longrun_no_outlier_jumps 需要 1200 帧而 data/sample/s1_480p.mp4 只有 577 帧(环境/数据,与本改动无关);external-frame 模式逐预设构造真实 Sensor,filters_fingerprint(filters_state()) 得 off(1.0,1,0.0) / low_latency(1.0,3,0.0) / balanced(0.5,3,0.0) / low_noise(0.3,3,10.0);写入→读回往返后 measurement/readout/preset 完整保留且 to_dict 幂等;旧扁平 meta 文档仍读回同一指纹;.repro/verify_cal_filters.py 50 项全绿。 - Not in this change: 未动 app(app 的 meta_from_sensor_json 只取 4 个键,不受影响);未升级 venv 内 SDK;examples/filters 的四个机器可读预设片段与 app 侧 wrapper/齿轮/CSV 17 列未动。
2026-09-14 10:43:58 +08:00
ykcheungab
514874e2f4
added 5 sensors multi-stream support, 5 finger reach > 100 fps stable using .mp4 video
2026-09-13 12:18:27 +08:00
ykcheungab
5f78115429
fix pypi cannot check after upload
2026-09-12 17:43:40 +08:00
ykcheungab
488c8b0bc1
fixed testpypi upload
2026-09-12 17:34:46 +08:00
ykcheungab
94f38bc389
fix github release
2026-09-12 17:01:35 +08:00
ykcheungab
174bceabc4
automate publishing: release github + release pypi
2026-09-12 16:50:55 +08:00
ykcheungab
388f34ca85
faster linux build
2026-09-12 16:36:59 +08:00
ykcheungab
35af74f639
exclude docs from wheel; harden bundle item handling; single-source version
2026-09-12 16:19:34 +08:00
ykcheungab
57bef85e32
fix preflight
2026-09-12 16:00:40 +08:00
ykcheungab
9537cf91a1
added preflight check
2026-09-12 15:49:28 +08:00
ykcheungab
96f4428230
added calibration data handling functions
2026-09-10 21:47:36 +08:00
ykcheungab
ad680b77dc
0.5.1
2026-09-02 21:47:51 +08:00
ykcheungab
5be2d9759a
hotfix/camera not connected error
2026-09-02 21:37:40 +08:00
ykcheungab
32823a7666
test if optical flow integration error: not significant for Mems
2026-09-01 21:27:10 +08:00
ykcheungab
8a4be5f8f2
update to 0.5.0
2026-08-26 20:20:37 +08:00
ykcheungab
577e3fe528
update pip install .copy manifest for developments
2026-08-26 20:04:40 +08:00