psychopy.org | Reference | Downloads | Github

Confusion about how to implement non-slip timing for trials with known end points


#1

Hello,

I am designing a task-based fMRI experiment with trials with known length (not variable). I put them in a loop in builder. Once in a loop, they turned from green to red. According to http://www.psychopy.org/general/timing/nonSlipTiming.html, routines shown in red are using relative timing and might cause de-synchronization. I don’t know why putting it in a loop causes it to turn red, and don’t know if I now need to be concerned about time slippage?

If so, I’m also confused about how to implement the non-slip timing using code like:

timer = core.Clock()
timer.add(5)
while timer.getTime()<0:
# do something

How do I integrate this code with my existing experiment, what goes in the ‘do something’ section? Can you direct me to an online example so I can see what goes in ‘do something’, and extrapolate how to implement this with my task?

Thank you!!!


#2

This is an unfortunate limitation of Builder that @jon and I have discussed in the past but haven’t done anything to resolve. You do really need to address it in your experiment: I’ve found in an fMRI study in exactly this sort of situation that the timing would drift by at least several hundred milliseconds over the course of 10 minutes or so if the routines weren’t coloured green.

I think my work-around for this was to insert some dummy fixed number like 9999 as the trial duration. Then push the “compile script” button. In that script, do a search for all instances of 9999 and replace with your relevant variable name. Make sure you save this edited script with a different name than the default, otherwise Builder will over-write it any time a change is made. Note that you now need to run this amended script rather than the original Builder experiment. In PsychoPy, this can be done from the Coder view rather than the Builder view. If any changes need to made to your experiment, you’ll need to go back to your original Builder experiment, make the changes graphically there, and then re-do this find and replace strategy in the new generated Python script.

You should insert some timing code to see what the effects of the slip vs non-slip timing are. If you have implemented non-slip timing correctly, you should find that the actual duration should be within 1 ms or so of the intended duration.


#3

Thanks Michael for that recommendation. I’ll play around with that.

I was wondering your feedback on another possibility. I would like to time-lock the stimulus presentation to the TR. (My TR is 2 seconds and my stimulus presentation is therefore also 2 seconds). Can I get around issues of slip-timing by simply adding a ‘wait for t’ component to my routine so that it shows the stimulus while it waits for the next ‘t’ trigger from the scanner and force ends the routine based on the incoming ‘t’?

Thanks so much!


#4

That probably just introduces unnecessary complexity. You can rely on the TR of the scanner being very precise. Similarly, PsychoPy can show stimuli very precisely for two second durations, subject to some caveats. The important thing is to text that your task duration matches the scanner run precisely. The only important TR signal to catch is the very first one. After that, if things are specified correctly, you should find that your task ends within a millisecond or two of the intended duration.

You just need to time all of this to satisfy yourself that it is working correctly. When it does, you’ll subjectively find that the final stimulus ends the moment the scanner noise noise stops.


#5

Hi Michael,

Okay, thanks for your feedback. Forgive my misunderstanding, but I looked through your original suggestion and I don’t understand what it accomplishes. If I put in a dummy fixed number as the trial duration, compile the code, look for the timing, and replace the variable name, how does that help me address non-slip timing? It seems like all I’d be doing is substituting one variable name for another. If you could provide a link to an example or more information about how to tackle this, I’d greatly appreciate it.

You also recommend inserting some timing code to see what the effects of slip vs. non-slip timing are. Can you give me any more specifics on what that would look like?

Thanks so much on any guidance you can provide!!


#6

Because the generated code is different when you have a fixed time duration. You are therefore inserting your variable name into non-slip code. If in the Builder interface you use a variable rather than a fixed time, your routine turns red and the resulting code is different.

By using a fixed time value, you are tricking Builder into generating the code you want, and can then edit that code to use your variable name instead.


#7

Something like the code below (I’m assuming you have a single trial routine running within a loop, where the first trial will start following the first trigger from the MRI). Insert a code component on that routine:

Begin routine tab:

if your_loop_name.thisN == 0: # only on the 1st trial
    start_time = globalClock.getTime()

End experiment tab:

expt_duration = globalClock.getTime() - start_time

print('This run lasted: ' + str(expt_duration))