def test_quest(self): conditions = data.importConditions( os.path.join(fixturesPath, 'multiStairConds.xlsx')) stairs = data.MultiStairHandler(stairType='quest', conditions=conditions, method='random', nTrials=20, name='QuestStairs', autoLog=False) exp = data.ExperimentHandler(name='testExp', savePickle=True, saveWideText=True, dataFileName=os.path.join( self.temp_dir, 'multiQuestExperiment'), autoLog=False) rng = np.random.RandomState(seed=self.random_seed) exp.addLoop(stairs) for intensity, condition in stairs: # make data that will cause different stairs to finish different # times if rng.rand() > condition['startVal']: corr = 1 else: corr = 0 stairs.addData(corr) stairs.saveAsExcel(os.path.join(self.temp_dir, 'multiQuestOut')) # contains more info stairs.saveAsPickle(os.path.join(self.temp_dir, 'multiQuestOut')) exp.close()
def test_QuestPlus(self): import sys if not (sys.version_info.major == 3 and sys.version_info.minor >= 6): pytest.skip('QUEST+ only works on Python 3.6+') conditions = data.importConditions( os.path.join(fixturesPath, 'multiStairQuestPlus.xlsx')) stairs = data.MultiStairHandler(stairType='questplus', conditions=conditions, method='random', nTrials=20, name='QuestPlusStairs', autoLog=False) exp = data.ExperimentHandler(name='testExp', savePickle=True, saveWideText=True, dataFileName=os.path.join( self.temp_dir, 'multiQuestPlusExperiment'), autoLog=False) rng = np.random.RandomState(seed=self.random_seed) exp.addLoop(stairs) for intensity, condition in stairs: response = np.random.choice(['Correct', 'Incorrect']) stairs.addResponse(response) stairs.saveAsExcel(os.path.join(self.temp_dir, 'multiQuestPlusOut')) # contains more info stairs.saveAsPickle(os.path.join(self.temp_dir, 'multiQuestPlusOut')) exp.close()
def test_simple(self): conditions = data.importConditions( pjoin(fixturesPath, 'multiStairConds.xlsx')) stairs = data.MultiStairHandler(stairType='simple', conditions=conditions, method='random', nTrials=20, name='simpleStairs', autoLog=False) exp = data.ExperimentHandler(name='testExp', savePickle=True, saveWideText=True, dataFileName=pjoin( self.temp_dir, 'multiStairExperiment'), autoLog=False) exp.addLoop(stairs) for intensity, condition in stairs: #make data that will cause different stairs to finish different times if random() > condition['startVal']: corr = 1 else: corr = 0 stairs.addData(corr) stairs.saveAsExcel(pjoin(self.temp_dir, 'multiStairOut')) stairs.saveAsPickle(pjoin(self.temp_dir, 'multiStairOut')) #contains more info
def test_invalid_method(): conditions = data.importConditions(os.path.join(fixturesPath, 'multiStairConds.xlsx')) kwargs = dict(method='foobar', stairType='simple', conditions=conditions, nTrials=5) with pytest.raises(ValueError): data.MultiStairHandler(**kwargs)
def testQuest(self): conditions = data.importConditions( pjoin(TESTSDATA_PATH, 'multiStairConds.xlsx')) stairs = data.MultiStairHandler(stairType='quest', conditions=conditions, method='random', nTrials=5) for intensity,condition in stairs: #make data that will cause different stairs to finish different times if random()>condition['startVal']: corr=1 else:corr=0 stairs.addData(corr) stairs.saveAsExcel(pjoin(self.temp_dir, 'multiQuestOut')) stairs.saveAsPickle(pjoin(self.temp_dir, 'multiQuestOut'))#contains more info
def test_fullRandom(): conditions = data.importConditions(os.path.join(fixturesPath, 'multiStairConds.xlsx')) seed = 11 first_pass = ['medium', 'low', 'medium'] kwargs = dict(method='fullRandom', randomSeed=seed, stairType='simple', conditions=conditions, nTrials=5) multistairs = data.MultiStairHandler(**kwargs) for staircase_idx, staircase in enumerate(multistairs.thisPassRemaining): assert staircase.condition['label'] == first_pass[staircase_idx]
def test_different_seeds(): conditions = data.importConditions(os.path.join(fixturesPath, 'multiStairConds.xlsx')) seeds = [7, 11] first_pass = [['high', 'medium', 'low'], ['low', 'high', 'medium']] kwargs = dict(method='random', stairType='simple', conditions=conditions, nTrials=5) for seed_idx, seed in enumerate(seeds): multistairs = data.MultiStairHandler(randomSeed=seed, **kwargs) for staircase_idx, staircase in enumerate(multistairs.thisPassRemaining): assert staircase.condition['label'] == first_pass[seed_idx][staircase_idx]
def test_multiStairQuest(self): nTrials = 5 conditions = [{ 'label': 'stim_01', 'startVal': 0.3, 'startValSd': 0.8, 'minVal': 0, 'maxVal': 1, 'pThreshold': 0.5, 'gamma': 0.01, 'delta': 0.01, 'grain': 0.01 }, { 'label': 'stim_02', 'startVal': 0.3, 'startValSd': 0.8, 'minVal': 0, 'maxVal': 1, 'pThreshold': 0.5, 'gamma': 0.01, 'delta': 0.01, 'grain': 0.01 }, { 'label': 'stim_03', 'startVal': 0.3, 'startValSd': 0.8, 'minVal': 0, 'maxVal': 1, 'pThreshold': 0.5, 'gamma': 0.01, 'delta': 0.01, 'grain': 0.01 }] multiStairHandler = data.MultiStairHandler(stairType='quest', method='sequential', conditions=conditions, nTrials=nTrials) responsesToMake = makeBasicResponseCycles() expectedLevels = [ 0.3, 0.26922321258393306, 0.24699865727320078, 0.265989972738, 0.282954436975, ] expectedLevels = np.repeat(expectedLevels, len(conditions)) self.doTrials(multiStairHandler, responsesToMake, expectedLevels)
thisComponent.setAutoDraw(False) # check responses if endInstructions.keys in ['', [], None]: # No response was made endInstructions.keys = None thisExp.addData('endInstructions.keys', endInstructions.keys) if endInstructions.keys != None: # we had a response thisExp.addData('endInstructions.rt', endInstructions.rt) 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 trials etc conditions = data.importConditions('stairDefinitions.xlsx') trials = data.MultiStairHandler(stairType='QUEST', name='trials', nTrials=40, conditions=conditions, originPath=-1) thisExp.addLoop(trials) # add the loop to the experiment # initialise values for first condition level = trials._nextIntensity # initialise some vals # Yiming: I assume the level is contrast condition = trials.currentStaircase.condition for level, condition in trials: currentLoop = trials # abbreviate parameter names if possible (e.g. rgb=condition.rgb) for paramName in condition: exec(paramName + '= condition[paramName]') # ------Prepare to start Routine "trial"------- t = 0
G['S']['goNogoStim'] = [None] # Container=[None] # nextfliptasks=[] G['S']['tooSoonTime'] = tooSoonTime # set up the staircase handler according specifications in Aron & Poldrack, 2009 # ""Cortical and Subcortical Contributions to Stop Signal Response Inhibition: # Role of the Subthalamic Nucleus"" # conditions = [ {'label':'staircase1', 'startVal':100, 'stepSizes':50, 'nTrials':10, 'nUp':1, 'nDown':1, 'applyInitialRule':False, 'stepType':'lin'}, {'label':'staircase2', 'startVal':150, 'stepSizes':50, 'nTrials':10, 'nUp':1, 'nDown':1, 'applyInitialRule':False, 'stepType':'lin'}, {'label':'staircase3', 'startVal':200, 'stepSizes':50, 'nTrials':10, 'nUp':1, 'nDown':1, 'applyInitialRule':False, 'stepType':'lin'}, {'label':'staircase4', 'startVal':250, 'stepSizes':50, 'nTrials':10, 'nUp':1, 'nDown':1, 'applyInitialRule':False, 'stepType':'lin'} ] G['S']['myMultiStairs'] = data.MultiStairHandler(stairType='simple', method='random', conditions=conditions, nTrials=40) # Obtain the Go Nogo Timing Parameters # for stop-signal task: read in the critucal timings from one of my 500 # OPTIMAL GLM Design specifications: tmp_rand_number = random.randint(1,501) #with open('efl/param_%d.txt' % (tmp_rand_number )) as f: # matrix=[[float(s) for s in re.findall(r'-?\d+\.?\d*', line)] for line in f] with open('efl/tmpFile.txt','rb') as f: matrix=pickle.load(f) SSnumber, SSstopgo, ISIwaitTime, tmp1, tmp2, LeftOrRight = zip(*matrix) G['S']['SSnumber']=SSnumber
def startExperiment(): try: expInfo, stairInfo, outputfile, monitorInfo = setupExperiment() win = open_window(monitorInfo) show_instructions(win, "Press spacebar to start experiment, doing " + str(expInfo['TrainingTrials']) + " training trials") # We instanciate 4 staircases, we must decide the starting values for each of them # The speed value is the speedValue in the for loop of staircases and is measured in [cm/s] # The staircase will terminate when nTrials AND nReversals have been exceeded. # If stepSizes was an array and has been exceeded before nTrials is # exceeded then the staircase will continue to reverse # Convert the string of steps to a list of floats to feed to every # staircase stepSizes = [float(x) for x in stairInfo['StepSizes'].replace('[', '').replace(']', '').split(',')] # Convert the initial velocities of the staircases SpeedBiRight = [float(x) for x in stairInfo['SpeedBiRight'].replace('[', '').replace(']', '').split(',')] SpeedBiLeft = [float(x) for x in stairInfo['SpeedBiLeft'].replace('[', '').replace(']', '').split(',')] SpeedUniRight = [float(x) for x in stairInfo['SpeedUniRight'].replace('[', '').replace(']', '').split(',')] SpeedUniLeft = [float(x) for x in stairInfo['SpeedUniLeft'].replace('[', '').replace(']', '').split(',')] conditionsBilateral = [ {'label': 'Bilateral-Right_0', 'Side': 'Right', 'startVal': SpeedBiRight[0], 'method':'2AFC', 'stepType':stairInfo['StepType'], 'stepSizes':stepSizes, 'nUp':stairInfo['nUpBiRight'], 'nDown':stairInfo['nDownBiRight'], 'nTrials':stairInfo['MinTrials'], 'nReversals':stairInfo['MinReversals'], 'minVal':0 }, {'label': 'Bilateral-Left_0', 'Side': 'Left', 'startVal': SpeedBiLeft[0], 'method':'2AFC', 'stepType':stairInfo['StepType'], 'stepSizes':stepSizes, 'nUp':stairInfo['nUpBiLeft'], 'nDown':stairInfo['nDownBiLeft'], 'nTrials':stairInfo['MinTrials'], 'nReversals':stairInfo['MinReversals'], 'minVal':0 }, {'label': 'Bilateral-Right_1', 'Side': 'Right', 'startVal': SpeedBiRight[1], 'method':'2AFC', 'stepType':stairInfo['StepType'], 'stepSizes':stepSizes, 'nUp':stairInfo['nUpBiRight'], 'nDown':stairInfo['nDownBiRight'], 'nTrials':stairInfo['MinTrials'], 'nReversals':stairInfo['MinReversals'], 'minVal':0 }, {'label': 'Bilateral-Left_1', 'Side': 'Left', 'startVal': SpeedBiLeft[1], 'method':'2AFC', 'stepType':stairInfo['StepType'], 'stepSizes':stepSizes, 'nUp':stairInfo['nUpBiLeft'], 'nDown':stairInfo['nDownBiLeft'], 'nTrials':stairInfo['MinTrials'], 'nReversals':stairInfo['MinReversals'], 'minVal':0 } ] ########## CONDITIONS UNILATERAL ########## conditionsUnilateral = [ {'label': 'Unilateral-Right_0', 'Side': 'Right', 'startVal': SpeedUniRight[0], 'method':'2AFC', 'stepType':stairInfo['StepType'], 'stepSizes':stepSizes, 'nUp':stairInfo['nUpUniRight'], 'nDown':stairInfo['nDownUniRight'], 'nTrials':stairInfo['MinTrials'], 'nReversals':stairInfo['MinReversals'], 'minVal':0 }, {'label': 'Unilateral-Left_0', 'Side': 'Left', 'startVal': SpeedUniLeft[0], 'method':'2AFC', 'stepType':stairInfo['StepType'], 'stepSizes':stepSizes, 'nUp':stairInfo['nUpUniLeft'], 'nDown':stairInfo['nDownUniLeft'], 'nTrials':stairInfo['MinTrials'], 'nReversals':stairInfo['MinReversals'], 'minVal':0 }, {'label': 'Unilateral-Right_1', 'Side': 'Right', 'startVal': SpeedUniRight[1], 'method':'2AFC', 'stepType':stairInfo['StepType'], 'stepSizes':stepSizes, 'nUp':stairInfo['nUpUniRight'], 'nDown':stairInfo['nDownUniRight'], 'nTrials':stairInfo['MinTrials'], 'nReversals':stairInfo['MinReversals'], 'minVal':0 }, {'label': 'Unilateral-Left_1', 'Side': 'Left', 'startVal': SpeedUniLeft[1], 'method':'2AFC', 'stepType':stairInfo['StepType'], 'stepSizes':stepSizes, 'nUp':stairInfo['nUpUniLeft'], 'nDown':stairInfo['nDownUniLeft'], 'nTrials':stairInfo['MinTrials'], 'nReversals':stairInfo['MinReversals'], 'minVal':0 } ] conditions = None if expInfo['Block'] == 'Unilateral': conditions = conditionsUnilateral if expInfo['Block'] == 'Bilateral': conditions = conditionsBilateral if expInfo['Block'] == 'Uni+Bi': conditions = conditionsUnilateral + conditionsBilateral from psychopy import data stairs = data.MultiStairHandler( conditions=conditions, nTrials=2, method=stairInfo['Selection']) if (monitorInfo['RunSpeedTest']): from common.draw_test_square import draw_test_square draw_test_square(win) # Do some training trials with no variation in speed for i in range(0, int(expInfo['TrainingTrials'])): speedValue = 1.25 * (i + 1) trackingTrial(win, expInfo, speedValue, conditions[randrange(0, 2)]) show_instructions( win, "Finished training trials, press spacebar to begin") velocityConditions = {} velocityConditions['Left'] = [] velocityConditions['Right'] = [] # Start of the trial loop # We save the last speed used for every side of stimulus presentation nTrial = 0 import copy # Has to initialize the first trial speedValue, thisCondition = stairs.next() nCatchTrials = 0 nValidTrials = 0 dfrows = [] # Collects all trials included catch trials print thisCondition while True: # Using while True is the correct way to insert catch trials velocityConditions[thisCondition['Side']].append(speedValue) # print thisCondition['Side'], speedValue # Catch trial presentato al 25% di probabilita if np.random.rand() < 0.25 and nTrial > 2: nCatchTrials += 1 catchCondition = copy.deepcopy(thisCondition) if thisCondition['Side'] == 'Left': catchCondition['Side'] = 'Left' catchSpeedValue = velocityConditions['Right'][-1] else: catchCondition['Side'] = 'Right' catchSpeedValue = velocityConditions['Left'][-1] catchResp = trackingTrial(win, expInfo, catchSpeedValue, catchCondition, simulation=expInfo['SimulationMode'], isCatchTrial=0) #doesn't print message dfrows.append({'label':catchCondition['label'], 'Side':catchCondition['Side'], 'CatchCondition':1, 'Speed':speedValue, 'Response':int(not catchResp)}) else: thisResp = trackingTrial(win, expInfo, speedValue, thisCondition, simulation=expInfo['SimulationMode'],isCatchTrial=0) dfrows.append({'label':thisCondition['label'], 'Side':thisCondition['Side'], 'CatchCondition':0, 'Speed':speedValue, 'Response':int(not thisResp)}) if thisResp is not None: stairs.addResponse(int(not thisResp)) nValidTrials += 1 try: speedValue, thisCondition = stairs.next() except StopIteration: break else: raise # Increase the trial counter and save the temporary results nTrial = nTrial + 1 stairs.saveAsText(outputfile) stairs.saveAsPickle(outputfile) df = pd.DataFrame(dfrows) # this holds all trials in raw mode stairs.saveAsExcel(outputfile) experiment_finished(win) df.to_excel(outputfile+'_trials_summary.xlsx') except: # If the experiments stops before a default response is inserted stairs.addResponse(0) stairs.saveAsExcel(outputfile) df.to_excel(outputfile+'_trials_summary.xlsx') win.close() raise
def startExperiment(): try: expInfo, stairInfo, outputfile, monitorInfo = setupExperiment() win = open_window(monitorInfo) show_instructions( win, "Press spacebar to start experiment, doing " + str(expInfo['TrainingTrials']) + " training trials") # We instanciate 4 staircases, we must decide the starting values for each of them # The speed value is the speedValue in the for loop of staircases and is measured in [cm/s] # The staircase will terminate when nTrials AND nReversals have been exceeded. # If stepSizes was an array and has been exceeded before nTrials is # exceeded then the staircase will continue to reverse # Convert the string of steps to a list of floats to feed to every # staircase stepSizes = [ float(x) for x in stairInfo['StepSizes'].replace('[', '').replace( ']', '').split(',') ] # Convert the initial velocities of the staircases SpeedBiRight = [ float(x) for x in stairInfo['SpeedBiRight'].replace('[', '').replace( ']', '').split(',') ] SpeedBiLeft = [ float(x) for x in stairInfo['SpeedBiLeft'].replace('[', '').replace( ']', '').split(',') ] SpeedUniRight = [ float(x) for x in stairInfo['SpeedUniRight'].replace('[', '').replace( ']', '').split(',') ] SpeedUniLeft = [ float(x) for x in stairInfo['SpeedUniLeft'].replace('[', '').replace( ']', '').split(',') ] conditionsBilateral = [{ 'label': 'Bilateral-Right_0', 'Side': 'Right', 'startVal': SpeedBiRight[0], 'method': '2AFC', 'stepType': stairInfo['StepType'], 'stepSizes': stepSizes, 'nUp': stairInfo['nUpBiRight'], 'nDown': stairInfo['nDownBiRight'], 'nTrials': stairInfo['MinTrials'], 'nReversals': stairInfo['MinReversals'], 'minVal': 0 }, { 'label': 'Bilateral-Left_0', 'Side': 'Left', 'startVal': SpeedBiLeft[0], 'method': '2AFC', 'stepType': stairInfo['StepType'], 'stepSizes': stepSizes, 'nUp': stairInfo['nUpBiLeft'], 'nDown': stairInfo['nDownBiLeft'], 'nTrials': stairInfo['MinTrials'], 'nReversals': stairInfo['MinReversals'], 'minVal': 0 }, { 'label': 'Bilateral-Right_1', 'Side': 'Right', 'startVal': SpeedBiRight[1], 'method': '2AFC', 'stepType': stairInfo['StepType'], 'stepSizes': stepSizes, 'nUp': stairInfo['nUpBiRight'], 'nDown': stairInfo['nDownBiRight'], 'nTrials': stairInfo['MinTrials'], 'nReversals': stairInfo['MinReversals'], 'minVal': 0 }, { 'label': 'Bilateral-Left_1', 'Side': 'Left', 'startVal': SpeedBiLeft[1], 'method': '2AFC', 'stepType': stairInfo['StepType'], 'stepSizes': stepSizes, 'nUp': stairInfo['nUpBiLeft'], 'nDown': stairInfo['nDownBiLeft'], 'nTrials': stairInfo['MinTrials'], 'nReversals': stairInfo['MinReversals'], 'minVal': 0 }] ########## CONDITIONS UNILATERAL ########## conditionsUnilateral = [{ 'label': 'Unilateral-Right_0', 'Side': 'Right', 'startVal': SpeedUniRight[0], 'method': '2AFC', 'stepType': stairInfo['StepType'], 'stepSizes': stepSizes, 'nUp': stairInfo['nUpUniRight'], 'nDown': stairInfo['nDownUniRight'], 'nTrials': stairInfo['MinTrials'], 'nReversals': stairInfo['MinReversals'], 'minVal': 0 }, { 'label': 'Unilateral-Left_0', 'Side': 'Left', 'startVal': SpeedUniLeft[0], 'method': '2AFC', 'stepType': stairInfo['StepType'], 'stepSizes': stepSizes, 'nUp': stairInfo['nUpUniLeft'], 'nDown': stairInfo['nDownUniLeft'], 'nTrials': stairInfo['MinTrials'], 'nReversals': stairInfo['MinReversals'], 'minVal': 0 }, { 'label': 'Unilateral-Right_1', 'Side': 'Right', 'startVal': SpeedUniRight[1], 'method': '2AFC', 'stepType': stairInfo['StepType'], 'stepSizes': stepSizes, 'nUp': stairInfo['nUpUniRight'], 'nDown': stairInfo['nDownUniRight'], 'nTrials': stairInfo['MinTrials'], 'nReversals': stairInfo['MinReversals'], 'minVal': 0 }, { 'label': 'Unilateral-Left_1', 'Side': 'Left', 'startVal': SpeedUniLeft[1], 'method': '2AFC', 'stepType': stairInfo['StepType'], 'stepSizes': stepSizes, 'nUp': stairInfo['nUpUniLeft'], 'nDown': stairInfo['nDownUniLeft'], 'nTrials': stairInfo['MinTrials'], 'nReversals': stairInfo['MinReversals'], 'minVal': 0 }] conditions = None if expInfo['Block'] == 'Unilateral': conditions = conditionsUnilateral if expInfo['Block'] == 'Bilateral': conditions = conditionsBilateral if expInfo['Block'] == 'Uni+Bi': conditions = conditionsUnilateral + conditionsBilateral from psychopy import data stairs = data.MultiStairHandler(conditions=conditions, nTrials=2, method=stairInfo['Selection']) if (monitorInfo['RunSpeedTest']): from common.draw_test_square import draw_test_square draw_test_square(win) # Do some training trials with no variation in speed for i in range(0, int(expInfo['TrainingTrials'])): speedValue = 1.25 * (i + 1) trackingTrial(win, expInfo, speedValue, conditions[randrange(0, 2)]) show_instructions(win, "Finished training trials, press spacebar to begin") velocityConditions = {} velocityConditions['Left'] = [] velocityConditions['Right'] = [] # Start of the trial loop # We save the last speed used for every side of stimulus presentation nTrial = 0 import copy for speedValue, thisCondition in stairs: velocityConditions[thisCondition['Side']].append(speedValue) # print thisCondition['Side'], speedValue # Catch trial presentato al 25% di probabilita if np.random.rand() < 0.25 and nTrial > 2: catchCondition = copy.deepcopy(thisCondition) if thisCondition['Side'] == 'Left': catchCondition['Side'] = 'Left' # print "Using speed value", velocityConditions['Right'][-1], " instead of ", speedValue # get the last speed used element speedValue = velocityConditions['Right'][-1] else: catchCondition['Side'] = 'Right' # print "Using speed value", velocityConditions['Left'][-1], " instead of ", speedValue # get the last speed used element speedValue = velocityConditions['Left'][-1] # print "0.25 catch trial, showing ", catchCondition['Side'], " # instead of ", thisCondition['Side'] trackingTrial(win, expInfo, speedValue, catchCondition, expInfo['SimulationMode']) # Catch trial lanciato quando una delle due staircase finita # e che randomizza il lato di presentazione elif np.random.rand() < 0.5: catchCondition = copy.deepcopy(thisCondition) if thisCondition['Side'] == 'Left': catchCondition['Side'] = 'Right' else: catchCondition['Side'] = 'Left' # print "0.5 catch trial, showing ", catchCondition['Side'], " # instead of ", thisCondition['Side'] trackingTrial(win, expInfo, speedValue, catchCondition, expInfo['SimulationMode']) else: thisResp = trackingTrial(win, expInfo, speedValue, thisCondition, expInfo['SimulationMode']) if thisResp is not None: # print speedValue, thisCondition, nTrial stairs.addData(not thisResp) else: raise nTrial = nTrial + 1 stairs.saveAsText(outputfile) # Finally save the results of the experiment stairs.saveAsText(outputfile) # stairs.saveAsExcel(outputfile) stairs.saveAsPickle(outputfile) experiment_finished(win) except: stairs.saveAsText(outputfile) # stairs.saveAsExcel(outputfile) stairs.saveAsPickle(outputfile) win.close() raise
'TF': 4 }, { 'label': 'practice', 'startVal': 1, 'startValSd': 0.1, 'pThreshold': .82, 'max_contr': .95, 'minVal': 0, 'maxVal': 1, 'stim_diam_degs': 3.5, 'SF': 10, 'TF': 4 }] loop_practice = data.MultiStairHandler(stairType='QUEST', name='loop_practice', nTrials=2, conditions=conditions, originPath=-1) thisExp.addLoop(loop_practice) # add the loop to the experiment # initialise values for first condition level = loop_practice._nextIntensity # initialise some vals condition = loop_practice.currentStaircase.condition trial_n = 0 for level, condition in loop_practice: trial_n += 1 currentLoop = loop_practice # abbreviate parameter names if possible (e.g. rgb=condition.rgb) for paramName in condition: exec(paramName + '= condition[paramName]')
def experiment_module(p, win): ######################## #### Instructions #### ######################## update_rule_names(p) if p.step_num == 0: for txt in p.instruct_text['intro']: message = visual.TextStim(win, height=p.text_height, text=dedent(txt)) message.draw() win.flip() keys = event.waitKeys(keyList=['space']) else: for txt in p.instruct_text['break_txt']: txt = txt.replace('COMPLETED', str(p.step_num)) txt = txt.replace('TOTAL', str(p.num_blocks)) message = visual.TextStim(win, text=dedent(txt)) message.draw() win.flip() keys = event.waitKeys(keyList=['space']) ######################## #### Visual Objects #### ######################## #colors p.dot_colors = p.lch_to_rgb(p) #dotstims init dotstims, cue = init_stims(p, win) #get fixation cross and feedback info fixation, feedback_text = get_basic_objects(win, p) ############################ #### Set up Staircasing #### ############################ conditions = [ # {'label':'easy', 'startVal': 0.6, 'stepSizes' : .01, 'stepType': 'lin', 'minVal': .51, 'maxVal': 1, 'nUp': 1, 'nDown': 5, 'nReversals': 15}, { 'label': 'hard', 'startVal': p.coherence[p.rule], 'stepSizes': .01, 'stepType': 'lin', 'minVal': p.min_value[p.rule], 'maxVal': 1, 'nUp': 1, 'nDown': 1, 'nReversals': p.n_reversals }, ] stairs = data.MultiStairHandler(conditions=conditions, nTrials=10) ######################## #### Run Experiment #### ######################## #start timer clock = core.Clock() #draw fixation draw_stim(win, fixation, 1 * win.framerate) p.resp = [] p.rt = [] p.choice_times = [] p.feedback_times = [] p.correct = [] p.incorrect = [] #only for switch p.bank = 0 win.recordFrameIntervals = True num_correct = 0 num_errors = 0 other_dimensions = [x for x in ['color', 'shape', 'motion'] if x != p.rule] for intensity, staircase in stairs: ############################ ###dot stim/choice period### ############################ p.coherence[p.rule] = intensity #initialize dots dotstims, cue = init_stims(p, win) #set up response key and rt recording rt_clock = clock.getTime() p.choice_times.append(rt_clock) correct = True #color, motion and shape for this trial trial_features = {} for other_dim in other_dimensions: trial_features[other_dim] = np.random.choice( p.rule_features[other_dim]) #get motion rule and correct response act_resp = list(zip(p.rule_features[p.rule], ['1', '2'])) np.random.shuffle(act_resp) trial_features[p.rule], correct_resp = act_resp[0] #present trial keys = present_dots_record_keypress(p, win, dotstims, cue, clock, trial_features['color'], trial_features['shape'], trial_features['motion'], p.rule) #record keypress if not keys: resp = np.NaN p.resp.append(resp) p.rt.append(np.NaN) else: resp = keys[0][0] p.resp.append(resp) p.rt.append(keys[0][1] - rt_clock) ##################### ###feedback period### ##################### #show feedback nframes = p.feedback_dur * win.framerate if np.isnan(p.rt[-1]): correct = False draw_error(win, nframes, p.too_slow_color) elif str(resp) != str(correct_resp): correct = False draw_error(win, nframes, p.fixation_color) if not correct: num_errors += 1 p.correct.append(correct) ##update staircase handler stairs.addResponse(int(correct)) stairs.addOtherData('rt', p.rt[-1]) stairs.addOtherData('color', trial_features['color']) stairs.addOtherData('shape', trial_features['shape']) stairs.addOtherData('motion', trial_features['motion']) ################ ###iti period### ################ draw_stim(win, fixation, p.iti * win.framerate) print_reversal = min(p.n_reversals, 6) print('mean reversal', p.rule, np.mean(stairs.staircases[0].reversalIntensities[-print_reversal:])) print('std reversal', p.rule, np.std(stairs.staircases[0].reversalIntensities[-print_reversal:])) print('mean_rt', np.nanmean(p.rt)) print('\nOverall, %i frames were dropped.\n' % win.nDroppedFrames) #save data out_f = op.join( p.outdir, p.sub + '_psychophys_run' + str(p.run) + '_' + p.rule + '.pkl') while op.exists(out_f): out_f = out_f[:-4] + '+' + '.pkl' with open(out_f, 'wb') as output: pickle.dump(p, output, pickle.HIGHEST_PROTOCOL) # save data as multiple formats filename = op.join(p.outdir, p.sub + '_run' + str(p.run) + '_staircase_' + p.rule) stairs.saveAsExcel(filename) # easy to browse stairs.saveAsPickle(filename)
if hasattr(thisComponent, "setAutoDraw"): thisComponent.setAutoDraw(False) # check responses if key_resp_3.keys in ['', [], None]: # No response was made key_resp_3.keys = None # store data for thisExp (ExperimentHandler) thisExp.addData('key_resp_3.keys', key_resp_3.keys) if key_resp_3.keys != None: # we had a response thisExp.addData('key_resp_3.rt', key_resp_3.rt) thisExp.nextEntry() # set up handler to look after randomisation of trials etc conditions = data.importConditions('staircaseflo_2.xlsx') trials_2 = data.MultiStairHandler(stairType='simple', name='trials_2', nTrials=5, conditions=conditions, originPath=None) thisExp.addLoop(trials_2) # add the loop to the experiment # initialise values for first condition level = trials_2._nextIntensity # initialise some vals condition = trials_2.currentStaircase.condition for level, condition in trials_2: currentLoop = trials_2 # abbreviate parameter names if possible (e.g. rgb=condition.rgb) for paramName in condition.keys(): exec(paramName + '= condition[paramName]') #------Prepare to start Routine "ISI_2"------- t = 0
def run_quest_procedure(self, n_trials=10, start=20, start_sd=10, maxvalue=40, beta=3.5, delta=0.01, gamma=0.01, grain=0.01): print("RUNNING QUEST\n" \ "-------------\n") startVal=start startValSd=start_sd pThreshold=0.75 nTrials=n_trials minVal=0 maxVal=maxvalue beta=beta delta=delta gamma=gamma grain=grain method='quantile' conditions = { 'startVal': startVal, 'startValSd': startValSd, 'minVal': 0, 'maxVal': maxVal, 'pThreshold': 0.75, 'gamma': gamma, 'delta': delta, 'grain': grain, 'method': method, 'nTrials': n_trials, } self.conditions = [ dict({'label': 'staircase_1'}.items() + conditions.items()), dict({'label': 'staircase_2'}.items() + conditions.items()), ] self.quest = data.MultiStairHandler(stairType='quest', method='random', conditions=self.conditions) t1 = self.quest.staircases[0].mean() t2 = self.quest.staircases[1].mean() sd1 = self.quest.staircases[0].sd() sd2 = self.quest.staircases[1].sd() beta1 = contrib.quest.QuestObject.beta(self.quest.staircases[0]) beta1 = contrib.quest.QuestObject.beta(self.quest.staircases[1]) t_mean = (t1 + t2) / 2 beta_mean = (beta1 + beta2) / 2 fit = data.FitWeibull(t_mean, beta_mean, sems=1/n_trials) for n, stim_level in enumerate(self.quest): print("Calibration trial {0} / {1}\n" \ "Stimulation level = {2}\n" \ "-----------------------------".format(n + 1, n_trials, stim_level)) response = None # Repeat if subject doesn't respond while response == None: trial = ConditioningTrial(self, n, True, max_voltage=stim_level) response = trial.run() # Add the response if response: print("Stimulation detected") else: print("Stimulation not detected") if n >= self.config['quest_settings']['n_ignored']: self.quest.addResponse(int(response)) p0 = fit.inverse(0) p25 = fit.inverse(.25) p50 = fit.inverse(.50) p75 = fit.inverse(.75) print("1% detection probability level = {0}\n" "25% detection probability level = {1}\n" "50% detection probability level = {2}\n" "75% detection probability level = {3}\n".format(self.quest.quantile(0.01), self.quest.quantile(.25), self.quest.quantile(.5), self.quest.quantile(.75))) return p0, p25, p50, p75
def startExperiment(): """ Begin the experiment 1. Set experimental parameters 2. Open the window and take measurements of the refresh rate 3. Start some training trials if needed 4. Start the interleaved staircase experiment 5. Save the result """ try: expInfo, stairInfo, outputfile, monitorInfo = setupExperiment() except: raise try: win = open_window(monitorInfo) show_instructions( win, "Press spacebar to start experiment, doing " + str(expInfo['TrainingTrials']) + " training trials") # Convert the string of steps to a list of floats to feed to every # staircase stepSizes = [ float(x) for x in stairInfo['StepSizes'].replace('[', '').replace( ']', '').split(',') ] expConditions = [{ 'label': 'Right', 'startVal': stairInfo['FlickerFreqRight'], 'method': '2AFC', 'stepType': stairInfo['StepType'], 'stepSizes': stepSizes, 'nUp': stairInfo['nUpRight'], 'nDown': stairInfo['nDownRight'], 'nTrials': stairInfo['MinTrials'], 'nReversals': stairInfo['MinReversals'], 'minVal': min(stepSizes) }, { 'label': 'Left', 'startVal': stairInfo['FlickerFreqLeft'], 'method': '2AFC', 'stepType': stairInfo['StepType'], 'stepSizes': stepSizes, 'nUp': stairInfo['nUpLeft'], 'nDown': stairInfo['nDownLeft'], 'nTrials': stairInfo['MinTrials'], 'nReversals': stairInfo['MinReversals'], 'minVal': min(stepSizes) }] from psychopy import data stairs = data.MultiStairHandler(conditions=expConditions, nTrials=1, method=stairInfo['Selection']) if (monitorInfo['RunSpeedTest']): from common.draw_test_square import draw_test_square draw_test_square(win) # Do some training trials with no variation in speed for i in range(0, int(expInfo['TrainingTrials'])): flickerTrial(win, expInfo, flickerFreq=1, side='Left', useOddBall=True) show_instructions(win, "Finished training trials, press spacebar to begin") for flickerFreq, thisCondition in stairs: thisResp = flickerTrial(win, expInfo, flickerFreq, side=thisCondition['label'], useOddBall=True) if thisResp is not None: stairs.addData(not thisResp) stairs.saveAsText(outputfile) stairs.saveAsText(outputfile) stairs.saveAsPickle(outputfile) stairs.saveAsExcel(outputfile) experiment_finished(win) except: stairs.saveAsText(outputfile) stairs.saveAsPickle(outputfile) stairs.saveAsExcel(outputfile) win.close() raise
def test_multiStairQuestSequentialIdenticalConditions(self): """ Identical parameters passed to both QuestHandlers, and identical simulated responses provided. We use the exact same settings as in TestQuestHandler.test_QuestHandler(). """ # These are the parameters for the QuestHandlers. nTrials = 10 # This is going to yield 10 trials per staircase. startVal, minVal, maxVal = 50, 0, 100 range = maxVal - minVal startValSd = 50 grain = 0.01 pThreshold = 0.82 beta, gamma, delta = 3.5, 0.5, 0.01 stopInterval = None method = 'quantile' # These parameters are shared between the two staircases. The only # thing we will need to add is individual labels, which will # happen below. conditions = { 'startVal': startVal, 'startValSd': startValSd, 'minVal': minVal, 'maxVal': maxVal, 'range': range, 'pThreshold': pThreshold, 'gamma': gamma, 'delta': delta, 'grain': grain, 'method': method, 'nTrials': nTrials, 'stopInterval': stopInterval } self.conditions = [ dict( list({'label': 'staircase_0'}.items()) + list(conditions.items())), dict( list({'label': 'staircase_1'}.items()) + list(conditions.items())), ] self.stairs = data.MultiStairHandler(stairType='quest', method='linear', conditions=self.conditions) # Responses for only one staircase. We will duplicate this below. responses = makeBasicResponseCycles(cycles=3, nCorrect=2, nIncorrect=2, length=10) self.responses = np.repeat(responses, 2) # Same procedure as with the responses: This lists the responses # for one of the staircases, and will be duplicated below. intensities = [ 50, 45.139710407074872, 37.291086503930742, 58.297413127139947, 80.182967131096547, 75.295251409003527, 71.57627192423783, 79.881680484036906, 90.712313302815517, 88.265808957695796 ] self.intensities = np.repeat(intensities, 2) mean = 86.0772169427 mode = 80.11 quantile = 86.3849031085 self.simulate() self.checkSimulationResults() assert np.allclose(self.stairs.staircases[0].mean(), mean) assert np.allclose(self.stairs.staircases[0].mode(), mode) assert np.allclose(self.stairs.staircases[0].quantile(), quantile) assert (self.stairs.staircases[0].intensities == self.stairs.staircases[1].intensities) assert ( self.stairs.staircases[0].data == self.stairs.staircases[1].data)
'maxVal': 1, 'nUp': 1, 'nDown': 2, 'stepSizes': steps }, { 'label': 'high', 'startVal': 0.65, 'stepType': 'lin', 'minVal': 0.01, 'maxVal': 1, 'nUp': 1, 'nDown': 2, 'stepSizes': steps }] stairs = data.MultiStairHandler(conditions=conditions, nTrials=120) instruction.draw() win.flip() event.waitKeys(keyList=['space']) instruction.setText(instr2) instruction.draw() win.flip() event.waitKeys(keyList=['space']) trial = 0 for thisIncrement in stairs: #will step through the staircase trial += 1 if trial == 121:
def run_session(self): path = os.path.join(self.res_dir, self.subject) if not os.path.exists(path): os.makedirs(path) # welcome msg = visual.TextStim(self.win, 'Welcome!' + '\n' + ' Press any key to start this session :)', color='black', units='deg', pos=(0, 0), height=0.8) msg.draw() self.win.mouseVisible = False self.win.flip() event.waitKeys() # read staircase parameters conditions = [ dict({'stimulus': key}, **value) for key, value in self.param.items() if key.startswith('stimulus') ] if conditions[0]['stairType'] == 'simple': stairs = data.MultiStairHandler(stairType='simple', conditions=conditions, nTrials=self.trial_nmb, method='sequential') elif conditions[0]['stairType'] == 'quest': stairs = [] for cond in conditions: if self.priors_file_path: prior_file = self.priors_file_path + cond[ 'label'] + '.psydat' print(prior_file) prior_handler = misc.fromFile(prior_file) else: prior_handler = None cur_handler = data.QuestHandler(cond['startVal'], cond['startValSd'], pThreshold=cond['pThreshold'], nTrials=self.trial_nmb, minVal=cond['min_val'], maxVal=cond['max_val'], staircase=prior_handler, extraInfo=cond) stairs.append(cur_handler) elif conditions[0]['stairType'] == 'psi': stairs = [] for cond in conditions: if self.priors_file_path: prior_file = self.priors_file_path + cond['label'] + '.npy' else: prior_file = None print(prior_file) cur_handler = data.PsiHandler(nTrials=self.trial_nmb, intensRange=[1, 10], alphaRange=[1, 10], betaRange=[0.01, 10], intensPrecision=0.1, alphaPrecision=0.1, betaPrecision=0.01, delta=0.01, extraInfo=cond, prior=prior_file, fromFile=(prior_file is not None)) stairs.append(cur_handler) # write configuration files xpp = config_tools.WriteXpp(self.subject, self.idx) xpp_file = xpp.head(self.cfg_file, self.par_file) config_tools.write_xrl(self.subject, cfg_file=self.cfg_file, par_file=self.par_file, xpp_file=xpp_file) xlsname = path + '/' + self.idx + self.param[ 'noise_condition'] + '.xlsx' """ running staircase """ if isinstance(stairs, data.MultiStairHandler): # start running the staircase using the MultiStairHandler for the up-down method count = 0 for rot, cond in stairs: count += 1 judge, thiskey, trial_time = self.run_trial(rot, cond, count) # check whether the theta is valid - if not, the rotation given by staircase should be corrected by # realizable values valid_theta = np.round(np.load(self.hue_list), decimals=1) disp_standard = self.take_closest( valid_theta, cond['standard']) # theta actually displayed stair_test = cond['standard'] + stairs._nextIntensity * (-1)**( cond['label'].endswith('m')) # theta for staircase if stair_test < 0: stair_test += 360 disp_test = self.take_closest(valid_theta, stair_test) disp_intensity = abs(disp_test - disp_standard) if disp_intensity > 300: disp_intensity = 360 - (disp_test + disp_standard) stairs.addResponse(judge, disp_intensity) xpp.task(count, cond, rot, float(disp_intensity), judge, trial_time) event.waitKeys(keyList=[ thiskey ]) # press the response key again to start the next trial config_tools.write_xrl(self.subject, xls_file=xlsname) stairs.saveAsExcel(xlsname) # save results psydat_file_path = os.path.join( path, "psydat", self.idx + self.param['condition'] + '.psydat') # save the handler into a psydat-file misc.toFile(psydat_file_path, stairs) elif isinstance(stairs, list): # start running the staircase using custom interleaving stairs for the quest and psi methods count = 0 rot_all = [] rot_all_disp = [] judge_all = [] estimates = {s.extraInfo['label']: [] for s in stairs} for trial_n in range(self.trial_nmb): for handler_idx, cur_handler in enumerate(stairs): count += 1 rot = next(cur_handler) if len(rot_all) <= handler_idx: rot_all.append([]) rot_all[handler_idx].append(rot) cond = cur_handler.extraInfo judge, thiskey, trial_time = self.run_trial( rot, cond, count) if len(judge_all) <= handler_idx: judge_all.append([]) judge_all[handler_idx].append(judge) # cur_handler.addResponse(judge) # to the next trial valid_theta = np.round(np.load(self.hue_list), decimals=1) disp_standard = self.take_closest( valid_theta, cond['standard']) # theta actually displayed stair_test = cond[ 'standard'] + cur_handler._nextIntensity * (-1)**( cond['label'].endswith('m')) # theta for staircase if stair_test < 0: stair_test += 360 disp_test = self.take_closest(valid_theta, stair_test) disp_intensity = abs(disp_test - disp_standard) if disp_intensity > 300: disp_intensity = 360 - (disp_test + disp_standard) cur_handler.addResponse(judge, disp_intensity) if len(rot_all_disp ) <= handler_idx: # add displayed intensities rot_all_disp.append([]) rot_all_disp[handler_idx].append(disp_intensity) print('stair test: ' + str(stair_test) + ', ' + 'disp_test:' + str(disp_test)) if isinstance(cur_handler, data.PsiHandler): estimates[cur_handler.extraInfo['label']].append([ cur_handler.estimateLambda()[0], # location cur_handler.estimateLambda768()[1], # slope cur_handler.estimateThreshold(0.75) ]) elif isinstance(cur_handler, data.QuestHandler): estimates[cur_handler.extraInfo['label']].append([ cur_handler.mean(), cur_handler.mode(), cur_handler.quantile(0.5) ]) xpp.task(count, cond, rot, disp_intensity, judge, trial_time) event.waitKeys(keyList=[ thiskey ]) # press the response key again to start the next trial config_tools.write_xrl(self.subject, xls_file=xlsname) # save results in xls-file workbook = xlsxwriter.Workbook(xlsname) for handler_idx, cur_handler in enumerate(stairs): worksheet = workbook.add_worksheet( cur_handler.extraInfo['label']) worksheet.write('A1', 'Reversal Intensities') worksheet.write('B1', 'Reversal Indices') worksheet.write('C1', 'All Intensities') worksheet.write('D1', 'All Responses') for i in range(len(rot_all[handler_idx])): # worksheet.write('C' + str(i + 2), rot_all[handler_idx][i]) worksheet.write('C' + str(i + 2), rot_all_disp[handler_idx][i]) worksheet.write('D' + str(i + 2), judge_all[handler_idx][i]) workbook.close() # print resulting parameters and estimates for each step res_file_path = os.path.join(path, self.idx + '_estimates.csv') res_writer = csv.writer(open(res_file_path, 'w')) for res_stim, res_vals in estimates.items(): for res_val_id, res_val in enumerate(res_vals): res_writer.writerow([ res_stim, res_val_id, res_val[0], res_val[1], res_val[2] ]) # save each handler into a psydat-file and save posterior into a numpy-file for cur_handler in stairs: file_name = os.path.join( path, self.idx + self.param['noise_condition'] + cur_handler.extraInfo['label']) misc.toFile(file_name + '.psydat', cur_handler) if isinstance(cur_handler, data.PsiHandler): cur_handler.savePosterior(file_name + '.npy')
# refresh the screen if continueRoutine: # don't flip if this routine is over or we'll get a blank screen win.flip() # -------Ending Routine "instruct"------- for thisComponent in instructComponents: if hasattr(thisComponent, "setAutoDraw"): thisComponent.setAutoDraw(False) # the Routine "instruct" was not non-slip safe, so reset the non-slip timer routineTimer.reset() # set up handler to look after randomisation of trials etc conditions = data.importConditions('2Nb-stimuls-5.xlsx') trials = data.MultiStairHandler(stairType='simple', name='trials', nTrials=1, conditions=conditions, originPath=-1) thisExp.addLoop(trials) # add the loop to the experiment # initialise values for first condition level = trials._nextIntensity # initialise some vals condition = trials.currentStaircase.condition for level, condition in trials: currentLoop = trials # abbreviate parameter names if possible (e.g. rgb=condition.rgb) for paramName in condition: exec(paramName + '= condition[paramName]') # ------Prepare to start Routine "trial"------- t = 0
def startExperiment(): try: expInfo, stairInfo, outputfile, monitorInfo = setupExperiment() win = open_window(monitorInfo, measureFPS=False) win.measuredFPS = 59.95 show_instructions( win, "Press spacebar to start experiment, doing " + str(expInfo['TrainingTrials']) + " training trials") # Convert the string of steps to a list of floats to feed to every # staircase stepSizes = [ float(x) for x in stairInfo['StepSizes'].replace('[', '').replace( ']', '').split(',') ] expConditions = [{ 'label': 'Right', 'startVal': stairInfo['ContrastRight'], 'method': '2AFC', 'stepType': stairInfo['StepType'], 'stepSizes': stepSizes, 'nUp': stairInfo['nUpRight'], 'nDown': stairInfo['nDownRight'], 'nTrials': stairInfo['MinTrials'], 'nReversals': stairInfo['MinReversals'], 'minVal': min(stepSizes), 'maxVal': 1 }, { 'label': 'Left', 'startVal': stairInfo['ContrastLeft'], 'method': '2AFC', 'stepType': stairInfo['StepType'], 'stepSizes': stepSizes, 'nUp': stairInfo['nUpLeft'], 'nDown': stairInfo['nDownLeft'], 'nTrials': stairInfo['MinTrials'], 'nReversals': stairInfo['MinReversals'], 'minVal': min(stepSizes), 'maxVal': 1 }] print "Minimum value for staircase = ", min(stepSizes) from psychopy import data stairs = data.MultiStairHandler(conditions=expConditions, nTrials=1, method=stairInfo['Selection']) if (monitorInfo['RunSpeedTest']): from common.draw_test_square import draw_test_square draw_test_square(win) # Do some training trials with no variation in speed for i in np.linspace(0.0, 2.0, expInfo['TrainingTrials']): contrastTrial(win, expInfo, contrastValue=i, side='Left', useSameStimuli=randrange(0, 2)) show_instructions(win, "Finished training trials, press spacebar to begin") for contrast, thisCondition in stairs: sameStimuli = randrange(0, 100) < 25 # To present 4 equal stimuli thisResp = contrastTrial(win, expInfo, contrastValue=contrast, side=thisCondition['label'], useSameStimuli=sameStimuli) if thisResp is not None: stairs.addData(not thisResp) else: print "skipped" # save data as multiple formats for every trial stairs.saveAsText(outputfile) stairs.saveAsText(outputfile) stairs.saveAsPickle(outputfile) stairs.saveAsExcel(outputfile) experiment_finished(win) except: win.close() raise
def run_session(self): path = os.path.join(self.res_dir, self.subject) if not os.path.exists(path): os.makedirs(path) psydat_path = os.path.join(path, 'psydat') if not os.path.exists(psydat_path): os.makedirs(psydat_path) # welcome msg = visual.TextStim(self.win, 'Welcome!' + '\n' + ' Press any key to start this session :)', color='black', units='deg', pos=(0, 0), height=0.8) msg.draw() self.win.mouseVisible = False self.win.flip() event.waitKeys() # read staircase parameters conditions = [ dict({'stimulus': key}, **value) for key, value in self.param.items() if key.startswith('stimulus') ] if conditions[0]['stairType'] == 'simple': stairs = data.MultiStairHandler(stairType='simple', conditions=conditions, nTrials=self.trial_nmb, method='sequential') elif conditions[0]['stairType'] == 'quest': stairs = [] for cond in conditions: if self.priors_file_path: prior_file = self.priors_file_path + cond[ 'label'] + '.psydat' print(prior_file) prior_handler = misc.fromFile(prior_file) else: prior_handler = None cur_handler = data.QuestHandler(cond['startVal'], cond['startValSd'], pThreshold=cond['pThreshold'], nTrials=self.trial_nmb, minVal=cond['min_val'], maxVal=cond['max_val'], staircase=prior_handler, extraInfo=cond, grain=0.02) stairs.append(cur_handler) elif conditions[0]['stairType'] == 'psi': stairs = [] for cond in conditions: if self.priors_file_path: prior_file = self.priors_file_path + cond['label'] + '.npy' else: prior_file = None print(prior_file) cur_handler = data.PsiHandler(nTrials=self.trial_nmb, intensRange=[1, 10], alphaRange=[1, 10], betaRange=[0.01, 10], intensPrecision=0.1, alphaPrecision=0.1, betaPrecision=0.01, delta=0.01, extraInfo=cond, prior=prior_file, fromFile=(prior_file is not None)) stairs.append(cur_handler) # write configuration files xpp = config_tools.WriteXpp(self.subject, self.idx) xpp_file = xpp.head(self.cfg_file, self.par_file) config_tools.write_xrl(self.subject, cfg_file=self.cfg_file, par_file=self.par_file, xpp_file=xpp_file) xlsname = path + '/' + self.idx + self.param[ 'noise_condition'] + '.xlsx' """ running staircase """ if isinstance(stairs, data.MultiStairHandler): # start running the staircase using the MultiStairHandler for the up-down method count = 0 for rot, cond in stairs: count += 1 direction = (-1)**(cond['label'].endswith('m') ) # direction as -1 if for minus stim rot = rot * direction # rotation for this trial judge, react_time, trial_time_start = self.run_trial( rot, cond, cond['std'], count) # check whether the theta is valid - if not, the rotation given by staircase should be corrected by # realizable values valid_theta = np.round(np.load(self.hue_list), decimals=1) disp_standard = self.take_closest( valid_theta, cond['standard']) # theta actually displayed stair_test = cond[ 'standard'] + stairs._nextIntensity * direction if stair_test < 0: stair_test += 360 disp_test = self.take_closest(valid_theta, stair_test) disp_intensity = disp_test - disp_standard if disp_intensity > 300: disp_intensity = (disp_test + disp_standard) - 360 stairs.addResponse(judge, abs(disp_intensity)) xpp.task(count, cond, rot, float(disp_intensity), judge, react_time, trial_time_start) if 'escape' in event.waitKeys(): config_tools.write_xrl(self.subject, break_info='userbreak') core.quit() config_tools.write_xrl(self.subject, xls_file=xlsname) stairs.saveAsExcel(xlsname) # save results misc.toFile( os.path.join( psydat_path, self.idx + self.param['noise_condition'] + '.psydat'), stairs) elif isinstance(stairs, list): # start running the staircase using custom interleaving stairs for the quest and psi methods count = 0 rot_all = [] rot_all_disp = [] judge_all = [] estimates = {s.extraInfo['label']: [] for s in stairs} for trial_n in range(self.trial_nmb): for handler_idx, cur_handler in enumerate(stairs): count += 1 direction = (-1)**( cur_handler.extraInfo['label'].endswith('m') ) # direction as -1 if for minus stim if cur_handler._nextIntensity >= 10.0: sys.exit( "Hue difference is out of range! Please enlarge the testing range or take more training!" ) rot = cur_handler._nextIntensity * direction # rotation for this trial if trial_n >= 5: # avoid repeating an intensity more than 3 times last_rots = [ np.round(r, decimals=1) for r in [ rot_all_disp[handler_idx][trial_n - 1], rot_all_disp[handler_idx][trial_n - 2], rot_all_disp[handler_idx][trial_n - 3] ] ] last_resp = [ judge_all[handler_idx][trial_n - 1], judge_all[handler_idx][trial_n - 2], judge_all[handler_idx][trial_n - 3] ] if last_rots[0] == last_rots[1] == last_rots[2] \ and last_resp[0] == last_resp[1] == last_resp[2]: if cur_handler._nextIntensity > 0.5: rot = (cur_handler._nextIntensity - 0.5) * direction print('Intensity decreases by 0.5!') if cur_handler._nextIntensity <= 0.5: rot = (cur_handler._nextIntensity + 0.5) * direction print('Intensity increases by 0.5!') cond = cur_handler.extraInfo judge, react_time, trial_time_start = self.run_trial( rot, cond, cond['std'], count) if len(rot_all) <= handler_idx: rot_all.append([]) rot_all[handler_idx].append(rot) if len(judge_all) <= handler_idx: judge_all.append([]) judge_all[handler_idx].append(judge) valid_theta = np.round(np.load(self.hue_list), decimals=1) disp_standard = self.take_closest(valid_theta, cond['standard']) stair_test = cond[ 'standard'] + rot # calculated test hue for this trial if stair_test < 0: stair_test += 360 disp_test = self.take_closest( valid_theta, stair_test) # actual displayed test hue for this trial disp_intensity = disp_test - disp_standard # actual displayed hue difference if disp_intensity > 300: disp_intensity = (disp_test + disp_standard) - 360 cur_handler.addResponse( judge, abs(disp_intensity) ) # only positive number is accepted by addResponse if len(rot_all_disp ) <= handler_idx: # add displayed intensities rot_all_disp.append([]) rot_all_disp[handler_idx].append(disp_intensity) if isinstance(cur_handler, data.PsiHandler): estimates[cur_handler.extraInfo['label']].append([ cur_handler.estimateLambda()[0], # location cur_handler.estimateLambda768()[1], # slope cur_handler.estimateThreshold(0.75) ]) elif isinstance(cur_handler, data.QuestHandler): estimates[cur_handler.extraInfo['label']].append([ cur_handler.mean(), cur_handler.mode(), cur_handler.quantile(0.5) ]) xpp.task(count, cond, rot, disp_intensity, judge, react_time, trial_time_start) if 'escape' in event.waitKeys(): config_tools.write_xrl(self.subject, break_info='userbreak') core.quit() config_tools.write_xrl(self.subject, xls_file=xlsname) # save results in xls-file workbook = xlsxwriter.Workbook(xlsname) for handler_idx, cur_handler in enumerate(stairs): worksheet = workbook.add_worksheet( cur_handler.extraInfo['label']) worksheet.write('A1', 'Reversal Intensities') worksheet.write('B1', 'Reversal Indices') worksheet.write('C1', 'All Intensities') worksheet.write('D1', 'All Responses') for i in range(len(rot_all[handler_idx])): # worksheet.write('C' + str(i + 2), rot_all[handler_idx][i]) worksheet.write('C' + str(i + 2), rot_all_disp[handler_idx][i]) worksheet.write('D' + str(i + 2), judge_all[handler_idx][i]) workbook.close() # print resulting parameters and estimates for each step res_file_path = os.path.join(path, self.idx + '_estimates.csv') res_writer = csv.writer(open(res_file_path, 'w')) for res_stim, res_vals in estimates.items(): for res_val_id, res_val in enumerate(res_vals): res_writer.writerow([ res_stim, res_val_id, res_val[0], res_val[1], res_val[2] ]) # save each handler into a psydat-file and save posterior into a numpy-file for cur_handler in stairs: file_name = os.path.join( psydat_path, self.idx + self.param['noise_condition'] + cur_handler.extraInfo['label']) misc.toFile(file_name + '.psydat', cur_handler) if isinstance(cur_handler, data.PsiHandler): cur_handler.savePosterior(file_name + '.npy')
thisComponent.setAutoDraw(False) # check responses if key_resp_3.keys in ['', [], None]: # No response was made key_resp_3.keys = None # store data for thisExp (ExperimentHandler) thisExp.addData('key_resp_3.keys', key_resp_3.keys) if key_resp_3.keys != None: # we had a response thisExp.addData('key_resp_3.rt', key_resp_3.rt) thisExp.nextEntry() # set up handler to look after randomisation of trials etc conditions = data.importConditions('staircaseflo_2.xlsx') trials_2 = data.MultiStairHandler( stairType='simple', name='trials_2', nTrials=5, conditions=conditions, originPath= u'/Users/jason/Dropbox/SteffenerColumbia/Scripts/ExperimentalStimuli/Johannes/staircaseEXP.psyexp' ) thisExp.addLoop(trials_2) # add the loop to the experiment # initialise values for first condition level = trials_2._nextIntensity # initialise some vals condition = trials_2.currentStaircase.condition for level, condition in trials_2: currentLoop = trials_2 # abbreviate parameter names if possible (e.g. rgb=condition.rgb) for paramName in condition.keys(): exec(paramName + '= condition[paramName]') #------Prepare to start Routine "ISI_2"-------
show_practice_trial() show_practice_trial() show_practice_trial() show_practice_trial() instructions6.draw() win.flip() event.waitKeys() # Start staircase current_run=0 total_run=range(4) for current_run in total_run: # create the staircase handler if params.staircase_style == 'QUEST': staircase = data.MultiStairHandler(stairType='QUEST', conditions=params.conditions_QUEST, nTrials=params.staircase_ntrials) else: staircase = data.MultiStairHandler(stairType='simple', conditions=params.conditions_simple, nTrials=params.staircase_ntrials) print('Created staircase: %s' % params.staircase_style) n_trials = 0 for this_stim_secs, this_condition in staircase: frame_n=0 # Print trial number, condition info to console n_trials += 1 print('trial:', str(n_trials), 'condition: ' + this_condition['label'] + " | " + 'stim_secs: ' + str(this_stim_secs)) # Initialize grating parameters for this condition this_max_contrast = this_condition['max_contr'] this_grating_degree = this_condition['grating_deg'] this_tf = this_condition['tf'] this_spf = this_condition['spf']
lineWidth=0, size=.75, pos=(0, 0)) message1 = visual.TextStim(win, pos=[0, +3], text='Hit a key when ready.') message2 = visual.TextStim( win, pos=[0, -3], text= "When the white box appears, press LEFT arrow to identify a horizontal grating or the UP arrow to identify a vertical grating." ) # create the staircase handler if params.stair_case_style == 'quest': staircase = data.MultiStairHandler(stairType='quest', conditions=params.conditions_QUEST, nTrials=50) else: staircase = data.MultiStairHandler(stairType='simple', conditions=params.conditions_simple, nTrials=50) #----------------------------------------------------------------------------------------------------------- # Start experiment #----------------------------------------------------------------------------------------------------------- # display instructions and wait message1.draw() message2.draw() fixation.draw() win.flip()