add session browsing, calibration diagnostics and the 2D layout preset
Phase 2 of the review: browse the whole session instead of only the rolling window, diagnose a calibration from the recorded points, and provide the reviewed two-panel layout. What - SessionStore gains extent(), visible(t0, t1, max_points) and statistics(t0, t1, unit). visible() walks only the blocks that overlap the window and decimates by taking each bucket's minimum and maximum, so a spike survives decimation and browsing a long session does not copy all of it. - ForcePlotsPanel gains follow/browse modes, a whole-session overview strip with the current window, pan and wheel zoom, a rubber-band zoom toggle, a shared time cursor across all three channels, and a selection readout (duration, valid samples, per-axis peak/mean/std). - CalibrationPoint records a bounded per-axis trace, an excluded flag, a validation flag and its fit residual. CalibrationRecorder gains set_excluded/set_validation/fit; the fit is a least-squares line over the non-excluded, non-validation points with per-point residuals and an independent validation error. - The calibration table becomes the reviewed diagnostic view (reference load | FN | FX | FY | stability | state) with the residual shown next to the loaded axis, plus exclude/restore and mark-validation actions and a fit summary line. Double clicking a row opens the point's three-axis trace. - Add a layout preset: free layout or 2D mode (depth map on the left, force charts on the right, calibration folded away), persisted in preferences. Why - Browsing is a display pause, not a capture pause: the record channel keeps running while the charts show an older window. - Excluding a point removes it from the fit and from the exported calibration but keeps it on record, so the evidence for the decision is not destroyed. - The non-loaded axes are recorded but never given a reference load: their true load is unknown during a single-axis calibration, so it stays empty. Verification - shared/tests/test_record_channel.py grows to 18 cases, covering extent, peak-preserving decimation, windowed reads, inverted/empty windows, unit-aware statistics and the time origin. - tools/ui_check.py gains "session browsing" and "layout preset" sections (223 checks, 0 failures overall). - apps/studio/tests/test_ui_smoke.py covers the same invariants. Not in this change: synchronised playback of video, depth and curves. It needs a decision on how depth is stored for replay (per-frame PNG, reduced-rate PNG, or offline recomputation); the cursor plumbing (cursor_moved / set_cursor) is already in place for it.
This commit is contained in:
@@ -102,7 +102,24 @@
|
||||
"fn": "FN",
|
||||
"fx": "FX",
|
||||
"fy": "FY",
|
||||
"no_data": "—"
|
||||
"no_data": "—",
|
||||
"mode_follow": "Following live",
|
||||
"mode_browse": "Browsing history (display paused; capture and recording continue)",
|
||||
"return_latest": "Back to latest",
|
||||
"return_latest_tip": "Leave history browsing and follow the newest data again",
|
||||
"overview": "Whole session",
|
||||
"overview_tip": "Fit the entire session; drag the overview strip to move the window",
|
||||
"box_zoom": "Box zoom",
|
||||
"box_zoom_tip": "Switch to rubber-band zoom (drag a region on the chart)",
|
||||
"selection": "Selection {duration}s / {samples} samples — {detail}",
|
||||
"selection_empty": "No valid samples in the selection",
|
||||
"browse_only_tip": "Drag or scroll on the chart to browse history"
|
||||
},
|
||||
"layout": {
|
||||
"default": "Free layout",
|
||||
"preset_2d_name": "2D mode (depth + charts)",
|
||||
"preset_2d": "2D mode: depth map on the left, force charts on the right, one shared time axis",
|
||||
"preset_default": "Free layout restored"
|
||||
},
|
||||
"record": {
|
||||
"label": "Record",
|
||||
@@ -135,10 +152,40 @@
|
||||
"sn_placeholder": "Serial number (optional)",
|
||||
"live_raw_label": "Live raw",
|
||||
"live_raw": "Live raw FN={fn} FX={fx} FY={fy}",
|
||||
"col_weight": "Weight (N)",
|
||||
"col_weight": "Reference load",
|
||||
"col_fn": "FN mean",
|
||||
"col_fx": "FX mean",
|
||||
"col_fy": "FY mean",
|
||||
"col_stability": "Stability",
|
||||
"col_state": "State",
|
||||
"col_raw": "Raw mean",
|
||||
"col_n": "n",
|
||||
"col_std": "σ",
|
||||
"state_ok": "OK",
|
||||
"state_excluded": "Excluded",
|
||||
"state_validation": "Validation",
|
||||
"state_exclude": "Exclude",
|
||||
"state_exclude_tip": "Drop the selected point from the fit and the export (kept on record, reversible)",
|
||||
"state_restore": "Restore",
|
||||
"mark_validation": "Mark validation",
|
||||
"mark_validation_tip": "Hold the selected point out of the fit and use it to test the fit",
|
||||
"excluded": "Point excluded from the fit",
|
||||
"restored": "Point restored",
|
||||
"marked_validation": "Point marked as a validation point",
|
||||
"unmarked_validation": "Validation mark removed",
|
||||
"fit_insufficient": "A fit needs at least 2 usable points (currently {count})",
|
||||
"fit_summary": "Fit {channel}: N = {gain} × raw + {offset} ({count} points, max residual {residual} N)",
|
||||
"fit_validation": "Independent validation on {count} point(s), max deviation {error} N",
|
||||
"point_title": "Calibration point {channel} @ {load} N",
|
||||
"point_channel": "Loaded axis",
|
||||
"point_direction": "Direction",
|
||||
"point_round": "Round",
|
||||
"point_duration": "Actual sampling time",
|
||||
"point_duration_value": "{actual} s (requested {requested} s)",
|
||||
"point_samples": "Samples",
|
||||
"point_samples_value": "{valid} valid / {total} total",
|
||||
"point_axes": "Three-axis mean ± std",
|
||||
"point_residual": "Fit residual",
|
||||
"col_actions": "",
|
||||
"recording": "Recording calibration samples…",
|
||||
"recording_stop_tip": "Click to cancel this calibration recording (always available)",
|
||||
|
||||
@@ -102,10 +102,26 @@
|
||||
"fn": "FN",
|
||||
"fx": "FX",
|
||||
"fy": "FY",
|
||||
"no_data": "—"
|
||||
"no_data": "—",
|
||||
"mode_follow": "跟随实时",
|
||||
"mode_browse": "浏览历史(显示暂停,采集与记录继续)",
|
||||
"return_latest": "返回最新",
|
||||
"return_latest_tip": "退出历史浏览,恢复跟随最新数据",
|
||||
"overview": "全程总览",
|
||||
"overview_tip": "把整个会话缩放到一屏;拖动下方总览条可移动视窗",
|
||||
"box_zoom": "框选",
|
||||
"box_zoom_tip": "切换为框选放大(拖动图表框选区域)",
|
||||
"selection": "选区 {duration}s / {samples} 点 — {detail}",
|
||||
"selection_empty": "选区无有效样本",
|
||||
"browse_only_tip": "拖动或滚轮即可进入历史浏览"
|
||||
},
|
||||
"record": {
|
||||
"label": "记录",
|
||||
"layout": {
|
||||
"default": "自由布局",
|
||||
"preset_2d_name": "二维模式(深度图 + 曲线)",
|
||||
"preset_2d": "已切换到二维模式:左侧深度图、右侧三轴曲线,共用时间轴",
|
||||
"preset_default": "已恢复自由布局"
|
||||
},
|
||||
"record": { "label": "记录",
|
||||
"mode_video_data": "视频 + 数据",
|
||||
"mode_data_only": "仅数据",
|
||||
"mode_tip": "视频记录的是处理前的相机输入图像(不含箭头与文字叠加)。MP4 是有损封装,不等于无损原始数据。",
|
||||
@@ -136,10 +152,40 @@
|
||||
"sn_placeholder": "序列号(可选)",
|
||||
"live_raw_label": "实时原始值",
|
||||
"live_raw": "实时原始值 FN={fn} FX={fx} FY={fy}",
|
||||
"col_weight": "重量 (N)",
|
||||
"col_weight": "参考载荷",
|
||||
"col_fn": "FN 均值",
|
||||
"col_fx": "FX 均值",
|
||||
"col_fy": "FY 均值",
|
||||
"col_stability": "稳定性",
|
||||
"col_state": "状态",
|
||||
"col_raw": "原始均值",
|
||||
"col_n": "n",
|
||||
"col_std": "σ",
|
||||
"state_ok": "正常",
|
||||
"state_excluded": "已排除",
|
||||
"state_validation": "验证点",
|
||||
"state_exclude": "排除",
|
||||
"state_exclude_tip": "把选中点排除出拟合与导出(记录保留,可恢复)",
|
||||
"state_restore": "恢复",
|
||||
"mark_validation": "设为验证点",
|
||||
"mark_validation_tip": "把选中点留作独立验证点:不参与拟合,用于检验拟合",
|
||||
"excluded": "该点已排除出拟合",
|
||||
"restored": "该点已恢复",
|
||||
"marked_validation": "该点已标记为验证点",
|
||||
"unmarked_validation": "该点已取消验证点标记",
|
||||
"fit_insufficient": "拟合需要至少 2 个有效点(当前 {count} 个)",
|
||||
"fit_summary": "拟合 {channel}: N = {gain} × raw + {offset}({count} 点,最大残差 {residual} N)",
|
||||
"fit_validation": "独立验证 {count} 点,最大偏差 {error} N",
|
||||
"point_title": "标定点 {channel} @ {load} N",
|
||||
"point_channel": "加载轴",
|
||||
"point_direction": "方向",
|
||||
"point_round": "轮次",
|
||||
"point_duration": "实际采样时长",
|
||||
"point_duration_value": "{actual} s(请求 {requested} s)",
|
||||
"point_samples": "样本数",
|
||||
"point_samples_value": "有效 {valid} / 共 {total}",
|
||||
"point_axes": "三轴均值 ± 标准差",
|
||||
"point_residual": "拟合残差",
|
||||
"col_actions": "",
|
||||
"recording": "正在采集标定样本…",
|
||||
"recording_stop_tip": "点击可取消本次标定采集(随时可用)",
|
||||
|
||||
Reference in New Issue
Block a user