Timing precision

PsychBench is built on Psychtoolbox. Psychtoolbox is designed with timing precision as a priority, and the same goes for PsychBench. Below is a technical summary of timing processes and precision. If you need more information, please contact us.

The timing precision of PsychBench is bounded by the timing precision of Psychtoolbox functions, which in turn depends on your operating system, hardware, and setup in general. For more information, see for example psychtoolbox.org/requirements.

Timing Precision / Compatibility

A number of screen object properties (usually set using pb_prefs → screen tab) set tradeoffs between visual timing precision and compatibility: doSyncTests, syncTestsParams, useCompositor. On systems where high precision settings cause problems in opening or closing the experiment window, you can switch to compatibility. If you do, you should not run experiments where precise timing is important (you can still develop and test them, and run other experiments). Most commonly this is on Macs, which is okay because according to Psychtoolbox you shouldn’t run precise timing experiments on Mac anyway.

Frames

Internally PsychBench divides time during trials into short increments called frames. Frames are locked to refresh of the screen the experiment is running on: frame transition is always at screen refresh, and nominal frame rate = screen refresh rate. A common screen refresh / frame rate is 60 frames/sec (interval = 1/60 ≈ 17 msec). See screen object record property refreshRate and trial object record property frameIntervals.

Frames define the timing resolution for most events during trials. For example, PsychBench checks to start/end elements once per frame, dynamic displays change on screen up to once per frame at screen refresh, response handlers often check for input from their device once per frame, etc.

Dropped frames

If a frame is too short for the processing that needs to run in it, it extends to multiple screen refresh intervals. The other frames that would have run in those intervals (one per interval) are “dropped”. This results in one iteration of all frame-based events where multiple were expected. For example, element start/end is delayed for one or more screen refreshes, moving element displays pause (but don’t disappear), etc.

PsychBench generally recovers timing after dropped frames. e.g. if frames are dropped during an element running and before it ends, its end time later doesn’t change and its synchronization with other elements is not be affected. (There are exceptions. For example, if dropped frames occur at element start and so delay its start time, and it has an end.duration cue set, then it will end later because the duration cue goes off actual start time. However, this is intended based on the definition of a duration cue.)

Element start/end

PsychBench checks to start/end elements once per frame, and element start/end aims to occur at the nearest frame transition. This is regardless of modality (visual, auditory, etc.). Note visual elements in particular are physically constrained to start or end at screen refresh.

Element synchronization

If you set the same start or end cue for different elements, they aim to start or end at the same nearest frame transition. This synchronizes them with the best precision Psychtoolbox allows.

Element start/end timing deviation

There are various potential sources of deviation between expected element start/end times and actual times you get during an experiment. Some have potential solutions which you can use if precise timing is important:

  • Timing may be less precise than usual in trial 1 due to MATLAB loading functions into memory on first use. If timing precision is important, consider discounting the results of trial 1.
  • The fact that element start/end snaps to frame transition causes a base deviation from expected start/end times of up to ±1/2 frame interval. This deviation averages to zero.
  • If frames are dropped due to processing at element start/end, that start/end is delayed by that many screen refresh intervals (Dropped frames above). If this type of delay is a problem, you can set a time “buffer” for the element. This tells PsychBench to expect the dropped frames and shift them from after the target start/end time to before it, giving PsychBench the time it needs to process the start/end on schedule. Note this can't eliminate the dropped frames, so for example some processes will still pause for the duration of the buffer, including display animation (not necessarily visible if you only set a short buffer, e.g. 1 frame ≈ 17 msec). But it can eliminate the delay in start/end time. See element properties startBuffer, endBuffer.
  • If an element is set to start/end at an event that occurs spontaneously (e.g. subject response, trigger, etc.), there is an additional delay of 2 frames average (1–3 frames min−max) from time of event. This is the sum of two delays: 0.5 frames average is from polling for events only once per frame. 1.5 frames average is from PsychBench’s timing algorithm, which needs to accommodate various competing demands.

Note this delay doesn’t apply to cues with time values where PsychBench can plan head, e.g. .t cues, end.duration cues > 2 frames, any cue with wait time .timeFrom > 2 frames, etc.

Measured times

Element start/end times

Element record properties startTime, endTime, duration record element times. Here are some common cases for how PsychBench gets these times:

  • Element presents a visual stimulus: Start/end times are frame transitions (screen refreshes) when the display starts/ends, measured by Psychtoolbox Screen('Flip').
  • Element presents an auditory stimulus: Start/end times are sound start/end times, measured by Psychtoolbox PsychPortAudio('GetStatus').
  • Element listens for input from a device: Start/end times are frame transitions that are the earliest and latest times input could be received, measured by Psychtoolbox Screen('Flip').
Input times

Response, trigger, and other input times are measured by Psychtoolbox GetSecs, KbCheck, KbQueueCheck, and similar functions depending on the device and method. In the case of an element that checks for input once per frame (e.g. KbCheck), PsychBench measures input time as the average of time of check where the input was received and time of check in the previous frame, with a basic uncertainty of 1/2 the interval between checks (≈ 8 msec at 60 frames/sec with no dropped frames). In other cases where a background process is used to listen for input (e.g. KbQueueCheck), input time is measured directly by the process. See response handler record properties responseTime, responseLatency, d_responseTime, and element record properties triggerTime, d_triggerTime.