Skip to main content
Skip table of contents

Example: A simple reaction time task

In this guide, we’ve covered the basics of registers, markers and schedules and our centralized I/O hub architecture. Now we will turn to a simple example of a reaction time task.

A target is flashed and participants must press a button, which is monitored on digital input channel 1. We will use the Digital Input Log, a schedule that records changes in the digital inputs.

We start our digital input log and set a marker on a register write tied to the next video frame (RegWrVSync). This starts our recording and simultaneously saves a timestamp of when our target appears.

Once the target appears, we begin routine register updates to check the button press occurred. We will compare the time of a press to the timestamp we recorded to measure reaction time. If the reaction time is more than 5 s after the target onset, we reject the trial.

MATLAB/Psychtoolbox
MATLAB
%%
%SETUP
Datapixx('Open');

%Next, we will set up a DInLog, using the default buffer address. This will record any changes in
%the digital input, which we will treat as a button press. For more on how to interpret our digital 
%input channels, see our RPx demos
Datapixx('SetDinLog');
Datapixx('EnableDinDebounce'); %reduces jitter
Datapixx('RegWr');

numberOfTrials = 5;
responseTimeCutoff = 5;
targetWidth=100;
targetColour=[50, 50, 50];

%%
%START
[windowPtr, rect] = Screen('OpenWindow', 2, [0,0,0]);
for k = 1:numberOfTrials
    isValid = 0;
    while ~isValid
        %Add a variable delay to keep participants attentive
        WaitSecs(randi(4));
        %Generate a random location for top left corner of target, and draw 
        targetLoc = [randi(rect(3)-targetWidth), randi(rect(4)-targetWidth)];
        Screen('FillRect', ...
               windowPtr, ...
               targetColour,...
               [targetLoc(1), targetLoc(2), targetLoc(1)+targetWidth, targetLoc(2)+targetWidth]);
        
        %Start our log and marker, implemented on next video frame, i.e., when target appears
        Datapixx('StartDinLog');
        Datapixx('SetMarker');
        Datapixx('RegWrVideoSync');
        Screen('Flip', windowPtr);
        
        %collect our marker
        Datapixx('RegWrRd');
        startTime = Datapixx('GetMarker');
        press = 0;
        
        %%
        %READ
        %Let's create an inner loop to check the log. The first thing in the log buffer should be our
        %press; if the buffer is empty, then we haven't recorded anything yet. 
        while ~press
            WaitSecs(0.25);
            Datapixx('RegWrRd');
            status=Datapixx('GetDinStatus');
            
            if status.newLogFrames > 0                
                %%
                %STOP
                Datapixx('StopDinLog');
                Datapixx('RegWr');
                Screen('Flip', windowPtr);
                press = 1;
            end
        end
        
        %Let's get the timestamp of the first event in our log, which we assume is the button press.
        %This timestamp is on the same clock as our marker. 
        Datapixx('RegWrRd');
        [~, logTimetags, ~] = Datapixx('ReadDinLog');
        if (logTimetags(1)-startTime) <= responseTimeCutoff
            isValid = 1;
            fprintf("Success! Your response time was %.2d seconds.n", (logTimetags(1)-startTime));
        else
            fprintf("Too slow! Your response time was %.2d seconds.n", (logTimetags(1)-startTime));
        end
    end
end 
   
Datapixx('Close');
Screen('Closeall');

Python (libdpx wrapper)
PY
##
#SETUP
​
from pypixxlib import _libdpx as dp​
from psychopy import visual, core
​import random
​
dp.DPxOpen()
​
#Next, we will set up a DInLog, using the default buffer address. This will record any changes in
#the digital input, which we will treat as a button press. For more on how to interpret our digital 
#input channels, see our RPx demos: https://www.vpixx.com/manuals/python/html/basicdemo.html
​myDinLog = dp.DPxSetDinLog()
dp.DPxEnableDinDebounce() #reduces jitter
dp.DPxWriteRegCache()
​
numberOfTrials = 5
responseTimeCutoff = 5
targetWidth=100
targetColour=(50, 50, 50)
​
##
#START
win = visual.Window(screen = 0, 
                    monitor = None,
                    size = [1920,1080],
                    fullscr=True,
                    pos = [0,0],
                    color='black',
                    units = "pix")
