Skip to content

Hardware Integration

Algol is tightly coupled to the RET hardware. Timestamp accuracy in measurement data depends on hardware-provided signals, and the data pipeline is designed to handle the timing characteristics of the on-board MCU.

Global PPS Signal

A single PPS (Pulse Per Second) signal, sourced from the GPS receiver, is the timing backbone of the entire device. It provides a precise one-second heartbeat aligned to UTC.

Two subsystems consume the PPS signal:

Subsystem Role
MCU Resets its internal free-running timer to zero on every PPS pulse; the timer then counts elapsed sub-second time until the next pulse
chronyd Uses the PPS device (e.g. /dev/pps0) as a hardware reference clock to discipline the Linux system clock (via chrony.ntppps.main)

The PPS device path is published by chronyd itself (from its --pps-device flag) as the read-only ntppps config component (chrony.ntppps.main), which the module also consumes to configure itself at runtime.

GPS-free operation: local PPS loop

When GPS is unavailable (no fix, antenna fault, indoor operation), the MCU can continue to generate its own 1 Hz pulse independently. This local PPS loop keeps all subsystems synchronized to the same second boundary even without a UTC reference:

  • The MCU timer still resets every second - relative sub-second precision across all data channels is preserved.
  • chronyd falls back to NTP servers or pools for coarse UTC alignment; without GPS, absolute accuracy degrades to NTP quality (~1-10 ms), but all channels on the device remain internally aligned.
  • The local PPS loop is transparent to the data pipeline - sample timestamping detects PPS activity from timer resets regardless of whether the source is GPS or the MCU's internal oscillator.

The practical effect: even without GPS, all sensor channels share the same sub-second clock domain, so cross-channel temporal alignment in recorded data is maintained. Only the absolute UTC anchor is weaker.

chronyd continuously disciplines the Linux system clock by adjusting its tick rate by small amounts (microseconds per second) via the kernel's adjtimex interface - this is clock slewing, not stepping. When NTP servers are reachable, slewing keeps the system clock from drifting too far from real-world UTC without introducing discontinuities. The MCU's local PPS loop remains unaffected by these adjustments since it runs on its own oscillator; sample timestamping uses the CPU timestamp only for second-level anchoring, so microsecond-scale slew corrections do not materially affect sample timestamps.

MCU Timestamps

The MCU is the primary clock source for sensor data. Because the RET host runs Linux (non-RTOS), the CPU cannot timestamp individual samples with sufficient precision - processing latency introduces jitter of several milliseconds. The MCU's hardware timer eliminates this jitter.

How timestamps are derived

GPS antenna
    |
    |  PPS pulse (1 Hz)
    v
MCU timer --resets to 0-->  counts sub-second elapsed time
                                         |
                                         |  timer value (e.g. 0.347 s)
                                         v
CPU processing timestamp ---------->  timestamp merge
  (second-level precision,                |
   always slightly after                  |  merge:
   actual sample time)                    |  UTC second  = trunc(cpuTime - timerValue)
                                         |  sub-second  = timerValue
                                         v
                                  UTC sample timestamp
                                  (sub-millisecond accuracy)

The merge:

  1. Extract the sub-second component from the MCU timer value.
  2. Subtract it from the CPU processing timestamp and truncate to the nearest UTC second boundary.
  3. Add the sub-second component back to get the precise UTC sample timestamp.

When PPS is active, the MCU timer resets reliably each second, so the derived timestamps align with UTC second boundaries. The system detects PPS activity by monitoring timer resets - a reset is expected within a 1.001 s window; if resets stop arriving, the system falls back to CPU-only timestamping with reduced precision.

Clock skew between the MCU timer and the Linux system clock is tracked continuously and exposed in the module's status telemetry.

Resampling

Even with precise MCU timestamps, the actual sampling rate of a sensor may drift slightly from its nominal frequency. Resampling normalises data channels to a fixed target frequency before batching and publishing.

Strategies

Two resampling strategies are available, configured per channel in the resampler processor:

addRemove

Corrects drift by inserting or removing samples to match the target rate. Actual sample values are preserved - synthetic samples are duplicated from adjacent real samples. Timestamps remain anchored to the MCU-derived UTC time.

Use when timing accuracy matters more than signal smoothness (e.g. vibration, structural monitoring).

linearInterpolation

Corrects drift by computing new samples at target timestamps via linear interpolation between the two nearest real samples. All output samples are synthetic - the output signal is smooth at the cost of introducing interpolated values.

Use when a smooth, evenly-spaced signal is required (e.g. slow sensors, display/visualisation feeds).

Drift detection

Both strategies use the same drift detection core (ADR-006). On each incoming frame:

  1. Compare the actual sample count and timing with the expected count at the target frequency.
  2. Compute the drift (excess or deficit samples).
  3. Apply corrections (add/remove, or interpolate) distributed across the affected sequence range.

Accumulated drift is exposed in channel status telemetry. A complete data-source reset is required if drift correction encounters an unrecoverable error.

Batch alignment (syncTimeInit)

The windower processor supports a syncTimeInit flag. When enabled, the first batch is withheld until the next UTC second boundary, so all channels with syncTimeInit=true begin their first published batch at the same second. This simplifies post-processing alignment across channels with different start times.