Best pratice for presenting a stimulus during X ms

Hi,
I would like some advice about the best pratice to present a stimulus during X ms. I have used 2 methods in the past, and each seems to have advantages and drawbacks. In addition, PsychoPy has evolved considerably during the past 2 years, and there might be more efficient methods.

Imagine that we want to present a stimulus during 100 ms.
Method 1: present the stimulus during X frames

framerate = win.getActualFrameRate()
frameDur = 1.0 /round(framerate)
resp = keyboard.Keyboard()
Nframes_100 = int(round(.1/frameDur))
for i in range (Nframes_100):
   stim.draw()
   win.flip()

Advantage: precision of presentation duration
Drawback: if you loose some frames for whatever reason, timing can be bad.

Method 2: determine presentation duration with a clock:


resp = keyboard.Keyboard()
win.callOnFlip(resp.clock.reset)
win.callOnFlip(resp.clearEvents, eventType='keyboard') 
check = 0
While True:
    if check == 1:
        t = resp.clock.getTime()
        if t >= .1:
            break
   stim.draw()
   win.flip()
   if check == 0:
      check =1

Advantage : can maintain a reasonable timing, even if you drop frames

Would you then advise to use Method 2 ?
Is there a way to refine the above code for Method 2 to increase the precision of presentation duration ?
Thanks for the advice.

Hi, yes, in most cases it is probably best now to use the timing approach, as it is more robust to frame-dropping issues. A good guide can be to look at how the latest version fo PsychoPy Builder (>= 3.2.0) controls the timing of stimuli. In particular, search for tThisFlip, the estimated time of the next screen refresh, given by win.getFutureFlipTime(), and frameTolerance.

Frame counting can still be a useful approach in certain situations, for example if you want to guarantee that a stimulus (especially a very brief one) is actually displayed, despite something that may have intruded on keeping up with the overall absolute timeline.

@Michael I just studied the code generated by the Builder (> 3.2). Really cool. A few comments:
Since the win.getFutureFlipTime() is computed as win._lastFrameTime + refreshInterval, it looks like this approach is not robust to frame-dropping issues. If you drop a frame, the win.getFutureFlipTime() estimate will be inaccurate right ? I am worried that this approach is essentially similar to the traditional frame counting approach. Why not using a simple timing approach like:

resp = keyboard.Keyboard()
win.callOnFlip(resp.clock.reset)
win.callOnFlip(resp.clearEvents, eventType='keyboard') 
check = 0
framerate = win.getActualFrameRate()
frameDur = 1.0 /round(framerate) 
While True:
    if check == 1:
        t = resp.clock.getTime()
        if t > (.1-frameDur/2.):
            break
   stim.draw()
   win.flip()
   if check == 0:
      check =1