Repository navigation
Time and synchronization
Every sample openSciLab shows has a time on one clock: the clock of the computer it runs on. A logic analyzer behind USB, a DAQ on another computer and a simulator each have clocks of their own. This page explains how their samples are placed on that clock, how well, and how to do better: with a measured latency, a sync signal, a shared sample clock or a shared time scale (NTP, PTP, GPS).
It matters when several instruments record the same event, when a flow sets an output and measures the reaction, or when values of a remote device have to line up with a capture. For a single capture on a single device, nothing on this page is needed.
| Method | How | Accuracy (guide values until measured) |
|---|---|---|
| simulated | a simulator knows when it took its samples | exact |
| sync signal | the same irregular signal recorded by both instruments, edges matched | a sample period of the slower recording |
| shared clock | both sample with one clock; a sync signal gives the offset only | as above, without drift |
| time scale | the device stamps in UTC/TAI (PTP, GPS) and this computer's clock follows it too | what PTP/NTP achieve (PTP with hardware time stamps: < 1 µs; in software: 10–100 µs) |
| latency | the arrival of the data, less a latency measured with a loopback | a fraction of a millisecond |
| bounds | between the command that started the capture and the arrival of its data | half the distance (about a millisecond over USB) |
| arrival | only the arrival of the data | an upper bound (late by the shortest latency) |
| network (remote devices) | the device's clock measured with pings | ± half the shortest round trip (wired: 0.1–0.5 ms, WiFi: ms) |
Without anything to do, openSciLab uses bounds: a sample cannot be taken before the command that started the acquisition, and a block of samples cannot arrive before its last sample was taken. The arrivals jitter (USB frames, buffers, the operating system); openSciLab draws a line under the fastest ones, which removes the jitter, and once a stream has run for about 10 s its slope also gives the drift of the device's sample clock. A capture that waited for a trigger has no start bound, so only its arrival (less a measured latency) places it.
Every instrument that captures has a Timing tab on its device card (Devices):
- Time of the samples: how the last capture or stream was placed (Placed by, e.g. between start command and arrival or sync signal), its Accuracy, the Sample clock, whether the device stamps its samples in a time scale (Device time stamps) and This computer's clock. This works for captures of a data view and of a flow alike. This computer's clock… opens Settings → Time; Align with a sync signal (example)… opens the example flow.
-
Sample clock: Own sample clock (offset and drift are fitted) or Shared or external sample
clock (only the offset is fitted).
timing.alignfollows this choice (itsdrift: auto). -
Latency: the latencies measured for the device, and a loopback measurement without a flow:
choose the Output, the channel it is wired to, the Rate and the Mode (Stream or
Capture), then Measure. On a simulator, Wire them (simulator) adds the wire.
Forget the latencies deletes them; In a flow (example)… opens the flow with
timing.calibrate. - Sync output: a sync signal on a Pin (with a Seed) from Start until Stop (or until the card is closed), e.g. for an input of a DAQ that records it along with its data.
The Details tab lists the same Time of the samples among everything else about the device.
An output of the instrument is wired to one of its own inputs and switched a few times. An edge cannot be recorded before the command that made it, and its sample cannot be later than its arrival; half of the shortest loop is the latency of the input. It is kept per instrument, mode and rate (and length of a capture) and used by every later capture or stream with the same settings – the wire is only needed once.
- Wire an output to a channel of the same device with a jumper (for example GP16 to GP17 on a Pico).
- On the device card, Timing → Latency: choose output, channel, the rate you capture with and the mode, then Measure. The result shows in a message and in the list.
- Or in a flow: node
timing.calibratewithpin,channel,rateandmode(real time only). Example: Templates → Time → Calibrate latency.
The measured latencies are listed (and can be forgotten) in Settings → Time as well.
The most precise way to put two instruments on one time axis: one output makes edges at irregular intervals (20–60 ms, the same for the same seed), and every instrument records it on a spare channel. Because the pattern of intervals is unique, the edges can be matched without ambiguity, even when the clocks are seconds apart.
- Choose a free output pin on one instrument and wire it to a channel of every instrument to align (and to the reference).
- In the flow,
timing.syncdrives the pin (or Sync output on the Timing tab does it). - Stream (or capture) the sync channel on each instrument.
-
timing.aligngets the signal as the instrument to align recorded it atsignal, and as the reference recorded it atreference(or the commandededgesoftiming.sync, as precise as that output). Itsdeviceinput is the instrument to align. - Everything wired to
inleavesouton the reference's time;offsetanduncertaintysay how far it was moved and how well. Later samples of that instrument are placed the same way.
drift of timing.align: auto (the default) follows the Sample clock setting of the device
card, fit fits offset and drift, none fits only the offset (a shared sample clock). The edges
are as precise as the recording: a DAQ at 10 kS/s aligns to about 30 µs, a logic analyzer at 100 MHz
to nanoseconds.
Example: Templates → Time → Align instruments – a simulated Uno drives the sync signal, a simulator that knows its time is the reference, a Pico behind (emulated) USB is aligned to a few microseconds. Templates → Start a project → Synchronized instruments does the same with a logic analyzer and a DAQ whose clock drifts.
When the sample clock of a device comes from another instrument (a DAQ clocked by the Pico, a 10 MHz
reference), the two never drift apart: only the offset has to be found, from one edge of a sync
signal or a shared start trigger. Set Shared or external sample clock on the Timing tab (or
drift: none on timing.align). Making such a clock in hardware is not part of openSciLab yet.
A device whose clock follows UTC or TAI (Linux with ptp4l and phc2sys, a GPS receiver, NTP)
can stamp its samples in that time scale. When this computer's clock follows it too, openSciLab
converts the device's times without measuring anything. Tell openSciLab in Settings → Time:
- This computer's clock follows: Nothing (no time scale), NTP (UTC, about milliseconds) or PTP (UTC/TAI, microseconds);
- Accuracy: how well it follows, in milliseconds (usual for it unless you know better).
PTP aligns the clocks of computers, not samples: an instrument behind USB still needs its latency or a sync signal to place its samples on that clock. macOS has no PTP client of its own; Windows has one with software time stamps.
A device on another computer stamps every value with its own clock when it measures it; the network
only delays it. openSciLab measures the offset and drift of that clock all the time with pings (a
fraction of a millisecond on a wired network, a few milliseconds over WiFi). The Remote tab of
its device card shows the Clock of the device: Method, Accuracy, Round trip, Jitter,
Drift. For microseconds, the device drives a sync output (or records a sync signal on one of its
inputs) and the flow node remote.sync matches it with a recording. See
Remote devices.
A simulator knows the exact time of its samples, unless it emulates a USB link:
- The simulated Pico emulates USB (frames, latency, jitter), so all the methods above work as with the real board. On any simulator, the Signals tab has USB link and clock (Emulate a USB link: Latency, Jitter, Frame; Clock drift) and Wires (Add wire… connects a pin to a channel, e.g. a loopback). See Simulators.
-
sim:daqis a measuring box on USB whose sample clock runs 30 ppm fast, with a loopback (P0.0 → P0.1) and P0.7 free for a sync signal. - The device list has a simulated remote DAQ with a drifting clock, with a clock that follows UTC (as with PTP) and with a shared sample clock. The Simulation: timing box on its Remote tab changes network latency, jitter and clock drift while it runs.
- The category Time of the templates has four examples: Align instruments, Calibrate latency, Remote DAQ and DAQ latency.
The threads that receive samples must never wait long: their arrival times place the samples, and the device's buffer fills meanwhile (the Pico firmware's stream buffer lasts about 22 ms at 6 MB/s). Therefore a Pico, an Arduino or a DSLogic is read in a process of its own (Settings → Devices → Read devices on USB in a process of their own, on by default), and the protocol decoders run in a process of their own as well. On a busy computer, Read devices with a higher priority (off by default) raises the priority of openSciLab and its device processes. Windows needs no rights for it; on macOS and Linux openSciLab asks when it starts, with the password dialog of the system, and on Linux Allow it for good (from the next login) saves the question. The Details tab of a device read in a device process shows its priority under Process.
- docs/timing.md – the details, including how device scripts measure their own latency
- Remote devices – devices on other computers and their clocks
- Simulators – USB link emulation, wires, clock drift
openSciLab · 0.1 beta
Instruments
Logic analyzer
The lab
More