ntpstats.ubx¶
u-blox UBX timing messages and PPS sawtooth correction.
GNSS timing receivers (u-blox ZED-F9T, LEA-M8T and others, also on the OCP Time Card) report how good their time is in binary UBX messages. ntpstats reads three of them from a raw receiver log (UBX frames, possibly mixed with NMEA text), with the layouts of the u-blox interface description (e.g. ZED-F9T, UBX-18053584):
UBX-NAV-CLOCK (0x01 0x22)
receiver clock bias clkB (ns) and drift clkD (ns/s), time
accuracy tAcc (ns) and frequency accuracy fAcc (ps/s) of each
navigation epoch. The series is the clock bias as reported, so its
stability is that of the receiver's own oscillator as GNSS sees it.
UBX-NAV-TIMEUTC (0x01 0x21)
the UTC date and time of each navigation epoch, used to time-stamp the
other messages, and its time accuracy estimate.
UBX-TIM-TP (0x0D 0x01)
the time of the next time pulse and its quantization error qErr
(ps): the receiver can only place the pulse on an edge of its internal
clock, so the PPS is off by up to half a clock period, and the error
drifts as a "sawtooth". qErr predicts it.
Times come from NAV-TIMEUTC when present (same iTOW); otherwise from the
GPS week of TIM-TP, with GPS - UTC = leap_seconds (18 s since 2017).
:func:apply_qerr removes the sawtooth from a time-interval-counter
measurement of the receiver's PPS. u-blox does not state the sign with which
qErr applies, so by default the sign that removes the sawtooth from the
data (the smaller sample-to-sample variance) is chosen and reported; it can
be fixed with sign=+1 or -1.
frames(data, max_len=4096)
¶
Valid UBX frames (class, id, payload); anything else (NMEA, RTCM, noise) is skipped.
is_ubx(head)
¶
True if head (the start of a file) contains a valid UBX frame.
parse_ubx(data, name='ubx', leap_seconds=LEAP_SECONDS)
¶
Series of a UBX log: the receiver clock (NAV-CLOCK) and the time-pulse quantization error (TIM-TP).
apply_qerr(pps, qerr, sign='auto', max_dt=0.5)
¶
Remove the quantization sawtooth from a PPS measurement with the receiver's qErr.
pps is a time-interval-counter series of the receiver's PPS against a
reference (any sign convention); each sample is paired with the qErr
of the pulse nearest in time (within max_dt s). The result is
pps + sign * qErr; sign="auto" picks the sign that minimises the
sample-to-sample variance (the sawtooth is the fastest component), and
the choice and the improvement are reported in meta.