At jet speed, clock error is distance

At 170 m/s, a ±40 ms clock bound is ±6.8 m of track; on a quad it is ±0.48 m. Draw it along the track, and you can see when a log cannot say which side of a line an event fell on.

On a timeline, ±40 ms is a short bar. On a map it is a stretch of track, and its length is speed times time. At 170 m/s the stretch is 13.6 m long.

That matters whenever an event sits near a line: a ridge that cuts line of sight, a range boundary, the edge of a keep-out area. Near a line, the question stops being when an event happened and becomes which side it happened on.

The Foxborne example dataset has no jet. The jet figures here are arithmetic on the dataset’s clock bounds, not an incident.

The arithmetic

Clock error becomes distance along the track: speed times the time bound. Take the ±40 ms bound that the example dataset carries on its PX4 flight logs, at three speeds:

  • Ground robot, 1.25 m/s. UGV-02 drove its lane at this commanded speed in INC-0143, an example from the Foxborne example dataset. 1.25 × 0.040 = ±0.05 m.
  • Quad, 12 m/s. The dataset lists its Q4 quad at this speed. 12 × 0.040 = ±0.48 m.
  • Jet, 170 m/s, about 330 knots. 170 × 0.040 = ±6.8 m, a 13.6 m stretch of track.

Bounds add when you place one source’s event on another source’s track. A journal line carries ±6 ms and the flight log’s track ±40 ms: ±46 ms in all, or ±7.8 m at 170 m/s.

A ground receive time is worse, and lopsided. In the example dataset the receiver carries ±15 ms plus link latency, 412 ms at the 95th percentile on the INC-0142 run. At 170 m/s the message left the aircraft up to 72.6 m back along the track (170 × 0.427), and at most 2.6 m ahead.

The receipts are sparse as well. With a 1 Hz heartbeat, as in the examples, receipts land 170 m apart.

±40 ms as distance along the track, one scale for all three−8 m−6 m−4 m−2 m0 m+2 m+4 m+6 m+8 mGround robot, 1.25 m/s±0.05 mQuad, 12 m/s±0.48 mJet, 170 m/s±6.8 m, a 13.6 m stretch of track46 ms combined bound: ±7.8 mJet at 170 m/s: what a ground receive time allows−180 m−150 m−120 m−90 m−60 m−30 m0 m170 m between heartbeats at 1 HzGround receiveprevious receiptsent up to 72.6 m back or 2.6 m aheadarrivalFlight logflight log at ±40 ms: ±6.8 m
Top: the example dataset’s ±40 ms flight log bound, drawn as track at three speeds. Bottom: at 170 m/s, a ground receive time allows departure up to 72.6 m back, and 1 Hz receipts are 170 m apart. The jet is arithmetic, not an incident.

Clock error runs along the track

A time error moves a point along the path the vehicle flew, forward or back. It never pushes the point off the track. Position error does, in any direction, and PX4 reports it separately in sensor_gps as eph, the horizontal position accuracy in meters.1

So draw the bound as a piece of the track itself. It runs from the position at the logged time minus the bound to the position at the logged time plus the bound.

On a turn, the piece follows the curve. For a receive time, extend it backward by the latency.

Near a line, ask which side

Range boundaries, keep-out areas and ridge lines are all lines on the ground. If an event’s piece of track crosses one, the log cannot put the event on either side. That is the spatial twin of order unknown, and the report should say “side unknown” just as plainly.

Speed decides how often that happens. At 12 m/s, only an event logged within 0.48 m of the line is in doubt. At 170 m/s, anything within 6.8 m is, and a ground receipt placed up to 72.6 m past the line could have left before it.

Ridge lines matter for links. If the link drops as the aircraft passes behind a ridge, the ground log places the drop only to within its receipt spacing. At 1 Hz, that is 170 m of track.

How GPS time anchors a fast-mover log

A PX4 log counts microseconds from boot. Its sensor_gps topic carries timestamp, the time since system start, and time_utc_usec, the UTC time from the GPS module. A third field, timestamp_time_relative, places that UTC time on the boot clock.1

Each fix is two readings of one instant, and a flight’s worth of fixes gives the offset from boot to UTC. The pair is only as good as the path the time took. PX4’s documentation notes that time sent over serial carries “latency and jitter from serial communication”.2

A PPS signal gives much higher precision. PX4’s PPS capture driver timestamps each pulse with a hardware timer, at sub-microsecond capture precision depending on the hardware.2 It then computes the offset between GNSS time and the autopilot clock, and the pps_capture topic carries the pair:3

