mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-11-07 04:53:47 +08:00
8cb60d82fe
Provide laptop and device build entry points, cache compatibility checks and developer tooling. Keep distribution assets and model packaging available before runtime consumers.
84 lines
4.4 KiB
Python
84 lines
4.4 KiB
Python
import math
|
|
from types import SimpleNamespace as NS
|
|
import unittest
|
|
|
|
from tools.diagnostics.longitudinal import analyze
|
|
|
|
|
|
class Event:
|
|
def __init__(self, service, seconds, **fields):
|
|
self.service = service
|
|
self.logMonoTime = int(seconds * 1e9)
|
|
self.valid = True
|
|
setattr(self, service, NS(**fields))
|
|
|
|
def which(self):
|
|
return self.service
|
|
|
|
|
|
def cluster(t, *, target=1.0, command=0.5, ego=0.2, source="cruise", experimental=False,
|
|
active=True, gas=False, brake=False):
|
|
return [Event("carState", t, aEgo=ego, gasPressed=gas, brakePressed=brake),
|
|
Event("selfdriveState", t, experimentalMode=experimental),
|
|
Event("longitudinalPlan", t, aTarget=target, longitudinalPlanSource=source),
|
|
Event("carControl", t, longActive=active, actuators=NS(accel=command))]
|
|
|
|
|
|
class TestLongitudinalTrace(unittest.TestCase):
|
|
def test_continuous_same_mode_rates_are_signal_derivatives(self):
|
|
messages = cluster(1) + cluster(1.1, target=1.2, command=0.6, ego=0.3) + cluster(1.2, target=1.4, command=0.7, ego=0.4)
|
|
report = analyze(messages)
|
|
command = report["signals"]["commandAccel"]
|
|
self.assertEqual(command["continuousFrameDeltaSeconds"]["sampleCount"], 2)
|
|
self.assertAlmostEqual(command["continuousDeltaRateMps3"]["mean"], 1)
|
|
self.assertEqual(report["pedalContextSamples"]["gas=False,brake=False"], 7)
|
|
|
|
def test_gap_and_mode_transitions_exclude_derivatives(self):
|
|
messages = cluster(1) + cluster(1.1) + cluster(2, active=False, source="lead0", experimental=True, gas=True)
|
|
report = analyze(messages)
|
|
self.assertEqual(report["transitions"]["source"], 1)
|
|
self.assertEqual(report["transitions"]["experimental"], 1)
|
|
self.assertEqual(report["transitions"]["longActive"], 1)
|
|
self.assertEqual(report["signals"]["commandAccel"]["continuousDeltaRateMps3"]["sampleCount"], 1)
|
|
gap = analyze(cluster(1) + cluster(1.1) + cluster(2))
|
|
self.assertGreater(gap["rejectedPairsOrSamples"]["carControl:gap"], 0)
|
|
|
|
def test_nonfinite_missing_and_timestamp_regression_reset_baseline(self):
|
|
messages = cluster(1) + cluster(1.1, command=math.nan) + cluster(1.05) + cluster(1.2)
|
|
report = analyze(messages)
|
|
self.assertEqual(report["signals"]["commandAccel"]["valuesMps2"]["missingCounts"]["missing_or_nonfinite"], 1)
|
|
self.assertGreater(report["rejectedPairsOrSamples"]["carControl:timestamp_regression"], 0)
|
|
self.assertEqual(report["signals"]["commandAccel"]["continuousDeltaRateMps3"]["sampleCount"], 0)
|
|
|
|
def test_stale_context_does_not_create_pair(self):
|
|
messages = cluster(1) + [Event("carControl", 2, longActive=True, actuators=NS(accel=1.0))]
|
|
report = analyze(messages)
|
|
self.assertEqual(report["rejectedPairsOrSamples"]["carControl:missing_or_stale_mode"], 1)
|
|
self.assertEqual(report["signals"]["commandAccel"]["continuousFrameDeltaSeconds"]["sampleCount"], 0)
|
|
|
|
def test_invalid_envelope_is_excluded(self):
|
|
messages = cluster(1) + cluster(1.1)
|
|
messages[-1].valid = False
|
|
messages.append(Event("longitudinalPlan", 1.15, aTarget=1.0, longitudinalPlanSource="cruise"))
|
|
report = analyze(messages)
|
|
self.assertEqual(report["rejectedPairsOrSamples"]["carControl:invalid_envelope"], 1)
|
|
self.assertEqual(report["rejectedPairsOrSamples"]["longitudinalPlan:missing_or_stale_mode"], 2)
|
|
self.assertEqual(report["signals"]["commandAccel"]["valuesMps2"]["sampleCount"], 1)
|
|
|
|
def test_away_and_back_or_invalid_recovery_breaks_other_signal_pair(self):
|
|
baseline = cluster(1) + cluster(1.1)
|
|
toggled = baseline + [Event("selfdriveState", 1.15, experimentalMode=True),
|
|
Event("selfdriveState", 1.16, experimentalMode=False),
|
|
Event("longitudinalPlan", 1.2, aTarget=1.4, longitudinalPlanSource="cruise")]
|
|
report = analyze(toggled)
|
|
self.assertEqual(report["transitions"]["experimental"], 2)
|
|
self.assertEqual(report["signals"]["plannerATarget"]["continuousDeltaRateMps3"]["sampleCount"], 0)
|
|
|
|
invalid = Event("carControl", 1.15, longActive=True, actuators=NS(accel=0.5))
|
|
invalid.valid = None
|
|
recovered = baseline + [invalid, Event("carControl", 1.16, longActive=True, actuators=NS(accel=0.5)),
|
|
Event("longitudinalPlan", 1.2, aTarget=1.4, longitudinalPlanSource="cruise")]
|
|
report = analyze(recovered)
|
|
self.assertEqual(report["rejectedPairsOrSamples"]["carControl:invalid_envelope"], 1)
|
|
self.assertEqual(report["signals"]["plannerATarget"]["continuousDeltaRateMps3"]["sampleCount"], 0)
|