88 lines
2.8 KiB
Python
88 lines
2.8 KiB
Python
"""Display-only force baseline / deadband (value cards)."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import numpy as np
|
|
|
|
from orisys_app_shared.force.presentation import ForcePresentation, ZeroEstimate
|
|
|
|
|
|
def test_fit_zero_rejects_insufficient_samples() -> None:
|
|
presentation = ForcePresentation(enabled=True, min_samples=30)
|
|
estimate = presentation.fit_zero([(1.0, 2.0, 3.0), (1.1, 2.1, 3.1)])
|
|
assert estimate.quality == "insufficient"
|
|
|
|
|
|
def test_fit_zero_and_accept_deadband() -> None:
|
|
rng = np.random.default_rng(0)
|
|
bias = np.array([1262.0, -11.0, -353.0])
|
|
noise = rng.normal(0.0, 20.0, size=(80, 3))
|
|
samples = (bias + noise).tolist()
|
|
presentation = ForcePresentation(
|
|
enabled=True,
|
|
min_samples=30,
|
|
baseline_seconds=0.0,
|
|
min_deadband=50.0,
|
|
deadband_percentile=99.0,
|
|
)
|
|
estimate = presentation.fit_zero(samples)
|
|
assert estimate.quality == "ok"
|
|
presentation.apply_estimate(estimate)
|
|
idle = presentation.accept(tuple(bias), unit="raw")
|
|
assert idle.zero_zone
|
|
assert idle.values == (0.0, 0.0, 0.0)
|
|
# Curves / CSV keep the measurement: accept never mutates the input tuple.
|
|
measured = (1262.0, -11.0, -353.0)
|
|
presentation.accept(measured, unit="raw")
|
|
assert measured == (1262.0, -11.0, -353.0)
|
|
|
|
|
|
def test_observe_skips_contact_contamination() -> None:
|
|
presentation = ForcePresentation(
|
|
enabled=True,
|
|
min_samples=5,
|
|
baseline_seconds=0.1,
|
|
require_no_contact=True,
|
|
)
|
|
for i in range(10):
|
|
out = presentation.observe(
|
|
(1000.0, 0.0, 0.0),
|
|
t_rel_s=i * 0.05,
|
|
contact_found=True,
|
|
flow_p95=0.1,
|
|
)
|
|
assert out is None
|
|
assert not presentation.ready
|
|
|
|
|
|
def test_observe_freezes_after_quiet_window() -> None:
|
|
presentation = ForcePresentation(
|
|
enabled=True,
|
|
min_samples=10,
|
|
baseline_seconds=0.5,
|
|
min_deadband=10.0,
|
|
)
|
|
estimate: ZeroEstimate | None = None
|
|
for i in range(40):
|
|
estimate = presentation.observe(
|
|
(100.0 + (i % 3), -5.0, 2.0),
|
|
t_rel_s=i * 0.02,
|
|
flow_p95=0.1,
|
|
contact_found=False,
|
|
)
|
|
if estimate is not None:
|
|
break
|
|
assert estimate is not None
|
|
assert estimate.quality == "ok"
|
|
assert presentation.ready
|
|
# Further observes do not chase a new zero once frozen.
|
|
later = presentation.observe((5000.0, 0.0, 0.0), t_rel_s=10.0, flow_p95=0.0)
|
|
assert later is None
|
|
|
|
|
|
def test_format_force_stable_digits() -> None:
|
|
presentation = ForcePresentation(enabled=True)
|
|
assert presentation.format_force(0.0, unit="raw") == "0"
|
|
assert presentation.format_force(1262.4, unit="raw") == "1262"
|
|
assert presentation.format_force(1.2345, unit="N") == "1.234"
|