msg/PpsCapture.msgv1.16.0, lines 1 to 3uORB
uint64 timestamp			  # time since system start (microseconds) at PPS capture event
uint64 rtc_timestamp		# Corrected GPS UTC timestamp at PPS capture event
uint8  pps_rate_exceeded_counter # Increments when PPS dt < 50ms

At 170 m/s, one microsecond is 0.17 mm of track. PPS capture needs a flight controller with a timer input that can capture the pulse, and CONFIG_DRIVERS_PPS_CAPTURE=y in its board configuration.2

How flight test recorders keep time

Flight test recorders that follow IRIG 106 solve the same problem with a counter. The Range Commanders Council publishes the standard chapter by chapter, and the edition on its TRMC page is 106-24R1.4 Chapter 11 of that edition puts a relative time counter in every packet header.6

The counter is a free-running 10 MHz binary counter, 48 bits wide and common to all data channels. It is derived from an internal crystal oscillator and stays free-running through each session, such as a recording.6 One count is 100 ns, which at 170 m/s is 17 µm of track.

Absolute time arrives in time data packets, which the standard treats “like another data channel”.5 With a time source other than None, the recorder writes one at least once a second.5 A time data packet must also be the first dynamic packet of each recording.5

Each time packet carries the time in its body, in formats that include IRIG-B, UTC time from GPS and native GPS time.6 The recorder captures the counter for the time packet’s header, so any data packet’s counter can be read against it.6

Within one recorder, every channel shares that counter, so a bus message and an analog sample share one clock.6 A cross-clock bound appears only when you merge the recording with a log kept on another clock.

Draw it on the map

  1. Keep the bound with the event. Store each event with its source’s clock, anchor and bound, not a bare UTC time.
  2. Use the speed at that moment. Take it from the flight log, not from a nominal cruise figure.
  3. Draw along the flown track. Extend receive times backward by the latency you measured on that link.
  4. Test every line that matters. Range boundaries, keep-out areas and the line-of-sight shadow from your own elevation data all count.
  5. Write “side unknown” when a piece crosses a line. Then look for a better source: the flight log instead of a receipt, or a PPS anchor instead of a serial one.

What the evidence shows

  • At 170 m/s, ±40 ms is ±6.8 m of track, and a 46 ms combined bound is ±7.8 m.
  • A ground receive time bounds departure mostly backward: up to 72.6 m at 170 m/s with the example’s 95th percentile latency.
  • An IRIG 106 recorder stamps every packet with one 10 MHz counter shared by all its channels.

What it does not

  • Where inside its piece of track an event happened. A bound gives a range, not a point.
  • The anchor error of any particular GPS receiver or recorder. That takes a measurement on your own hardware.
  • Which side of a line an event fell on, once its piece of track crosses the line.

Sources

  1. 1SensorGps (uORB message)PX4 User Guide. Accessed September 26, 2026.
  2. 2PPS time synchronizationPX4 User Guide. Accessed September 26, 2026.
  3. 3PpsCapture.msgPX4 Autopilot v1.16.0. Accessed September 26, 2026.
  4. 4106 Telemetry Standards (106-24R1)Range Commanders Council, TRMC wiki. Accessed September 26, 2026.
  5. 5IRIG 106-24R1 Chapter 10, Digital Recording StandardsRange Commanders Council. Accessed September 26, 2026.
  6. 6IRIG 106-24R1 Chapter 11, Recorder Data Packet Format StandardRange Commanders Council. Accessed September 26, 2026.

More field notes

Flight testIRIG 106 for people who live in PX4 logsA range recorder stamps every packet with a 48-bit counter that ticks at 10 MHz, and it records absolute time as a channel of its own. If you can put a ULog on UTC, you already know the method.Time and clocksBoot time, wall time, arrival time: one incident, three clocksA PX4 flight log counts from boot, the companion journal keeps wall time and the ground station logs arrival. Give each an explicit error bound, and you know which events you can put in order and which you cannot.Companion computersReading an OOM kill in a journalctl exportThe kernel’s out-of-memory report names the thread that asked, the process it killed and every page it counted. systemd then records the unit’s result, and two settings decide what happens next.

A pilot on your own data

Bring your hardest incident.

Send one failure you have already investigated. We rebuild it on your data, beside your current tools, and show where the evidence agrees with your conclusion and where it doesn’t.

  1. 1
    Send one incidentA failure you have already investigated, with the flight log and whatever companion or ground evidence you kept.
  2. 2
    We reconstruct itBeside your current tools, on your data, with every claim traced to its source.
  3. 3
    Compare the answersWhere the evidence agrees with your conclusion, where it does not, and what it cannot decide.