psychopy.org | Reference | Downloads | Github

Measuring key lift time relative to stimulus onset

Hi There,

We want to measure the time a key is lifted relative to the start of a stimulus occurring (i.e. the start but not the end of the key duration measurement should be synchronised with the refresh of the screen). We think we have a solution but I am reaching out to check if others agree with this solution (and also to make a record for future users, because I couldn’t find anywhere this was discussed!)

Using the Keyboard class, we can measure RTs in multiple ways the two main ways being:

key.rt: time from clock reset to key press event
key.duration: time from key press event to key lift event

The first method can be locked to the refresh of the screen through resetting the clock when the window flips (i.e. win.callOnFlip(kb.clock.reset)). The second would result in a measurement where both the start and end of the measurement is asynchronous to screen refresh. To get a measurement of duration that it locked to the start of a stimulus/screen refresh we could think we can use method 4 or 5 below (i.e. using the key press time, clock reset time and key lift time, to measure the time from the start of the stimulus to the key lift).

I guess this isn’t so much a question as a point of discussion to see if others are in agreement with this approach/notice any possible issues.

Thanks all in advance,
Becca


from psychopy.hardware import keyboard #allows us to watch for key lifts 
from psychopy import event, core, visual # for when the key is first pressed
import numpy as np

# A window to show a message in
win = visual.Window(
    fullscr=False,
    monitor='testMonitor', color=[-1,-1,-1], colorSpace='rgb',
    blendMode='avg', mouseVisible = False, allowGUI=False)

# Some text for the message
waiting_message=visual.TextStim(win, pos=[0, 0], height=1, color= [1,1,1],
    text="Ready for key press")

# Set the Keyboard
kb = keyboard.Keyboard(bufferSize=10, waitForStart=True)

# 5 "trials"
for trial in range(5):
    
    waiting_message.draw()
    win.flip()
    
    k = event.waitKeys()
    
    win.callOnFlip(kb.clock.reset)
    count = 0
    while count==0:
        win.flip()
        remainingKeys = kb.getKeys(keyList=['space', 'escape'], waitRelease=False, clear=False)
        if remainingKeys:
            for key in remainingKeys:
                if key.duration:#if the key has been lifted
                    
                    # Show 5 examples of different RTs that can be measured using the Keyboard class
                    
                    method_1 = kb.clock.getTime() # this gets the current time on the kb clock
                    method_2 = key.duration # this gets the time from the key pressed event to the key lift event (will include the 2 seconds of core.wait)
                    method_3 = key.rt # this gets the time the key is pressed versus the time the kb clock was reset (we reset the clock after button press so it is negative)
                    method_4 =key.duration-np.abs((key.tDown-kb.clock.getLastResetTime())) # this gets the time the kb clock was reset to the key lift event
                    method_5 = key.duration + key.rt #this also gets the time the kb clock was reset to the key lift event but if we 
                    
                    print('method 1 (clock reset to clock now):', method_1, 'method 2 (duration):', method_2, 'method 3 (rt):', method_3, 'method 4 (clock reset to key lift):', method_4, 'method 5 (duration + rt):', method_5)
                    
                    kb.clearEvents() #clear the key events
                    
                    count = count + 1