Skip to content

physiosync

Timing corrections for multi-signal physiological recordings: the stamp sawtooth, hidden frame clocks, the ECG-to-PPG delay and its sawtooth, and the resolution of fiducial points. Dataset-neutral.

Repository github.com/metrology-atlas/physiosync
Branch main
Visibility public
Licence MIT
Language Python 3.10+ (numpy, scipy)
Related vitaldb-bench, lineaccess

What it is

physiosync works on times and samples it is given. It reads no file format and assumes no particular dataset, monitor, sampling rate or frame rate; a dataset's import code calls it and stores the results (corrected timing and quality labels). Corrections are applied only where they are corroborated, and each comes with a confidence tier.

Its part in the atlas

It holds the general methods that several VitalDB studies rely on: the stamp-clock fit (The stamp sawtooth model for SNUADC and BIS), the frame-clock search (The PPG's 30 Hz frame clock), the ECG-PPG sawtooth removal (The PPG sawtooth and its correction) and fiducial resolution (Every time is quantised, and fiducials inherit it). vitaldb-bench scripts call it on VitalDB cases.

What is in it

stamps.py Record stamps that follow a sample clock between corrections; fits the rate and offsets and removes the stamp sawtooth.
frames.py Finds a hidden frame clock at any rate, from the spectrum of sample-to-sample change and fiducial locking.
quantisation.py Effective temporal resolution of fiducial points, on whole-sample grids or partly locked to a period.
ecg_ppg.py The ECG-to-PPG delay; fits and removes the frame-slip sawtooth, with confidence tiers.
labels.py One label per sawtooth tooth, with its correction, resolution and confidence.
chains.py Rate-consistent chains of slips, as lower-confidence labels.
measurement.py The PAT measurement model of a recording, for downstream estimators.
pairing.py Beat pairing between ECG and PPG.
reference.py Published pulse arrival times by study and hardware.

Studies that use it

Study Code Summary
The PPG sawtooth and its correction physiosync/ecg_ppg.py, physiosync/labels.py The ECG→PPG delay creeps at 18–52 ppm and jumps up by one 33.3 ms frame at each slip, every 11–31 minutes. A tooth-by-tooth model removes it; where the correction is confident it is essentially exact on injected test data.
The PPG's 30 Hz frame clock physiosync/frames.py, physiosync/quantisation.py ECG and PPG fiducials resolve to one 2 ms sample, but PPG fiducials taken on raw samples lock to a hidden 33.3 ms frame grid. Scanning for it finds the oximeter's frame clock to about 1 ppm, a fixed fingerprint of each recording setup.
The stamp sawtooth model for SNUADC and BIS physiosync/stamps.py Fitting each track's record stamps against its sample count as a drift with corrections (a sawtooth) puts SNUADC and BIS on one timeline without any artefact. Checked against shared bursts, the EEG–ECG timing error falls from about 790 ms on the recorded stamps to 33 ms with one constant per SNUADC mode in the pilot, and 42 ms over the whole release.

Observations it handles

Observation Status Summary
Every time is quantised, and fiducials inherit it established A time on a grid of step Δ carries an error of Δ/√12 (1 SD). In VitalDB that is 0.58 ms for a 500 Hz sample, 2.3 ms for BIS EEG, 0.8 ms for the arrhythmia annotations' 1/360 s grid, and up to ±17 ms for PPG fiducials taken on raw samples, which lock to the 33.3 ms frame.
The ECG→PPG delay is a sawtooth established Inside the oximeter the PPG content creeps 18–52 ppm against its 30 Hz frames; every 11–31 minutes a frame repeats and the delay jumps up by 33 ms. The rate is fixed per recording setup.
The plethysmogram is built in 30 Hz frames established The SNUADC PLETH waveform comes from the oximeter in 33.3 ms frames, smoothed to 500 Hz. Its content changes once per frame, on the oximeter's own clock, about 0.4 s after the finger.

Worked examples

Example Side Status Summary
Pulse arrival time in two correction steps time draft The time from the ECG R wave to the pulse at the finger, as stored, after the PLETH's sawtooth is removed, and after its device offset is removed, smoothed by maximum likelihood, with the arterial line as the reference.

Mentioned in

References

  • Harris CR, Millman KJ, van der Walt SJ, et al. Array programming with NumPy. Nature. 2020;585(7825):357-362. ↗
  • Virtanen P, Gommers R, Oliphant TE, et al. SciPy 1.0: fundamental algorithms for scientific computing in Python. Nat Methods. 2020;17(3):261-272. ↗
  • LaussenLabs. hrvmatch [source code]. GitHub. ↗
  • Krekel H, Oliveira B, Pfannschmidt R, Bruynooghe F, Laugher B, Bruhin F. pytest. 2004. ↗