Synchronizing BLE sensor data on Android

A multi-modal recording might combine an EEG headset sampling at 250 Hz, an electrodermal activity sensor at 4 Hz, and a heart-rate monitor delivering RR intervals at irregular times. Each device can have its own clock and BLE connection. Meeting a defined cross-stream alignment tolerance requires an explicit timing architecture and validation fixture; phone arrival timestamps alone are not enough.

This guide separates four different problems that are often collapsed into "sync": sample timing inside each device, clock offset between devices, clock-rate drift over the session, and variable BLE delivery delay.

Build a relative clock-error budget

Every independent peripheral clock has frequency error and temperature sensitivity. As an illustrative bound, a device at +20 ppm can gain about 1.2 milliseconds per minute while another at -20 ppm loses the same amount, producing about 72 milliseconds of relative separation over 30 minutes. Use the oscillator specification and measured assembled hardware for the real error budget.

Required alignment depends on the phenomenon, preprocessing, analysis window, and study protocol. Have the scientific owner define the maximum offset and drift before engineering chooses a synchronization method.

Temperature, supply voltage, ageing, and board design can change clock rate. Characterize the finished devices over the operating conditions rather than copying a nominal crystal curve into the correction model.

Timestamp Architecture: Phone Clock as the Reference

The first architectural decision is the time reference. The phone's monotonic clock is useful for one-phone sessions, but it cannot recover capture time from BLE arrival time by itself. A peripheral master or hardware trigger may be better when devices can share timing.

On Android, SystemClock.elapsedRealtimeNanos() is a monotonic phone clock that includes deep sleep and is not changed by wall-clock adjustments. Retain wall time separately when correlation with civil time is required; do not use System.currentTimeMillis() for interval measurement.

Stamp every incoming BLE notification with elapsedRealtimeNanos() at the earliest possible point: inside the onCharacteristicChanged callback, before any processing. This gives you a phone-clock arrival timestamp for every packet from every sensor.

Why Not NTP?

NTP estimates wall-clock offset over a network; it does not timestamp a sample at the sensor. It may help correlate separate systems when its uncertainty is recorded, but it does not replace local monotonic time or device-side sample clocks.

Use NTP only when you need to correlate a mobile recording with data collected on a separate system, such as a lab computer or another mobile device. In that case, record both the monotonic timestamp and the NTP-synced wall-clock time, and perform the cross-device alignment offline.

Handling BLE Notification Jitter

The arrival time of a BLE notification on Android is not the time the sample was captured on the sensor. Between the ADC sampling instant and your onCharacteristicChanged callback, several variable-latency stages intervene: the peripheral's BLE stack queuing the notification for the next connection event, the over-the-air transmission, the Android Bluetooth HAL receiving and buffering the packet, and the Binder IPC delivering the callback to your app.

The delay between capture and callback includes firmware buffering, connection scheduling, controller and host queues, and app scheduling. Its distribution changes with packet cadence, active connections, RF contention, phone state, and OS build. Measure it with a shared hardware event or instrumented firmware; do not assume an arrival-jitter range.

To reconstruct capture timing through delivery jitter, the peripheral needs to expose a counter or timestamp tied to acquisition. Phone-clock arrival timestamps remain useful transport observations, but offset estimation needs repeated exchanges, a shared event, or another method with an uncertainty bound.

The Synchronization Algorithm

A synchronization pipeline can use four stages:

  1. Offset estimation. Exchange timestamped messages repeatedly or use a shared event, then estimate offset with an uncertainty bound. BLE batching and asymmetric firmware work must be included in that bound.
  2. Drift estimation. Fit peripheral time against the chosen session clock over enough observations to separate clock rate from delivery jitter. Report residuals and reject a linear model when the evidence does not support it.
  3. Clock mapping. Convert device timestamps into session time while preserving the originals and an uncertainty estimate. Start a new mapping segment after counter reset, reconnect, or evidence of a rate change.
  4. Cross-stream analysis. Preserve each stream at its native cadence. Resample only when the downstream method requires it, using a modality-appropriate rule documented by the scientific owner.

Example: three incompatible time representations

Imagine one stream exposes a wrapping sample counter, another exposes device wall time, and a third reports intervals between events. Normalize each only after documenting its unit, epoch, wrap behavior, reset behavior, and whether the timestamp represents acquisition, packet creation, or transmission.

Extend wrapping counters before conversion, map device clocks to the chosen session clock with repeated offset and drift estimates, and preserve the original timestamp fields for audit. Never claim a synchronization accuracy from the mathematical model alone. Validate it against a shared electrical or optical trigger captured by every device.

Android-Specific Pitfalls

Several Android behaviors can sabotage your synchronization:

Validating Synchronization Quality

Physiological responses are variable and have modality-specific latency, so a clap or deep breath cannot validate millisecond synchronization. Use a shared electrical trigger, LED plus photodiode, mechanical pulse, or another fixture that produces a sharply observable event in every acquisition path.

Run the fixture at the start, middle, and end of sessions long enough to expose drift. Report offset error, drift error, uncertainty, missed triggers, and behavior through counter wrap, reconnect, and process interruption.

DEVSFLOW / Connected Neurotechnology builds mobile data pipelines for multi-modal products, including cross-stream timing evidence and uncertainty reporting. Review our connected-device engineering scope.