统一力值阈值处理并保留原始采样

移除自动显示基线,使逐轴阈值统一作用于曲线、读数与记录输出,标定拟合继续使用原始采样。
共享层全量测试和相关 Studio 测试通过。
This commit is contained in:
ykcheungab
2026-10-07 12:25:12 +08:00
parent 6194778a6f
commit 86996694b4
27 changed files with 507 additions and 1512 deletions
+35 -41
View File
@@ -634,6 +634,8 @@ def test_unit_switch_rebuilds_from_the_session_store(make_window):
import math
window, stuck = _running_window(make_window)
window.recording.set_force_thresholds(raw=0.0, newton=0.0)
window.force_plots.set_deadband_floors(raw=0.0, newton=0.0)
window.toolbar.units_combo.setCurrentIndex(1) # raw
window.force_plots.reset()
for index in range(60):
@@ -1700,7 +1702,7 @@ def test_the_replay_view_loads_a_recording_and_scrubs_it(make_window, replay_rec
window.brand_bar.btn_playback.click()
QApplication.processEvents()
assert window._load_recording(replay_recording)
assert window.replay_ctl.load_recording(replay_recording)
QApplication.processEvents()
panel = window.force_plots
assert panel.is_recording_source(), "the charts did not switch to the recording"
@@ -1787,15 +1789,12 @@ def test_a_late_calibration_does_not_plot_raw_counts_on_the_newton_axis(make_win
# The sample that caused the switch still reaches the readouts; the early
# return used to leave the cards showing the previous sample. The number on
# the card is the *display* copy of it: this fake FN is a slow 2.0…2.4 N ramp
# with no contact flagged, which is exactly the resting drift the display
# baseline holds at zero. What matters here is that the card is not a raw
# count, not the previous sample and not a dash.
# the card uses the newton sample, with only the configured absolute threshold.
assert abs(plots._last_values[0] - (2.0 + 39 * 0.01)) < 1e-9
assert plots.presentation.display_quality != "none", (
assert plots.presentation.display_quality == "threshold", (
"the display policy was not applied to the freshly shown newton unit"
)
assert plots.value_labels[0].text() == "0.000", plots.value_labels[0].text()
assert plots.value_labels[0].text() == "2.39", plots.value_labels[0].text()
assert plots.value_labels[0].text() != t("chart.value_unavailable")
_finish(window, stuck)
@@ -1940,9 +1939,9 @@ def test_a_replay_keeps_the_2d_pane_from_the_live_camera(
window, stuck = _running_window(make_window)
window.brand_bar.btn_playback.click()
QApplication.processEvents()
assert window._load_recording(replay_recording), "the replay could not open it"
assert window.replay_ctl.load_recording(replay_recording), "the replay could not open it"
QApplication.processEvents()
assert window._replay_owns_image(), "the replay does not own the 2D pane"
assert window.replay_ctl.owns_image(), "the replay does not own the 2D pane"
label = window.arrow_panel.image_label
# Park the playhead at the end of the recording and remember what the pane and
@@ -1971,7 +1970,7 @@ def test_a_replay_keeps_the_2d_pane_from_the_live_camera(
# meaningful rather than a dead pane.
window.brand_bar.btn_live.click()
QApplication.processEvents()
assert not window._replay_owns_image()
assert not window.replay_ctl.owns_image()
stuck.emit(ui_check._fake_packet(9, mono_t=9 / 30.0, frame=live))
window._on_run_tick()
QApplication.processEvents()
@@ -1993,7 +1992,7 @@ def test_the_readout_describes_the_point_the_cursor_is_on(
window = _show(make_window(), (1440, 880))
window.brand_bar.btn_playback.click()
QApplication.processEvents()
assert window._load_recording(replay_recording)
assert window.replay_ctl.load_recording(replay_recording)
QApplication.processEvents()
plots = window.force_plots
assert plots.mode() == "browse", "opening a recording did not browse it"
@@ -2028,7 +2027,7 @@ def test_a_raw_only_recording_is_never_shown_in_newton(make_window, replay_recor
QApplication.processEvents()
window.brand_bar.btn_playback.click()
QApplication.processEvents()
assert window._load_recording(replay_recording)
assert window.replay_ctl.load_recording(replay_recording)
QApplication.processEvents()
panel = window.force_plots
@@ -2051,7 +2050,7 @@ def test_the_replay_transport_plays_and_pauses(make_window, replay_recording):
window = _show(make_window(), (1440, 880))
window.brand_bar.btn_playback.click()
QApplication.processEvents()
assert window._load_recording(replay_recording)
assert window.replay_ctl.load_recording(replay_recording)
QApplication.processEvents()
panel = window.force_plots
@@ -2091,7 +2090,7 @@ def test_the_recompute_switch_asks_for_analysis_not_an_acquire_chain(
window = _show(make_window(), (1440, 880))
window.brand_bar.btn_playback.click()
QApplication.processEvents()
assert window._load_recording(replay_recording)
assert window.replay_ctl.load_recording(replay_recording)
QApplication.processEvents()
panel = window.force_plots
assert panel.is_recording_source(), "the charts do not read the recording"
@@ -2140,7 +2139,7 @@ def test_the_replay_view_offers_a_stop_that_always_works(make_window, replay_rec
window = _show(make_window(), (1440, 880))
window.brand_bar.btn_playback.click()
QApplication.processEvents()
assert window._load_recording(replay_recording)
assert window.replay_ctl.load_recording(replay_recording)
QApplication.processEvents()
assert window.toolbar.btn_reset.isEnabled(), (
@@ -2197,7 +2196,7 @@ def test_escape_stops_the_replay_too(make_window, replay_recording):
window = _show(make_window(), (1440, 880))
window.brand_bar.btn_playback.click()
QApplication.processEvents()
assert window._load_recording(replay_recording)
assert window.replay_ctl.load_recording(replay_recording)
QApplication.processEvents()
window.toolbar.btn_run.setChecked(True)
QApplication.processEvents()
@@ -2252,7 +2251,7 @@ def test_the_replay_reset_is_the_display_reset_and_never_the_device(
window._finger_worker = stuck
window.brand_bar.btn_playback.click()
QApplication.processEvents()
assert window._load_recording(replay_recording)
assert window.replay_ctl.load_recording(replay_recording)
QApplication.processEvents()
assert window.toolbar.reset_target() == "display"
@@ -2298,9 +2297,8 @@ def test_the_replay_reset_is_the_display_reset_and_never_the_device(
window.close()
def test_the_live_reset_zeroes_the_device_and_restarts_the_display_baseline(make_window):
"""The live half of the same control: the device is asked, and the tip's side
effect (the display baseline restarting) really happens."""
def test_the_live_reset_zeroes_the_device_without_changing_threshold(make_window):
"""The device reset must not erase or re-estimate the configured threshold."""
from orisys_app_shared.i18n import t
from PySide6.QtWidgets import QApplication
@@ -2322,14 +2320,11 @@ def test_the_live_reset_zeroes_the_device_and_restarts_the_display_baseline(make
assert window.toolbar.btn_reset.isEnabled()
assert window.toolbar.btn_reset.text() == t("toolbar.reset_sensor")
assert window.toolbar.btn_reset.toolTip() == t("toolbar.reset_sensor_tip")
restarts: list = []
window.force_plots.request_presentation_reestimate = lambda: restarts.append(True)
threshold = window.force_plots.presentation.min_deadband_for("raw")
window.toolbar.btn_reset.click()
assert stuck.reset_requests == 1, "the live reset did not reach the device"
assert restarts == [True], (
"the display baseline was not restarted with the zero (the tooltip's side effect)"
)
assert window.force_plots.presentation.min_deadband_for("raw") == threshold
assert window.statusBar().currentMessage() == t("status.reset_pending"), (
window.statusBar().currentMessage()
)
@@ -2460,7 +2455,7 @@ def test_a_bare_video_plays_even_though_it_is_not_a_recording(
window.brand_bar.btn_playback.click()
QApplication.processEvents()
assert not window.replay.has_video()
assert window._load_replay_video(bare) is True, "a playable video was refused"
assert window.replay_ctl.load_video(bare) is True, "a playable video was refused"
QApplication.processEvents()
assert window.replay.has_video(), "nothing is playable"
assert window.replay.is_video_only(), "a bare video was taken for a recording"
@@ -2534,8 +2529,8 @@ def test_the_replay_and_the_live_paths_share_one_image_backend(
app_module.render_image = spy
try:
window.layout_ctl.apply_preset("replay")
assert window._load_replay_video(bare) is True
window._render_replay_frame()
assert window.replay_ctl.load_video(bare) is True
window.replay_ctl.render_frame()
QApplication.processEvents()
assert window.arrow_panel.plan_modes() == ("recorded",), (
"a recording must not offer a derived view"
@@ -2623,7 +2618,7 @@ def test_the_replay_entries_exist_only_in_the_replay_view(
assert not window.toolbar.btn_recompute.isEnabled()
# Programmatic use is refused too, and leaves nothing half-changed.
assert window._load_replay_video(bare) is False
assert window.replay_ctl.load_video(bare) is False
QApplication.processEvents()
assert not window.replay.has_video()
assert window.toolbar.source_mode() == "camera"
@@ -2637,7 +2632,7 @@ def test_the_replay_entries_exist_only_in_the_replay_view(
QApplication.processEvents()
for action in (window.act_open_video, window.act_playback, window.act_playback_latest):
assert action.isEnabled()
assert window._load_replay_video(bare) is True
assert window.replay_ctl.load_video(bare) is True
QApplication.processEvents()
assert window.arrow_panel.plan_modes() == ("recorded",)
assert window.toolbar.btn_recompute.isEnabled(), (
@@ -2670,7 +2665,7 @@ def test_a_file_that_is_not_a_video_at_all_is_refused_with_a_reason(
try:
window.brand_bar.btn_playback.click()
QApplication.processEvents()
assert window._load_replay_video(broken) is False, (
assert window.replay_ctl.load_video(broken) is False, (
"a file that cannot be decoded was accepted for playback"
)
QApplication.processEvents()
@@ -2700,7 +2695,7 @@ def test_a_video_inside_a_recording_opens_the_recording_and_plays(
QApplication.processEvents()
segments = sorted(Path(replay_recording).glob("raw_*.mp4"))
assert segments, "the fixture wrote no video segment"
assert window._load_replay_video(segments[0]) is True
assert window.replay_ctl.load_video(segments[0]) is True
QApplication.processEvents()
assert window.replay.is_loaded()
assert window.toolbar.btn_run.isEnabled(), "the transport is not offered"
@@ -2736,11 +2731,11 @@ def test_a_recording_without_a_video_says_it_cannot_be_played(make_window, recor
window = _show(make_window(), (1440, 880))
window.brand_bar.btn_playback.click()
QApplication.processEvents()
if not window._load_recording(directory):
if not window.replay_ctl.load_recording(directory):
pytest.skip("this recording layout was refused before it could be played")
QApplication.processEvents()
assert window.replay.duration_s() <= 0.0
window._start_playback()
window.replay_ctl.start_playback()
QApplication.processEvents()
assert not window._play_timer.isActive()
assert t("playback.empty_recording")[:8] in window.statusBar().currentMessage(), (
@@ -2784,7 +2779,7 @@ def test_a_selection_moves_its_statistics_onto_the_value_cards(make_window):
), summary
# The numbers a reader cannot fit in the strip are on the cards instead.
expected_peak = float(plots._selection.peaks[0])
expected = f"{expected_peak:.3f}"
expected = f"{expected_peak:.2f}"
assert plots.value_labels[0].text() == expected, (
f"the FN card is not the selection's peak: {plots.value_labels[0].text()!r}"
)
@@ -3074,9 +3069,9 @@ def test_the_plot_dialog_carries_the_ranges_and_the_zero_threshold(qt_app):
assert raw.settings()["fn_raw_min"] == 0.0
assert raw.settings()["fn_min"] == 0.0
assert raw.settings()["window_sec"] == 4.0
assert raw.deadbands() == {"deadband_n": 0.0, "deadband_raw": 0.0}, (
"the shipped deadband answer is 'auto'"
)
assert raw.deadbands() == {"deadband_n": 0.0, "deadband_raw": 50.0}
assert raw.settings()["newton_decimals"] == 2
assert raw.settings()["raw_decimals"] == 0
def test_the_plot_dialog_values_reach_the_chart(make_window):
@@ -3113,12 +3108,11 @@ def test_the_plot_dialog_values_reach_the_chart(make_window):
window.close()
def test_the_display_baseline_is_on_for_every_sensor_by_default(make_window):
"""It used to be Finger-raw only; an idle box sensor drifts just as much."""
def test_force_threshold_is_on_for_every_sensor_by_default(make_window):
window, stuck = _running_window(make_window) # sensor_type="box"
plots = window.force_plots
assert plots._presentation_enabled is True, "a box sensor lost its baseline"
assert plots._presentation_enabled is True
assert plots.presentation.enabled is True
# The per-unit floors came from the preferences, not from a sensor type.
assert plots.presentation.min_deadband_for("raw") == 50.0