trialClocks and frames - understanding the logic of the generated code

In a loop that sets up variables within a given trial, I have:

t = 0 
trialClock.reset() #Resets the trialClock (trial clock was initialized as core.Clock() )
frameN = -1

Then a while loop that follows this ( while continueRoutine: ) contains the following code:

t = trialClock.getTime()
frameN = frameN + 1  
score_text.setAutoDraw(False) # removes the last score_text from the screen
score_update = 'this is some text that is generated based upon the score in the last trial, I've taken the code out here to simplify everything' 
score_text = visual.TextStim(win=win, name='score_text', text= score_update , font='Arial', pos=(0.6, 0.3), height=0.1, wrapWidth=None, ori=0, color='white', colorSpace='rgb', opacity=1,depth=-2.0);
                    
if t >= 0.0 and audio_stimulus.status == NOT_STARTED:
  audio_stimulus.tStart = t
  audio_stimulus.frameNStart = frameN  
  audio_stimulus.play()  
                    
if t >= 0.0 and key_resp_2.status == NOT_STARTED:
  key_resp_2.tStart = t
  key_resp_2.frameNStart = frameN  # exact frame index
  key_resp_2.status = STARTED
  win.callOnFlip(key_resp_2.clock.reset)  
  event.clearEvents(eventType='keyboard')
                    
if key_resp_2.status == STARTED:
   theseKeys = event.getKeys(keyList=key_strings) 
   if "escape" in theseKeys:
       endExpNow = True

In the initial loop:
• Why does t need to be set to 0 if in the following loop it’s going to be set to trialClock.getTime() anyway?
• Why set frameN = -1?
In the while continueRoutine: frameN is set as:
frameN = frameN + 1
Couldn’t it just be set at this point as:
frameN = 0 ?

–

The t >= 0.0 part of the if statements doesn’t seem to say anything… isn’t t always >= 0 here? However if I simplify this to e.g. audio_stimulus.status == NOT_STARTED: then the code won’t run anymore… I don’t understand why?

I presume that once audio_stimulus is set to audio_stimulus.play(), or key_resp_2 is set to key_resp_2.status = STARTED, that something behind the scenes starts measuring time from the starting point of e.g. audio_stimulus.tStart, and starts measuring frames from the starting point of e.g. audio_stimulus.frameNStart ? Why couldn’t audio_stimulus.frameNStart = frameN have simply been audio_stimulus.frameNStart = -0 ?

–

The following bit of code:

win.callOnFlip(key_resp_2.clock.reset)  
event.clearEvents(eventType='keyboard')

seems to clear the set of keys already saved from the previous trial, and set up an instruction for the clock for key_resp_2 to reset when the off screen buffer is flipped to appear on screen - is that correct?

The final bit of code collects the keys punched on this particular trial. One problem I have here is that I only want to allow participants to press one key, but currently they can correct their response at any given time but pressing a new key. How might I change this? Would this have implications upon this issue I have: frameRemains = 1000 + 1.0- win.monitorFramePeriod * 0.75

It doesn’t, as long as it isn’t used before the t = trialClock.getTime() line.

No, because that is inside the loop, so it would keep being reset to 0. The point is that this value needs to increment on every iteration of the loop. If you don’t want to initialise the counter before the loop, then you have to do some conditional code within the loop (i.e. if this is the first iteration, set the counter to 0, otherwise, increment it).

Remember that Builder is automatically generating code, so to simplify things, it deals in the general case. Components can start at any time within the trial, so there is always a check that the current time is greater than the onset time of a given stimulus. If you are writing your own code, of course you can make things more efficient by not doing some things at that are relatively mindless.

Neither can we, in the absence of more detailed information than “the code won’t run anymore”.

Don’t presume that. Most of the code you are showing is all about monitoring the time and frame numbers. Nothing “behind the scenes” could be measuring time or counting frames, unless it is explicitly told about the clocks you are using in your code, when they get reset, and the frames you are counting.

No, no keys are saved unless you explicitly do that into a variable. The buffer is cleared each time you call event.getKeys(). You call event.clearEvents() to remove any keys that have been pressed during a period in which you weren’t checking for responses (e.g. keypresses tased in an inter trial interval). That way, only new responses will be detected.

Yes.

Only deal with the first response in the buffer.

1 Like

Thanks for all of that.

Sorry ‘Why set frameN = -1’ was a slightly stupid question. Obviously the reason it is set as this is that ‘frameN = frameN + 1’ adds 1 frame on each iteration of the loop. I think I’m just still bamboozled by the idea of what a frame is. Is there really just a single frame for each iteration of my loop that both updates onscreen text and that has another text stimulus appear later that tells the participant whether or not their response was correct (that’s what the frame counter implies). I would have guessed that two screen updates would constitute at least 2 frames? My current understanding of frames comes from your previous response and: https://en.wikipedia.org/wiki/Frame_rate

