diff --git a/three-back.psyexp b/three-back.psyexp index 3ff4c84ddd10e601ee809d136039300ac6b92b42..8a44b8594c9dab571ccd439f782d198325b88333 100644 --- a/three-back.psyexp +++ b/three-back.psyexp @@ -1,10 +1,10 @@ <?xml version="1.0" ?> -<PsychoPy2experiment encoding="utf-8" version="3.2.4"> +<PsychoPy2experiment encoding="utf-8" version="2020.1.0"> <Settings> <Param name="Audio latency priority" updates="None" val="use prefs" valType="str"/> <Param name="Audio lib" updates="None" val="use prefs" valType="str"/> <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="Data filename" updates="None" val="u'data/%s/%s_%s_%s' % (expInfo['participant'], 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', 'backN': '3', 'probability': '0.2'}" valType="code"/> <Param name="Force stereo" updates="None" val="True" valType="bool"/> @@ -23,7 +23,7 @@ <Param name="Show mouse" updates="None" val="False" valType="bool"/> <Param name="Units" updates="None" val="deg" valType="str"/> <Param name="Use version" updates="None" val="" valType="str"/> - <Param name="Window size (pixels)" updates="None" val="[1366, 768]" valType="code"/> + <Param name="Window size (pixels)" updates="None" val="[1920, 1080]" valType="code"/> <Param name="blendMode" updates="None" val="avg" valType="str"/> <Param name="color" updates="None" val="$[1,1,1]" valType="str"/> <Param name="colorSpace" updates="None" val="rgb" valType="str"/> @@ -53,9 +53,9 @@ <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="constant" val="$"The n-back task presents stimuli sequentially and require you to decide if the current stimulus is the same as one presented n-numbers previous (or back).\n"&#10;+ "\n"&#10;+ "For example, the 3-back you will indicate if the current number matches the number presented 3 places previous\n"&#10;+ "(e.g. A H G A B G B shows that 'A' and 'G' have matches in this sequence).\n"&#10;+ "\n"&#10;+ f"This is an {expInfo['backN']}-back task.\n"&#10;+ f"Press SPACE if the current stimulus is the same a {expInfo['backN']} places previous.\n"&#10;+ "\n"&#10;+ "Press SPACE bar when ready to start." " valType="str"/> + <Param name="text" updates="constant" val="$"The n-back task presents stimuli sequentially and require you to decide if the current stimulus is the same as one presented n-numbers previous (or back).\n"&#10;+ "\n"&#10;+ "For example, the 3-back you will indicate if the current number matches the number presented 3 places previous\n"&#10;+ "(e.g. A H G A B G B shows that 'A' and 'G' have matches in this sequence).\n"&#10;+ "\n"&#10;+ f"This is an {expInfo['backN']}-back task.\n"&#10;+ f"Press SPACE if the current stimulus is the same a {expInfo['backN']} places previous.\n"&#10;+ "\n"&#10;+ "The task will start after some minutes of rest."" valType="str"/> <Param name="units" updates="None" val="from exp settings" valType="str"/> - <Param name="wrapWidth" updates="constant" val="30" valType="code"/> + <Param name="wrapWidth" updates="constant" val="45" valType="code"/> </TextComponent> <KeyboardComponent name="instructions_key"> <Param name="allowedKeys" updates="constant" val="'space'" valType="code"/> @@ -126,12 +126,12 @@ <CodeComponent name="trial_code"> <Param name="Begin Experiment" updates="constant" val="prevN = np.array([])" 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="if (currentLoop.thisN < int(expInfo['backN'])) or (np.random.uniform() > float(expInfo['probability'])):&#10; stimleft = np.delete(stimuli,[np.argwhere(stimuli==i) for i in prevN])&#10; stimulus = np.random.choice(stimleft)&#10; correctResponse = None&#10;else:&#10; stimulus = prevN[-int(expInfo['backN'])]&#10; correctResponse = 'space'" valType="extendedCode"/> - <Param name="Code Type" updates="None" val="Py" valType="str"/> + <Param name="Begin JS Routine" updates="constant" val="if (((currentLoop.thisN < Number.parseInt(expInfo["backN"])) || (np.random.uniform() > Number.parseFloat(expInfo["probability"])))) {&#10; stimleft = np.delete(stimuli, function () {&#10; var _pj_a = [], _pj_b = prevN;&#10; for (var _pj_c = 0, _pj_d = _pj_b.length; (_pj_c < _pj_d); _pj_c += 1) {&#10; var i = _pj_b[_pj_c];&#10; _pj_a.push(np.argwhere((stimuli === i)));&#10; }&#10; return _pj_a;&#10;}&#10;.call(this));&#10; stimulus = np.random.choice(stimleft);&#10; correctResponse = null;&#10;} else {&#10; stimulus = prevN.slice((- Number.parseInt(expInfo["backN"])))[0];&#10; correctResponse = "space";&#10;}&#10;" valType="extendedCode"/> + <Param name="Begin Routine" updates="constant" val="if (currentLoop.thisN < int(expInfo['backN'])) or (np.random.uniform() > float(expInfo['probability'])):&#10; stimleft = np.delete(stimuli,[np.argwhere(stimuli==i) for i in prevN])&#10; stimulus = np.random.choice(stimleft)&#10; thisExp.addData('trial_type', 'none')&#10; correctResponse = None&#10;else:&#10; stimulus = prevN[-int(expInfo['backN'])]&#10; thisExp.addData('trial_type', 'back')&#10; correctResponse = 'space'" valType="extendedCode"/> + <Param name="Code Type" updates="None" val="Auto->JS" 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 Experiment" updates="constant" val="trialNone = 0; trialBack = 0; hit = 0; miss = 0; fa = 0&#10;for n, t in enumerate(thisExp.entries):&#10; if t['trial_type'] == 'none':&#10; trialNone += 1&#10; if not(t['trial_resp.corr']): fa += 1&#10; if t['trial_type'] == 'back':&#10; trialBack += 1&#10; if t['trial_resp.corr']: hit += 1&#10; else: miss += 1&#10;logging.log(level=logging.DATA, msg='hit={:.2f}%,miss={:.2f}%,fa={:.2f}%'.format(hit/trialBack*100,miss/trialBack*100,fa/trialNone*100))&#10;" 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="thisExp.addData('tial_stimulus.stim', stimulus)&#10;prevN = np.hstack((prevN,stimulus))&#10;prevN = prevN[-3:]" valType="extendedCode"/> @@ -181,9 +181,100 @@ <Param name="syncScreenRefresh" updates="constant" val="True" valType="bool"/> </KeyboardComponent> </Routine> + <Routine name="Rest"> + <PolygonComponent name="rest_bg"> + <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="0" valType="code"/> + <Param name="nVertices" updates="constant" val="4" valType="int"/> + <Param name="name" updates="None" val="rest_bg" 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="300" valType="code"/> + <Param name="syncScreenRefresh" updates="None" val="True" valType="bool"/> + <Param name="units" updates="None" val="norm" valType="str"/> + </PolygonComponent> + <TextComponent name="rest_text"> + <Param name="color" updates="constant" val="black" valType="str"/> + <Param name="colorSpace" updates="constant" val="rgb" valType="str"/> + <Param name="disabled" updates="None" val="False" valType="bool"/> + <Param name="durationEstim" updates="None" val="" 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="1" valType="code"/> + <Param name="name" updates="None" val="rest_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="270" valType="code"/> + <Param name="syncScreenRefresh" updates="None" val="True" valType="bool"/> + <Param name="text" updates="constant" val="Rest" valType="str"/> + <Param name="units" updates="None" val="from exp settings" valType="str"/> + <Param name="wrapWidth" updates="constant" val="" valType="code"/> + </TextComponent> + <TextComponent name="rest_text2"> + <Param name="color" updates="constant" val="black" valType="str"/> + <Param name="colorSpace" updates="constant" val="rgb" valType="str"/> + <Param name="disabled" updates="None" val="False" valType="bool"/> + <Param name="durationEstim" updates="None" val="" 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="1" valType="code"/> + <Param name="name" updates="None" val="rest_text2" 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="270" valType="code"/> + <Param name="stopType" updates="None" val="duration (s)" valType="str"/> + <Param name="stopVal" updates="constant" val="29" valType="code"/> + <Param name="syncScreenRefresh" updates="None" val="True" valType="bool"/> + <Param name="text" updates="constant" val="Get ready!" valType="str"/> + <Param name="units" updates="None" val="from exp settings" valType="str"/> + <Param name="wrapWidth" updates="constant" val="" valType="code"/> + </TextComponent> + <CodeComponent name="rest_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="" valType="extendedCode"/> + <Param name="Code Type" updates="None" val="Auto->JS" valType="str"/> + <Param name="Each Frame" updates="constant" val="if routineTimer.getTime() <= 10:&#10; rest_text2.setText("Get ready!\n{}".format(round(routineTimer.getTime())), log=False)&#10;" valType="extendedCode"/> + <Param name="Each JS Frame" updates="constant" val="/* Syntax Error: Fix Python code */" 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="" valType="extendedCode"/> + <Param name="disabled" updates="None" val="False" valType="bool"/> + <Param name="name" updates="None" val="rest_code" valType="code"/> + </CodeComponent> + </Routine> </Routines> <Flow> <Routine name="Instructions"/> + <Routine name="Rest"/> <LoopInitiator loopType="TrialHandler" name="loop"> <Param name="Selected rows" updates="None" val="" valType="str"/> <Param name="conditions" updates="None" val="None" valType="str"/> diff --git a/three-back.py b/three-back.py index 3da3ce464f2e6e29713f4cb77ad6ee494bd14b13..a342541e62092bb1c60730c5e64dcb1e525d9307 100644 --- a/three-back.py +++ b/three-back.py @@ -1,8 +1,8 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- """ -This experiment was created using PsychoPy3 Experiment Builder (v3.2.4), - on November 15, 2019, at 12:50 +This experiment was created using PsychoPy3 Experiment Builder (v2020.1.0), + on February 13, 2020, at 15:00 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) @@ -28,12 +28,14 @@ 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.4' +psychopyVersion = '2020.1.0' expName = 'three-back' # from the Builder filename that created this script expInfo = {'participant': '', 'session': '001', 'backN': '3', 'probability': '0.2'} dlg = gui.DlgFromDict(dictionary=expInfo, sortKeys=False, title=expName) @@ -44,12 +46,12 @@ 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']) +filename = _thisDir + os.sep + u'data/%s/%s_%s_%s' % (expInfo['participant'], 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='C:\\Users\\User\\Documents\\PROJECT_FOLDER\\three-back\\three-back.py', + originPath='C:\\Users\\nemo\\Desktop\\NEMO\\Paradigms\\three-back\\three-back.py', savePickle=True, saveWideText=True, dataFileName=filename) # save a log file for detail verbose info @@ -63,7 +65,7 @@ frameTolerance = 0.001 # how close to onset before 'same' frame # Setup the Window win = visual.Window( - size=[1366, 768], fullscr=True, screen=0, + size=[1920, 1080], fullscr=True, screen=0, winType='pyglet', allowGUI=False, allowStencil=False, monitor='testMonitor', color=[1,1,1], colorSpace='rgb', blendMode='avg', useFBO=True, @@ -89,9 +91,9 @@ instructions = visual.TextStim(win=win, name='instructions', + f"This is an {expInfo['backN']}-back task.\n" + f"Press SPACE if the current stimulus is the same a {expInfo['backN']} places previous.\n" + "\n" -+ "Press SPACE bar when ready to start." , ++ "The task will start after some minutes of rest.", font='Arial', - pos=(0, 0), height=1, wrapWidth=30, ori=0, + pos=(0, 0), height=1, wrapWidth=45, ori=0, color='black', colorSpace='rgb', opacity=1, languageStyle='LTR', depth=0.0); @@ -100,6 +102,30 @@ instructions_key = keyboard.Keyboard() stimuli = np.array(['A','B','C','D','E','F','G','H']) stimuliContainer = [] +# Initialize components for Routine "Rest" +RestClock = core.Clock() +rest_bg = visual.Rect( + win=win, name='rest_bg',units='norm', + width=(2, 2)[0], height=(2, 2)[1], + ori=0, pos=(0, 0), + lineWidth=0, lineColor=[1,1,1], lineColorSpace='rgb', + fillColor=[1,1,1], fillColorSpace='rgb', + opacity=1, depth=0.0, interpolate=True) +rest_text = visual.TextStim(win=win, name='rest_text', + text='Rest', + font='Arial', + pos=(0, 0), height=1, wrapWidth=None, ori=0, + color='black', colorSpace='rgb', opacity=1, + languageStyle='LTR', + depth=-1.0); +rest_text2 = visual.TextStim(win=win, name='rest_text2', + text='Get ready!', + font='Arial', + pos=(0, 0), height=1, wrapWidth=None, ori=0, + color='black', colorSpace='rgb', opacity=1, + languageStyle='LTR', + depth=-2.0); + # Initialize components for Routine "trial" trialClock = core.Clock() prevN = np.array([]) @@ -121,6 +147,7 @@ continueRoutine = True # update component parameters for each repeat instructions_key.keys = [] instructions_key.rt = [] +_instructions_key_allKeys = [] # keep track of which components have finished InstructionsComponents = [instructions, instructions_key] for thisComponent in InstructionsComponents: @@ -170,14 +197,13 @@ while continueRoutine: win.timeOnFlip(instructions_key, 'tStartRefresh') # time at next scr refresh instructions_key.status = STARTED # keyboard checking is just starting + instructions_key.clock.reset() # now t=0 if instructions_key.status == STARTED: theseKeys = instructions_key.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 + _instructions_key_allKeys.extend(theseKeys) + if len(_instructions_key_allKeys): + instructions_key.keys = _instructions_key_allKeys[-1].name # just the last key pressed + instructions_key.rt = _instructions_key_allKeys[-1].rt # a response ends the routine continueRoutine = False @@ -205,6 +231,116 @@ for thisComponent in InstructionsComponents: # the Routine "Instructions" was not non-slip safe, so reset the non-slip timer routineTimer.reset() +# ------Prepare to start Routine "Rest"------- +continueRoutine = True +routineTimer.add(300.000000) +# update component parameters for each repeat +# keep track of which components have finished +RestComponents = [rest_bg, rest_text, rest_text2] +for thisComponent in RestComponents: + 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") +RestClock.reset(-_timeToFirstFrame) # t0 is time of first possible flip +frameN = -1 + +# -------Run Routine "Rest"------- +while continueRoutine and routineTimer.getTime() > 0: + # get current time + t = RestClock.getTime() + tThisFlip = win.getFutureFlipTime(clock=RestClock) + tThisFlipGlobal = win.getFutureFlipTime(clock=None) + frameN = frameN + 1 # number of completed frames (so 0 is the first frame) + # update/draw components on each frame + + # *rest_bg* updates + if rest_bg.status == NOT_STARTED and tThisFlip >= 0.0-frameTolerance: + # keep track of start time/frame for later + rest_bg.frameNStart = frameN # exact frame index + rest_bg.tStart = t # local t and not account for scr refresh + rest_bg.tStartRefresh = tThisFlipGlobal # on global time + win.timeOnFlip(rest_bg, 'tStartRefresh') # time at next scr refresh + rest_bg.setAutoDraw(True) + if rest_bg.status == STARTED: + # is it time to stop? (based on global clock, using actual start) + if tThisFlipGlobal > rest_bg.tStartRefresh + 300-frameTolerance: + # keep track of stop time/frame for later + rest_bg.tStop = t # not accounting for scr refresh + rest_bg.frameNStop = frameN # exact frame index + win.timeOnFlip(rest_bg, 'tStopRefresh') # time at next scr refresh + rest_bg.setAutoDraw(False) + + # *rest_text* updates + if rest_text.status == NOT_STARTED and tThisFlip >= 0.0-frameTolerance: + # keep track of start time/frame for later + rest_text.frameNStart = frameN # exact frame index + rest_text.tStart = t # local t and not account for scr refresh + rest_text.tStartRefresh = tThisFlipGlobal # on global time + win.timeOnFlip(rest_text, 'tStartRefresh') # time at next scr refresh + rest_text.setAutoDraw(True) + if rest_text.status == STARTED: + # is it time to stop? (based on global clock, using actual start) + if tThisFlipGlobal > rest_text.tStartRefresh + 270-frameTolerance: + # keep track of stop time/frame for later + rest_text.tStop = t # not accounting for scr refresh + rest_text.frameNStop = frameN # exact frame index + win.timeOnFlip(rest_text, 'tStopRefresh') # time at next scr refresh + rest_text.setAutoDraw(False) + + # *rest_text2* updates + if rest_text2.status == NOT_STARTED and tThisFlip >= 270-frameTolerance: + # keep track of start time/frame for later + rest_text2.frameNStart = frameN # exact frame index + rest_text2.tStart = t # local t and not account for scr refresh + rest_text2.tStartRefresh = tThisFlipGlobal # on global time + win.timeOnFlip(rest_text2, 'tStartRefresh') # time at next scr refresh + rest_text2.setAutoDraw(True) + if rest_text2.status == STARTED: + # is it time to stop? (based on global clock, using actual start) + if tThisFlipGlobal > rest_text2.tStartRefresh + 29-frameTolerance: + # keep track of stop time/frame for later + rest_text2.tStop = t # not accounting for scr refresh + rest_text2.frameNStop = frameN # exact frame index + win.timeOnFlip(rest_text2, 'tStopRefresh') # time at next scr refresh + rest_text2.setAutoDraw(False) + if routineTimer.getTime() <= 10: + rest_text2.setText("Get ready!\n{}".format(round(routineTimer.getTime())), log=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 RestComponents: + 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 "Rest"------- +for thisComponent in RestComponents: + if hasattr(thisComponent, "setAutoDraw"): + thisComponent.setAutoDraw(False) +thisExp.addData('rest_bg.started', rest_bg.tStartRefresh) +thisExp.addData('rest_bg.stopped', rest_bg.tStopRefresh) +thisExp.addData('rest_text.started', rest_text.tStartRefresh) +thisExp.addData('rest_text.stopped', rest_text.tStopRefresh) +thisExp.addData('rest_text2.started', rest_text2.tStartRefresh) +thisExp.addData('rest_text2.stopped', rest_text2.tStopRefresh) + # set up handler to look after randomisation of conditions etc loop = data.TrialHandler(nReps=150, method='sequential', extraInfo=expInfo, originPath=-1, @@ -231,13 +367,16 @@ for thisLoop in loop: if (currentLoop.thisN < int(expInfo['backN'])) or (np.random.uniform() > float(expInfo['probability'])): stimleft = np.delete(stimuli,[np.argwhere(stimuli==i) for i in prevN]) stimulus = np.random.choice(stimleft) + thisExp.addData('trial_type', 'none') correctResponse = None else: stimulus = prevN[-int(expInfo['backN'])] + thisExp.addData('trial_type', 'back') correctResponse = 'space' trial_stimulus.setText(stimulus) trial_resp.keys = [] trial_resp.rt = [] + _trial_resp_allKeys = [] # keep track of which components have finished trialComponents = [trial_stimulus, trial_resp] for thisComponent in trialComponents: @@ -302,20 +441,15 @@ for thisLoop in loop: trial_resp.status = FINISHED if trial_resp.status == STARTED and not waitOnFlip: theseKeys = trial_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 - if trial_resp.keys == []: # then this was the first keypress - trial_resp.keys = theseKeys.name # just the first key pressed - trial_resp.rt = theseKeys.rt - # was this 'correct'? - if (trial_resp.keys == str(correctResponse)) or (trial_resp.keys == correctResponse): - trial_resp.corr = 1 - else: - trial_resp.corr = 0 + _trial_resp_allKeys.extend(theseKeys) + if len(_trial_resp_allKeys): + trial_resp.keys = _trial_resp_allKeys[0].name # just the first key pressed + trial_resp.rt = _trial_resp_allKeys[0].rt + # was this correct? + if (trial_resp.keys == str(correctResponse)) or (trial_resp.keys == correctResponse): + trial_resp.corr = 1 + else: + trial_resp.corr = 0 # check for quit (typically the Esc key) if endExpNow or defaultKeyboard.getKeys(keyList=["escape"]): @@ -362,6 +496,17 @@ for thisLoop in loop: # completed 150 repeats of 'loop' +trialNone = 0; trialBack = 0; hit = 0; miss = 0; fa = 0 +for n, t in enumerate(thisExp.entries): + if t['trial_type'] == 'none': + trialNone += 1 + if not(t['trial_resp.corr']): fa += 1 + if t['trial_type'] == 'back': + trialBack += 1 + if t['trial_resp.corr']: hit += 1 + else: miss += 1 +logging.log(level=logging.DATA, msg='hit={:.2f}%,miss={:.2f}%,fa={:.2f}%'.format(hit/trialBack*100,miss/trialBack*100,fa/trialNone*100)) + # Flip one final time so any remaining win.callOnFlip() # and win.timeOnFlip() tasks get executed before quitting diff --git a/three-back_lastrun.py b/three-back_lastrun.py new file mode 100644 index 0000000000000000000000000000000000000000..33a24c277b244633d28d00d948151ebd18046b11 --- /dev/null +++ b/three-back_lastrun.py @@ -0,0 +1,522 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +""" +This experiment was created using PsychoPy3 Experiment Builder (v2020.1.0), + on February 13, 2020, at 14:49 +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 = '2020.1.0' +expName = 'three-back' # from the Builder filename that created this script +expInfo = {'participant': '', 'session': '001', 'backN': '3', 'probability': '0.2'} +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_%s' % (expInfo['participant'], 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='C:\\Users\\nemo\\Desktop\\NEMO\\Paradigms\\three-back\\three-back_lastrun.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=[1920, 1080], fullscr=True, screen=0, + winType='pyglet', allowGUI=False, allowStencil=False, + monitor='testMonitor', 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() +instructions = visual.TextStim(win=win, name='instructions', + text="The n-back task presents stimuli sequentially and require you to decide if the current stimulus is the same as one presented n-numbers previous (or back).\n" ++ "\n" ++ "For example, the 3-back you will indicate if the current number matches the number presented 3 places previous\n" ++ "(e.g. A H G A B G B shows that 'A' and 'G' have matches in this sequence).\n" ++ "\n" ++ f"This is an {expInfo['backN']}-back task.\n" ++ f"Press SPACE if the current stimulus is the same a {expInfo['backN']} places previous.\n" ++ "\n" ++ "The task will start after some minutes of rest.", + font='Arial', + pos=(0, 0), height=1, wrapWidth=45, ori=0, + color='black', colorSpace='rgb', opacity=1, + languageStyle='LTR', + depth=0.0); +instructions_key = keyboard.Keyboard() +# Set experiment start values for variable component stimuli +stimuli = np.array(['A','B','C','D','E','F','G','H']) +stimuliContainer = [] + +# Initialize components for Routine "Rest" +RestClock = core.Clock() +rest_bg = visual.Rect( + win=win, name='rest_bg',units='norm', + width=(2, 2)[0], height=(2, 2)[1], + ori=0, pos=(0, 0), + lineWidth=0, lineColor=[1,1,1], lineColorSpace='rgb', + fillColor=[1,1,1], fillColorSpace='rgb', + opacity=1, depth=0.0, interpolate=True) +rest_text = visual.TextStim(win=win, name='rest_text', + text='Rest', + font='Arial', + pos=(0, 0), height=1, wrapWidth=None, ori=0, + color='black', colorSpace='rgb', opacity=1, + languageStyle='LTR', + depth=-1.0); +rest_text2 = visual.TextStim(win=win, name='rest_text2', + text='Get ready!', + font='Arial', + pos=(0, 0), height=1, wrapWidth=None, ori=0, + color='black', colorSpace='rgb', opacity=1, + languageStyle='LTR', + depth=-2.0); + +# Initialize components for Routine "trial" +trialClock = core.Clock() +prevN = np.array([]) +trial_stimulus = visual.TextStim(win=win, name='trial_stimulus', + text='default text', + font='Arial', + pos=(0, 0), height=2.5, wrapWidth=None, ori=0, + color='black', colorSpace='rgb', opacity=1, + languageStyle='LTR', + depth=-1.0); +trial_resp = keyboard.Keyboard() + +# 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"------- +continueRoutine = True +# update component parameters for each repeat +instructions_key.keys = [] +instructions_key.rt = [] +_instructions_key_allKeys = [] +# keep track of which components have finished +InstructionsComponents = [instructions, instructions_key] +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 + +# -------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) + + # *instructions_key* updates + if instructions_key.status == NOT_STARTED and t >= 0.0-frameTolerance: + # keep track of start time/frame for later + instructions_key.frameNStart = frameN # exact frame index + instructions_key.tStart = t # local t and not account for scr refresh + instructions_key.tStartRefresh = tThisFlipGlobal # on global time + win.timeOnFlip(instructions_key, 'tStartRefresh') # time at next scr refresh + instructions_key.status = STARTED + # keyboard checking is just starting + instructions_key.clock.reset() # now t=0 + if instructions_key.status == STARTED: + theseKeys = instructions_key.getKeys(keyList=['space'], waitRelease=False) + _instructions_key_allKeys.extend(theseKeys) + if len(_instructions_key_allKeys): + instructions_key.keys = _instructions_key_allKeys[-1].name # just the last key pressed + instructions_key.rt = _instructions_key_allKeys[-1].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) +# the Routine "Instructions" was not non-slip safe, so reset the non-slip timer +routineTimer.reset() + +# ------Prepare to start Routine "Rest"------- +continueRoutine = True +routineTimer.add(300.000000) +# update component parameters for each repeat +# keep track of which components have finished +RestComponents = [rest_bg, rest_text, rest_text2] +for thisComponent in RestComponents: + 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") +RestClock.reset(-_timeToFirstFrame) # t0 is time of first possible flip +frameN = -1 + +# -------Run Routine "Rest"------- +while continueRoutine and routineTimer.getTime() > 0: + # get current time + t = RestClock.getTime() + tThisFlip = win.getFutureFlipTime(clock=RestClock) + tThisFlipGlobal = win.getFutureFlipTime(clock=None) + frameN = frameN + 1 # number of completed frames (so 0 is the first frame) + # update/draw components on each frame + + # *rest_bg* updates + if rest_bg.status == NOT_STARTED and tThisFlip >= 0.0-frameTolerance: + # keep track of start time/frame for later + rest_bg.frameNStart = frameN # exact frame index + rest_bg.tStart = t # local t and not account for scr refresh + rest_bg.tStartRefresh = tThisFlipGlobal # on global time + win.timeOnFlip(rest_bg, 'tStartRefresh') # time at next scr refresh + rest_bg.setAutoDraw(True) + if rest_bg.status == STARTED: + # is it time to stop? (based on global clock, using actual start) + if tThisFlipGlobal > rest_bg.tStartRefresh + 300-frameTolerance: + # keep track of stop time/frame for later + rest_bg.tStop = t # not accounting for scr refresh + rest_bg.frameNStop = frameN # exact frame index + win.timeOnFlip(rest_bg, 'tStopRefresh') # time at next scr refresh + rest_bg.setAutoDraw(False) + + # *rest_text* updates + if rest_text.status == NOT_STARTED and tThisFlip >= 0.0-frameTolerance: + # keep track of start time/frame for later + rest_text.frameNStart = frameN # exact frame index + rest_text.tStart = t # local t and not account for scr refresh + rest_text.tStartRefresh = tThisFlipGlobal # on global time + win.timeOnFlip(rest_text, 'tStartRefresh') # time at next scr refresh + rest_text.setAutoDraw(True) + if rest_text.status == STARTED: + # is it time to stop? (based on global clock, using actual start) + if tThisFlipGlobal > rest_text.tStartRefresh + 270-frameTolerance: + # keep track of stop time/frame for later + rest_text.tStop = t # not accounting for scr refresh + rest_text.frameNStop = frameN # exact frame index + win.timeOnFlip(rest_text, 'tStopRefresh') # time at next scr refresh + rest_text.setAutoDraw(False) + + # *rest_text2* updates + if rest_text2.status == NOT_STARTED and tThisFlip >= 270-frameTolerance: + # keep track of start time/frame for later + rest_text2.frameNStart = frameN # exact frame index + rest_text2.tStart = t # local t and not account for scr refresh + rest_text2.tStartRefresh = tThisFlipGlobal # on global time + win.timeOnFlip(rest_text2, 'tStartRefresh') # time at next scr refresh + rest_text2.setAutoDraw(True) + if rest_text2.status == STARTED: + # is it time to stop? (based on global clock, using actual start) + if tThisFlipGlobal > rest_text2.tStartRefresh + 29-frameTolerance: + # keep track of stop time/frame for later + rest_text2.tStop = t # not accounting for scr refresh + rest_text2.frameNStop = frameN # exact frame index + win.timeOnFlip(rest_text2, 'tStopRefresh') # time at next scr refresh + rest_text2.setAutoDraw(False) + if routineTimer.getTime() <= 10: + rest_text2.setText("Get ready!\n{}".format(round(routineTimer.getTime())), log=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 RestComponents: + 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 "Rest"------- +for thisComponent in RestComponents: + if hasattr(thisComponent, "setAutoDraw"): + thisComponent.setAutoDraw(False) +thisExp.addData('rest_bg.started', rest_bg.tStartRefresh) +thisExp.addData('rest_bg.stopped', rest_bg.tStopRefresh) +thisExp.addData('rest_text.started', rest_text.tStartRefresh) +thisExp.addData('rest_text.stopped', rest_text.tStopRefresh) +thisExp.addData('rest_text2.started', rest_text2.tStartRefresh) +thisExp.addData('rest_text2.stopped', rest_text2.tStopRefresh) + +# set up handler to look after randomisation of conditions etc +loop = data.TrialHandler(nReps=150, method='sequential', + extraInfo=expInfo, originPath=-1, + trialList=[None], + seed=None, name='loop') +thisExp.addLoop(loop) # add the loop to the experiment +thisLoop = loop.trialList[0] # so we can initialise stimuli with some values +# abbreviate parameter names if possible (e.g. rgb = thisLoop.rgb) +if thisLoop != None: + for paramName in thisLoop: + exec('{} = thisLoop[paramName]'.format(paramName)) + +for thisLoop in loop: + currentLoop = loop + # abbreviate parameter names if possible (e.g. rgb = thisLoop.rgb) + if thisLoop != None: + for paramName in thisLoop: + exec('{} = thisLoop[paramName]'.format(paramName)) + + # ------Prepare to start Routine "trial"------- + continueRoutine = True + routineTimer.add(2.000000) + # update component parameters for each repeat + if (currentLoop.thisN < int(expInfo['backN'])) or (np.random.uniform() > float(expInfo['probability'])): + stimleft = np.delete(stimuli,[np.argwhere(stimuli==i) for i in prevN]) + stimulus = np.random.choice(stimleft) + thisExp.addData('trial_type', 'none') + correctResponse = None + else: + stimulus = prevN[-int(expInfo['backN'])] + thisExp.addData('trial_type', 'back') + correctResponse = 'space' + trial_stimulus.setText(stimulus) + trial_resp.keys = [] + trial_resp.rt = [] + _trial_resp_allKeys = [] + # keep track of which components have finished + trialComponents = [trial_stimulus, trial_resp] + for thisComponent in trialComponents: + 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") + trialClock.reset(-_timeToFirstFrame) # t0 is time of first possible flip + frameN = -1 + + # -------Run Routine "trial"------- + while continueRoutine and routineTimer.getTime() > 0: + # get current time + t = trialClock.getTime() + tThisFlip = win.getFutureFlipTime(clock=trialClock) + 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_stimulus* updates + if trial_stimulus.status == NOT_STARTED and tThisFlip >= 0-frameTolerance: + # keep track of start time/frame for later + trial_stimulus.frameNStart = frameN # exact frame index + trial_stimulus.tStart = t # local t and not account for scr refresh + trial_stimulus.tStartRefresh = tThisFlipGlobal # on global time + win.timeOnFlip(trial_stimulus, 'tStartRefresh') # time at next scr refresh + trial_stimulus.setAutoDraw(True) + if trial_stimulus.status == STARTED: + # is it time to stop? (based on global clock, using actual start) + if tThisFlipGlobal > trial_stimulus.tStartRefresh + 0.03-frameTolerance: + # keep track of stop time/frame for later + trial_stimulus.tStop = t # not accounting for scr refresh + trial_stimulus.frameNStop = frameN # exact frame index + win.timeOnFlip(trial_stimulus, 'tStopRefresh') # time at next scr refresh + trial_stimulus.setAutoDraw(False) + + # *trial_resp* updates + waitOnFlip = False + if trial_resp.status == NOT_STARTED and tThisFlip >= 0.0-frameTolerance: + # keep track of start time/frame for later + trial_resp.frameNStart = frameN # exact frame index + trial_resp.tStart = t # local t and not account for scr refresh + trial_resp.tStartRefresh = tThisFlipGlobal # on global time + win.timeOnFlip(trial_resp, 'tStartRefresh') # time at next scr refresh + trial_resp.status = STARTED + # keyboard checking is just starting + waitOnFlip = True + win.callOnFlip(trial_resp.clock.reset) # t=0 on next screen flip + win.callOnFlip(trial_resp.clearEvents, eventType='keyboard') # clear events on next screen flip + if trial_resp.status == STARTED: + # is it time to stop? (based on global clock, using actual start) + if tThisFlipGlobal > trial_resp.tStartRefresh + 2-frameTolerance: + # keep track of stop time/frame for later + trial_resp.tStop = t # not accounting for scr refresh + trial_resp.frameNStop = frameN # exact frame index + win.timeOnFlip(trial_resp, 'tStopRefresh') # time at next scr refresh + trial_resp.status = FINISHED + if trial_resp.status == STARTED and not waitOnFlip: + theseKeys = trial_resp.getKeys(keyList=['space'], waitRelease=False) + _trial_resp_allKeys.extend(theseKeys) + if len(_trial_resp_allKeys): + trial_resp.keys = _trial_resp_allKeys[0].name # just the first key pressed + trial_resp.rt = _trial_resp_allKeys[0].rt + # was this correct? + if (trial_resp.keys == str(correctResponse)) or (trial_resp.keys == correctResponse): + trial_resp.corr = 1 + else: + trial_resp.corr = 0 + + # 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 trialComponents: + 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"------- + for thisComponent in trialComponents: + if hasattr(thisComponent, "setAutoDraw"): + thisComponent.setAutoDraw(False) + thisExp.addData('tial_stimulus.stim', stimulus) + prevN = np.hstack((prevN,stimulus)) + prevN = prevN[-3:] + loop.addData('trial_stimulus.started', trial_stimulus.tStartRefresh) + loop.addData('trial_stimulus.stopped', trial_stimulus.tStopRefresh) + # check responses + if trial_resp.keys in ['', [], None]: # No response was made + trial_resp.keys = None + # was no response the correct answer?! + if str(correctResponse).lower() == 'none': + trial_resp.corr = 1; # correct non-response + else: + trial_resp.corr = 0; # failed to respond (incorrectly) + # store data for loop (TrialHandler) + loop.addData('trial_resp.keys',trial_resp.keys) + loop.addData('trial_resp.corr', trial_resp.corr) + if trial_resp.keys != None: # we had a response + loop.addData('trial_resp.rt', trial_resp.rt) + loop.addData('trial_resp.started', trial_resp.tStartRefresh) + loop.addData('trial_resp.stopped', trial_resp.tStopRefresh) + thisExp.nextEntry() + +# completed 150 repeats of 'loop' + +trialNone = 0; trialBack = 0; hit = 0; miss = 0; fa = 0 +for n, t in enumerate(thisExp.entries): + if t['trial_type'] == 'none': + trialNone += 1 + if not(t['trial_resp.corr']): fa += 1 + if t['trial_type'] == 'back': + trialBack += 1 + if t['trial_resp.corr']: hit += 1 + else: miss += 1 +logging.log(level=logging.DATA, msg='hit={:.2f}%,miss={:.2f}%,fa={:.2f}%'.format(hit/trialBack*100,miss/trialBack*100,fa/trialNone*100)) + + +# 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()