sync_clocks#

pypillometry.sync_clocks(src, dst, src_units=UNSET, dst_units=UNSET, slope=True, tol=5)[source]#

Fit a linear map from one clock to another from paired times.

Behaviour logs (e.g., from Psychtoolbox, PsychoPy or Presentation) and eye trackers use different clocks. They differ in their zero point and drift apart slowly, so an offset alone can be off by several ms within a session. Given the times of the same moments on both clocks (e.g., the start of each block), this fits dst = offset + slope * src by least squares.

The pairs are matched by order. A summary of the fit is logged; the residuals show whether the pairing is right (large residuals mean that a pair is shifted or missing).

Parameters:
  • src (array-like, Quantity or Events) – times on the source clock (e.g., from the behaviour log)

  • dst (array-like, Quantity or Events) – times of the same moments on the target clock, in the same order (e.g., d.events.filter("Start Block"))

  • src_units (str or Unit, optional) – units of plain numbers in src and dst (e.g., “sec”, “ms”); needed unless the times carry units or are Events

  • dst_units (str or Unit, optional) – units of plain numbers in src and dst (e.g., “sec”, “ms”); needed unless the times carry units or are Events

  • slope (bool) – if True (default), fit offset and slope (drift); if False, only the offset. With a single pair, only the offset is fitted.

  • tol (float, str or Quantity, optional) – a warning is given if a residual is larger than this (plain numbers in ms); default 5 ms

Return type:

ClockSync

Returns:

the fitted map; call it on times or Events to map them to the target clock

Raises:

ValueError – if src and dst differ in length, are empty or contain NaN, or if units are missing

Examples

Map the stimulus times of a behaviour log behav (a table with times in sec) onto the eye-tracker clock of d, using the start of each block (a “Start Block” event in d) as the common moments:

>>> starts = behav.groupby("block").trialstart.min()
>>> sync = pp.sync_clocks(starts, d.events.filter("Start Block"),
...                       src_units="sec")
>>> d.add_events(sync(pp.Events.from_table(behav, ["stim_on"],
...                                        units="sec")))