Skip to the content
FixTheRobot Explore Robotics / UAV / Module 7 / M7-T10

UAV Systems Engineering · Module 7

M7-T10: Software timestamping

A timestamp is a measurement with an error budget. Know where yours comes from and bound it.

  • Lesson 10 of 19
  • Embedded Systems, Timing and System Integration
  • Established engineering
  • About 6 minutes to read

Not every sensor can be hardware-triggered. For the rest, the timestamp is a software measurement taken some time after the event. The error is mostly a fixed delay (which can be calibrated) plus a variable delay (which can be reduced, but not removed). This lesson is about making that budget explicit.

Learning objectives

After this lesson, you should be able to:

  • List the sources of timestamp delay between the physical event and the message header.
  • Choose the stamping point (device, driver, kernel, application) appropriate to the accuracy needed.
  • Reduce arrival-time jitter with a fitted period model and quantify the remaining error.
  • Estimate a constant sensor-to-host delay from data and verify it.

Conceptual explanation

Established Delay sources and smoothing methods are standard in sensor integration. The size of each delay is device-specific: the example numbers are illustrative and must be replaced by measurements of your sensors.

Where each delay comes from, with who can fix it:

undefined
StageTypical effectRemedy
Exposure / integrationThe sample represents an interval, not an instant (camera exposure; IMU filter group delay)Stamp the midpoint; model filter delay
Readout and transferFixed (readout) plus variable (bus arbitration) delayDevice timestamps, or calibrate the fixed part
Driver and kernel queueInterrupt latency, buffering, batching of packetsKernel or device timestamps (SO_TIMESTAMPING, hardware timestamps), real-time priority
ApplicationScheduling delay before the callback calls now()Stamp in the driver at the earliest point; avoid stamping in a busy callback

Sensors differ in what they offer: some provide device timestamps on a device clock (many IMUs, lidars, some cameras), which are precise but on a different clock to be related to the host; others provide nothing and the driver stamps on arrival. A device clock can be related to the host clock by fitting: collect pairs (device time, host arrival time), whose lower envelope is the true offset plus the minimum delay.

Where timestamp error entersBetween the physical event and the message header, each stage adds delay: exposure and integration, readout, transfer, driver, kernel queue and the application’s own scheduling. Stamp as close to the event as the hardware allows.Physical eventphoton, motionExposure / sampleintegration timeReadout + transferUSB / CSI / SPIDriver + kernelinterrupt, queueApplication stampros::Time::nowEach stage adds delay and jitter. Later stamps are easier to make and less accurate.
The delay chain. Stamp early; model what you cannot remove.
Animation of arrival-time smoothing. Frames arrive at about 30 hertz with a fixed delay and a long-tailed extra delay; plotted against frame index the arrival times lie above the true schedule with occasional large outliers. A straight line is then fitted from below, through the lower convex hull of the points, and the estimated schedule follows the true one far more closely than the raw arrival times, with the error standard deviation falling from several milliseconds to a fraction of a millisecond.
Arrival delays are non-negative with a long tail, so averaging is biased late; the early arrivals carry the schedule. A line fitted below the points (a linear programme, the lower hull) recovers the sample schedule and period up to a constant offset that must be calibrated. Synthetic 30 Hz stream with a 22 ms fixed delay, 40 ppm clock rate error and gamma plus stall delays. (Looping, about 6 seconds; drawn and computed for this course with illustrative values.)

Engineering intuition

Arrival times are the true schedule plus a one-sided, positive delay with a long tail: data cannot arrive earlier than physics allows, but it can arrive late for many reasons. Because the delay is one-sided, averaging arrival times biases the answer late, and the good information is in the early arrivals. If the sensor runs at a steady rate, fit a straight line to arrival times against sample index, then pull the line down so that it sits under (almost) all the arrivals: the line is your best estimate of when the samples actually left the sensor, plus the minimum delay.

The remaining unknown is the fixed delay (readout, transfer). It is the same for every sample, so it behaves like a constant time offset that can be calibrated against another sensor (for example camera-IMU offset estimation) or measured with a hardware reference such as an LED or a sync pulse.

Mathematical formulation

For samples at nominal period TT indexed kk, with arrival times ak=t0+k Ttrue+δ+ηka_{k}=t_{0}+k\,T_{\text{true}}+\delta +\eta _{k} (ηk ≥ 0 variable delay, δ\delta fixed delay, TtrueT_{\text{true}} the sensor’s actual period, which differs from the nominal one by clock drift), the estimate of the grid is the line that minimises the sum of the residuals subject to being below all points (a linear program, solved as a lower convex hull; the “convex hull” timestamp filter), or more robustly a low quantile regression:

One-sided fit of arrival times
min⁡ ∑k(ak−(b0+b1k))subject tob0+b1k≤ak  for all k\min\ \sum_k\left(a_k - (b_0 + b_1 k)\right) \quad\text{subject to}\quad b_0 + b_1 k \le a_k \ \text{ for all } k
Estimated schedule
t^k=b0+b1k\hat t_k = b_0 + b_1 k

Remaining error: the stamp then has the jitter of the sample at the lower envelope of η\eta (small), plus the unmodelled fixed offset δ\delta . Clock drift matters over long durations: a 50 ppm difference between device and host clocks accumulates 50 µs per second, 3 ms per minute, which is why the slope b1b_{1} must be estimated continuously, not set to the nominal period.

aka_{k}
arrival time of sample kk at the host.
ηk\eta _{k}
non-negative variable delay.
δ\delta
fixed delay (readout, transfer, driver).
b0b_{0}, b1b_{1}
fitted intercept and period.

Architecture and data flow

