Stop Signal Task timing issue

OS: Windows 10 (version 1903)
PsychoPy version: 3.2.4
Standard Standalone?: Yes

What are you trying to achieve?:
I am trying to create a stop signal task similar to the one available on the PsyToolKit website.

What did you try to make it work?:
So far, I have managed to get the stop signal (red circle) to appear at the appropriate time (see SST_Task_V1.psyexp), however, when I try to add a ‘you should have pressed’ error (see SST_Task_V2.psyexp) the timing goes out of sync.

I believe this is due to setting the errorStart = False, as this essentially sets errorStart = 0. I have also tried to set errorStart = None, however, I get the following error:

   if stop.status == NOT_STARTED and tThisFlip >= stopSigStart-frameTolerance:
TypeError: unsupported operand type(s) for -: 'NoneType' and 'float'

Finally, I tried setting errorStart = float(), however, I get the same issue as when setting errorStart = False i.e., errorStart = 0 (as described above).

Is there a way to create an empty numeric variable that is not a NoneType and not set to 0? If not, please can you suggest some ways around my issue?

Thanks in advance.
SST_Task_V1.psyexp (11.9 KB) SST_Task_V2.psyexp (13.9 KB)

I have had to upload each file in seperate responses as new users are limited to 2 files per topic.

go_right go_left [SST_cond.xlsx|attachment]

