feat(pps): preserve loop dynamics across nav periods

This commit is contained in:
2026-07-29 00:45:16 +03:00
parent a6bb080270
commit 347e1c671d
19 changed files with 889 additions and 111 deletions
@@ -80,6 +80,10 @@ that the repository did not capture:
```bash
python3 -m pps_end_to_end_validation.stability_analysis
python3 -m pps_end_to_end_validation.stability_analysis \
--update-period-ms 500
python3 -m pps_end_to_end_validation.stability_analysis \
--update-period-ms 1000
python3 -m unittest \
pps_end_to_end_validation/test_stability_analysis.py
```
@@ -89,7 +93,7 @@ Generated results are in `output/stability/`:
- `stability_report.md`: real-data inventory, discrete poles, absolute phase
wander, period jitter, dynamic parameter sweep, and recommendations;
- `parameter_sweep.csv`: machine-readable results for every scenario/tuning;
- `synthetic_telemetry.csv`: 5 Hz ABS_SAMPLE, REM_CODE_PHASE, corrected 125 MHz
- `synthetic_telemetry.csv`: solve-cadence ABS_SAMPLE, REM_CODE_PHASE, corrected 125 MHz
capture, HDOP/VDOP/TDOP/GDOP, C/N0, pseudorange noise, clock sigma/drift,
oscillator and timing-error inputs.
@@ -102,8 +106,9 @@ temperature, and trusted-edge timing remain unavailable. The stability CSV
labels replacements as synthetic; it must not be read as board telemetry.
The current acquire, precision, and robust fixed-point poles are inside the
unit circle at the 200 ms update rate, and the stress analysis observes no
unlock. It also exposes an important metrics issue: cycle-to-cycle PPS period
unit circle at the 200, 500, and 1000 ms supported update rates, and the stress
analysis observes no unlock. It also exposes an important metrics issue:
cycle-to-cycle PPS period
jitter can remain below 20 ns while absolute phase moves slowly through tens
of nanoseconds. A physical 20 ns maximum therefore requires a common-clock
time-interval-counter capture and cable/output-delay calibration; a p95 period
@@ -112,8 +117,28 @@ jitter assertion or synthetic run cannot certify it.
The sweep includes the current coefficients, quieter/faster precision loops,
a robust-noise guard, a larger Doppler-drift gain, and a quality-scheduled
candidate. The generated report contains the current numerical comparison.
The stability analysis does not alter loop constants. Production firmware now
uses the current-RTL-compatible 180 ms epoch correction described below.
Production firmware maps the proven 200 ms discrete poles to the selected NAV
period and leaves the 200 ms Q2.46 constants bit-identical. The model and
firmware also scale quality/lock/settling timers in wall-clock time, convert
software bias/drift gains from actual elapsed time, and extend the stale-data
watchdog to `max(2 s, 3 * solve period)`. This preserves deterministic settling
and damping; it cannot preserve measurement-noise statistics when fewer WLS
samples are available. Production firmware uses the current-RTL-compatible
180 ms epoch correction independently of solve cadence.
A deterministic four-seed, 180 s smoke sweep with the current profiles gave:
| solve period | real-geometry absolute RMS | worst period step over current scenarios | unlocks |
|---:|---:|---:|---:|
| 200 ms | 11.17 ns | 16 ns | 0 |
| 500 ms | 15.96 ns | 16 ns | 0 |
| 1000 ms | 25.09 ns | 24 ns | 0 |
Thus 1000 ms is linearly stable but is not recommended when the stated
synthetic maximum-period-jitter target is 20 ns. Use 200 ms by default, or
500 ms when CPU load requires it. A 1000 ms solve needs hardware validation
and likely oscillator-temperature/frequency prediction; pole remapping alone
cannot recreate the missing measurements.
## Live board telemetry replay
@@ -146,9 +171,13 @@ omits latitude/longitude.
For an already-running board, replay imports the first logged locked
filter/PI snapshot. Starting the model from reset would erase the observed
integrator and create a false acquisition transient. When status is decimated,
commit sequence numbers expand the trace back to the nominal 200 ms cadence;
commit sequence numbers expand the trace back to the inferred solve cadence;
intermediate values are explicitly marked `interpolated=true`.
The replay infers cadence from UART host time divided by commit-sequence
advance, snapped to the 20 ms navigation-bit grid. Use
`--update-period-ms` only when host timestamps are unreliable.
The report separates three quantities that should not be conflated:
- direct `hw_phase` statistics from the board;
@@ -187,7 +216,9 @@ correction, consistently in both satellite-state and PPS calculations. It is
containing the current eighth bit, firmware must return to 160 ms in the same
coordinated release.
The validation intentionally does not modify production RTL or firmware.
The validation intentionally does not modify production RTL. Firmware changes
for period-aware control are exercised by the same coefficient and timing
tests; the 180 ms absolute epoch convention remains unchanged.
## Other regression coverage
@@ -201,16 +232,20 @@ The unit tests verify:
- 180 ms firmware compatibility with current RTL;
- invariance to synthetic CPU/APB stalls when capture timestamps are used;
- DUT-versus-trusted output-delay sign; and
- rejection behavior for the firmware-permitted `NAV_SOLVE_TIMER=40` case.
- rejection behavior explaining why firmware now compile-rejects
`NAV_SOLVE_TIMER=40`; and
- zero NAV-solve rejection and unchanged absolute epoch at N=10/25/50
(200/500/1000 ms).
The `N=40` case divides the GPS week but not a 300-bit subframe. When firmware
The `N=40` case divides the GPS week but not a 300-bit subframe. When the model
refreshes the HOW/sample anchor after six seconds, the timer phase is half a
solve period away from that anchor and the current `N * 20 ms` snap rejects
otherwise valid solves. Production `N=10` divides 300 and is unaffected.
otherwise valid solves. Firmware therefore requires N to divide both the GPS
week and the 300-bit subframe. Production-safe examples are N=10, 25, and 50.
If general timer periods are required, reconstruct elapsed time on the
fundamental 20 ms navigation-bit grid. A narrower compatibility restriction is
to accept only periods for which `300 % N == 0`.
If arbitrary timer periods are required later, reconstruct elapsed time on the
fundamental 20 ms navigation-bit grid instead of snapping through a refreshed
HOW anchor.
## Hardware confirmation