feat(perception): qualify world-frame motion tracking

This commit is contained in:
DCCONSTRUCTIONS
2026-07-24 11:17:10 +03:00
parent 23181c867b
commit e6dd8c2cf1
8 changed files with 1828 additions and 0 deletions
+176
View File
@@ -0,0 +1,176 @@
from __future__ import annotations
from pathlib import Path
import pytest
from k1link.compute.world_motion import (
WorldMotionTracker,
evaluate_motion_benchmark,
read_motion_benchmark,
read_world_motion_profile,
)
def _profile() -> dict[str, object]:
root = Path(__file__).resolve().parents[1]
profile, digest = read_world_motion_profile(
root / "experiments" / "perception" / "e24_world_motion_profile.json"
)
assert len(digest) == 64
return profile
def _object(track_id: int, x: float, *, group: str = "vehicle") -> dict[str, object]:
label = "person" if group == "person" else "car"
half_size = [0.35, 0.35, 0.9] if group == "person" else [2.25, 0.925, 0.775]
return {
"association_group": group,
"bbox_xyxy": [100.0, 100.0, 200.0, 200.0],
"clustered_points": 32,
"cuboid_center_map": [x, 2.0, 0.8],
"cuboid_half_size": half_size,
"cuboid_quaternion_xyzw": [0.0, 0.0, 0.0, 1.0],
"cuboid_status": "accepted-class-prior-amodal-v1",
"distance_smoothed_m": 10.0,
"geometry": "class-prior-completed-from-visible-lidar-support",
"label": label,
"score": 0.9,
"track_id": track_id,
}
def _provisional_person(track_id: int, x: float) -> dict[str, object]:
value = _object(track_id, x, group="person")
value.update(
{
"cuboid_center_map": None,
"cuboid_half_size": None,
"cuboid_quaternion_xyzw": None,
"cuboid_status": "rejected-amodal-completion-support-coverage-below-threshold",
"observed_cuboid_center_map": [x, 2.0, 0.8],
"observed_cuboid_quaternion_xyzw": [0.0, 0.0, 0.0, 1.0],
}
)
return value
def test_e24_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["authority"] == {
"commands_enabled": False,
"navigation_or_safety_accepted": False,
}
def test_e24_reassociates_changed_source_id_and_classifies_static() -> None:
tracker = WorldMotionTracker(_profile())
last = []
for frame in range(30):
source_id = 10 if frame < 12 else 77
jitter = 0.025 if frame % 2 else -0.025
last, world = tracker.update(
frame_index=frame,
session_seconds=frame * 0.1,
objects=[_object(source_id, 10.0 + jitter)],
)
assert last[0]["track_id"] == 240001
assert last[0]["source_track_id"] == 77
assert world[0]["motion_state"] == "static"
assert tracker.snapshot()["reassociated_source_ids"] == 1
def test_e24_classifies_sustained_world_motion_dynamic() -> None:
tracker = WorldMotionTracker(_profile())
world = []
for frame in range(35):
_, world = tracker.update(
frame_index=frame,
session_seconds=frame * 0.1,
objects=[_object(20, 5.0 + frame * 0.12, group="person")],
)
assert world[0]["motion_state"] == "dynamic"
assert world[0]["speed_mps"] is not None
assert world[0]["speed_mps"] > 0.75
def test_e24_confirms_sparse_visible_support_without_promoting_first_hit() -> None:
tracker = WorldMotionTracker(_profile())
first, first_world = tracker.update(
frame_index=0,
session_seconds=0.0,
objects=[_provisional_person(21, 5.0)],
)
tracker.update(
frame_index=1,
session_seconds=0.5,
objects=[_provisional_person(21, 5.5)],
)
third, third_world = tracker.update(
frame_index=2,
session_seconds=1.0,
objects=[_provisional_person(21, 6.0)],
)
assert first[0]["cuboid_status"].startswith("rejected-")
assert first_world == []
assert third[0]["cuboid_status"] == "accepted-world-track-provisional-e24-v1"
assert third_world[0]["track_hits"] == 3
def test_e24_holds_confirmed_track_briefly_then_expires() -> None:
tracker = WorldMotionTracker(_profile())
for frame in range(12):
tracker.update(
frame_index=frame,
session_seconds=frame * 0.1,
objects=[_object(30, 3.0)],
)
held, held_world = tracker.update(
frame_index=12,
session_seconds=1.2,
objects=[],
)
expired, expired_world = tracker.update(
frame_index=20,
session_seconds=2.0,
objects=[],
)
assert held[0]["cuboid_status"] == "accepted-world-track-hold-e24-v1"
assert held_world[0]["observation_age_ms"] == pytest.approx(100.0)
assert expired == []
assert expired_world == []
def test_e24_benchmark_contract_and_evaluator() -> None:
root = Path(__file__).resolve().parents[1]
benchmark, digest = read_motion_benchmark(
root / "experiments" / "perception" / "e24_motion_benchmark.json"
)
event = benchmark["events"][0]
rows = [
{
"session_seconds": 55.0 + index * 0.2,
"objects": [
{
"track_id": 1,
"class": event["class_group"],
"motion_state": event["expected_motion"],
"observation_age_ms": 0.0,
}
],
}
for index in range(5)
]
one_event = {**benchmark, "events": [event]}
result = evaluate_motion_benchmark(rows, one_event)
assert len(digest) == 64
assert result["passed"] is True
assert result["events"][0]["best_hits"] == 5