Skip to content
Docs
foxborne.comRequest a pilot

Alignment and event order

Foxborne says one event came before another only when the clocks allow it. When two events sit inside their combined error, the timeline and the report call their order unknown.

ExplanationMarkdown
On this page9

A merged timeline tempts every reader to write "then". Foxborne checks each "then" against the clocks before it makes the claim. When the clocks cannot separate two events, it says so on screen and in the report.

Each event is an interval#

An event has a time and the error bound of its source's clock. A receipt on the ground also carries link latency, because the message left the vehicle before it arrived. Foxborne combines the three into an interval:

Text
interval = [ t − error − latency , t + error ]

Latency extends the interval on one side only. A transmission can come earlier than its receipt, never later. For anything that is not a receipt, latency is zero and the interval is the time plus or minus its error.

SourceError in the example datasetLatency
Flight log±40 msNone
Companion journal±6 msNone
Process samples±6 msNone
Ground receive log±15 msUp to 412 ms, the 95th percentile of run R-0931

Clocks, anchors and error bounds explains where each bound comes from.

How two events are compared#

Foxborne compares two events in three steps and stops at the first that applies:

  1. Same clock: always ordered. Two events on one clock keep the order of their timestamps, however close they are. The journal and the process samples share the companion's clock, so they count as one.
  2. Unaligned companion clock: no claim. While the companion clock has no anchor, Foxborne makes no before or after claim between its events and those of anchored sources.
  3. Different clocks: compare intervals. The later event comes after the earlier one only if its interval starts after the earlier interval ends. If the intervals overlap, the order is unknown.

Step 3 has a plain reading. Two events on different clocks are ordered only when their separation exceeds the sum of their errors. When the later event is a receipt, its link latency counts too.

Order unknown: 39 ms against 46 ms#

In INC-0142 the flight log's last obstacle_distance sample before a stall and the kernel's kill of perception_node sit 39 ms apart, on different clocks.

Example data.000.040.080.120.16014:32:04Flight loglast obstacle_distance sample14:32:04.079 ±40 msCompanion journalkernel kills perception_node14:32:04.118 ±6 msIntervals overlap: order unknown39 ms between the two times46 ms combined bound, 40 + 6.000.040.080.120.160Flight loglast obstacle sample14:32:04.079 ±40 msCompanion journalkernel kills perception_node14:32:04.118 ±6 msIntervals overlap: order unknown39 ms between the two times46 ms combined bound, 40 + 6
INC-0142. The sample at 14:32:04.079 ±40 ms and the kill at 14:32:04.118 ±6 ms are 39 ms apart, inside their 46 ms combined bound, so their intervals overlap.
EventSource and boundTimeInterval
Last obstacle_distance sampleFlight log, ±40 ms14:32:04.07904.039 to 04.119
Kernel kills perception_nodeCompanion journal, ±6 ms14:32:04.11804.112 to 04.124

The sample could be as late as 04.119 and the kill as early as 04.112. For those 7 ms either order fits, so Foxborne claims neither. The same test does order the exit of perception.service at 14:32:04.133, which sits 54 ms after the sample, outside the 46 ms bound.

Ordered, and filed as correlated: 0.76 s against 0.43 s#

After the kill, mavlink-router.service stopped at 14:32:04.152 on the companion journal. At range control the next heartbeat was due at 14:32:04.912, and it never arrived.

EventSource and boundTimeInterval
mavlink-router.service stoppedCompanion journal, ±6 ms14:32:04.15204.146 to 04.158
Heartbeat due and not receivedGround receive log, ±15 ms, up to 412 ms latency14:32:04.91204.485 to 04.927

The two are 0.76 s apart against a bound of 6 + 15 + 412 = 433 ms. The order holds: the router stopped first.

The report files the line as correlated, with the note "Due 0.76 s after mavlink-router.service stopped. Bound ±0.43 s including link latency."

It stays correlated rather than observed, because no log line shows the stop causing the silence. Evidence levels explains the difference.

A clock with no anchor makes no claim#

When chrony never synchronizes, the companion's journal and process samples have no anchor. Foxborne keeps them on their own axis, gives them no position on the map and compares them with nothing on the anchored clocks. The clock_uncertain rule, which is always on, raises a warning.

The console says so wherever order comes up. The run page's matrix reads No claim for those pairs, and the inspector adds "The companion clock has no shared anchor with the flight log."

The report's clock line reads "The companion clock is not aligned. No order is claimed between the companion and the flight log."

Manual alignment adds its bound#

An engineer can align the companion clock by hand from two events that happened at the same moment on both clocks. The alignment maps companion times onto UTC with an offset and adds its own bound to every companion event. Each order claim that depends on it is marked as manual.

In INC-0139, chrony found no suitable source at boot on UAS-07. The matching pair is mavlink-routerd opening the flight controller UART and PX4 seeing the first onboard controller heartbeat on TELEM2. Heartbeats arrive at 1 Hz, so the alignment carries ±1.04 s, from the 1 s heartbeat period and the 40 ms GPS anchor.

Once it is applied, companion events carry ±1.05 s: their own 6 ms plus the alignment's 1.04 s. That is below the 2.0 s ordering bound, so before and after claims become possible, each one marked as manual. The report lists the alignment under 4 Limitations with the pair it came from, and Remove alignment restores the original state.

Align a clock by hand walks through the dialog.

The ordering bound#

Above a set bound, Foxborne makes no before or after claim between two sources, whatever the times say. The bound is 2.0 s by default, and admins choose 0.5 s, 1.0 s, 2.0 s or 5.0 s in Settings, under Time and position.

The dialog states the trade-off: "Lowering it makes more pairs unknown. Raising it is recorded in every report produced afterwards." A source that has no anchor, or whose error exceeds the bound, triggers clock_uncertain.

What the console shows#

The clock note above an incident's timeline sums up the comparison. The source count below is INC-0142's:

SituationClock note
Pairs inside their combined boundAll 4 sources are on one timeline, with the widest bound and the number of pairs whose order is not claimed. Show the pair, or Show the first pair when there are several, zooms to it.
No such pairsAll 4 sources are on one timeline: "No two events are closer than their combined clock error."
One sourceOne source, anchored to GPS time
Companion clock with no anchorThe companion clock was never synchronised, with Align from matching events
Companion clock aligned by handCompanion clock aligned by hand, with Remove alignment

The same verdicts appear everywhere else order comes up:

WhereWhat it shows
TimelineThe overlap of an unknown pair, hatched across both lanes and labeled Order unknown
Evidence inspectorOrder against nearby events marks each neighbor Order unknown or gives its separation, earlier or later. Events on an unaligned clock appear together under No claim.
Run pageOrdering bounds between sources: Same clock, a combined bound such as ±46 ms or No claim
Report sequenceBoth lines of the pair read Order unknown, with a note such as "Order against E3 is unknown: 39 ms apart, inside ±46 ms combined."
Report limitationsThe pair by name, ending "Their order is not claimed."
Before you export"No order is claimed inside a clock bound. One pair is marked unknown."

Next#