ykcheungab 148573934f 采集端统一由 SDK 滤波、显示端不再二次滤波,session.json 记录生效值 - What: sdk_worker/finger_worker 删除硬编码的 sensor.configure(lowpass_cutoff_hz=LOWPASS_CUTOFF_HZ, lowpass_sample_rate_hz=...) —— 它会让界面上的曲线与 CSV 走两条不同的滤波路径;改为在会话打开设备后调用 FilterSettings.apply_to(sensor),并把两件事分别记下来:self._filter_state = effective_filters(sensor)(设备报的**实际**生效值,供界面与记录使用)与 self._filters_unsupported(该 SDK 应用不了的键,老 SDK 必须被看见而不是被吞掉);新增 worker 的 set_filter_settings()/filter_settings()/filter_state()/filters_unsupported() 访问器,start() 时清空上一会话的 filter_state(与 _calibration_version 同样的理由:新会话不能继承旧会话的说法)。finger_worker 保留原有的"runtime 可能拒绝 configure"的容错,但改成记日志并把全部键标为未应用。app_window 新增 _filter_settings()(从 preferences 的 plot_* 键读,空/坏值即"什么都不滤")与 _filter_metadata()(向**正在跑的** worker 要设备实际状态,写成 session.json 的 filters 块:measurement/readout/describe/source,SDK 缺键时附 unsupported_by_sdk);_start_session 在 start() 之前把设置交给 worker。ui/force_plots.py 把 MetricHistory 的 lowpass_cutoff_hz 从 LOWPASS_CUTOFF_HZ 改成 0.0:SDK 已经滤过一遍,且这个 buffer 就是进记录的那个,显示端再滤会让曲线画出 CSV 里根本没有的数据(原来用的还是零相位 filtfilt,非因果)。acquisition/constants.py 删掉 LOWPASS_CUTOFF_HZ("app 在 10 Hz 滤波"这件事不存在了),FORCE_SAMPLE_RATE_HZ 保留。tests/test_force_filters.py 增 3 项:worker 未开设备时 filter_state() 为 {}("没问过"不等于"没在滤")、effective_filters() 对没有 filters_state() 的 SDK 返回 {}、以及对着真实 SDK 的端到端断言(external-frame 构造 box Sensor → apply_to → filters_state 回报 flowEMA(0.5)+median(3)+lowpass(10Hz,order2) → force_triplets 两个 buffer 都在 → 全关也可表达)。apps/studio/tools/ui_check.py 的 _StuckWorker 补上新合约方法(set_filter_settings/filter_settings/filter_state/filters_unsupported),否则窗口一启动就 AttributeError。 - Why: 用户的核心要求是"显示的和记录的必须一致,包括所有滤波",并决定整条链留在 SDK、app 只通过 Sensor.configure 驱动。此前 app 硬编码 10 Hz 低通(SDK 侧)**加上**显示端 filtfilt(app 侧),同一次采集的两份数据经过两条不同的滤波路径;session.json 里的 filter 块也只是照抄常量,说的不是设备在做的事。 - Verification: shared 全量 156 passed(含新增的真实 SDK 端到端断言);studio 85 项测试通过(修好 _StuckWorker 合约后);ui_check 554 项检查、4 个场景 0 失败;编译通过。 - Not in this change: 曲线表头的齿轮按钮与滤波设置对话框(因此现在还只能改 preferences.json 的 plot_* 键来换滤波)、CSV 的 17 列与未滤波第二 buffer、回放界面显示滤波前曲线、发布说明里"默认不再滤波"的措辞。
2026-09-14 11:01:55 +08:00
采集端统一由 SDK 滤波、显示端不再二次滤波,session.json 记录生效值 - What: sdk_worker/finger_worker 删除硬编码的 sensor.configure(lowpass_cutoff_hz=LOWPASS_CUTOFF_HZ, lowpass_sample_rate_hz=...) —— 它会让界面上的曲线与 CSV 走两条不同的滤波路径;改为在会话打开设备后调用 FilterSettings.apply_to(sensor),并把两件事分别记下来:self._filter_state = effective_filters(sensor)(设备报的**实际**生效值,供界面与记录使用)与 self._filters_unsupported(该 SDK 应用不了的键,老 SDK 必须被看见而不是被吞掉);新增 worker 的 set_filter_settings()/filter_settings()/filter_state()/filters_unsupported() 访问器,start() 时清空上一会话的 filter_state(与 _calibration_version 同样的理由:新会话不能继承旧会话的说法)。finger_worker 保留原有的"runtime 可能拒绝 configure"的容错,但改成记日志并把全部键标为未应用。app_window 新增 _filter_settings()(从 preferences 的 plot_* 键读,空/坏值即"什么都不滤")与 _filter_metadata()(向**正在跑的** worker 要设备实际状态,写成 session.json 的 filters 块:measurement/readout/describe/source,SDK 缺键时附 unsupported_by_sdk);_start_session 在 start() 之前把设置交给 worker。ui/force_plots.py 把 MetricHistory 的 lowpass_cutoff_hz 从 LOWPASS_CUTOFF_HZ 改成 0.0:SDK 已经滤过一遍,且这个 buffer 就是进记录的那个,显示端再滤会让曲线画出 CSV 里根本没有的数据(原来用的还是零相位 filtfilt,非因果)。acquisition/constants.py 删掉 LOWPASS_CUTOFF_HZ("app 在 10 Hz 滤波"这件事不存在了),FORCE_SAMPLE_RATE_HZ 保留。tests/test_force_filters.py 增 3 项:worker 未开设备时 filter_state() 为 {}("没问过"不等于"没在滤")、effective_filters() 对没有 filters_state() 的 SDK 返回 {}、以及对着真实 SDK 的端到端断言(external-frame 构造 box Sensor → apply_to → filters_state 回报 flowEMA(0.5)+median(3)+lowpass(10Hz,order2) → force_triplets 两个 buffer 都在 → 全关也可表达)。apps/studio/tools/ui_check.py 的 _StuckWorker 补上新合约方法(set_filter_settings/filter_settings/filter_state/filters_unsupported),否则窗口一启动就 AttributeError。 - Why: 用户的核心要求是"显示的和记录的必须一致,包括所有滤波",并决定整条链留在 SDK、app 只通过 Sensor.configure 驱动。此前 app 硬编码 10 Hz 低通(SDK 侧)**加上**显示端 filtfilt(app 侧),同一次采集的两份数据经过两条不同的滤波路径;session.json 里的 filter 块也只是照抄常量,说的不是设备在做的事。 - Verification: shared 全量 156 passed(含新增的真实 SDK 端到端断言);studio 85 项测试通过(修好 _StuckWorker 合约后);ui_check 554 项检查、4 个场景 0 失败;编译通过。 - Not in this change: 曲线表头的齿轮按钮与滤波设置对话框(因此现在还只能改 preferences.json 的 plot_* 键来换滤波)、CSV 的 17 列与未滤波第二 buffer、回放界面显示滤波前曲线、发布说明里"默认不再滤波"的措辞。
2026-09-14 11:01:55 +08:00
2026-09-12 14:03:00 +08:00
采集端统一由 SDK 滤波、显示端不再二次滤波,session.json 记录生效值 - What: sdk_worker/finger_worker 删除硬编码的 sensor.configure(lowpass_cutoff_hz=LOWPASS_CUTOFF_HZ, lowpass_sample_rate_hz=...) —— 它会让界面上的曲线与 CSV 走两条不同的滤波路径;改为在会话打开设备后调用 FilterSettings.apply_to(sensor),并把两件事分别记下来:self._filter_state = effective_filters(sensor)(设备报的**实际**生效值,供界面与记录使用)与 self._filters_unsupported(该 SDK 应用不了的键,老 SDK 必须被看见而不是被吞掉);新增 worker 的 set_filter_settings()/filter_settings()/filter_state()/filters_unsupported() 访问器,start() 时清空上一会话的 filter_state(与 _calibration_version 同样的理由:新会话不能继承旧会话的说法)。finger_worker 保留原有的"runtime 可能拒绝 configure"的容错,但改成记日志并把全部键标为未应用。app_window 新增 _filter_settings()(从 preferences 的 plot_* 键读,空/坏值即"什么都不滤")与 _filter_metadata()(向**正在跑的** worker 要设备实际状态,写成 session.json 的 filters 块:measurement/readout/describe/source,SDK 缺键时附 unsupported_by_sdk);_start_session 在 start() 之前把设置交给 worker。ui/force_plots.py 把 MetricHistory 的 lowpass_cutoff_hz 从 LOWPASS_CUTOFF_HZ 改成 0.0:SDK 已经滤过一遍,且这个 buffer 就是进记录的那个,显示端再滤会让曲线画出 CSV 里根本没有的数据(原来用的还是零相位 filtfilt,非因果)。acquisition/constants.py 删掉 LOWPASS_CUTOFF_HZ("app 在 10 Hz 滤波"这件事不存在了),FORCE_SAMPLE_RATE_HZ 保留。tests/test_force_filters.py 增 3 项:worker 未开设备时 filter_state() 为 {}("没问过"不等于"没在滤")、effective_filters() 对没有 filters_state() 的 SDK 返回 {}、以及对着真实 SDK 的端到端断言(external-frame 构造 box Sensor → apply_to → filters_state 回报 flowEMA(0.5)+median(3)+lowpass(10Hz,order2) → force_triplets 两个 buffer 都在 → 全关也可表达)。apps/studio/tools/ui_check.py 的 _StuckWorker 补上新合约方法(set_filter_settings/filter_settings/filter_state/filters_unsupported),否则窗口一启动就 AttributeError。 - Why: 用户的核心要求是"显示的和记录的必须一致,包括所有滤波",并决定整条链留在 SDK、app 只通过 Sensor.configure 驱动。此前 app 硬编码 10 Hz 低通(SDK 侧)**加上**显示端 filtfilt(app 侧),同一次采集的两份数据经过两条不同的滤波路径;session.json 里的 filter 块也只是照抄常量,说的不是设备在做的事。 - Verification: shared 全量 156 passed(含新增的真实 SDK 端到端断言);studio 85 项测试通过(修好 _StuckWorker 合约后);ui_check 554 项检查、4 个场景 0 失败;编译通过。 - Not in this change: 曲线表头的齿轮按钮与滤波设置对话框(因此现在还只能改 preferences.json 的 plot_* 键来换滤波)、CSV 的 17 列与未滤波第二 buffer、回放界面显示滤波前曲线、发布说明里"默认不再滤波"的措辞。
2026-09-14 11:01:55 +08:00
2026-09-12 14:03:00 +08:00