You’ve written this to me previously (thanks so much for all of the help by the way):

“The key to understanding frames and frame counting is that win.flip() is not executed immediately. Instead, your code effectively pauses at that point until the next screen refresh cycle occurs. e.g. an LCD screen typically updates at 60 Hz, or every 16.666 ms. If it takes you 4 ms to manipulate and draw your stimuli, and then you call win.flip(), then there will be a 12.666 ms pause until that content actually appears on screen. i.e. our code has to operate within the bounds of that inexorable hardware cycle. The problem here is when it takes longer than 16.666 ms to do everything needed: in that case, the current content stays on the screen unchanged until the next cycle, which is what is called “dropping a frame”.”

So this is to say that on win.flip() the code pauses for 12.666ms (unless it takes longer than 16.666ms to do everything, in which case that counts as a dropped frame) and then the frame changes. Does the frame then continue to change from this point at a frequency of 60Hz (i.e., a series of frames that look the same), or does the next frame occur on the next time the on screen material updates (so the next time win.flip() is called, I guess?). …You can tell I still don’t understand this…

Every time ‘frameN = frameN + 1’ appears in the code, does that constitute a single frame having occured? Should it actually constitute 2 frames if two onscreen events are taking place? win.flip() is called only once in my code, yet (in the time before it is next called) at two separate moments: the onscreen text is updated, and a bit of text appears saying ‘incorrect’ if the participant’s response is incorrect - how is that even possible?

In terms of this bit, it turns out that I’m wrong. If I delete t >= 0.0 then it still runs fine. Apologies

I set it to print time and frame starts and got the following:

(‘audio_stimulus.tStart’, 0.04929304122924805)
(‘audio_stimulus.frameNStart’, 0)
(‘key_resp_2.tStart’, 0.04929304122924805)
(‘key_resp_2.frameNStart’, 0)
(‘audio_feedback.tStart’, 2.540242910385132)
(‘audio_feedback.frameNStart’, 29)
(‘audio_stimulus.tStart’, 0.048152923583984375)
(‘audio_stimulus.frameNStart’, 0)
(‘key_resp_2.tStart’, 0.048152923583984375)
(‘key_resp_2.frameNStart’, 0)
(‘audio_feedback.tStart’, 1.0753200054168701)
(‘audio_feedback.frameNStart’, 12)
(‘audio_stimulus.tStart’, 0.04902482032775879)
(‘audio_stimulus.frameNStart’, 0)
(‘key_resp_2.tStart’, 0.04902482032775879)
(‘key_resp_2.frameNStart’, 0)

That seems to answer my question as to whether frames correlate to screen updates as ‘no.’ It’s measuring frames from the starting point which is always 0, and it’s measuring time from whatever the current value of t is. Within each trial I’m doing the following:

trialClock.reset() 
frameN = -1

Is it correct to reset both of these within each trial? Or should this be happening for every block of trials? or ?

The code seems to be accurately counting frames such that e.g., audio_feedback.frameNStart = 12 (audio_feedback is played once the participant has responded (only if incorrectly), so this makes sense). However this doesn’t seem to have much to do with the frameN = frameN + 1 counter that only appears once every trial - how are the frames being counted?

The code for this is currently:

if len(theseKeys) > 0:  # at least one key was pressed
   key_resp_2.keys = theseKeys[-1]  # just the last key pressed
   key_resp_2.rt = key_resp_2.clock.getTime()

I guess I should then update it to:

if len(theseKeys) > 0:  # at least one key was pressed
   key_resp_2.keys = theseKeys[0]  # just the last key pressed
   key_resp_2.rt = key_resp_2.clock.getTime()

Will this still collect the correct key_resp_2.rt though?

Is there no way of just limiting

theseKeys = event.getKeys(keyList=key_strings)

to a length of 1 (unless escape is pressed) ?

…OK I’ve just got PsychoPy to print the ‘t’ and ‘FrameN’ variables as it goes and I think I might be understanding frames better now…

Each of the while continueRoutine: loops completes up until the point that it reaches the win.flip() line. At this point win.flip() pauses the code until the next computer screen update. At this point it starts the loop again. As such I get an output that looks like this (t followed by frameN on each iteration of the loop):

0.162472963333
1
0.245879888535
2
0.345243930817
3
0.428670883179
4
0.511047840118
5

Does that sound like a decent enough explanation of how the code counts frames? (Thanks again for the help - sorry for the barrage of questions…)