(upload://jM0uRqzL401d9jBdlmvofnhg8SO.xlsx) (10.0 KB) stop_left ![stop_right|411x411]

(upload://w4cTxYM8DUiU3su8WOYFDPrK6HL.png) shouldPress

stop_right

You have posted a lot of supporting information but what we need to know is what do you actually want to happen. NB read your post and think “could someone understand what I need, knowing other than what I have written here?”

e.g. “to appear at the appropriate time” doesn’t tell us anything we can work with.

Hi Michael,

Apologies for the vague post.

At the start of the trial, a fixation cross (labelled “fix” in the .psyexp file) should be displayed for 500ms. Next, an arrow pointing left or right, surrounded by a white circle (either go_left.png or go_right.png; labelled “arrow” in the .psyexp file) should appear for 1500ms. In “go” trials (i.e., ssig in SST_cond.xlsx == False), the participant should response with the “c” key if the arrow is pointing to the left or the “m” key if the arrow is pointing to the right. If the participant does not respond on a go trial, the “you should have pressed” error (shouldPress.png; labelled shouldPress in the .psyexp file) should appear after 3000ms (i.e., 500ms after the arrow) for a duration of 1000ms. However, in stop trials, the error should not appear as the participant is not meant to press anything. Instead, an arrow surrounded by a red circle (either stop_left.png or stop_right.png; labelled “stop” in the .psyexp file) should be presented after 1300ms (i.e., 300 ms after the initial arrow surrounded by a white circle) for a duration of 1200ms (i.e., until the first arrow disappears).

Please let me know if you need any other details in order to help.

Thanks

Your conditions file.

Apologies! Here you go.

Thanks

SST_cond.xlsx (10.8 KB)

if stop.status == NOT_STARTED and tThisFlip >= stopSigStart-frameTolerance: 

TypeError: unsupported operand type(s) for -: 'NoneType' and 'float'

OK, so what is happening here is that you have set your variable stopSigStart to be None but this is placed in a time-based field. Builder’s code is trying to decide when to show the stimulus by comparing the time of the upcoming screen refresh to the time you’ve specified. But since the value you’ve provided is None, it can’t be used in the required arithmetic (i.e. it can’t subtract the the numeric value
frameTolerance from the non-numeric value None).

So you should try switching the start time field for your “stop” stimulus from containing a “time” to containing a “condition” (i.e. instead of a simple number, this will be a logical expression that has to evaluate to True in order for the stimulus to be shown):

Then try something like this in that field:

$ssig and t >= 3.0

Both elements in this expression have to be True for the entire and expression to evaluate as True. i.e. if ssig is False on this trial, the stimulus won’t be shown at all. If ssig is True, then the stimulus will be shown, but only after 3.0 seconds has elapsed.

You can delete the associated code from your code component, as it is no longer required.

The other stimulus is more tricky. Either amend the code for that one as required, or try using something like this in its “condition” field:

$not ssig and not SST_resp.keys and t >= 3.00

Solution 1:

$ssig and t >= 3.0

Solution 2:

$not ssig and not SST_resp.keys and t >= 3.00

Response:
I did not realise that you could put conditional statements within the time field. I’m sure this will come in handy when designing future experiments!

The first solution (for the stop signal) works well. However, the second suggestion (for the “you should have pressed” error) returns the following error:

    if shouldPress.status == NOT_STARTED and tThisFlip >= not ssig and not SST_resp.keys and t >= 3.00-frameTolerance:
                                                            ^
SyntaxError: invalid syntax

Thanks again.

Was that second field also set to be a “condition”? From the code, it still looks like it is set to “Time (s)”

Yes, I forgot to change the second field from “time” to “condition”. Well spotted, thanks. This advice fixed the error, and both the “go” and “stop” trials are now behaving correctly during the first trial. However, subsequent trials do not appear i.e., after the first trial, no stimuli are presented - just a plain grey background.

Please find the content of two log files below as no error code is output and the forum does not permit the .log extension.

Thanks again. I really appreciate you taking the time to help me out!

Example “go” trial log:

7.4472 	WARNING 	User requested fullscreen with size [1024  768], but screen is actually [2560, 1080]. Using actual size
8.5888 	EXP 	Created window1 = Window(allowGUI=False, allowStencil=False, args=UNKNOWN, autoLog=True, bitsMode=UNKNOWN, blendMode='avg', color=array([0., 0., 0.]), colorSpace='rgb', fullscr=<method-wrapper '__getattribute__' of attributeSetter object at 0x000002B563448DD8>, gamma=None, gammaErrorPolicy='raise', kwargs=UNKNOWN, lms=UNKNOWN, monitor=<psychopy.monitors.calibTools.Monitor object at 0x000002B563284B00>, multiSample=False, name='window1', numSamples=2, pos=[0.0, 0.0], screen=0, size=array([2560, 1080]), stereo=False, units='height', useFBO=True, useRetina=False, viewOri=0.0, viewPos=None, viewScale=None, waitBlanking=True, winType='pyglet')
8.5888 	EXP 	window1: recordFrameIntervals = False
8.7551 	EXP 	window1: recordFrameIntervals = True
8.9386 	EXP 	window1: recordFrameIntervals = False
9.3792 	EXP 	Created fix = TextStim(__class__=<class 'psychopy.visual.text.TextStim'>, alignHoriz='center', alignVert='center', antialias=True, autoLog=True, bold=False, color='white', colorSpace='named', contrast=1.0, depth=0.0, flipHoriz=False, flipVert=False, font='Arial', fontFiles=[], height=0.1, italic=False, languageStyle='LTR', name='fix', opacity=1.0, ori=0, pos=array([0., 0.]), rgb=array([255., 255., 255.]), text='+', units='height', win=Window(...), wrapWidth=1)
9.3809 	EXP 	Created arrow = ImageStim(__class__=<class 'psychopy.visual.image.ImageStim'>, autoLog=True, color=array([1., 1., 1.]), colorSpace='rgb', contrast=1.0, depth=-1.0, flipHoriz=False, flipVert=False, image='sin', interpolate=True, mask=None, maskParams=None, name='arrow', opacity=1.0, ori=0.0, pos=array([0., 0.]), size=array([0.25, 0.25]), texRes=128, units='height', win=Window(...))
9.3819 	EXP 	Created stop = ImageStim(__class__=<class 'psychopy.visual.image.ImageStim'>, autoLog=True, color=array([1., 1., 1.]), colorSpace='rgb', contrast=1.0, depth=-2.0, flipHoriz=False, flipVert=False, image='sin', interpolate=True, mask=None, maskParams=None, name='stop', opacity=1.0, ori=0.0, pos=array([0., 0.]), size=array([0.25, 0.25]), texRes=128, units='height', win=Window(...))
9.3882 	EXP 	Created shouldPress = ImageStim(__class__=<class 'psychopy.visual.image.ImageStim'>, autoLog=True, color=array([1., 1., 1.]), colorSpace='rgb', contrast=1.0, depth=-3.0, flipHoriz=False, flipVert=False, image='shouldPress.png', interpolate=True, mask=None, maskParams=None, name='shouldPress', opacity=1.0, ori=0.0, pos=array([0., 0.]), size=array([0.25, 0.25]), texRes=128, units='height', win=Window(...))
9.4325 	EXP 	Imported SST_cond.xlsx as conditions, 40 conditions, 4 params
9.4328 	EXP 	Created sequence: random, trialTypes=40, nReps=1, seed=None
9.4330 	EXP 	New trial (rep=0, index=0): OrderedDict([('arrows', 'go_right.png'), ('corrAns', 'm'), ('ssig', False), ('ssigImg', 'None')])
9.4801 	EXP 	arrow: image = 'go_right.png'
9.4801 	EXP 	stop: image = 'None'
9.4801 	EXP 	fix: autoDraw = True
9.9803 	EXP 	fix: autoDraw = False
10.4470 	EXP 	arrow: autoDraw = True
11.9476 	EXP 	arrow: autoDraw = False
11.9643 	EXP 	shouldPress: autoDraw = True
12.9646 	EXP 	shouldPress: autoDraw = False
44.2778 	DATA 	Keypress: escape
44.4295 	EXP 	window1: mouseVisible = True

Example “stop” trial log:

14.3695 	WARNING 	User requested fullscreen with size [1024  768], but screen is actually [2560, 1080]. Using actual size
15.4607 	EXP 	Created window1 = Window(allowGUI=False, allowStencil=False, args=UNKNOWN, autoLog=True, bitsMode=UNKNOWN, blendMode='avg', color=array([0., 0., 0.]), colorSpace='rgb', fullscr=<method-wrapper '__getattribute__' of attributeSetter object at 0x0000012F39938DD8>, gamma=None, gammaErrorPolicy='raise', kwargs=UNKNOWN, lms=UNKNOWN, monitor=<psychopy.monitors.calibTools.Monitor object at 0x0000012F39774B00>, multiSample=False, name='window1', numSamples=2, pos=[0.0, 0.0], screen=0, size=array([2560, 1080]), stereo=False, units='height', useFBO=True, useRetina=False, viewOri=0.0, viewPos=None, viewScale=None, waitBlanking=True, winType='pyglet')
15.4607 	EXP 	window1: recordFrameIntervals = False
15.6269 	EXP 	window1: recordFrameIntervals = True
15.8104 	EXP 	window1: recordFrameIntervals = False
16.1525 	EXP 	Created fix = TextStim(__class__=<class 'psychopy.visual.text.TextStim'>, alignHoriz='center', alignVert='center', antialias=True, autoLog=True, bold=False, color='white', colorSpace='named', contrast=1.0, depth=0.0, flipHoriz=False, flipVert=False, font='Arial', fontFiles=[], height=0.1, italic=False, languageStyle='LTR', name='fix', opacity=1.0, ori=0, pos=array([0., 0.]), rgb=array([255., 255., 255.]), text='+', units='height', win=Window(...), wrapWidth=1)
16.1541 	EXP 	Created arrow = ImageStim(__class__=<class 'psychopy.visual.image.ImageStim'>, autoLog=True, color=array([1., 1., 1.]), colorSpace='rgb', contrast=1.0, depth=-1.0, flipHoriz=False, flipVert=False, image='sin', interpolate=True, mask=None, maskParams=None, name='arrow', opacity=1.0, ori=0.0, pos=array([0., 0.]), size=array([0.25, 0.25]), texRes=128, units='height', win=Window(...))
16.1550 	EXP 	Created stop = ImageStim(__class__=<class 'psychopy.visual.image.ImageStim'>, autoLog=True, color=array([1., 1., 1.]), colorSpace='rgb', contrast=1.0, depth=-2.0, flipHoriz=False, flipVert=False, image='sin', interpolate=True, mask=None, maskParams=None, name='stop', opacity=1.0, ori=0.0, pos=array([0., 0.]), size=array([0.25, 0.25]), texRes=128, units='height', win=Window(...))
16.1613 	EXP 	Created shouldPress = ImageStim(__class__=<class 'psychopy.visual.image.ImageStim'>, autoLog=True, color=array([1., 1., 1.]), colorSpace='rgb', contrast=1.0, depth=-3.0, flipHoriz=False, flipVert=False, image='shouldPress.png', interpolate=True, mask=None, maskParams=None, name='shouldPress', opacity=1.0, ori=0.0, pos=array([0., 0.]), size=array([0.25, 0.25]), texRes=128, units='height', win=Window(...))
16.2039 	EXP 	Imported SST_cond.xlsx as conditions, 40 conditions, 4 params
16.2042 	EXP 	Created sequence: random, trialTypes=40, nReps=1, seed=None
16.2044 	EXP 	New trial (rep=0, index=0): OrderedDict([('arrows', 'go_left.png'), ('corrAns', 'None'), ('ssig', True), ('ssigImg', 'stop_left.png')])
16.2519 	EXP 	arrow: image = 'go_left.png'
16.2519 	EXP 	stop: image = 'stop_left.png'
16.2519 	EXP 	fix: autoDraw = True
16.7521 	EXP 	fix: autoDraw = False
17.2022 	EXP 	arrow: autoDraw = True
17.5190 	EXP 	stop: autoDraw = True
18.7027 	EXP 	arrow: autoDraw = False
18.7194 	EXP 	stop: autoDraw = False
52.2171 	DATA 	Keypress: escape
52.3846 	EXP 	window1: mouseVisible = True

I’m guessing that the first trial is never actually coming to an end. You probably need to post your latest version of the .psyexp file so we can see what code it generates. I aspect the issue will be something to do with the rest of the Builder code somehow not getting properly informed that a given stimulus has ended, given that we are controlling its time of onset through some custom code.

When/how do you intend for the routine to end? i.e. should it just end after the last stimulus has stopped drawing?

Please find the latest .psyexp file attached.

SST_Task_V4.psyexp (12.5 KB)

Ideally, on “go” trials with no error, the trial should end after the arrow has been presented for 1500ms (i.e., after a total trial duration of 2500ms). Similarly, on “stop” trials, the trial should end after the stop signal has been diplayed for 1200ms (i.e., after a total trial duration of 2500ms) Finally, on “go” trials with a “should press” error, trials should end following a 1000ms presentation of the “should press” error (i.e., after a total trial duration of 3500ms).

I can’t see anything obviously wrong, so you’ll need to do some debugging.

Push the “compile script” button and search for this section of code:

for thisComponent in trialComponents:
    if hasattr(thisComponent, "status") and thisComponent.status != FINISHED:
        continueRoutine = True
        break  # at least one component has not yet finished

and edit it like this:

for thisComponent in trialComponents:
    if t > 3.5:
        print('TESTING:') 
    if hasattr(thisComponent, "status") and thisComponent.status != FINISHED:
        continueRoutine = True
        if t > 3.5:
            print(thisComponent.name)       

Run that edited script from within the Coder window. NB it will be overwritten if you run the Builder .psyexp file again, so you might want to save this edited .py file with a different name.

Once the trial hits 3.5 seconds, it should start printing out the name of any component that hasn’t been properly set to “FINISHED”, which should narrow down the issue.

Apologies for the late reply!

I tried what you suggested (see SST_Task_V4_debug_code.py attached) and left the task running for over 30 secs but still got a blank screen, and the log file did not provide any additional information (see below). Did I do something wrong?

SST_Task_V4_debug_code.py (15.4 KB)

N.B. Amended code starts on line 289.

23.5393 	WARNING 	User requested fullscreen with size [1024  768], but screen is actually [2560, 1080]. Using actual size
24.6185 	EXP 	Created window1 = Window(allowGUI=False, allowStencil=False, args=UNKNOWN, autoLog=True, bitsMode=UNKNOWN, blendMode='avg', color=array([0., 0., 0.]), colorSpace='rgb', fullscr=<method-wrapper '__getattribute__' of attributeSetter object at 0x00000158CDB27DD8>, gamma=None, gammaErrorPolicy='raise', kwargs=UNKNOWN, lms=UNKNOWN, monitor=<psychopy.monitors.calibTools.Monitor object at 0x00000158CD968AC8>, multiSample=False, name='window1', numSamples=2, pos=[0.0, 0.0], screen=0, size=array([2560, 1080]), stereo=False, units='height', useFBO=True, useRetina=False, viewOri=0.0, viewPos=None, viewScale=None, waitBlanking=True, winType='pyglet')
24.6185 	EXP 	window1: recordFrameIntervals = False
24.7845 	EXP 	window1: recordFrameIntervals = True
24.9680 	EXP 	window1: recordFrameIntervals = False
25.3083 	EXP 	Created fix = TextStim(__class__=<class 'psychopy.visual.text.TextStim'>, alignHoriz='center', alignVert='center', antialias=True, autoLog=True, bold=False, color='white', colorSpace='named', contrast=1.0, depth=0.0, flipHoriz=False, flipVert=False, font='Arial', fontFiles=[], height=0.1, italic=False, languageStyle='LTR', name='fix', opacity=1.0, ori=0, pos=array([0., 0.]), rgb=array([255., 255., 255.]), text='+', units='height', win=Window(...), wrapWidth=1)
25.3099 	EXP 	Created arrow = ImageStim(__class__=<class 'psychopy.visual.image.ImageStim'>, autoLog=True, color=array([1., 1., 1.]), colorSpace='rgb', contrast=1.0, depth=-1.0, flipHoriz=False, flipVert=False, image='sin', interpolate=True, mask=None, maskParams=None, name='arrow', opacity=1.0, ori=0.0, pos=array([0., 0.]), size=array([0.25, 0.25]), texRes=128, units='height', win=Window(...))
25.3109 	EXP 	Created stop = ImageStim(__class__=<class 'psychopy.visual.image.ImageStim'>, autoLog=True, color=array([1., 1., 1.]), colorSpace='rgb', contrast=1.0, depth=-2.0, flipHoriz=False, flipVert=False, image='sin', interpolate=True, mask=None, maskParams=None, name='stop', opacity=1.0, ori=0.0, pos=array([0., 0.]), size=array([0.25, 0.25]), texRes=128, units='height', win=Window(...))
25.3172 	EXP 	Created shouldPress = ImageStim(__class__=<class 'psychopy.visual.image.ImageStim'>, autoLog=True, color=array([1., 1., 1.]), colorSpace='rgb', contrast=1.0, depth=-3.0, flipHoriz=False, flipVert=False, image='shouldPress.png', interpolate=True, mask=None, maskParams=None, name='shouldPress', opacity=1.0, ori=0.0, pos=array([0., 0.]), size=array([0.25, 0.25]), texRes=128, units='height', win=Window(...))
25.3604 	EXP 	Imported SST_cond.xlsx as conditions, 40 conditions, 4 params
25.3607 	EXP 	Created sequence: random, trialTypes=40, nReps=1, seed=None
25.3609 	EXP 	New trial (rep=0, index=0): OrderedDict([('arrows', 'go_left.png'), ('corrAns', 'c'), ('ssig', False), ('ssigImg', 'None')])
25.3941 	EXP 	arrow: image = 'go_left.png'
25.3941 	EXP 	stop: image = 'None'
25.3941 	EXP 	fix: autoDraw = True
25.8942 	EXP 	fix: autoDraw = False
26.3770 	EXP 	arrow: autoDraw = True
27.8781 	EXP 	arrow: autoDraw = False
27.8953 	EXP 	shouldPress: autoDraw = True
28.8952 	EXP 	shouldPress: autoDraw = False
85.6460 	DATA 	Keypress: escape
85.6468 	DATA 	Mouse: Left button down, pos=(1561,805)
85.6469 	DATA 	Mouse:  Left button up, pos=(1561,805)
85.7098 	EXP 	window1: mouseVisible = True

No, those print statements don’t go to the log file. They should appear in a separate window. It is not always obvious when running from Builder, so perhaps push the “Compile script” button in the toolbar and then run the resulting script when it opens from the Coder view. Look for the results that appear (hopefully in real-time) in the “Output” pane of the Coder window.

My mistake. As you say, I was looking in the wrong place. After running the script for a few seconds, the output is:

pygame 1.9.4
Hello from the pygame community. https://www.pygame.org/contribute.html
TESTING:
TESTING:
TESTING:
TESTING:
shouldPress
TESTING:
TESTING:
TESTING:
TESTING:
TESTING:
shouldPress
TESTING:
TESTING:
TESTING:
TESTING:
TESTING:
shouldPress
TESTING:
TESTING:
TESTING:
TESTING:
TESTING:
shouldPress

Am I right in thinking that this means there is an issue with the “shouldPress” component?

Yes, it is the failure of that particular component to be set to FINISHED status that is causing the routine to keep running.