Files
NODEDC_MISSION_CORE/tests/test_e45_binding_sensitivity.py
T

117 lines
2.9 KiB
Python

from __future__ import annotations
import math
import pytest
from k1link.compute.e45_binding_sensitivity import (
E45_ROW_SCHEMA,
E45BindingSensitivityError,
E45BindingSensitivityProfile,
analyze_binding_sensitivity,
)
def _row(
item_id: str,
*,
radius: float,
speed: float,
angular: float,
lidar_age: float,
pose_age: float,
residual: float,
points: int,
) -> dict[str, object]:
age_seconds = (lidar_age + pose_age) / 1000.0
return {
"schema_version": E45_ROW_SCHEMA,
"item_id": item_id,
"image_radius_normalized": radius,
"translation_speed_mps": speed,
"angular_speed_deg_s": angular,
"lidar_camera_age_ms": lidar_age,
"pose_point_age_ms": pose_age,
"motion_exposure_translation_m": speed * age_seconds,
"motion_exposure_rotation_deg": angular * age_seconds,
"centroid_residual_bbox_diagonal": residual,
"occupied_points_in_bbox": points,
"supported": points >= 2,
}
def test_e45_stratifies_existing_diagnostic_residual_without_target_claim() -> None:
rows = [
_row(
"one",
radius=0.2,
speed=0.0,
angular=0.0,
lidar_age=5.0,
pose_age=2.0,
residual=0.1,
points=5,
),
_row(
"two",
radius=0.7,
speed=0.5,
angular=6.0,
lidar_age=40.0,
pose_age=15.0,
residual=0.2,
points=8,
),
_row(
"three",
radius=1.0,
speed=2.0,
angular=20.0,
lidar_age=80.0,
pose_age=35.0,
residual=0.4,
points=12,
),
]
analysis = analyze_binding_sensitivity(rows)
assert analysis["correspondence_count"] == 3
assert analysis["supported_fraction"] == 1.0
assert [
item["count"] for item in analysis["strata"]["image_radius"]
] == [1, 1, 1]
assert math.isclose(
analysis["spearman_residual_correlation"][
"image_radius_normalized"
],
1.0,
)
assert (
analysis["measured_calibration_target_residual_available"] is False
)
assert analysis["physical_mount_inferred"] is False
def test_e45_rejects_missing_support_in_accepted_correspondence() -> None:
rows = [
_row(
"one",
radius=0.2,
speed=0.0,
angular=0.0,
lidar_age=5.0,
pose_age=2.0,
residual=0.1,
points=1,
)
]
with pytest.raises(E45BindingSensitivityError, match="supported"):
analyze_binding_sensitivity(rows)
def test_e45_profile_rejects_overlapping_or_reversed_edges() -> None:
with pytest.raises(E45BindingSensitivityError):
E45BindingSensitivityProfile(image_radius_edges=(0.8, 0.4))