NODEDC_MISSION_CORE/tests/test_e25_occupancy_motion.py

303 lines
8.8 KiB
Python

from __future__ import annotations
from pathlib import Path
import numpy as np
from k1link.compute.occupancy_motion import (
PersistentSupportTracker,
SupportMeasurement,
_apply_occupancy_evidence,
evaluate_persistent_support_benchmark,
read_persistent_support_benchmark,
read_persistent_support_profile,
)
def _profile() -> dict[str, object]:
root = Path(__file__).resolve().parents[1]
profile, digest = read_persistent_support_profile(
root / "experiments" / "perception" / "e25_persistent_support_profile.json"
)
assert len(digest) == 64
return profile
def _support(x: float, y: float = 2.0) -> np.ndarray:
return np.asarray(
[
[x - 0.2, y - 0.2, 0.4],
[x + 0.2, y - 0.2, 0.5],
[x - 0.2, y + 0.2, 0.6],
[x + 0.2, y + 0.2, 0.7],
],
dtype=np.float64,
)
def test_e25_profile_is_bounded_and_has_no_control_authority() -> None:
profile = _profile()
assert profile["source"]["coordinate_frame"] == "k1-map"
assert profile["bounds"]["maximum_tracks"] == 192
assert profile["occupancy"]["maximum_snapshots_per_track"] == 32
assert profile["authority"] == {
"commands_enabled": False,
"navigation_or_safety_accepted": False,
}
def test_e25_static_support_survives_visible_surface_center_jitter() -> None:
tracker = PersistentSupportTracker(_profile())
evidence = {}
for frame in range(30):
jitter = 0.18 if frame % 2 else -0.18
evidence = tracker.observe(
track_id=250001,
source_track_id=10,
group="vehicle",
session_seconds=frame * 0.1,
points_map=_support(10.0 + jitter),
)
assert evidence["motion_state"] == "static"
assert evidence["occupancy_overlap_fraction"] is not None
assert evidence["occupancy_overlap_fraction"] >= 0.55
def test_e25_coherent_translation_becomes_dynamic() -> None:
tracker = PersistentSupportTracker(_profile())
evidence = {}
for frame in range(20):
evidence = tracker.observe(
track_id=250002,
source_track_id=20,
group="person",
session_seconds=frame * 0.1,
points_map=_support(4.0 + frame * 0.5),
)
assert evidence["motion_state"] == "dynamic"
assert evidence["speed_mps"] is not None
assert evidence["speed_mps"] > 1.0
assert evidence["occupancy_overlap_fraction"] <= 0.25
def test_e25_does_not_claim_motion_without_older_support() -> None:
tracker = PersistentSupportTracker(_profile())
evidence = tracker.observe(
track_id=250003,
source_track_id=30,
group="vehicle",
session_seconds=0.0,
points_map=_support(8.0),
)
assert evidence["motion_state"] == "unknown"
assert evidence["motion_confidence"] == 0.0
def test_e25_current_support_is_not_attached_to_an_e24_held_hypothesis() -> None:
tracker = PersistentSupportTracker(_profile())
measurement = SupportMeasurement(
source_track_id=40,
label="car",
group="vehicle",
score=0.9,
points_map=_support(10.0),
source_indices=np.asarray([1, 2, 3, 4], dtype=np.int64),
)
_apply_occupancy_evidence(
[
{
"track_id": 250040,
"source_track_id": 40,
"temporal_status": "e24-observed",
}
],
{40: measurement},
tracker,
0.0,
)
result = _apply_occupancy_evidence(
[
{
"track_id": 250041,
"source_track_id": 40,
"temporal_status": "e24-observed",
},
{
"track_id": 250040,
"source_track_id": 40,
"temporal_status": "e24-held-prediction",
},
],
{40: measurement},
tracker,
0.1,
)
assert result[0]["occupancy_evidence_current"] is True
assert result[1]["occupancy_evidence_current"] is False
assert tracker.snapshot()["support_observations"] == 2
def test_e25_target_benchmark_cannot_be_satisfied_by_another_object() -> None:
event = {
"id": "target-five",
"kind": "target-motion",
"window_seconds": [10.0, 12.0],
"class_group": "vehicle",
"target_source_track_ids": [5],
"expected_motion": "dynamic",
"minimum_hits": 2,
"minimum_span_seconds": 0.1,
"minimum_coverage_fraction": 0.5,
}
source_rows = [
{
"session_seconds": 10.0 + index * 0.2,
"objects": [
{
"track_id": 5,
"association_group": "vehicle",
}
],
}
for index in range(3)
]
wrong_fusion_rows = [
{
"session_seconds": 10.0 + index * 0.2,
"objects": [
{
"track_id": 250099,
"source_track_id": 99,
"association_group": "vehicle",
"motion_state": "dynamic",
"occupancy_evidence_current": True,
}
],
}
for index in range(3)
]
result = evaluate_persistent_support_benchmark(
source_rows,
wrong_fusion_rows,
{"events": [event]},
)
assert result["passed"] is False
assert result["events"][0]["evidence_observations"] == 0
def test_e25_benchmark_deduplicates_world_hypotheses_for_one_source_object() -> None:
event = {
"id": "target-five",
"kind": "target-motion",
"window_seconds": [10.0, 12.0],
"class_group": "vehicle",
"target_source_track_ids": [5],
"expected_motion": "dynamic",
"minimum_hits": 2,
"minimum_span_seconds": 0.1,
"minimum_coverage_fraction": 0.5,
}
source_rows = [
{
"frame_index": index,
"session_seconds": 10.0 + index * 0.2,
"objects": [{"track_id": 5, "association_group": "vehicle"}],
}
for index in range(3)
]
fusion_rows = [
{
"frame_index": index,
"session_seconds": 10.0 + index * 0.2,
"objects": [
{
"track_id": world_track,
"source_track_id": 5,
"association_group": "vehicle",
"motion_state": "dynamic",
"motion_confidence": 0.8,
"occupancy_cell_count": 4,
"occupancy_support_observations": 6,
"occupancy_evidence_current": True,
}
for world_track in (250005, 250006)
],
}
for index in range(3)
]
result = evaluate_persistent_support_benchmark(
source_rows,
fusion_rows,
{"events": [event]},
)
assert result["events"][0]["coverage_fraction"] == 1.0
assert result["events"][0]["evidence_observations"] == 3
assert result["events"][0]["duplicate_evidence_observations"] == 3
def test_e25_static_control_rejects_excess_false_dynamic_evidence() -> None:
event = {
"id": "parked-vehicles",
"kind": "static-control",
"window_seconds": [20.0, 22.0],
"class_group": "vehicle",
"expected_motion": "static",
"minimum_source_observations": 3,
"minimum_coverage_fraction": 0.5,
"minimum_classified_fraction": 0.5,
"maximum_false_dynamic_fraction": 0.1,
}
source_rows = [
{
"session_seconds": 20.0 + index * 0.2,
"objects": [{"track_id": 7, "association_group": "vehicle"}],
}
for index in range(3)
]
fusion_rows = [
{
"session_seconds": 20.0 + index * 0.2,
"objects": [
{
"track_id": 250007,
"source_track_id": 7,
"association_group": "vehicle",
"motion_state": "dynamic",
"occupancy_evidence_current": True,
}
],
}
for index in range(3)
]
result = evaluate_persistent_support_benchmark(
source_rows,
fusion_rows,
{"events": [event]},
)
assert result["passed"] is False
assert result["events"][0]["false_dynamic_fraction"] == 1.0
def test_e25_benchmark_contract_uses_reviewed_source_track_bindings() -> None:
root = Path(__file__).resolve().parents[1]
benchmark, digest = read_persistent_support_benchmark(
root / "experiments" / "perception" / "e25_motion_benchmark.json"
)
target_events = [event for event in benchmark["events"] if event["kind"] == "target-motion"]
assert len(digest) == 64
assert target_events
assert all(event["target_source_track_ids"] for event in target_events)