orisys-app

Desktop applications that consume the Orisys SDK.

App Status
apps/studio Scaffold shell (theme / locale / prefs / logging)
apps/internal Stub for future calibration & automated testing

Layout

  • shared/ — common paths, prefs, theme, i18n, logging
  • apps/studio/config/ — locales, default prefs, editable sensors/ copies
  • apps/studio/outputs/ — generated logs and calibration exports (gitignored)
  • build/ — Windows PyInstaller packaging (build/studio/build.ps1)

Run (studio shell)

cd D:\repo\orisys-app
python -m pip install -e .\shared -e .\apps\studio
python .\apps\studio\run.py

Or without install:

$env:PYTHONPATH = "D:\repo\orisys-app\shared\src;D:\repo\orisys-app\apps\studio\src"
python D:\repo\orisys-app\apps\studio\run.py

Local orisys SDK

orisys_app_shared.force imports orisys.calibration at module scope, so the studio app cannot start against an SDK build that predates that module (the published 0.5.2 wheel does not include it). When working from a repo checkout, install the SDK from source instead of from an index:

python -m pip install .\..\orisys-sdk          # same checkout that built this app

If a pip build is blocked by the environment, the equivalent manual install is to copy orisys-sdk/src/orisys/**/*.py over site-packages/orisys/ and delete the stale __init__.cp310-win_amd64.pyd (an extension module shadows the package __init__.py, which hides sibling modules such as calibration.py).

