fix(gps): adapt Doppler bandwidth from board validation
This commit is contained in:
@@ -59,6 +59,90 @@ def noisy_observations(
|
||||
|
||||
|
||||
class AdaptivePpsTests(unittest.TestCase):
|
||||
def test_board_calibrated_doppler_predictor_reduces_pps_error(self):
|
||||
"""Genesys2 WLS statistics: predictor-on must beat fallback-only."""
|
||||
quality_metrics = QualityMetrics(
|
||||
1.50, 2.92, 15.87, 40.3, 34.8, 0.35, 0.23, 7
|
||||
)
|
||||
aided_phase_rms = []
|
||||
fallback_phase_rms = []
|
||||
aided_edge_jitter = []
|
||||
fallback_edge_jitter = []
|
||||
for seed in range(8):
|
||||
rng = random.Random(7300 + seed)
|
||||
observations = []
|
||||
for update in range(900):
|
||||
time_s = 0.2 * update
|
||||
long_omega = 2.0 * math.pi / 75.0
|
||||
short_omega = 2.0 * math.pi / 19.0
|
||||
varying_drift_mps = (
|
||||
5.0 * math.sin(long_omega * time_s)
|
||||
+ 2.0 * math.sin(short_omega * time_s)
|
||||
)
|
||||
varying_bias_m = (
|
||||
5.0 * (1.0 - math.cos(long_omega * time_s)) / long_omega
|
||||
+ 2.0 * (1.0 - math.cos(short_omega * time_s))
|
||||
/ short_omega
|
||||
)
|
||||
# 15.87 m / c = 52.94 ns; 3.47 m/s is the measured
|
||||
# board standard deviation of the reference bias drift.
|
||||
noise_s = rng.gauss(0.0, 15.87 / 299_792_458.0)
|
||||
if update % 113 == 0 and update != 0:
|
||||
noise_s += rng.choice((-1.0, 1.0)) * 120.0e-9
|
||||
observations.append(
|
||||
Observation(
|
||||
time_s,
|
||||
noise_s,
|
||||
varying_drift_mps + rng.gauss(0.0, 3.47),
|
||||
quality_metrics,
|
||||
True,
|
||||
-291.75,
|
||||
1,
|
||||
varying_bias_m,
|
||||
)
|
||||
)
|
||||
aided = run_observations(
|
||||
observations,
|
||||
finish_time_s=180.0,
|
||||
oscillator_ppm=1.592,
|
||||
)
|
||||
fallback = run_observations(
|
||||
[
|
||||
Observation(
|
||||
item.time_s,
|
||||
item.timing_error_s,
|
||||
item.clock_drift_error_mps,
|
||||
item.quality,
|
||||
False,
|
||||
item.reference_range_rate_mps,
|
||||
item.reference_id,
|
||||
item.reference_datum_offset_m,
|
||||
)
|
||||
for item in observations
|
||||
],
|
||||
finish_time_s=180.0,
|
||||
oscillator_ppm=1.592,
|
||||
)
|
||||
aided_phase_rms.append(aided.phase_rms(after_s=60.0))
|
||||
fallback_phase_rms.append(fallback.phase_rms(after_s=60.0))
|
||||
aided_edge_jitter.append(
|
||||
aided.one_second_edge_jitter_rms(after_s=60.0)
|
||||
)
|
||||
fallback_edge_jitter.append(
|
||||
fallback.one_second_edge_jitter_rms(after_s=60.0)
|
||||
)
|
||||
self.assertEqual(aided.unlock_events, 0)
|
||||
|
||||
self.assertLess(
|
||||
sum(aided_phase_rms) / len(aided_phase_rms),
|
||||
0.35 * sum(fallback_phase_rms) / len(fallback_phase_rms),
|
||||
)
|
||||
self.assertLess(
|
||||
sum(aided_edge_jitter) / len(aided_edge_jitter),
|
||||
0.70 * sum(fallback_edge_jitter) / len(fallback_edge_jitter),
|
||||
)
|
||||
self.assertLess(max(aided_phase_rms), 30.0e-9)
|
||||
|
||||
def test_quality_hysteresis_rejects_metric_chatter(self):
|
||||
selector = QualitySelector()
|
||||
for _ in range(7):
|
||||
|
||||
Reference in New Issue
Block a user