diff --git a/sequence.py b/sequence.py deleted file mode 100644 index 82c3f642f493d1ff7c7a199724f34d2795219390..0000000000000000000000000000000000000000 --- a/sequence.py +++ /dev/null @@ -1,13 +0,0 @@ -from numpy.random import permutation, choice, uniform -from numpy import append - -def nback(low,high,size,nback,prob): - seq = permutation(range(low,high+1))[0:nback] - - for i in range(size): - if uniform(0,1,1)[0] < prob: - seq = append(seq,seq[-nback]) - else: - pool = [i for i in range(low,high+1) if all(i != seq[-nback:])] - seq = append(seq,choice(pool,1)) - return seq \ No newline at end of file diff --git a/three-back.psyexp b/three-back.psyexp index 2548f61362a1968a0efd3a75af9ff93a6cf3e9f8..d2b8a4e7d1d814bf9cff90d13fa37eba96d28df9 100644 --- a/three-back.psyexp +++ b/three-back.psyexp @@ -6,7 +6,7 @@ <Param name="Completed URL" updates="None" val="" valType="str"/> <Param name="Data filename" updates="None" val="u'data/%s_%s_%s' % (expInfo['participant'], expName, expInfo['date'])" valType="code"/> <Param name="Enable Escape" updates="None" val="True" valType="bool"/> - <Param name="Experiment info" updates="None" val="{'participant': '', 'session': '001'}" valType="code"/> + <Param name="Experiment info" updates="None" val="{'n-Back': '3', 'probability': '0.2', 'participant': '', 'session': '001'}" valType="code"/> <Param name="Force stereo" updates="None" val="True" valType="bool"/> <Param name="Full-screen window" updates="None" val="False" valType="bool"/> <Param name="HTML path" updates="None" val="html" valType="str"/> @@ -32,8 +32,8 @@ <Param name="logging level" updates="None" val="exp" valType="code"/> </Settings> <Routines> - <Routine name="trial"> - <TextComponent name="letter"> + <Routine name="Instructions"> + <TextComponent name="instructions"> <Param name="color" updates="constant" val="white" valType="str"/> <Param name="colorSpace" updates="constant" val="rgb" valType="str"/> <Param name="disabled" updates="None" val="False" valType="bool"/> @@ -41,43 +41,123 @@ <Param name="flip" updates="constant" val="" valType="str"/> <Param name="font" updates="constant" val="Arial" valType="str"/> <Param name="languageStyle" updates="None" val="LTR" valType="str"/> - <Param name="letterHeight" updates="constant" val="2.5" valType="code"/> - <Param name="name" updates="None" val="letter" valType="code"/> + <Param name="letterHeight" updates="constant" val="2.4" valType="code"/> + <Param name="name" updates="None" val="instructions" valType="code"/> <Param name="opacity" updates="constant" val="1" valType="code"/> <Param name="ori" updates="constant" val="0" valType="code"/> <Param name="pos" updates="constant" val="(0, 0)" valType="code"/> <Param name="saveStartStop" updates="None" val="True" valType="bool"/> <Param name="startEstim" updates="None" val="" valType="code"/> <Param name="startType" updates="None" val="time (s)" valType="str"/> - <Param name="startVal" updates="None" val="0" valType="code"/> - <Param name="stopType" updates="None" val="duration (s)" valType="str"/> - <Param name="stopVal" updates="constant" val="0.03" valType="code"/> + <Param name="startVal" updates="None" val="0.0" valType="code"/> + <Param name="stopType" updates="None" val="condition" valType="str"/> + <Param name="stopVal" updates="constant" val="False" valType="code"/> <Param name="syncScreenRefresh" updates="None" val="True" valType="bool"/> - <Param name="text" updates="set every repeat" val="a" valType="str"/> + <Param name="text" updates="constant" val="Press SPACE to start" valType="str"/> <Param name="units" updates="None" val="from exp settings" valType="str"/> <Param name="wrapWidth" updates="constant" val="" valType="code"/> </TextComponent> - <KeyboardComponent name="key_resp"> + <KeyboardComponent name="key_start"> <Param name="allowedKeys" updates="constant" val="'space'" valType="code"/> <Param name="correctAns" updates="constant" val="" valType="str"/> <Param name="disabled" updates="None" val="False" valType="bool"/> - <Param name="discard previous" updates="constant" val="True" valType="bool"/> + <Param name="discard previous" updates="constant" val="False" valType="bool"/> <Param name="durationEstim" updates="None" val="" valType="code"/> - <Param name="forceEndRoutine" updates="constant" val="False" valType="bool"/> - <Param name="name" updates="None" val="key_resp" valType="code"/> + <Param name="forceEndRoutine" updates="constant" val="True" valType="bool"/> + <Param name="name" updates="None" val="key_start" valType="code"/> <Param name="saveStartStop" updates="None" val="True" valType="bool"/> <Param name="startEstim" updates="None" val="" valType="code"/> <Param name="startType" updates="None" val="time (s)" valType="str"/> <Param name="startVal" updates="None" val="0.0" valType="code"/> <Param name="stopType" updates="None" val="duration (s)" valType="str"/> - <Param name="stopVal" updates="constant" val="2" valType="code"/> + <Param name="stopVal" updates="constant" val="" valType="code"/> <Param name="store" updates="constant" val="last key" valType="str"/> - <Param name="storeCorrect" updates="constant" val="True" valType="bool"/> - <Param name="syncScreenRefresh" updates="constant" val="True" valType="bool"/> + <Param name="storeCorrect" updates="constant" val="False" valType="bool"/> + <Param name="syncScreenRefresh" updates="constant" val="False" valType="bool"/> </KeyboardComponent> + <VariableComponent name="stimuli"> + <Param name="disabled" updates="None" val="False" valType="bool"/> + <Param name="durationEstim" updates="None" val="" valType="code"/> + <Param name="name" updates="None" val="stimuli" valType="code"/> + <Param name="saveEndExp" updates="constant" val="False" valType="bool"/> + <Param name="saveEndRoutine" updates="constant" val="True" valType="bool"/> + <Param name="saveFrameValue" updates="constant" val="never" valType="str"/> + <Param name="saveStartExp" updates="constant" val="False" valType="bool"/> + <Param name="saveStartRoutine" updates="constant" val="False" valType="bool"/> + <Param name="saveStartStop" updates="None" val="True" valType="bool"/> + <Param name="startEstim" updates="None" val="" valType="code"/> + <Param name="startExpValue" updates="constant" val="['A','B','C','D','E','F','G','H']" valType="code"/> + <Param name="startFrameValue" updates="None" val="" valType="code"/> + <Param name="startRoutineValue" updates="constant" val="" valType="code"/> + <Param name="startType" updates="None" val="time (s)" valType="str"/> + <Param name="startVal" updates="None" val="" valType="code"/> + <Param name="stopType" updates="None" val="duration (s)" valType="str"/> + <Param name="stopVal" updates="constant" val="" valType="code"/> + <Param name="syncScreenRefresh" updates="None" val="False" valType="bool"/> + </VariableComponent> + <VariableComponent name="prevN"> + <Param name="disabled" updates="None" val="False" valType="bool"/> + <Param name="durationEstim" updates="None" val="" valType="code"/> + <Param name="name" updates="None" val="prevN" valType="code"/> + <Param name="saveEndExp" updates="constant" val="False" valType="bool"/> + <Param name="saveEndRoutine" updates="constant" val="True" valType="bool"/> + <Param name="saveFrameValue" updates="constant" val="never" valType="str"/> + <Param name="saveStartExp" updates="constant" val="False" valType="bool"/> + <Param name="saveStartRoutine" updates="constant" val="False" valType="bool"/> + <Param name="saveStartStop" updates="None" val="True" valType="bool"/> + <Param name="startEstim" updates="None" val="" valType="code"/> + <Param name="startExpValue" updates="constant" val="np.random.choice(stimuli,int(expInfo['n-Back']))" valType="code"/> + <Param name="startFrameValue" updates="None" val="" valType="code"/> + <Param name="startRoutineValue" updates="constant" val="" valType="code"/> + <Param name="startType" updates="None" val="time (s)" valType="str"/> + <Param name="startVal" updates="None" val="" valType="code"/> + <Param name="stopType" updates="None" val="duration (s)" valType="str"/> + <Param name="stopVal" updates="constant" val="" valType="code"/> + <Param name="syncScreenRefresh" updates="None" val="False" valType="bool"/> + </VariableComponent> </Routine> - <Routine name="Instructions"> - <TextComponent name="instructions"> + <Routine name="trial_n"> + <CodeComponent name="trial_n_code"> + <Param name="Begin Experiment" updates="constant" val="" valType="extendedCode"/> + <Param name="Begin JS Experiment" updates="constant" val="" valType="extendedCode"/> + <Param name="Begin JS Routine" updates="constant" val="" valType="extendedCode"/> + <Param name="Begin Routine" updates="constant" val="stimleft = np.delete(stimuli,[np.argwhere(stimuli==i) for i in prevN])&#10;stimulus = np.random.choice(stimleft)" valType="extendedCode"/> + <Param name="Code Type" updates="None" val="Py" valType="str"/> + <Param name="Each Frame" updates="constant" val="" valType="extendedCode"/> + <Param name="Each JS Frame" updates="constant" val="" valType="extendedCode"/> + <Param name="End Experiment" updates="constant" val="" valType="extendedCode"/> + <Param name="End JS Experiment" updates="constant" val="" valType="extendedCode"/> + <Param name="End JS Routine" updates="constant" val="" valType="extendedCode"/> + <Param name="End Routine" updates="constant" val="prevN = np.hstack((prevN[1:],stimulus))" valType="extendedCode"/> + <Param name="disabled" updates="None" val="False" valType="bool"/> + <Param name="name" updates="None" val="trial_n_code" valType="code"/> + </CodeComponent> + <PolygonComponent name="trial_n_screen"> + <Param name="disabled" updates="None" val="False" valType="bool"/> + <Param name="durationEstim" updates="None" val="" valType="code"/> + <Param name="fillColor" updates="constant" val="$[-1,-1,-1]" valType="str"/> + <Param name="fillColorSpace" updates="constant" val="rgb" valType="str"/> + <Param name="interpolate" updates="constant" val="linear" valType="str"/> + <Param name="lineColor" updates="constant" val="$[1,1,1]" valType="str"/> + <Param name="lineColorSpace" updates="constant" val="rgb" valType="str"/> + <Param name="lineWidth" updates="constant" val="1" valType="code"/> + <Param name="nVertices" updates="constant" val="4" valType="int"/> + <Param name="name" updates="None" val="trial_n_screen" valType="code"/> + <Param name="opacity" updates="constant" val="1" valType="code"/> + <Param name="ori" updates="constant" val="0" valType="code"/> + <Param name="pos" updates="constant" val="(0, 0)" valType="code"/> + <Param name="saveStartStop" updates="None" val="True" valType="bool"/> + <Param name="shape" updates="constant" val="rectangle" valType="str"/> + <Param name="size" updates="constant" val="(2, 2)" valType="code"/> + <Param name="startEstim" updates="None" val="" valType="code"/> + <Param name="startType" updates="None" val="time (s)" valType="str"/> + <Param name="startVal" updates="None" val="0.0" valType="code"/> + <Param name="stopType" updates="None" val="duration (s)" valType="str"/> + <Param name="stopVal" updates="constant" val="2" valType="code"/> + <Param name="syncScreenRefresh" updates="None" val="True" valType="bool"/> + <Param name="units" updates="None" val="norm" valType="str"/> + </PolygonComponent> + <TextComponent name="tial_n_letter"> <Param name="color" updates="constant" val="white" valType="str"/> <Param name="colorSpace" updates="constant" val="rgb" valType="str"/> <Param name="disabled" updates="None" val="False" valType="bool"/> @@ -85,56 +165,64 @@ <Param name="flip" updates="constant" val="" valType="str"/> <Param name="font" updates="constant" val="Arial" valType="str"/> <Param name="languageStyle" updates="None" val="LTR" valType="str"/> - <Param name="letterHeight" updates="constant" val="2.4" valType="code"/> - <Param name="name" updates="None" val="instructions" valType="code"/> + <Param name="letterHeight" updates="constant" val="2.5" valType="code"/> + <Param name="name" updates="None" val="tial_n_letter" valType="code"/> <Param name="opacity" updates="constant" val="1" valType="code"/> <Param name="ori" updates="constant" val="0" valType="code"/> <Param name="pos" updates="constant" val="(0, 0)" valType="code"/> <Param name="saveStartStop" updates="None" val="True" valType="bool"/> <Param name="startEstim" updates="None" val="" valType="code"/> <Param name="startType" updates="None" val="time (s)" valType="str"/> - <Param name="startVal" updates="None" val="0.0" valType="code"/> - <Param name="stopType" updates="None" val="condition" valType="str"/> - <Param name="stopVal" updates="constant" val="False" valType="code"/> + <Param name="startVal" updates="None" val="0" valType="code"/> + <Param name="stopType" updates="None" val="duration (s)" valType="str"/> + <Param name="stopVal" updates="constant" val="0.03" valType="code"/> <Param name="syncScreenRefresh" updates="None" val="True" valType="bool"/> - <Param name="text" updates="constant" val="Press SPACE to start" valType="str"/> + <Param name="text" updates="set every repeat" val="$stimulus" valType="str"/> <Param name="units" updates="None" val="from exp settings" valType="str"/> <Param name="wrapWidth" updates="constant" val="" valType="code"/> </TextComponent> - <KeyboardComponent name="key_start"> - <Param name="allowedKeys" updates="constant" val="'space'" valType="code"/> - <Param name="correctAns" updates="constant" val="" valType="str"/> + </Routine> + <Routine name="trial_back"> + <TextComponent name="text"> + <Param name="color" updates="constant" val="white" valType="str"/> + <Param name="colorSpace" updates="constant" val="rgb" valType="str"/> <Param name="disabled" updates="None" val="False" valType="bool"/> - <Param name="discard previous" updates="constant" val="False" valType="bool"/> <Param name="durationEstim" updates="None" val="" valType="code"/> - <Param name="forceEndRoutine" updates="constant" val="True" valType="bool"/> - <Param name="name" updates="None" val="key_start" valType="code"/> + <Param name="flip" updates="constant" val="" valType="str"/> + <Param name="font" updates="constant" val="Arial" valType="str"/> + <Param name="languageStyle" updates="None" val="LTR" valType="str"/> + <Param name="letterHeight" updates="constant" val="2.5" valType="code"/> + <Param name="name" updates="None" val="text" valType="code"/> + <Param name="opacity" updates="constant" val="1" valType="code"/> + <Param name="ori" updates="constant" val="0" valType="code"/> + <Param name="pos" updates="constant" val="(0, 0)" valType="code"/> <Param name="saveStartStop" updates="None" val="True" valType="bool"/> <Param name="startEstim" updates="None" val="" valType="code"/> <Param name="startType" updates="None" val="time (s)" valType="str"/> <Param name="startVal" updates="None" val="0.0" valType="code"/> <Param name="stopType" updates="None" val="duration (s)" valType="str"/> - <Param name="stopVal" updates="constant" val="" valType="code"/> - <Param name="store" updates="constant" val="last key" valType="str"/> - <Param name="storeCorrect" updates="constant" val="False" valType="bool"/> - <Param name="syncScreenRefresh" updates="constant" val="False" valType="bool"/> - </KeyboardComponent> + <Param name="stopVal" updates="constant" val="1.0" valType="code"/> + <Param name="syncScreenRefresh" updates="None" val="True" valType="bool"/> + <Param name="text" updates="set every repeat" val="$[t['stimulus'] for t in loop_n.trialList]" valType="str"/> + <Param name="units" updates="None" val="from exp settings" valType="str"/> + <Param name="wrapWidth" updates="constant" val="" valType="code"/> + </TextComponent> </Routine> </Routines> <Flow> <Routine name="Instructions"/> - <LoopInitiator loopType="TrialHandler" name="trials"> + <LoopInitiator loopType="TrialHandler" name="loop_n"> <Param name="Selected rows" updates="None" val="" valType="str"/> <Param name="conditions" updates="None" val="None" valType="str"/> <Param name="conditionsFile" updates="None" val="" valType="str"/> <Param name="endPoints" updates="None" val="[0, 1]" valType="num"/> <Param name="isTrials" updates="None" val="True" valType="bool"/> - <Param name="loopType" updates="None" val="random" valType="str"/> - <Param name="nReps" updates="None" val="20" valType="code"/> - <Param name="name" updates="None" val="trials" valType="code"/> + <Param name="loopType" updates="None" val="sequential" valType="str"/> + <Param name="nReps" updates="None" val="expInfo['n-Back']" valType="code"/> + <Param name="name" updates="None" val="loop_n" valType="code"/> <Param name="random seed" updates="None" val="" valType="code"/> </LoopInitiator> - <Routine name="trial"/> - <LoopTerminator name="trials"/> + <Routine name="trial_n"/> + <LoopTerminator name="loop_n"/> </Flow> </PsychoPy2experiment> diff --git a/three-back.py b/three-back.py new file mode 100644 index 0000000000000000000000000000000000000000..3fbf43bba35a8f1585edc5a662e5a90b8dab4319 --- /dev/null +++ b/three-back.py @@ -0,0 +1,347 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +""" +This experiment was created using PsychoPy3 Experiment Builder (v3.2.0), + on November 11, 2019, at 19:58 +If you publish work using this script the most relevant publication is: + + Peirce J, Gray JR, Simpson S, MacAskill M, Höchenberger R, Sogo H, Kastman E, Lindeløv JK. (2019) + PsychoPy2: Experiments in behavior made easy Behav Res 51: 195. + https://doi.org/10.3758/s13428-018-01193-y + +""" + +from __future__ import absolute_import, division + +from psychopy import locale_setup +from psychopy import prefs +from psychopy import sound, gui, visual, core, data, event, logging, clock +from psychopy.constants import (NOT_STARTED, STARTED, PLAYING, PAUSED, + STOPPED, FINISHED, PRESSED, RELEASED, FOREVER) + +import numpy as np # whole numpy lib is available, prepend 'np.' +from numpy import (sin, cos, tan, log, log10, pi, average, + sqrt, std, deg2rad, rad2deg, linspace, asarray) +from numpy.random import random, randint, normal, shuffle +import os # handy system and path functions +import sys # to get file system encoding + +from psychopy.hardware import keyboard + +# Ensure that relative paths start from the same directory as this script +_thisDir = os.path.dirname(os.path.abspath(__file__)) +os.chdir(_thisDir) + +# Store info about the experiment session +psychopyVersion = '3.2.0' +expName = 'three-back' # from the Builder filename that created this script +expInfo = {'n-Back': '3', 'probability': '0.2', 'participant': '', 'session': '001'} +dlg = gui.DlgFromDict(dictionary=expInfo, sortKeys=False, title=expName) +if dlg.OK == False: + core.quit() # user pressed cancel +expInfo['date'] = data.getDateStr() # add a simple timestamp +expInfo['expName'] = expName +expInfo['psychopyVersion'] = psychopyVersion + +# Data file name stem = absolute path + name; later add .psyexp, .csv, .log, etc +filename = _thisDir + os.sep + u'data/%s_%s_%s' % (expInfo['participant'], expName, expInfo['date']) + +# An ExperimentHandler isn't essential but helps with data saving +thisExp = data.ExperimentHandler(name=expName, version='', + extraInfo=expInfo, runtimeInfo=None, + originPath='D:\\Projects\\three-back\\three-back.py', + savePickle=True, saveWideText=True, + dataFileName=filename) +# save a log file for detail verbose info +logFile = logging.LogFile(filename+'.log', level=logging.EXP) +logging.console.setLevel(logging.WARNING) # this outputs to the screen, not a file + +endExpNow = False # flag for 'escape' or other condition => quit the exp +frameTolerance = 0.001 # how close to onset before 'same' frame + +# Start Code - component code to be run before the window creation + +# Setup the Window +win = visual.Window( + size=[1600, 900], fullscr=False, screen=0, + winType='pyglet', allowGUI=True, allowStencil=False, + monitor='Alienware Laptop Monitor', color=[-1,-1,-1], colorSpace='rgb', + blendMode='avg', useFBO=True, + units='deg') +# store frame rate of monitor if we can measure it +expInfo['frameRate'] = win.getActualFrameRate() +if expInfo['frameRate'] != None: + frameDur = 1.0 / round(expInfo['frameRate']) +else: + frameDur = 1.0 / 60.0 # could not measure, so guess + +# create a default keyboard (e.g. to check for escape) +defaultKeyboard = keyboard.Keyboard() + +# Initialize components for Routine "Instructions" +InstructionsClock = core.Clock() +from numpy.random import choice +instructions = visual.TextStim(win=win, name='instructions', + text='Press SPACE to start', + font='Arial', + pos=(0, 0), height=2.4, wrapWidth=None, ori=0, + color='white', colorSpace='rgb', opacity=1, + languageStyle='LTR', + depth=-1.0); +key_start = keyboard.Keyboard() +# Set experiment start values for variable component stimuli +stimuli = ['A','B','C','D','E','F','G','H'] +stimuliContainer = [] +# Set experiment start values for variable component trialInit +trialInit = choice(stimuli,int(expInfo[n-Back])) +trialInitContainer = [] + +# Initialize components for Routine "trial_n" +trial_nClock = core.Clock() +trial_n_screen = visual.Rect( + win=win, name='trial_n_screen',units='norm', + width=(2, 2)[0], height=(2, 2)[1], + ori=0, pos=(0, 0), + lineWidth=1, lineColor=[1,1,1], lineColorSpace='rgb', + fillColor=[-1,-1,-1], fillColorSpace='rgb', + opacity=1, depth=-1.0, interpolate=True) +tial_n_letter = visual.TextStim(win=win, name='tial_n_letter', + text='default text', + font='Arial', + pos=(0, 0), height=2.5, wrapWidth=None, ori=0, + color='white', colorSpace='rgb', opacity=1, + languageStyle='LTR', + depth=-2.0); + +# Create some handy timers +globalClock = core.Clock() # to track the time since experiment started +routineTimer = core.CountdownTimer() # to track time remaining of each (non-slip) routine + +# ------Prepare to start Routine "Instructions"------- +# update component parameters for each repeat +key_start.keys = [] +key_start.rt = [] +# keep track of which components have finished +InstructionsComponents = [instructions, key_start] +for thisComponent in InstructionsComponents: + thisComponent.tStart = None + thisComponent.tStop = None + thisComponent.tStartRefresh = None + thisComponent.tStopRefresh = None + if hasattr(thisComponent, 'status'): + thisComponent.status = NOT_STARTED +# reset timers +t = 0 +_timeToFirstFrame = win.getFutureFlipTime(clock="now") +InstructionsClock.reset(-_timeToFirstFrame) # t0 is time of first possible flip +frameN = -1 +continueRoutine = True + +# -------Run Routine "Instructions"------- +while continueRoutine: + # get current time + t = InstructionsClock.getTime() + tThisFlip = win.getFutureFlipTime(clock=InstructionsClock) + tThisFlipGlobal = win.getFutureFlipTime(clock=None) + frameN = frameN + 1 # number of completed frames (so 0 is the first frame) + # update/draw components on each frame + + # *instructions* updates + if instructions.status == NOT_STARTED and tThisFlip >= 0.0-frameTolerance: + # keep track of start time/frame for later + instructions.frameNStart = frameN # exact frame index + instructions.tStart = t # local t and not account for scr refresh + instructions.tStartRefresh = tThisFlipGlobal # on global time + win.timeOnFlip(instructions, 'tStartRefresh') # time at next scr refresh + instructions.setAutoDraw(True) + if instructions.status == STARTED: + if bool(False): + # keep track of stop time/frame for later + instructions.tStop = t # not accounting for scr refresh + instructions.frameNStop = frameN # exact frame index + win.timeOnFlip(instructions, 'tStopRefresh') # time at next scr refresh + instructions.setAutoDraw(False) + + # *key_start* updates + if key_start.status == NOT_STARTED and t >= 0.0-frameTolerance: + # keep track of start time/frame for later + key_start.frameNStart = frameN # exact frame index + key_start.tStart = t # local t and not account for scr refresh + key_start.tStartRefresh = tThisFlipGlobal # on global time + win.timeOnFlip(key_start, 'tStartRefresh') # time at next scr refresh + key_start.status = STARTED + # keyboard checking is just starting + key_start.clock.reset() # now t=0 + if key_start.status == STARTED: + theseKeys = key_start.getKeys(keyList=['space'], waitRelease=False) + if len(theseKeys): + theseKeys = theseKeys[0] # at least one key was pressed + + # check for quit: + if "escape" == theseKeys: + endExpNow = True + key_start.keys = theseKeys.name # just the last key pressed + key_start.rt = theseKeys.rt + # a response ends the routine + continueRoutine = False + + # check for quit (typically the Esc key) + if endExpNow or defaultKeyboard.getKeys(keyList=["escape"]): + core.quit() + + # check if all components have finished + if not continueRoutine: # a component has requested a forced-end of Routine + break + continueRoutine = False # will revert to True if at least one component still running + for thisComponent in InstructionsComponents: + if hasattr(thisComponent, "status") and thisComponent.status != FINISHED: + continueRoutine = True + break # at least one component has not yet finished + + # refresh the screen + if continueRoutine: # don't flip if this routine is over or we'll get a blank screen + win.flip() + +# -------Ending Routine "Instructions"------- +for thisComponent in InstructionsComponents: + if hasattr(thisComponent, "setAutoDraw"): + thisComponent.setAutoDraw(False) +thisExp.addData('instructions.started', instructions.tStartRefresh) +thisExp.addData('instructions.stopped', instructions.tStopRefresh) +# check responses +if key_start.keys in ['', [], None]: # No response was made + key_start.keys = None +thisExp.addData('key_start.keys',key_start.keys) +if key_start.keys != None: # we had a response + thisExp.addData('key_start.rt', key_start.rt) +thisExp.addData('key_start.started', key_start.tStart) +thisExp.addData('key_start.stopped', key_start.tStop) +thisExp.nextEntry() +# the Routine "Instructions" was not non-slip safe, so reset the non-slip timer +routineTimer.reset() + +# set up handler to look after randomisation of conditions etc +loop_n = data.TrialHandler(nReps=expInfo['n-Back'], method='sequential', + extraInfo=expInfo, originPath=-1, + trialList=[None], + seed=None, name='loop_n') +thisExp.addLoop(loop_n) # add the loop to the experiment +thisLoop_n = loop_n.trialList[0] # so we can initialise stimuli with some values +# abbreviate parameter names if possible (e.g. rgb = thisLoop_n.rgb) +if thisLoop_n != None: + for paramName in thisLoop_n: + exec('{} = thisLoop_n[paramName]'.format(paramName)) + +for thisLoop_n in loop_n: + currentLoop = loop_n + # abbreviate parameter names if possible (e.g. rgb = thisLoop_n.rgb) + if thisLoop_n != None: + for paramName in thisLoop_n: + exec('{} = thisLoop_n[paramName]'.format(paramName)) + + # ------Prepare to start Routine "trial_n"------- + routineTimer.add(2.000000) + # update component parameters for each repeat + stimulus=choice(stimuli) + tial_n_letter.setText(stimulus) + # keep track of which components have finished + trial_nComponents = [trial_n_screen, tial_n_letter] + for thisComponent in trial_nComponents: + thisComponent.tStart = None + thisComponent.tStop = None + thisComponent.tStartRefresh = None + thisComponent.tStopRefresh = None + if hasattr(thisComponent, 'status'): + thisComponent.status = NOT_STARTED + # reset timers + t = 0 + _timeToFirstFrame = win.getFutureFlipTime(clock="now") + trial_nClock.reset(-_timeToFirstFrame) # t0 is time of first possible flip + frameN = -1 + continueRoutine = True + + # -------Run Routine "trial_n"------- + while continueRoutine and routineTimer.getTime() > 0: + # get current time + t = trial_nClock.getTime() + tThisFlip = win.getFutureFlipTime(clock=trial_nClock) + tThisFlipGlobal = win.getFutureFlipTime(clock=None) + frameN = frameN + 1 # number of completed frames (so 0 is the first frame) + # update/draw components on each frame + + # *trial_n_screen* updates + if trial_n_screen.status == NOT_STARTED and tThisFlip >= 0.0-frameTolerance: + # keep track of start time/frame for later + trial_n_screen.frameNStart = frameN # exact frame index + trial_n_screen.tStart = t # local t and not account for scr refresh + trial_n_screen.tStartRefresh = tThisFlipGlobal # on global time + win.timeOnFlip(trial_n_screen, 'tStartRefresh') # time at next scr refresh + trial_n_screen.setAutoDraw(True) + if trial_n_screen.status == STARTED: + # is it time to stop? (based on global clock, using actual start) + if tThisFlipGlobal > trial_n_screen.tStartRefresh + 2-frameTolerance: + # keep track of stop time/frame for later + trial_n_screen.tStop = t # not accounting for scr refresh + trial_n_screen.frameNStop = frameN # exact frame index + win.timeOnFlip(trial_n_screen, 'tStopRefresh') # time at next scr refresh + trial_n_screen.setAutoDraw(False) + + # *tial_n_letter* updates + if tial_n_letter.status == NOT_STARTED and tThisFlip >= 0-frameTolerance: + # keep track of start time/frame for later + tial_n_letter.frameNStart = frameN # exact frame index + tial_n_letter.tStart = t # local t and not account for scr refresh + tial_n_letter.tStartRefresh = tThisFlipGlobal # on global time + win.timeOnFlip(tial_n_letter, 'tStartRefresh') # time at next scr refresh + tial_n_letter.setAutoDraw(True) + if tial_n_letter.status == STARTED: + # is it time to stop? (based on global clock, using actual start) + if tThisFlipGlobal > tial_n_letter.tStartRefresh + 0.03-frameTolerance: + # keep track of stop time/frame for later + tial_n_letter.tStop = t # not accounting for scr refresh + tial_n_letter.frameNStop = frameN # exact frame index + win.timeOnFlip(tial_n_letter, 'tStopRefresh') # time at next scr refresh + tial_n_letter.setAutoDraw(False) + + # check for quit (typically the Esc key) + if endExpNow or defaultKeyboard.getKeys(keyList=["escape"]): + core.quit() + + # check if all components have finished + if not continueRoutine: # a component has requested a forced-end of Routine + break + continueRoutine = False # will revert to True if at least one component still running + for thisComponent in trial_nComponents: + if hasattr(thisComponent, "status") and thisComponent.status != FINISHED: + continueRoutine = True + break # at least one component has not yet finished + + # refresh the screen + if continueRoutine: # don't flip if this routine is over or we'll get a blank screen + win.flip() + + # -------Ending Routine "trial_n"------- + for thisComponent in trial_nComponents: + if hasattr(thisComponent, "setAutoDraw"): + thisComponent.setAutoDraw(False) + loop_n.addData('trial_n_screen.started', trial_n_screen.tStartRefresh) + loop_n.addData('trial_n_screen.stopped', trial_n_screen.tStopRefresh) + loop_n.addData('tial_n_letter.started', tial_n_letter.tStartRefresh) + loop_n.addData('tial_n_letter.stopped', tial_n_letter.tStopRefresh) + thisExp.nextEntry() + +# completed expInfo['n-Back'] repeats of 'loop_n' + + +# Flip one final time so any remaining win.callOnFlip() +# and win.timeOnFlip() tasks get executed before quitting +win.flip() + +# these shouldn't be strictly necessary (should auto-save) +thisExp.saveAsWideText(filename+'.csv') +thisExp.saveAsPickle(filename) +logging.flush() +# make sure everything is closed down +thisExp.abort() # or data files will save again on exit +win.close() +core.quit() diff --git a/three-back_lastrun.py b/three-back_lastrun.py index 54ca775f6a09e1f2415cf942195d3c3899a89dd3..8168bd7f15eab88b0c808847db4c1a3a7bf3f48e 100644 --- a/three-back_lastrun.py +++ b/three-back_lastrun.py @@ -2,7 +2,7 @@ # -*- coding: utf-8 -*- """ This experiment was created using PsychoPy3 Experiment Builder (v3.2.0), - on November 04, 2019, at 11:31 + on November 11, 2019, at 20:14 If you publish work using this script the most relevant publication is: Peirce J, Gray JR, Simpson S, MacAskill M, Höchenberger R, Sogo H, Kastman E, Lindeløv JK. (2019) @@ -35,7 +35,7 @@ os.chdir(_thisDir) # Store info about the experiment session psychopyVersion = '3.2.0' expName = 'three-back' # from the Builder filename that created this script -expInfo = {'participant': '', 'session': '001'} +expInfo = {'n-Back': '3', 'probability': '0.2', 'participant': '', 'session': '001'} dlg = gui.DlgFromDict(dictionary=expInfo, sortKeys=False, title=expName) if dlg.OK == False: core.quit() # user pressed cancel @@ -88,17 +88,29 @@ instructions = visual.TextStim(win=win, name='instructions', languageStyle='LTR', depth=0.0); key_start = keyboard.Keyboard() +# Set experiment start values for variable component stimuli +stimuli = ['A','B','C','D','E','F','G','H'] +stimuliContainer = [] +# Set experiment start values for variable component prevN +prevN = np.random.choice(stimuli,int(expInfo['n-Back'])) +prevNContainer = [] -# Initialize components for Routine "trial" -trialClock = core.Clock() -letter = visual.TextStim(win=win, name='letter', +# Initialize components for Routine "trial_n" +trial_nClock = core.Clock() +trial_n_screen = visual.Rect( + win=win, name='trial_n_screen',units='norm', + width=(2, 2)[0], height=(2, 2)[1], + ori=0, pos=(0, 0), + lineWidth=1, lineColor=[1,1,1], lineColorSpace='rgb', + fillColor=[-1,-1,-1], fillColorSpace='rgb', + opacity=1, depth=-1.0, interpolate=True) +tial_n_letter = visual.TextStim(win=win, name='tial_n_letter', text='default text', font='Arial', pos=(0, 0), height=2.5, wrapWidth=None, ori=0, color='white', colorSpace='rgb', opacity=1, languageStyle='LTR', - depth=0.0); -key_resp = keyboard.Keyboard() + depth=-2.0); # Create some handy timers globalClock = core.Clock() # to track the time since experiment started @@ -208,33 +220,33 @@ thisExp.nextEntry() routineTimer.reset() # set up handler to look after randomisation of conditions etc -trials = data.TrialHandler(nReps=20, method='random', +loop_n = data.TrialHandler(nReps=expInfo['n-Back'], method='sequential', extraInfo=expInfo, originPath=-1, trialList=[None], - seed=None, name='trials') -thisExp.addLoop(trials) # add the loop to the experiment -thisTrial = trials.trialList[0] # so we can initialise stimuli with some values -# abbreviate parameter names if possible (e.g. rgb = thisTrial.rgb) -if thisTrial != None: - for paramName in thisTrial: - exec('{} = thisTrial[paramName]'.format(paramName)) + seed=None, name='loop_n') +thisExp.addLoop(loop_n) # add the loop to the experiment +thisLoop_n = loop_n.trialList[0] # so we can initialise stimuli with some values +# abbreviate parameter names if possible (e.g. rgb = thisLoop_n.rgb) +if thisLoop_n != None: + for paramName in thisLoop_n: + exec('{} = thisLoop_n[paramName]'.format(paramName)) -for thisTrial in trials: - currentLoop = trials - # abbreviate parameter names if possible (e.g. rgb = thisTrial.rgb) - if thisTrial != None: - for paramName in thisTrial: - exec('{} = thisTrial[paramName]'.format(paramName)) +for thisLoop_n in loop_n: + currentLoop = loop_n + # abbreviate parameter names if possible (e.g. rgb = thisLoop_n.rgb) + if thisLoop_n != None: + for paramName in thisLoop_n: + exec('{} = thisLoop_n[paramName]'.format(paramName)) - # ------Prepare to start Routine "trial"------- + # ------Prepare to start Routine "trial_n"------- routineTimer.add(2.000000) # update component parameters for each repeat - letter.setText('a') - key_resp.keys = [] - key_resp.rt = [] + stimleft = np.delete(stimuli,[np.argwhere(stimuli==i) for i in prevN]) + stimulus = np.random.choice(stimleft) + tial_n_letter.setText(stimulus) # keep track of which components have finished - trialComponents = [letter, key_resp] - for thisComponent in trialComponents: + trial_nComponents = [trial_n_screen, tial_n_letter] + for thisComponent in trial_nComponents: thisComponent.tStart = None thisComponent.tStop = None thisComponent.tStartRefresh = None @@ -244,72 +256,52 @@ for thisTrial in trials: # reset timers t = 0 _timeToFirstFrame = win.getFutureFlipTime(clock="now") - trialClock.reset(-_timeToFirstFrame) # t0 is time of first possible flip + trial_nClock.reset(-_timeToFirstFrame) # t0 is time of first possible flip frameN = -1 continueRoutine = True - # -------Run Routine "trial"------- + # -------Run Routine "trial_n"------- while continueRoutine and routineTimer.getTime() > 0: # get current time - t = trialClock.getTime() - tThisFlip = win.getFutureFlipTime(clock=trialClock) + t = trial_nClock.getTime() + tThisFlip = win.getFutureFlipTime(clock=trial_nClock) tThisFlipGlobal = win.getFutureFlipTime(clock=None) frameN = frameN + 1 # number of completed frames (so 0 is the first frame) # update/draw components on each frame - # *letter* updates - if letter.status == NOT_STARTED and tThisFlip >= 0-frameTolerance: + # *trial_n_screen* updates + if trial_n_screen.status == NOT_STARTED and tThisFlip >= 0.0-frameTolerance: # keep track of start time/frame for later - letter.frameNStart = frameN # exact frame index - letter.tStart = t # local t and not account for scr refresh - letter.tStartRefresh = tThisFlipGlobal # on global time - win.timeOnFlip(letter, 'tStartRefresh') # time at next scr refresh - letter.setAutoDraw(True) - if letter.status == STARTED: + trial_n_screen.frameNStart = frameN # exact frame index + trial_n_screen.tStart = t # local t and not account for scr refresh + trial_n_screen.tStartRefresh = tThisFlipGlobal # on global time + win.timeOnFlip(trial_n_screen, 'tStartRefresh') # time at next scr refresh + trial_n_screen.setAutoDraw(True) + if trial_n_screen.status == STARTED: # is it time to stop? (based on global clock, using actual start) - if tThisFlipGlobal > letter.tStartRefresh + 0.03-frameTolerance: + if tThisFlipGlobal > trial_n_screen.tStartRefresh + 2-frameTolerance: # keep track of stop time/frame for later - letter.tStop = t # not accounting for scr refresh - letter.frameNStop = frameN # exact frame index - win.timeOnFlip(letter, 'tStopRefresh') # time at next scr refresh - letter.setAutoDraw(False) + trial_n_screen.tStop = t # not accounting for scr refresh + trial_n_screen.frameNStop = frameN # exact frame index + win.timeOnFlip(trial_n_screen, 'tStopRefresh') # time at next scr refresh + trial_n_screen.setAutoDraw(False) - # *key_resp* updates - waitOnFlip = False - if key_resp.status == NOT_STARTED and tThisFlip >= 0.0-frameTolerance: + # *tial_n_letter* updates + if tial_n_letter.status == NOT_STARTED and tThisFlip >= 0-frameTolerance: # keep track of start time/frame for later - key_resp.frameNStart = frameN # exact frame index - key_resp.tStart = t # local t and not account for scr refresh - key_resp.tStartRefresh = tThisFlipGlobal # on global time - win.timeOnFlip(key_resp, 'tStartRefresh') # time at next scr refresh - key_resp.status = STARTED - # keyboard checking is just starting - waitOnFlip = True - win.callOnFlip(key_resp.clock.reset) # t=0 on next screen flip - win.callOnFlip(key_resp.clearEvents, eventType='keyboard') # clear events on next screen flip - if key_resp.status == STARTED: + tial_n_letter.frameNStart = frameN # exact frame index + tial_n_letter.tStart = t # local t and not account for scr refresh + tial_n_letter.tStartRefresh = tThisFlipGlobal # on global time + win.timeOnFlip(tial_n_letter, 'tStartRefresh') # time at next scr refresh + tial_n_letter.setAutoDraw(True) + if tial_n_letter.status == STARTED: # is it time to stop? (based on global clock, using actual start) - if tThisFlipGlobal > key_resp.tStartRefresh + 2-frameTolerance: + if tThisFlipGlobal > tial_n_letter.tStartRefresh + 0.03-frameTolerance: # keep track of stop time/frame for later - key_resp.tStop = t # not accounting for scr refresh - key_resp.frameNStop = frameN # exact frame index - win.timeOnFlip(key_resp, 'tStopRefresh') # time at next scr refresh - key_resp.status = FINISHED - if key_resp.status == STARTED and not waitOnFlip: - theseKeys = key_resp.getKeys(keyList=['space'], waitRelease=False) - if len(theseKeys): - theseKeys = theseKeys[0] # at least one key was pressed - - # check for quit: - if "escape" == theseKeys: - endExpNow = True - key_resp.keys = theseKeys.name # just the last key pressed - key_resp.rt = theseKeys.rt - # was this 'correct'? - if (key_resp.keys == str('')) or (key_resp.keys == ''): - key_resp.corr = 1 - else: - key_resp.corr = 0 + tial_n_letter.tStop = t # not accounting for scr refresh + tial_n_letter.frameNStop = frameN # exact frame index + win.timeOnFlip(tial_n_letter, 'tStopRefresh') # time at next scr refresh + tial_n_letter.setAutoDraw(False) # check for quit (typically the Esc key) if endExpNow or defaultKeyboard.getKeys(keyList=["escape"]): @@ -319,7 +311,7 @@ for thisTrial in trials: if not continueRoutine: # a component has requested a forced-end of Routine break continueRoutine = False # will revert to True if at least one component still running - for thisComponent in trialComponents: + for thisComponent in trial_nComponents: if hasattr(thisComponent, "status") and thisComponent.status != FINISHED: continueRoutine = True break # at least one component has not yet finished @@ -328,30 +320,18 @@ for thisTrial in trials: if continueRoutine: # don't flip if this routine is over or we'll get a blank screen win.flip() - # -------Ending Routine "trial"------- - for thisComponent in trialComponents: + # -------Ending Routine "trial_n"------- + for thisComponent in trial_nComponents: if hasattr(thisComponent, "setAutoDraw"): thisComponent.setAutoDraw(False) - trials.addData('letter.started', letter.tStartRefresh) - trials.addData('letter.stopped', letter.tStopRefresh) - # check responses - if key_resp.keys in ['', [], None]: # No response was made - key_resp.keys = None - # was no response the correct answer?! - if str('').lower() == 'none': - key_resp.corr = 1; # correct non-response - else: - key_resp.corr = 0; # failed to respond (incorrectly) - # store data for trials (TrialHandler) - trials.addData('key_resp.keys',key_resp.keys) - trials.addData('key_resp.corr', key_resp.corr) - if key_resp.keys != None: # we had a response - trials.addData('key_resp.rt', key_resp.rt) - trials.addData('key_resp.started', key_resp.tStartRefresh) - trials.addData('key_resp.stopped', key_resp.tStopRefresh) + prevN = np.hstack((prevN[1:],stimulus)) + loop_n.addData('trial_n_screen.started', trial_n_screen.tStartRefresh) + loop_n.addData('trial_n_screen.stopped', trial_n_screen.tStopRefresh) + loop_n.addData('tial_n_letter.started', tial_n_letter.tStartRefresh) + loop_n.addData('tial_n_letter.stopped', tial_n_letter.tStopRefresh) thisExp.nextEntry() -# completed 20 repeats of 'trials' +# completed expInfo['n-Back'] repeats of 'loop_n' # Flip one final time so any remaining win.callOnFlip()