Verifying UI changes

Both tools render the real main window with the offscreen Qt platform — no display, camera or sensor hardware required:

python .\apps\studio\tools\ui_check.py                      # layout/theme assertions
python .\apps\studio\tools\ui_snapshot.py --theme light --demo `
    --sensor finger --panels cal,3d --size 1600x900 --out shot.png

ui_check.py needs only the runtime dependencies. The pytest suite in shared/tests and apps/studio/tests covers the same ground plus locale and preference-schema parity:

pip install pytest
python -m pytest

On Windows the offscreen platform finds no fonts unless QT_QPA_FONTDIR points at C:\Windows\Fonts; both tools set it automatically.

ui_check.py also runs the palette rules (WCAG contrast, colour separation, ramp monotonicity) that guard the brand tokens; see apps/studio/docs/ui-palette.md for the colour system, its relationship to the UI design spec, and every deliberate deviation from it.

ui_check.py includes a record channel section as well; see apps/studio/docs/record-channel.md for why recording and calibration sampling no longer hang off the UI refresh timer, and for the data-reliability fixes that came with it.

Branding

Window / EXE icon: shared/resources/branding/logo.png
Top bar / About: shared/resources/branding/logo_topbar.png

Dark mode is the default. Logos currently sit on a black tile; a transparent (or light) variant may be needed for polished light mode later.

Versioning

  • Studio app version (orisys_studio.__version__) — shown in Help → About and used for releases.
  • Shared package version (orisys_app_shared.__version__) — internal library version.
  • Shared API (orisys_app_shared.API_VERSION) — compatibility tag. Studio declares REQUIRES_SHARED_API; startup logs a warning on mismatch.

Deferred

Run/Stop pipeline, arrow/force plots, units, calibration capture, Open3D finger mesh, sync-from-wheel for config/sensors, PyInstaller packaging, and the internal app.

S
Description
No description provided
Readme 68 MiB
Languages
Python 84.8%
HTML 11.7%
C 2.6%
PowerShell 0.8%
FreeBASIC 0.1%