Spaces:
Sleeping
Sleeping
File size: 3,328 Bytes
78738de | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | """Test phần TOÁN THUẦN của poolcoach_cv.resim (lát A2 phần 2) — chạy
trên venv app KHÔNG pooltool thật (conftest stub): mọi test ở đây chỉ đụng
sample_traj / rmse_mm / align_t0 / các đường ra sớm của resim_result.
Pipeline pooltool thật nghiệm thu bằng probe tự-nhất-quán trên venv CV
(sim → lấy chính sim làm quan sát → RMSE 0.0mm, 13/08) + rerun rack_a1.
"""
from __future__ import annotations
import numpy as np
import pytest
from poolcoach_cv import resim as rs
def test_sample_traj_noi_suy_va_kep_hai_dau():
sim_t = np.array([0.0, 1.0, 2.0])
sim_xy = np.array([[0.0, 0.0], [1.0, 0.0], [1.0, 1.0]])
out = rs.sample_traj(sim_t, sim_xy, np.array([-0.5, 0.5, 1.5, 9.0]))
assert out == pytest.approx(np.array(
[[0.0, 0.0], # trước t=0 — kẹp điểm đầu (bi chưa đánh)
[0.5, 0.0], # nội suy tuyến tính
[1.0, 0.5],
[1.0, 1.0]])) # sau khi sim dừng — kẹp điểm cuối (lệch là thật)
def test_rmse_mm():
obs = np.array([[0.0, 0.0], [1.0, 0.0]])
sim = np.array([[0.0, 0.003], [1.0, -0.004]])
assert rs.rmse_mm(obs, sim) == pytest.approx(
np.sqrt((3.0 ** 2 + 4.0 ** 2) / 2))
def test_align_t0_chon_dung_nac_lech():
"""Quan sát = chính quỹ đạo sim dịch sớm 1 bước frame (motion_start
trễ sau cú chạm) — lưới dò phải chọn Δ ≈ dt và RMSE về ~0."""
dt = 1 / 30.0
sim_t = np.arange(0.0, 2.0, 0.01)
sim_xy = np.stack([0.3 + 1.5 * sim_t, 0.4 + 0.9 * sim_t], axis=1)
ms = 0.5
true_t0 = ms - dt # cú chạm sớm hơn motion_start 1 frame
obs_t = np.arange(ms, 1.8, dt)
obs_xy = rs.sample_traj(sim_t, sim_xy, obs_t - true_t0)
t0, delta, err = rs.align_t0(obs_t, obs_xy, sim_t, sim_xy, ms, dt)
assert delta == pytest.approx(dt, abs=dt / rs.ALIGN_STEPS + 1e-9)
assert err < 2.0 # mm — lưới dò hữu hạn, không đòi 0 tuyệt đối
assert t0 == pytest.approx(ms - delta)
def test_resim_result_khong_motion_start_ra_error_ca_hai_bo():
out = rs.resim_result({"metrics": {"motion_start_s": None},
"track": [], "shotnet": None}, state={})
assert set(out["sets"]) == {"shotnet", "analytic"}
for blk in out["sets"].values():
assert "motion_start" in blk["error"]
assert "rmse_mm" not in blk
assert out["table_w_m"] == 1.27 and out["table_l_m"] == 2.54
def test_resim_result_track_thieu_ra_error():
out = rs.resim_result(
{"metrics": {"motion_start_s": 0.5},
"track": [{"t_s": 0.6, "x_m": 0.5, "y_m": 0.5}]}, state={})
for blk in out["sets"].values():
assert "track" in blk["error"]
def test_obs_arrays_cue_nghi_la_median_truoc_motion_start():
res = {"metrics": {"motion_start_s": 0.5},
"track": [{"t_s": 0.1, "x_m": 0.60, "y_m": 0.70},
{"t_s": 0.2, "x_m": 0.62, "y_m": 0.70},
{"t_s": 0.3, "x_m": 0.61, "y_m": 0.72},
{"t_s": 0.6, "x_m": 0.80, "y_m": 0.90},
{"t_s": 0.7, "x_m": 0.90, "y_m": 1.00}]}
obs_t, obs_xy, cue0 = rs._obs_arrays(res)
assert list(obs_t) == [0.6, 0.7]
assert cue0 == pytest.approx([0.61, 0.70])
|