​
for k in range(numberOfTrials):
    isValid = 0
    while not isValid: 
        #Add a variable delay to keep participants attentive
        core.wait(random.randint(1, 4))
        #Generate a random location for center point of target, and draw 
        targetLoc = [random.randint(int((-(1920/2))+(targetWidth/2)), int((1920/2)-(targetWidth/2))), 
                     random.randint(int((-(1080/2))+(targetWidth/2)), int((1080/2)-(targetWidth/2)))];
        myRect = visual.Rect(win, 
                             width=targetWidth, 
                             height=targetWidth, 
                             pos=(targetLoc[0], targetLoc[1]), 
                             fillColorSpace = 'rgb255', 
                             fillColor=targetColour)
        myRect.draw()
        #start our log and marker, implemented on the next video frame
        dp.DPxStartDinLog()
        dp.DPxSetMarker()
        dp.DPxWriteRegCacheAfterVideoSync()
        win.flip()
        dp.DPxUpdateRegCache()
        startTime = dp.DPxGetMarker()
        press = 0
        ##
        #READ
        #Let's create an inner loop to check the log. The first thing in the buffer should be our
        #press; if the buffer is empty, then we haven't recorded anything yet. 
        while not press:
            core.wait(0.25)
            dp.DPxUpdateRegCache()
            dp.DPxGetDinStatus(myDinLog) 
            if myDinLog['newLogFrames'] > 0:
                dp.DPxStopDinLog()
                dp.DPxWriteRegCache()
                win.flip()
                press = 1
        #Let's get the timestamp of the first event in our log, which we assume is the button press.
        #This timestamp is on the same clock as our marker.
        dp.DPxUpdateRegCache()
        bufferContent = dp.DPxReadDinLog(myDinLog, int(myDinLog['newLogFrames']))
        if (bufferContent[0][0]-startTime) <= responseTimeCutoff:
            isValid = 1
            print("Succes! Your response time was ", (bufferContent[0][0]-startTime), " seconds.")
        else:
            print("Too slow! Your response time was ", (bufferContent[0][0]-startTime), " seconds.")
​
dp.DPxClose()
win.close()

Python (object-oriented)
PY
##
#SETUP
from pypixxlib.viewpixx import VIEWPixx
from pypixxlib import _libdpx as dp
from psychopy import visual, core
import random
device = VIEWPixx()
device.open()

#Next, we will set up a DInLog, using the default buffer address. This will record any changes in
#the digital input, which we will treat as a button press. For more on how to interpret our digital 
#input channels, see our RPx demos: https://www.vpixx.com/manuals/python/html/basicdemo.html
myDinLog = device.din.setDinLog()
device.din.setDebounce(True) #reduce jitter
device.writeRegisterCache()

numberOfTrials = 5
responseTimeCutoff = 5
targetWidth=100
targetColour=(50, 50, 50)

##
#START
win = visual.Window(screen = 0, 
                    monitor = None,
                    size = [1920,1080],
                    fullscr=True,
                    pos = [0,0],
                    color='black',
                    units = "pix")
for k in range(numberOfTrials):
    isValid = 0
    while not isValid: 
        #Add a variable delay to keep participants attentive
        core.wait(random.randint(1, 4))
        #Generate a random location for center point of target, and draw 
        targetLoc = [random.randint(int((-(1920/2))+(targetWidth/2)), int((1920/2)-(targetWidth/2))), 
                     random.randint(int((-(1080/2))+(targetWidth/2)), int((1080/2)-(targetWidth/2)))];
        myRect = visual.Rect(win, 
                             width=targetWidth, 
                             height=targetWidth, 
                             pos=(targetLoc[0], targetLoc[1]), 
                             fillColorSpace = 'rgb255', 
                             fillColor=targetColour)
        myRect.draw()
        
        #start our log and marker, implemented on the next video frame
        device.din.startDinLog()
        dp.DPxSetMarker() #This function is from libdpx; an OOP version will be created eventually. 
        device.writeRegCacheAfterVideoSync()
        win.flip()
        
        device.updateRegisterCache()
        startTime = dp.DPxGetMarker() #This function is from libdpx; an OOP version will be created eventually. 
        press = 0
        
        ##
        #READ
        #Let's create an inner loop to check the log. The first thing in the buffer should be our
        #press; if the buffer is empty, then we haven't recorded anything yet. 
        while not press:
            core.wait(0.25)
            device.updateRegisterCache()
            device.din.getDinLogStatus(myDinLog) 
            if myDinLog['newLogFrames'] > 0:
                device.din.stopDinLog()
                device.writeRegisterCache()
                win.flip()
                press = 1
        #Let's get the timestamp of the first event in our log, which we assume is the button press.
        #This timestamp is on the same clock as our marker.
        device.updateRegisterCache()
        bufferContent = device.din.readDinLog(myDinLog, int(myDinLog['newLogFrames']))
        if (bufferContent[0][0]-startTime) <= responseTimeCutoff:
            isValid = 1
            print("Succes! Your response time was ", (bufferContent[0][0]-startTime), " seconds.")
        else:
            print("Too slow! Your response time was ", (bufferContent[0][0]-startTime), " seconds.")
device.close()
win.close()

JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.