psychopy.org | Reference | Downloads | Github

Experiment seems to be running at 30Hz rather than 60Hz?

I just noticed that my experiment seems to be running at half my actual screen refresh rate rather than full 60 hz. objects set to appear after e.g. 120 frames appear after 4 sec rather than 2 sec.
I don’t see anywhere in the screen options to specify refresh rate manually.

If I compile code and exchange win.getActualFrameRate() with 60 I get approximately the right timing, that is two objects set to appear after 120 frames and 2 seconds will appear roughly at the same time, but definitely not on the same frame. However my windows gaming overlay (windows key + G) still says my refresh rate in the experiment is at 30 hz.

Can anybody help??

OS (e.g. Win10): Win10
PsychoPy version (e.g. 1.84.x): 2021.2.3
Standard Standalone? (y/n) yes
**What are you trying to achieve?: run at 60 hz rather than 30

I did not know about the (window key + g) gaming overlay in win10: learn something new every day. :wink: It’s ‘FPS’ field appears to be reporting the rate at which the full screen app is calling win.flip(), not the refresh rate of your monitor (for example 60 Hz).

I’m guessing it is taking 2 retraces for your experiment to execute any per frame logic, including the display each ‘frame’ i.e. draw() the necessary resources and call win.flip(). Therefore your experiment frame rate is only 30 Hz, even though your screen retrace rate is 60 Hz.

To test this I created a simple project that displayed a single word of text for 300 frames. Alone, it runs for the expected 5 seconds, and the gaming overlay reports 60 fps. If I add a code component to the trial and do a core.wait(0.02) on Each Frame (forcing each frame to take an extra retrace), then it runs for 10 seconds and gaming overlay reports 30 - 40 fps on my computer.

I’m not sure there is anything you can do other than switch to using time based durations.

1 Like

Hm, I see. The issue came up as I was attempting to write some code to use with eyetracking, to see how for long a participant was looking at a certain stimuli on screen. My idea was to run something like the following code to append a ‘1’ to a list each frame gaze position was within the stimuli:

for stimulus in stimuli:
    if stimulus.contains(eyetracker.getLastGazePosition()):
        gazeFrameList.append(1)

at the end of each routine I could then save the sum of the list and thus have a number of frames - however that requires both a staple framerate and that I know the duration of a frame for this to be translatable to a passage of time.
Can you think of a way to achieve something similar time based rather than frame based?
I am using Eyelink 1000, for which the inbuilt roi component doesn’t work properly.

If you have a lot of elements in stimuli this should speed things up since each call to eyetracker.getLastGazePosition() can take ~ 0.25 msec:

gpos = eyetracker.getLastGazePosition()
for stimulus in stimuli:
    if stimulus.contains(gpos):
        gazeFrameList.append(1)

Thanks @sol that is good to know!
Alright I have investigated a bit, and I am now even slightly more confused than before.
By going to my nvidia control panel I can influence the rate at which the code in “every frame” tab is running. By forcing the graphics card to “maximal performance” I am getting the code to run at something like 100-110 Hz, whereas setting it to “even performance” will set the code to run at expected 60 Hz. Furthermore, displaying an object which is updating on every frame can in some circumstances drop this code to only run at 30 Hz, in my case putting a text component with a $round(myClock.getTime(),3) set to update every frame, caused this to happen in some cases but not always. Furthermore changing settings in the nvidia control panels doesn’t always seem to change the behavior in the exact same way every time for whatever reason.
So beware if you have your graphics settings set to maximum performance, I suspect that it will then render more frames than your display refresh rate, and psychopy will take this as your refresh rate (havent fully tested this).

This must be effecting whether the video card is waiting for the buffer swap or not when win.flip() is called. If it is not waiting, and drawing can occur faster then the retrace rate, you will get a reported frame rate > the retrace rate. You are absolutely right that this is something to watch out for.

TextStim is very slow at redrawing updated text, so that probably explains what it going on here. If you do not update the text every frame the fps should increase a lot.

Short update:
having a text element updating every frame will half the code run rate to 30hz if forced to run on integrated graphics (in my case some radeon vega 8 mobile). forcing it to run on my gtx 1650 instead will restore code run rate to 60 hz, even with the updating text component.