Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Apparent off-by-one (or more) timing error in Builder scripts #4828

Closed
m-macaskill opened this issue May 10, 2022 · 2 comments
Closed

Apparent off-by-one (or more) timing error in Builder scripts #4828

m-macaskill opened this issue May 10, 2022 · 2 comments
Labels
🐞 bug Issue describes a bug (crash or error) or undefined behavior. 🐍 Py Builder outputs Issues with the way the Python is written by Builder

Comments

@m-macaskill
Copy link
Contributor

m-macaskill commented May 10, 2022

Builder components can record their.started and .stopped attributes in the datafile, using an absolute time in seconds. In this minimal example, the first text stimulus t_0 has a specified onset time of 0 s relative to the start of the trial, with subsequent text stimuli having onsets at 2 and 4 s:

Screen Shot 2022-05-10 at 19 42 18

Over two separate runs of five trials, subtracting the times of onset between the three stimuli gives the following relative onset times (which should be 2.0, 4.0, and 2.0):

trial t2-t0 t4-t0 t4-t2
0 1.9551 3.9537 1.9986
1 1.9833 3.9839 2.0006
2 1.9831 3.9840 2.0009
3 1.9831 3.9834 2.0003
4 1.9836 3.9842 2.0006
trial t2-t0 t4-t0 t4-t2
0 1.9658 3.9659 2.0001
1 1.9841 3.9834 1.9993
2 1.9655 3.9837 2.0182
3 1.9859 3.9836 1.9977
4 1.9678 3.9682 2.0004

(1) The intervals between the onset of stimuli t_4 and t_2 (the third column) are effectively exactly 2.0 seconds, as intended.
(2) The intervals between the onset of t_0 and the later stimuli are shorter than intended, by 1, 2 or even more frames.
(3) When subtracting the time of onset of t_4 from its time of onset on the previous trial, it was short by approximately 1 frame. i.e. this is an empirical measure of the total routine duration, including transitions between one routine and the next, and should be 5.0 seconds in this case. The shortened duration means the timing error would tend to accumulate over loop iterations. This might particularly affect fMRI tasks, and other studies which require multiple consecutive trials on a fixed schedule.

The error in relative onset times seems to apply only with respect to stimuli appearing at t = 0, as the relative times between the later stimuli are correct. This would be consistent with the onset of the first stimulus being delayed (e.g. a dropped frame). But that wouldn't be consistent with the overall duration of the trial being apparently shortened by a frame.

Because stimuli (and keyboard components) are appearing at times other than intended relative to the start of the routine, this can lead to systematically incorrect measured reaction times.

The issue can be more pronounced in the first iteration of a loop, although given the way Builder stimuli are pre-created before the routine, it isn't obvious why there might be such a start-up cost.

This issue does not just apply to visual stimuli but also sound stimuli, and presumably other components. It was first noted in a regular experiment, but is easily reproducible in a minimal .psyexp file like the one attached, which was used to generate the values above. It occurs both in fullscreen and windowed modes. This has been observed when running local Python scripts: I haven't tested it on Pavlovia.

Example file below. I just calculated the time intervals manually, by opening the .csv files in a spreadsheet and subtracting columns of .started attributes from each other.

timing_issue.psyexp.zip

@m-macaskill m-macaskill added 🐍 Py Builder outputs Issues with the way the Python is written by Builder 🐞 bug Issue describes a bug (crash or error) or undefined behavior. labels May 10, 2022
@peircej
Copy link
Member

peircej commented Jun 16, 2022

Thanks @m-macaskill
I can see the issue, and the question is how to handle it. The non-slip mechanism in Builder code is limiting the overall time of the trial, but not altering the time of individual components. That's fine if the trials are overrunning, but not so good if they're underunning, as in your case (the trial ends early, because all the stimuli have finished, before the non-slip timer has a chance to kick in). I'll need to look at how to refactor this so that the timer is applied to all individual components rather than only the trial endpoint

@peircej
Copy link
Member

peircej commented Jun 16, 2022

OK, this was actually relatively to fix and the result is sort of simpler! 😄
Explanation is in the PR #4933 but basically, from now on we'll just have a single (count-UP) clock that's used for every Routine and each Routine resets that timer, ready for the next, by either:

  • subtracting its own known duration (non-slip)
  • or setting to zero (if duration is not known)

and then this timer is used by all components in the subsequent Routine. This will be included in the upcoming 2022.2.0
Attached is a data file from your study showing the fixed timings where the only timing delay is with the render of the very first stimulus and the rest are tight (under sub-optimal conditions on a laptop using windowed mode and many apps open):
timing_fixed_2022-06-16_12h06.27.867.xlsx

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🐞 bug Issue describes a bug (crash or error) or undefined behavior. 🐍 Py Builder outputs Issues with the way the Python is written by Builder
Projects
None yet
Development

No branches or pull requests

2 participants