Loop Skips Presentation of Images when Presented at Fast Rate (30Hz)

OS : Windows 11
Monitor: 60 Hz refresh rate
PsychoPy version: 2023.1.3
Standard Standalone? (y/n) Yes
What are you trying to achieve?:
I am presenting images at different rates (different Hz, the fastest being 30Hz) for 15s. I have a loop structured with 450 repetitions and all the components are 33.3ms, so that each repetition of the loop equates to the images flashing at 30Hz for 15s on one side of the screen.

Depending on the condition, I want the images presented to alternate with a blank screen (33.3ms presentation of an image, then 33.3 ms of a blank image, then back 33.3s ms of image) for the entire 15 seconds.

What did you try to make it work?:
I used a code component (begin routine) to change the image variable to an empty image for every other trial. From the output csv file, this looks like the code does it correctly, but from the output (and while watching the screen), it is clear the loop skips some presentations.

As you can see from the screenshot, column AK shows the start time of each routine, with each row being a new cycle in the loop. If you look at column AM, pic2 (an image presented on the left), we see with every other row that the image is correctly changed to a blank image (empty.png). We see though that the start time for the routine is blank for random rows. For these rows that have blank timings, they do not actually present in the experiment, and results in seeing multiple images in a row without a blank between, or multiple blank screens without seeing any image flash.

My question is, how do I get the experiment to not skip these routines, and actually present the images? This is not caused by any “continueRoutine = False” code. My thought is that it is something with trying to update the picture image makes the loop structure freak out and unable to present the routine in time, so it skips to the next row.

Hello

How are you trying to achieve the presentation rate? We just see the results of your approach. Does your monitor support this presentation rate? Depending on your approach, it may be better to use frames rather than ms to set presentation durations.

Based on a suggestion from @wakecarter, I have a change blindness experiment that requires relatively fast image changes. I think this could be adapted to your needs, at least it might help to find a suitable solution.

In the Begin routine tab of the image presentation routine

stage = 1
skip = 0
trial_clock = core.Clock()
trial_end = core.Clock()

then in the Each frame tab

    thisExp.addData("resp.keys", " ")
    thisExp.addData("resp.rt", 60.00)
    skip = 1
    continueRoutine = False

if stage == 1:
    Bild.setImage(original, log = False)
    if trial_clock.getTime()*1000 >= picdur:
        stage = 2
        trial_clock=core.Clock()
elif stage == 2:
    Bild.setImage(flicker, log = False)
    if trial_clock.getTime()*1000 >= maskdur:
        stage = 3
        trial_clock=core.Clock()
elif stage == 3:
    Bild.setImage(original, log = False)
    if trial_clock.getTime()*1000 >= picdur:
        stage = 4
        trial_clock=core.Clock()
elif stage == 4:
    Bild.setImage(flicker, log = False)
    if trial_clock.getTime()*1000 >= maskdur:
        stage = 5
        trial_clock=core.Clock()
elif stage == 5:
    Bild.setImage(changed, log = False)
    if trial_clock.getTime()*1000 >= picdur:
        stage = 6
        trial_clock=core.Clock()
elif stage == 6:
    Bild.setImage(flicker, log = False)
    if trial_clock.getTime()*1000 >= maskdur:
        stage = 7
        trial_clock=core.Clock()
elif stage == 7:
    Bild.setImage(changed, log = False)
    if trial_clock.getTime()*1000 >= picdur:
        stage = 8
        trial_clock=core.Clock()
else:
    Bild.setImage(flicker, log = False)
    if trial_clock.getTime()*1000 >= maskdur:
        stage = 1
        trial_clock=core.Clock()

original, changed, flicker are column names of an Excel file that I use to load the original image, the changed image and the flicker mask. picdur and maskdur are column names of the Excel file that represent the duration of the image and the mask. Maximal trial duration is 60 seconds.

Here is the trial setup.

grafik

Best wishes Jens

Dear Jens,

Thank you for your suggestions and reply! The monitor is able to support presentations at 30Hz, as it has a 60Hz refresh rate.
Below is a picture of my routine and loop structure – all of the components here are set to 0.0333s duration (33.3 ms). The pictured routine is contained in loop30hz, which is set to repeat 450 times. My code to change what image is presented when is contained in the code_15 begin routine tab, where either a image is presented every rep in the loop, or switches between a blank image (‘empty.png’) or a real image.


When I change the component’s duration to frame duration, it fixes the problem of the loop skipping over some iterations, but critically, it presents for too long.
Instead of the images flashing for 15s total, it goes over by multiple seconds, sometimes out to a full minute. I calculated the number of reps for the loop to be 450 based on 15s/0.0333s, so it goes through all 450 reps fine, but overall presents for far too long. When I subtract start and stop times per loop iteration in my csv, I see that each trial is presented for .15s instead of 0.0333s.

I will look into your suggestion in the meantime, and thank you again for your reply and feedback.

Thanks,
Jess Smith

Hello

Your loop30Hz is in terms of the experiment one trial? Is it just one image you show in loop30Hz? If this is the case I would try a different approach, more as outlined in the change blindess experiment. Just swap the image and blank every other frame.

See toy-example below using text instead of an image.

Flicker.psyexp (16.2 KB)

Best wishes Jens