Sensor (device clock, optional device timestamp) → bus → driver (kernel timestamp, if supported) → driver node (stamp assignment, smoothing) → message header stamp → consumers (estimator, VIO). The clock-offset estimator (device-to-host) runs inside the driver or as a node, and its parameters and residual statistics are logged. Downstream consumers should treat the stamp as the sensor time, and handle remaining offset through an estimated camera-IMU time offset parameter where available.

Real-world UAV applications

  • Stamping USB cameras and lidars that offer no trigger.
  • Relating an IMU’s device clock to the host clock.
  • Reducing the jitter of arrival-stamped data before feeding VIO.
  • Documenting timestamp accuracy in an interface control document.

Implementation example

This runs as shown. Synthetic 30 Hz data with a fixed delay of 22 ms, a long-tailed variable delay and a 40 ppm clock rate difference. A lower-envelope line fit (a linear program via a quantile-style iteration) recovers the sample schedule far better than the raw arrival times, leaving the fixed delay as a constant offset.

import numpy as np
rng = np.random.default_rng(10)
n, T_nom = 1800, 1 / 30.0; ppm = 40e-6
T_true = T_nom * (1 + ppm); k = np.arange(n)
t_true = 5.0 + k * T_true                                      # true sample times on the host clock
delta = 0.022; eta = rng.gamma(1.5, 0.004, n); eta[rng.random(n) < 0.02] += 0.05          # fixed delay, long-tailed variable delay, rare large stalls
a = t_true + delta + eta                                       # arrival times (the only thing the driver sees)

def lower_envelope_line(k, a):
    # exact solution of: maximise sum(line) (equivalently minimise sum(a - line)) subject to line <= a.
    # The optimum passes through two points of the lower convex hull; try every hull edge and keep the best.
    hull = []
    for p in zip(k, a):
        while len(hull) >= 2 and (hull[-1][0] - hull[-2][0]) * (p[1] - hull[-2][1]) - (hull[-1][1] - hull[-2][1]) * (p[0] - hull[-2][0]) <= 0: hull.pop()
        hull.append(p)
    best = None
    for (x0, y0), (x1, y1) in zip(hull[:-1], hull[1:]):
        b1 = (y1 - y0) / (x1 - x0); b0 = y0 - b1 * x0
        obj = n * b0 + b1 * k.sum()
        if best is None or obj > best[0]: best = (obj, b0, b1)
    return np.array([best[2], best[1]])                         # (slope, intercept) like np.polyfit
b = lower_envelope_line(k.astype(float), a)
t_hat = np.polyval(b, k)
err_raw = a - t_true; err_fit = t_hat - t_true
print(f"raw arrival stamp: mean error {err_raw.mean() * 1e3:5.1f} ms, std {err_raw.std() * 1e3:5.1f} ms; fitted: mean {err_fit.mean() * 1e3:5.1f} ms (about the fixed delay), std {err_fit.std() * 1e3:5.2f} ms")
print(f"estimated period {b[0]:.7f} s (true {T_true:.7f}, nominal {T_nom:.7f})")
assert err_fit.std() < 0.2 * err_raw.std() and abs(b[0] - T_true) < 2e-7 and abs(err_fit.mean() - delta) < 0.006
A one-sided line fit to arrival times removes most of the variable delay and estimates the true period; the fixed delay remains as a constant offset.

Common engineering mistakes

Averaging arrival times

The delay is one-sided, so the mean is biased late.

Using the nominal period

Clock drift accumulates; estimate the period.

Stamping in a busy callback

The application’s scheduling delay is added to every stamp.

Ignoring the fixed delay

It appears as a constant camera-IMU offset; calibrate it.

Mixing stamping methods across sensors

Different error structures make fusion inconsistent.

Failure modes

Failure modes, symptoms and causes
Failure modeHow it shows upLikely cause
VIO unstable at high rates of rotationPoor tracking in fast motionTime offset between camera and IMU of several ms
Stamp jumpsOccasional large offsetsStalls or bursts of buffered packets stamped on arrival
Slow drift between sensorsAlignment degrades over minutesClock rate difference not estimated
Negative intervalsTime goes backwardsNon-monotonic clock or bad smoothing

Debugging approach

  1. Plot arrival time minus fitted line to see the delay distribution and its tail.
  2. Compare with a hardware reference (LED, sync pulse, trigger) to measure the fixed delay.
  3. Check kernel and device timestamp options on the driver.
  4. Log the estimated period and offset so drift can be seen.

Practical exercises

  1. Change the stall probability to 10 % and see how the fitted stamp error changes.
  2. Estimate the fixed delay by comparing a software-stamped camera against a hardware-triggered one.
  3. Compute the accumulated offset after 10 minutes for a 100 ppm clock difference.
  4. List the timestamp source and expected accuracy for each sensor on your vehicle.

Interview questions

Write an answer in your own words, then reveal the model answer. Nothing is sent anywhere.

Question 1

Why does averaging arrival times give a biased timestamp?

Model answer

The delay between event and arrival is non-negative with a long tail, so the average is late by the mean delay; the information about the true time is in the earliest arrivals.

Question 2

How can you reduce timestamp jitter without hardware support?

Model answer

Fit a straight line (period and offset) to arrival times from below, or use device timestamps related to the host clock by a regression, so that the variable delay is largely removed.

Question 3

What stays after smoothing?

Model answer

The fixed delay (readout, transfer, driver), which acts as a constant offset and must be calibrated or estimated online.

References and further reading

Primary papers, official documentation and standards. Each claim above that is specific to a tool or version points here.

What’s next

Mark this lesson

Saved in this browser and synced to your account when you are signed in.

Practice this lesson

M7-L2: Analyze timestamp synchronization

Compare sensor timestamps.

Next lesson

M7-T11: PTP synchronization

Describe IEEE 1588 PTP, grandmaster and boundary clocks, hardware timestamping and the accuracy it can deliver.