def test_staircaseDB(self): nTrials = 20 stairs = data.StairHandler(startVal=0.8, nUp=1, nDown=3, minVal=0, maxVal=1, nReversals=4, stepSizes=[0.4, 0.2, 0.2, 0.1], nTrials=nTrials, stepType='db') responsesToMake = makeBasicResponseCycles() levels = [ 0.8, 0.763994069, 0.729608671, 0.696770872, 0.665411017, 0.680910431, 0.696770872, 0.713000751, 0.729608671, 0.729608671, 0.729608671, 0.713000751, 0.713000751, 0.72125691, 0.729608671, 0.738057142, 0.746603441, 0.746603441, 0.746603441, 0.738057142 ] reversals = [0.665411017, 0.729608671, 0.713000751, 0.746603441] self.doTrials(stairs, responsesToMake[:nTrials], levels=levels)
def test_staircaseLinear(self): nTrials = 20 stairs = data.StairHandler(startVal=0.8, nUp=1, nDown=3, minVal=0, maxVal=1, nReversals=4, stepSizes=[0.1, 0.01, 0.001], nTrials=nTrials, stepType='lin') responsesToMake = makeBasicResponseCycles() levels = [ 0.8, 0.7, 0.6, 0.5, 0.4, 0.41, 0.42, 0.43, 0.44, 0.44, 0.44, 0.439, 0.439, 0.44, 0.441, 0.442, 0.443, 0.443, 0.443, 0.442 ] reversals = [0.4, 0.44, 0.439, 0.443] self.doTrials(stairs, responsesToMake[:nTrials], levels=levels, reversals=reversals)
def test_applyInitialRule_False(self): start_val = 10 step_sizes = 2 staircase = data.StairHandler(startVal=start_val, stepSizes=step_sizes, nReversals=2, nUp=1, nDown=2, applyInitialRule=False, stepType='lin') responses = [0, 1, 1, 0] intensities = [10, 12, 12, 10] for r in responses: try: staircase.__next__() staircase.addResponse(r) except StopIteration: break assert staircase.data == responses assert staircase.intensities == intensities
def test_StairHandlerLog(self): nTrials = 20 startVal, minVal, maxVal = 0.8, 0, 1 # We try to reproduce the values from test_StairHandlerDb(). stepSizes = [0.4 / 20, 0.2 / 20, 0.2 / 20, 0.1 / 20] nUp, nDown = 1, 3 nReversals = 4 stepType = 'log' self.stairs = data.StairHandler(startVal=startVal, nUp=nUp, nDown=nDown, minVal=minVal, maxVal=maxVal, nReversals=nReversals, stepSizes=stepSizes, nTrials=nTrials, stepType=stepType) self.responses = makeBasicResponseCycles(cycles=3, nCorrect=4, nIncorrect=4, length=20) self.intensities = [ 0.8, 0.763994069, 0.729608671, 0.696770872, 0.665411017, 0.680910431, 0.696770872, 0.713000751, 0.729608671, 0.729608671, 0.729608671, 0.713000751, 0.713000751, 0.72125691, 0.729608671, 0.738057142, 0.746603441, 0.746603441, 0.746603441, 0.738057142 ] self.reversalPoints = [4, 10, 12, 18] self.reversalIntensities = list( itemgetter(*self.reversalPoints)(self.intensities)) self.simulate() self.checkSimulationResults()
def test_StairHandlerDb(self): nTrials = 20 startVal, minVal, maxVal = 0.8, 0, 1 stepSizes = [0.4, 0.2, 0.2, 0.1] nUp, nDown = 1, 3 nReversals = 4 stepType = 'db' self.stairs = data.StairHandler(startVal=startVal, nUp=nUp, nDown=nDown, minVal=minVal, maxVal=maxVal, nReversals=nReversals, stepSizes=stepSizes, nTrials=nTrials, stepType=stepType) self.responses = makeBasicResponseCycles(cycles=3, nCorrect=4, nIncorrect=4, length=20) self.intensities = [ 0.8, 0.763994069, 0.729608671, 0.696770872, 0.665411017, 0.680910431, 0.696770872, 0.713000751, 0.729608671, 0.729608671, 0.729608671, 0.713000751, 0.713000751, 0.72125691, 0.729608671, 0.738057142, 0.746603441, 0.746603441, 0.746603441, 0.738057142 ] self.reversalIntensities = [ 0.665411017, 0.729608671, 0.713000751, 0.746603441 ] self.simulate() self.checkSimulationResults()
def create_structure(): ''' This function creates the core structure of the experiment, which is a dictionary containing all important components of the experiment. It is used to store all the settings, experimental components like stimuli or response screens, and participant responses. On top of results datafiles and logs, this structure is saved into a json file after each session, allowing to retrieve many additional information about the experiments execution. ''' structure = {} gui.DlgFromDict(expInfo) structure['expInfo'] = expInfo structure['performTraining'] = performTraining structure['performStaircase'] = performStaircase structure['performSession'] = performSession structure['EEG'] = EEG structure['attention'] = attention # Create clocks for the experiment structure['globalClock'] = core.Clock() structure['trainingClock'] = core.Clock() structure['trialClock'] = core.Clock() # Create a chosen response device structure['responseDevice'] = responseDevice structure['keyBoard'] = keyboard.Keyboard() structure['buttonBox'] = None structure['stairSamples'] = stairSamples if responseDevice == 'buttonBox': try: # to use the Cedrus response box import pyxid2 as pyxid except ImportError: import pyxid for n in range(10): # doesn't always work first time! try: devices = pyxid.get_xid_devices() core.wait(0.1) structure['buttonBox'] = devices[0] structure['buttonBox'].clock = core.Clock() break # found the device so can break the loop except Exception: pass if not structure['buttonBox']: logging.error('could not find a Cedrus device.') core.quit() # Create a filename for the results date = data.getDateStr() structure['expFileName'] = join(resultsFolder, expInfo['ID'] + '_' + date) # Create an experimental window structure['win'] = visual.Window(size=[1920, 1080], screen=1, fullscr=True, checkTiming=True, color='grey', monitor='testMonitor', colorSpace='rgb') structure['frameRate'] = round(structure['win'].getActualFrameRate(), 0) structure['expInfo']['frameRate'] = structure['frameRate'] structure['data'] = data.ExperimentHandler( name='test', extraInfo=expInfo, dataFileName=structure['expFileName']) structure['instructionScreen'] = visual.ImageStim(win=structure['win'], image=None, interpolate=True, depth=-1.0) crossVert = [(6, 1), (6, -1), (1, -1), (1, -6), (-1, -6), (-1, -1), (-6, -1), (-6, 1), (-1, 1), (-1, 6), (1, 6), (1, 1)] structure['fixationCross'] = visual.ShapeStim(win=structure['win'], vertices=crossVert, units='pix', lineWidth=0, fillColor='white') structure['dot'] = visual.Circle(win=structure['win'], units='pix', size=8, fillColor='white', lineWidth=0) structure['cuelocation'] = visual.ShapeStim(win=structure['win'], name='polygon', vertices='star7', size=(10, 10), units='pix', ori=0, pos=(0, 0), lineWidth=0.01, lineColor='black', lineColorSpace='rgb', fillColor='black', fillColorSpace='rgb', opacity=1, depth=0.0, interpolate=True) structure['cuecentral'] = visual.ShapeStim(win=structure['win'], name='polygon', vertices='star7', size=(10, 10), units='pix', ori=0, pos=(0, 0), lineWidth=0.01, lineColor='black', lineColorSpace='rgb', fillColor='black', fillColorSpace='rgb', opacity=1, depth=0.0, interpolate=True) structure['cueupperleft'] = visual.ShapeStim(win=structure['win'], name='polygon', vertices='star7', size=(10, 10), units='pix', ori=0, pos=(-77, 77), lineWidth=0.01, lineColor='black', lineColorSpace='rgb', fillColor='black', fillColorSpace='rgb', opacity=1, depth=0.0, interpolate=True) structure['cueupperright'] = visual.ShapeStim(win=structure['win'], name='polygon', vertices='star7', size=(10, 10), units='pix', ori=0, pos=(77, 77), lineWidth=0.01, lineColor='black', lineColorSpace='rgb', fillColor='black', fillColorSpace='rgb', opacity=1, depth=0.0, interpolate=True) structure['cuelowerleft'] = visual.ShapeStim(win=structure['win'], name='polygon', vertices='star7', size=(10, 10), units='pix', ori=0, pos=(-77, -77), lineWidth=0.01, lineColor='black', lineColorSpace='rgb', fillColor='black', fillColorSpace='rgb', opacity=1, depth=0.0, interpolate=True) structure['cuelowerright'] = visual.ShapeStim(win=structure['win'], name='polygon', vertices='star7', size=(10, 10), units='pix', ori=0, pos=(77, -77), lineWidth=0.01, lineColor='black', lineColorSpace='rgb', fillColor='black', fillColorSpace='rgb', opacity=1, depth=0.0, interpolate=True) structure['nocue'] = visual.ShapeStim(win=structure['win'], vertices=crossVert, units='pix', lineWidth=0, fillColor='white') arrowVert = [(-15, 3), (-15, -3), (0, -3), (0, -9), (15, 0), (0, 9), (0, 3)] structure['arrow'] = visual.ShapeStim(win=structure['win'], units='pix', vertices=arrowVert, fillColor='black', lineWidth=0) structure['gabor'] = visual.GratingStim(win=structure['win'], name='gaborUpLeft', units='pix', tex='sin', mask='gauss', ori=45, pos=(0, 0), size=(128, 128), sf=1.5 / 40.0, phase=1.0, color=1.0, colorSpace='rgb', opacity=0.2, texRes=512, interpolate=True, depth=-2.0) structure['responseScreen'] = visual.ImageStim(win=structure['win'], image=None, interpolate=True, depth=-1.0) structure['fixationShape'] = fixation_shape structure['fixationDur'] = fixation_dur structure['postFixationDur'] = post_fixation_dur structure['cueDur'] = cue_dur structure['cueISI'] = cue_ISI structure['gaborDur'] = gabor_dur structure['blockLength'] = block_length # Create instruction screens structure['welcome'] = join('materials/instructions', '1_welcome.png') structure['training_instruction'] = join('materials/instructions', '2_instruction.png') structure['location_instruction'] = join('materials/instructions', '3_location_demo.png') structure['orientation_instruction'] = join('materials/instructions', '4_orientation_demo.png') structure['pas_instruction'] = join('materials/instructions', '5_pas_demo.png') structure['training_start'] = join('materials/instructions', '6_training_start.png') structure['training_end'] = join('materials/instructions', '7_training_end.png') structure['correct_screen'] = join('materials/instructions', '8_correct.png') structure['incorrect_screen'] = join('materials/instructions', '9_incorrect.png') structure['staircase_start'] = join('materials/instructions', '10_staircase_start.png') structure['session_start'] = join('materials/instructions', '11_session_start.png') structure['break'] = join('materials/instructions', '12_break.png') structure['end'] = join('materials/instructions', '13_end.png') structure['training_trials_file'] = join('materials', 'training_trials.csv') # structure['trainingConditions'] = data.importConditions(structure['training_trials_file']) structure['trainingConditions'] = data.importConditions( structure['training_trials_file'], selection='0:5') structure['trainingTrials'] = data.TrialHandler( structure['trainingConditions'], nReps=1) structure['data'].addLoop(structure['trainingTrials']) structure['trials_file'] = join('materials', 'experiment_trials.csv') structure['experimentConditions'] = data.importConditions( structure['trials_file']) structure['experimentTrials'] = data.TrialHandler( structure['experimentConditions'], nReps=trial_num / 64) structure['data'].addLoop(structure['experimentTrials']) #structure['trials_file'] = join('materials', 'experiment_trials.csv') #structure['experimentConditions'] = data.importConditions(structure['trials_file']) #structure['experimentTrials'] = data.TrialHandler(structure['experimentConditions'], nReps=trial_num/64) #structure['data'].addLoop(structure['experimentTrials']) structure['locationResponse'] = locationResponse structure['orientationResponse'] = orientationResponse structure['pasResponse'] = pasResponse structure['staircaseTrials'] = data.StairHandler(**staircase) structure['data'].addLoop(structure['staircaseTrials']) return structure
opacity=1, depth=0.0) RunningClock = core.Clock() Nloads = GridCount**2 NumberOfReversals = 20 #staircase = data.StairHandler(startVal = 1, # stepType = 'lin', stepSizes=1, # nUp=1, nDown=3, # will home in on the 80% threshold # nReversals = NumberOfReversals,minVal = 1,maxVal = 20) staircase = data.StairHandler( startVal=Nloads, stepType='lin', stepSizes=[1], nUp=1, nDown=3, # will home in on the 80% threshold nReversals=NumberOfReversals, minVal=1, maxVal=Nloads) # For each block change the selection list # Need instructions and wait textInstr1.setAutoDraw(True) # Put the probe dot on the screen win.flip() # Start the probe timer WaitingFlag = True while WaitingFlag is True: theseKeys = event.getKeys(keyList=['escape', '5'])
sound_1 = sound.Sound(u'NumberSounds/6.wav', secs=-1) sound_1.setVolume(1) # 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 Staircase "Stairs" -------- # set up handler to look after next chosen value etc Stairs = data.StairHandler(startVal=3, extraInfo=expInfo, stepSizes=-1, stepType='lin', nReversals=0, nTrials=14, nUp=2, nDown=1, minVal=3, maxVal=20, originPath=-1, name='Stairs') thisExp.addLoop(Stairs) # add the loop to the experiment level = thisStair = 3 # initialise some vals for thisStair in Stairs: currentLoop = Stairs level = thisStair # ------Prepare to start Routine "trial"------- t = 0 trialClock.reset() # clock
#pause until there's a keypress event.waitKeys() for trialLoop in range(5): formatString = 'Trial %i of 5.' % trialLoop messagetrial = visual.TextStim(win, pos=[0, +vOffset], text=formatString) messagetrial.draw() win.flip() event.waitKeys() staircase = data.StairHandler( startVal=0.5, # Array as list alters the size of steps - do we want this? nReversals=4, stepType='lin', stepSizes=[0.04, 0.02, 0.01, 0.005], minVal=0, maxVal=1, nUp=1, nDown=3, # will home in on the 80% threshold nTrials=10) for thisIncrement in staircase: # will continue the staircase until it terminates! # set location of stimuli targetSide = random.choice([-1, 1]) # will be either +1(right) or -1(left) maskerTL.setPos([hOffset * targetSide, vOffset]) maskerTL.setContrast(0.5) maskerTR.setPos([-hOffset * targetSide, vOffset]) maskerTR.setContrast(0.5) maskerBL.setPos([hOffset * targetSide, -vOffset])
def run_exp(): """ Runs psychophysics experiment to determine threshold for distortion for ensemble and individual mode. After starting, you will be prompted for subject name and experiment type for experiment type put either "ensemble" or "single" """ DIR_DATA = '../data' save_dir = op.join(DIR_DATA, 'perceptual_experiment') # create folder for psychophysics data if not there already safe_mkdir(save_dir) # params numTrials = 60 alphaMin = 0 alphaMax = 60 alphaStart = 40 alphaSteps = [10, 5, 5, 2, 2] images = ['church', 'dog', 'fish', 'horn', 'truck'] # set file name info = {'Subject': 'ld', 'Experiment Type': 'ensemble'} info['dateStr'] = data.getDateStr() # add the current time # present a dialogue to change params dlg = gui.DlgFromDict(info, title='Percpetual Exp', fixed=['dateStr']) if dlg.OK: toFile(op.join(save_dir, 'lastParams.pickle'), info) # save params to file for next time else: core.quit() # the user hit cancel so exit # make a text file to save data fileName = save_dir + '/Experiment_' + info['Experiment Type'] + '_' + info['Subject'] + '_' + info['dateStr'] dataFile = open(fileName + '.csv', 'w') # a simple text file with 'comma-separated-values' dataFile.write('distortedSide, trialNum,image, alpha, correct, experimentType\n') # create a window win = visual.Window([1000, 600], monitor="testMonitor", units="deg") # create some stimuli dist_ind, dist_ensemble = create_distortions() preprocessed_images = load_images() fixation = visual.GratingStim(win=win, size=0.5, pos=[0, 0], sf=0, color=-1) # display instructions message1 = visual.TextStim(win, pos=[0, +3], text='Hit a key when ready.') message2 = visual.TextStim(win, pos=[0, -3], text="Then press left or right to indicate which image was more distorted.") message3 = visual.TextStim(win, pos=[0, +3], text="press left or right") message1.draw() message2.draw() fixation.draw() win.flip() event.waitKeys() # setup stair procedure stairs = [] info['baseImages'] = images for imgName in info['baseImages']: thisInfo = copy.copy(info) thisInfo['imgName'] = imgName thisStair = data.StairHandler(startVal=alphaStart, extraInfo=thisInfo, nTrials=100, nUp=1, nDown=2, nReversals=5, minVal=alphaMin, maxVal=alphaMax, stepSizes=alphaSteps) stairs.append(thisStair) for trial in np.arange(numTrials): # shuffle stairs shuffle(stairs) # print('Trial Num:', trial) for thisStair in stairs: thisAlpha = next(thisStair) # get the alpha value for this trial thisImage = thisStair.extraInfo['imgName'] # which image are we on dist_ind, dist_ensemble = create_distortions() preprocessed_images = load_images() if info['Experiment Type'] == 'ensemble': base_image, distorted_image = random_trial(preprocessed_images, dist_ind, dist_ensemble, alpha=thisAlpha, img=thisImage, ensemble=1) if info['Experiment Type'] == 'single': base_image, distorted_image = random_trial(preprocessed_images, dist_ind, dist_ensemble, alpha=thisAlpha, img=thisImage) distortedImg = visual.ImageStim(win=win, image=distorted_image, units='pix', size=260, ori=180) baseImg = visual.ImageStim(win=win, image=base_image, units='pix', size=260, ori=180) # randomly assign side on screen to images targetSide = np.random.choice([-1, 1]) distortedImg.setPos([250 * targetSide, 0]) baseImg.setPos([-250 * targetSide, 0]) # randomize which image is presented first order = np.random.choice([-1, 1]) # Trial if order == 1: # draw first stimulus fixation.draw() distortedImg.draw() win.flip() # wait 1s core.wait(1.0) # draw second stimulus fixation.draw() baseImg.draw() win.flip() else: # draw first stimulus fixation.draw() baseImg.draw() win.flip() # wait 1s core.wait(1.0) # draw second stimulus fixation.draw() distortedImg.draw() win.flip() # wait 1s core.wait(1.0) # blank screen message3.draw() fixation.draw() win.flip() # get response thisResp = None while thisResp == None: allKeys = event.waitKeys() for thisKey in allKeys: if thisKey == 'left': if targetSide == -1: thisResp = 1 # correct else: thisResp = -1 # incorrect elif thisKey == 'right': if targetSide == 1: thisResp = 1 # correct else: thisResp = -1 # incorrect elif thisKey in ['q', 'escape']: core.quit() # abort experiment event.clearEvents() # clear other (eg mouse) events - they clog the buffer # adjust stairs thisStair.addData(thisResp) # save responses to_write = f"{targetSide:d}, {trial:d}, {thisImage:s}, {thisAlpha:.3f}, {thisResp:d}," \ f" {info['Experiment Type']} \n" dataFile.write(to_write) core.wait(0.5) # close file dataFile.close() win.clearBuffer() # make screen black endText = visual.TextStim(win, pos=[0, +3], text='Thanks! You have finished the experiment.') endText.draw() win.flip() win.close() core.quit() return
stimFrames.append( visual.PatchStim(myWin, texRes=pixels, mask='circle', size=pixels * 2, sf=1.0 / pixels, ori=90, tex=(noiseMatrix * info['contrastModNoise'] * lumGratings[3]))) stairCases = [] #two staircases - one from the top, one from below - to average stairCases.append( data.StairHandler(startVal=info['highGamma'], nTrials=info['nTrials'], stepSizes=[0.5, 0.5, 0.1, 0.1, 0.1, 0.1, 0.05, 0.05], stepType='lin', nUp=1, nDown=1)) stairCases.append( data.StairHandler(startVal=info['lowGamma'], nTrials=info['nTrials'], stepSizes=[0.5, 0.5, 0.1, 0.1, 0.1, 0.1, 0.05, 0.05], stepType='lin', nUp=1, nDown=1)) def getResponse(direction): """if subject said up when direction was up (+1) then increase gamma Otherwise, decrease gamma""" event.clearEvents() #clear the event buffer to start with
def test_json_dump_to_file(self): s = data.StairHandler(5) s.saveAsJson(fileName=self.tmp_dir, fileCollisionMethod='overwrite')
def test_comparison_not_equal_after_iteration(self): s1 = data.StairHandler(5) s2 = data.StairHandler(6) s1.__next__() s2.__next__() assert s1 != s2
def test_comparison_equals(self): s1 = data.StairHandler(5) s2 = data.StairHandler(5) assert s1 == s2
expInfo['dateStr'] = data.getDateStr() # add the current time # present a dialogue to change params dlg = gui.DlgFromDict(expInfo, title='simple JND Exp', fixed=['dateStr']) if dlg.OK: toFile('lastParams.pickle', expInfo) # save params to file for next time else: core.quit() # the user hit cancel so exit # make a text file to save data fileName = expInfo['observer'] + expInfo['dateStr'] dataFile = open(fileName+'.csv', 'w') # a simple text file with 'comma-separated-values' dataFile.write('targetSide,oriIncrement,correct\n') # create the staircase handler staircase = data.StairHandler(startVal = 20.0, stepType = 'db', stepSizes=[8,4,4,2], nUp=1, nDown=3, # will home in on the 80% threshold nTrials=1) # create window and stimuli win = visual.Window([800,600],allowGUI=True, monitor='testMonitor', units='deg') foil = visual.GratingStim(win, sf=1, size=4, mask='gauss', ori=expInfo['refOrientation']) target = visual.GratingStim(win, sf=1, size=4, mask='gauss', ori=expInfo['refOrientation']) fixation = visual.GratingStim(win, color=-1, colorSpace='rgb', tex=None, mask='circle', size=0.2) # and some handy clocks to keep track of time globalClock = core.Clock() trialClock = core.Clock()
lumGratings.append(filters.makeGrating(pixels, 0, cyclesSpace, phase=180)) stimFrames.append(visual.PatchStim(myWin, texRes=pixels, mask='circle', size=pixels*2, sf=1.0/pixels, ori=90, tex= (noiseMatrix*info['lumModNoise'] + lumGratings[2]*info['lumModLum']) )) lumGratings.append(filters.makeGrating(pixels, 0, cyclesSpace, phase=270)/2.0 + 0.5) stimFrames.append(visual.PatchStim(myWin, texRes=pixels, mask='circle', size=pixels*2, sf=1.0/pixels, ori=90, tex= (noiseMatrix*info['contrastModNoise']*lumGratings[3]) )) stairCases=[] #two staircases - one from the top, one from below - to average stairCases.append(data.StairHandler(startVal=info['startGamma'][0], nTrials=info['nTrials'], stepSizes=[0.5,0.5,0.1,0.1,0.1,0.1,0.05,0.05],stepType='lin', nUp=1, nDown=1)) stairCases.append(data.StairHandler(startVal=info['startGamma'][1], nTrials=info['nTrials'], stepSizes=[0.5,0.5,0.1,0.1,0.1,0.1,0.05,0.05],stepType='lin', nUp=1, nDown=1)) def getResponse(direction): """if subject said up when direction was up (+1) then increase gamma Otherwise, decrease gamma""" event.clearEvents()#clear the event buffer to start with resp=None#initially while 1:#forever until we return for key in event.getKeys(): #quit if key in ['escape', 'q']: myWin.close()
def expcolornoise(noise_condition, theta, subject='None', c=0.12, sscale=2.6, dlum=0): # set two reference left = theta + 20 right = theta - 20 leftRef = visual.Circle(win=win, units='deg', fillColorSpace='rgb255', lineColorSpace='rgb255', pos=[-8, 2]) leftRef.fillColor = colorpalette.newcolor(left, c, sscale, dlum, unit='degree', subject=subject)[1] leftRef.lineColor = leftRef.fillColor rightRef = visual.Circle(win=win, units='deg', fillColorSpace='rgb255', lineColorSpace='rgb255', pos=[8, 2]) rightRef.fillColor = colorpalette.newcolor(right, c, sscale, dlum, unit='degree', subject=subject)[1] rightRef.lineColor = rightRef.fillColor # set position and color of stimuli sPatch = patchstim() tPatch = patchstim() sPatch.xys = patchpos([-1, 1], [1, 3]) tPatch.xys = patchpos([-1, 1], [-3, -1]) # create staircases info = { 'startVal': [-3], 'steps': [[2, 1], [1, 2]] } # set two stairs here, with different startpoints; # later maybe make it as diffferent size? stairs = [] for startVal in info['startVal']: thisInfo = copy.copy(info) thisInfo['startVal'] = startVal for steps in info['steps']: thisInfo['steps'] = steps thisStair = data.StairHandler(startVal=startVal, extraInfo=thisInfo, nTrials=ntrial, stepSizes=0.5, nUp=steps[0], nDown=steps[1], minVal=-5, maxVal=5) stairs.append(thisStair) track = np.empty((0, 6)) for trialN in range(ntrial): random.shuffle( stairs ) # this shuffles 'in place' (ie stairs itself is changed, nothing returned) for thisStair in stairs: standard = theta # standard should be fixed # rotation = next(thisStair) # what is rotation = 0? skip this trial? rotation = thisStair test = standard + rotation # choose noise condition if noise_condition == 'L-L': # low - low noise sPatch.colors = colorpalette.newcolor(standard, c, sscale, dlum, unit='degree', subject=subject)[1] tPatch.colors = colorpalette.newcolor(test, c, sscale, dlum, unit='degree', subject=subject)[1] elif noise_condition == 'L-H': # low - high noise: only compare stimulus has high noise sPatch.colors = colorpalette.newcolor(standard, c, sscale, dlum, unit='degree', subject=subject)[1] tPatch.colors = randcolor(test, sigma, npatch, c, sscale, dlum, unit='degree', subject=subject)[1] elif noise_condition == 'H-H': # high - high noise sPatch.colors = randcolor(standard, sigma, npatch, c, sscale, dlum, unit='degree', subject=subject)[1] tPatch.colors = randcolor(test, sigma, npatch, c, sscale, dlum, unit='degree', subject=subject)[1] else: print("No noise condition corresponds to the input!") core.quit() # draw all stimuli leftRef.draw() rightRef.draw() sPatch.draw() tPatch.draw() win.flip() core.wait(1) # foe how long the stimuli will show win.flip() # get response judge = None while judge is None: allkeys = event.waitKeys() for key in allkeys: # press left -> adjust comparision stim counter-clockwise to standard stim; press right -> clockwisely if (key == 'left' and rotation > 0) or (key == 'right' and rotation < 0): judge = 1 # correct elif (key == 'left' and rotation < 0) or (key == 'right' and rotation > 0): judge = 0 # incorrect elif key == 'escape': core.quit() thisStair.addResponse(judge) thisStair.saveAsExcel(path + '/stair' + str(trialN)) track = np.append(track, [[left, right, standard, test, rotation, judge]], axis=0) win.close() core.quit() savedata(noise_condition, track) return track
win=visual.Window([400,400]) #--------------------- #create the stimuli #--------------------- #create staircases stairs=[] for thisStart in info['startPoints']: #we need a COPY of the info for each staircase #(or the changes here will be made to all the other staircases) thisInfo = copy.copy(info) #now add any specific info for this staircase thisInfo['thisStart']=thisStart #we might want to keep track of this thisStair = data.StairHandler(startVal=thisStart, extraInfo=thisInfo, nTrials=50, nUp=1, nDown=3, minVal = 0.5, maxVal=8, stepSizes=[4,4,2,2,1,1]) stairs.append(thisStair) for trialN in range(info['nTrials']): shuffle(stairs) #this shuffles 'in place' (ie stairs itself is changed, nothing returned) #then loop through our randomised order of staircases for this repeat for thisStair in stairs: thisIntensity = next(thisStair) print('start=%.2f, current=%.4f' %(thisStair.extraInfo['thisStart'], thisIntensity)) #--------------------- #run your trial and get an input #--------------------- keys = event.waitKeys() #(we can simulate by pushing left for 'correct')
text = visual.TextStim(win=win, name='text', text="Bat: press 'a'\n\nBet: press 'e'", font='Arial', pos=(0, 0), height=0.1, wrapWidth=None, ori=0, color='white', colorSpace='rgb', opacity=1, depth=-3.0); # Create some handy timers globalClock = core.Clock() # to track the time since experiment started routineTimer = core.CountdownTimer() # to track time remaining of each (non-slip) routine # --------Prepare to start Staircase "trials" -------- # set up handler to look after next chosen value etc trials = data.StairHandler(startVal=10, extraInfo=expInfo, stepSizes=[2], stepType='lin', nReversals=1, nTrials=50, nUp=1, nDown=3, minVal=-50, maxVal=50, originPath=-1, name='trials') thisExp.addLoop(trials) # add the loop to the experiment level = thisTrial = 10 # initialise some vals for thisTrial in trials: currentLoop = trials level = thisTrial # ------Prepare to start Routine "trial"------- t = 0 trialClock.reset() # clock frameN = -1 continueRoutine = True # update component parameters for each repeat
def test_json_dump_to_file(self): s = data.StairHandler(5) _, path = mkstemp(dir=self.tmp_dir, suffix='.json') s.saveAsJson(fileName=path, fileCollisionMethod='overwrite')
info['participant'] = '' dlg = gui.DlgFromDict(info) # present dialog to collect info if not dlg.OK: core.quit() info['dateStr'] = data.getDateStr() #will create str of current date/time info['refDisp'] = 0.16 # disparity of reference stays constant at 0.16 deg #create the base filename for our data files #fileName = "data/{participant}_{dateStr}".format(**info) #dataFile = open(fileName+'.csv', 'w')#a simple text file with 'comma-separated-values' #create the staircase handler staircase = data.StairHandler( startVal=0.3, stepType='lin', stepSizes=[0.05, 0.03, 0.03, 0.02, 0.02, 0.01, 0.01], nUp=1, nDown=1, minVal=0, maxVal=0.3) #will home in on the 50% threshold # initialise stimuli fixation = visual.Circle(win, size=0.25, lineColor='white', fillColor='lightGrey') rds = visual.DotStim(win, nDots=500, fieldSize=(4, 4), fieldShape='sqr', dotLife=-1,
depth=-4.0, interpolate=True) # 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 Staircase "trials" -------- # set up handler to look after next chosen value etc trials = data.StairHandler(startVal=0.5, extraInfo=expInfo, stepSizes=[0.4, 0.2, 0.2, 0.1], stepType='log', nReversals=0, nTrials=50, nUp=1, nDown=3, minVal=0, maxVal=1, originPath=-1, name='trials') thisExp.addLoop(trials) # add the loop to the experiment level = thisTrial = 0.5 # initialise some vals for thisTrial in trials: currentLoop = trials level = thisTrial # ------Prepare to start Routine "trial"------- t = 0 trialClock.reset() # clock
def test_comparison_not_equal(self): s1 = data.StairHandler(5) s2 = data.StairHandler(6) assert s1 != s2
# Setting up the conditions: condList = data.importConditions(conditionsFilePath) stairs, completedStairs = [], [] for thisCond in condList: thisInfo = copy.copy(thisCond) stairLabel = 'st' + str(thisCond['startContr']) + \ '_mcBv' + str(thisCond['mcBv']) + \ '_targTon' + str(thisCond['targTon']) + \ '_ecc' + str(thisCond['targXoff2']) if domTest: stairLabel += '_targEyeR' + str(thisCond['targEyeR']) thisInfo['label'] = stairLabel thisStair = data.StairHandler(startVal=thisInfo['startContr'], extraInfo=thisInfo, maxVal=1, minVal=-2, nReversals=thisInfo['nRevs'], nUp=1, nDown=1, stepType='lin', stepSizes=contrSteps[0:thisInfo['nRevs']], name=stairLabel) stairs.append(thisStair) # An empty data set for storing behavioural responses: behResp = [] # Creating a copy of the Conditions file for book-keeping and analyses: if not os.path.exists(filePath): os.makedirs(filePath) shutil.copyfile(conditionsFilePath, filePath + os.sep + os.path.basename(conditionsFilePath)) dataFileName = filePath + os.sep + fileName + '.csv'
def test_json_dump(self): s = data.StairHandler(5) dump = s.saveAsJson() s.origin = '' assert s == json_tricks.np.loads(dump)
#extraInfo = thisInfo, pThreshold = threshCriterion, #0.25, gamma = 1./26, delta=0.02, #lapse rate, I suppose for Weibull function fit method = 'quantile', #uses the median of the posterior as the final answer stepType = 'log', #will home in on the 80% threshold. But stepType = 'log' doesn't usually work minVal=1, maxVal = 100 ) print('created QUEST staircase') else: stepSizesLinear = [.2,.2,.1,.1,.05,.05] stepSizesLog = [log(1.4,10),log(1.4,10),log(1.3,10),log(1.3,10),log(1.2,10)] staircase = data.StairHandler(startVal = 0.1, stepType = 'log', #if log, what do I want to multiply it by stepSizes = stepSizesLog, #step size to use after each reversal minVal=0, maxVal=1, nUp=1, nDown=3, #will home in on the 80% threshold nReversals = 2, #The staircase terminates when nTrials have been exceeded, or when both nReversals and nTrials have been exceeded nTrials=1) print('created conventional staircase') if prefaceStaircaseTrialsN > len(prefaceStaircaseNoise): #repeat array to accommodate desired number of easyStarterTrials prefaceStaircaseNoise = np.tile( prefaceStaircaseNoise, ceil( prefaceStaircaseTrialsN/len(prefaceStaircaseNoise) ) ) prefaceStaircaseNoise = prefaceStaircaseNoise[0:prefaceStaircaseTrialsN] phasesMsg = ('Doing '+str(prefaceStaircaseTrialsN)+'trials with noisePercent= '+str(prefaceStaircaseNoise)+' then doing a max '+str(staircaseTrials)+'-trial staircase') print(phasesMsg); logging.info(phasesMsg) #staircaseStarterNoise PHASE OF EXPERIMENT corrEachTrial = list() #only needed for easyStaircaseStarterNoise staircaseTrialN = -1; mainStaircaseGoing = False
tex=None, mask='circle', size=0.2) message1 = visual.TextStim(win, pos=[0, +3], text='Hit a key when ready.') message2 = visual.TextStim( win, pos=[0, -3], text="Then press left or right to identify the %.1fdegree probe." % expInfo['refOrientation']) # create the staircase handler staircase = data.StairHandler( startVal=20.0, stepType='lin', stepSizes=[8, 4, 4, 2, 2, 1, 1], # reduce step size every two reversals minVal=0, maxVal=90, nUp=1, nDown=3, # will home in on the 80% threshold nTrials=50) # display instructions and wait message1.draw() message2.draw() fixation.draw() win.flip() # check for a keypress event.waitKeys() for thisIncrement in staircase: # will step through the staircase # set location of stimuli
for trial in training: training.addData('training.rt', random.random() * 0.5 + 0.5) if random.random() > 0.5: training.addData('training.key', 'left') else: training.addData('training.key', 'right') exp.nextEntry() # then run 3 repeats of a staircase outerLoop = data.TrialHandler(trialList=[], nReps=3, name='stairBlock', method='random') exp.addLoop(outerLoop) for thisRep in outerLoop: # the outer loop doesn't save any data staircase = data.StairHandler(startVal=10, name='staircase', nTrials=5) exp.addLoop(staircase) for thisTrial in staircase: id = random.random() if random.random() > 0.5: staircase.addData(1) else: staircase.addData(0) exp.addData('id', id) exp.nextEntry() for e in exp.entries: print(e) print( "Done. 'exp' experimentHandler will now (end of script) save data to testExp.csv" ) print(" and also to testExp.psydat, which is a pickled version of `exp`")
if continueRoutine: # don't flip if this routine is over or we'll get a blank screen win.flip() # -------Ending Routine "instructs"------- for thisComponent in instructsComponents: if hasattr(thisComponent, "setAutoDraw"): thisComponent.setAutoDraw(False) # the Routine "instructs" was not non-slip safe, so reset the non-slip timer routineTimer.reset() # --------Prepare to start Staircase "Stair" -------- # set up handler to look after next chosen value etc Stair = data.StairHandler(startVal=81, extraInfo=expInfo, stepSizes=[1], stepType='lin', nReversals=1, nTrials=1, nUp=1, nDown=1, minVal=65, maxVal=160, originPath=-1, name='Stair') thisExp.addLoop(Stair) # add the loop to the experiment level = thisStair = 81 # initialise some vals for thisStair in Stair: currentLoop = Stair level = thisStair # ------Prepare to start Routine "Endogenous"------- t = 0 EndogenousClock.reset() # clock frameN = -1 continueRoutine = True # update component parameters for each repeat
def task(sdist): # Open logfile log = logfiler.logger(expinfo['Subject ID'], 'jnd_distspace') # Set-up staircase staircase = data.StairHandler(startVal=10, stepType='lin', stepSizes=[5, 5, 5, 5, 2, 2, 1, 1], minVal=0, maxVal=60, nUp=1, nDown=3, nTrials=75) # Iterate through steps for step in staircase: # Set location tside = np.random.choice([sdist * -1, sdist]) target.setPos([tside, 0.0]) distractor.setPos([tside * -1, 0.0]) # Set distractor color print(step) dcol = int(expinfo['Target Color']) + step distractor.setFillColor(allcols[dcol]) distractor.setLineColor(allcols[dcol]) # Draw and show target.draw() distractor.draw() win.flip() core.wait(.15) win.flip() # Response handling resp = event.waitKeys(keyList=['left', 'right', 'escape']) cor = None if (resp[0] == 'left' and tside == (sdist*-1)) \ or (resp[0] == 'right' and tside == sdist): cor = 1 corsound.play() else: cor = 0 errsound.play() # Do we quit? if resp[0] == 'escape': log.close() tracker.endExperiment('C:\\edfs\\Nick\\distspace\\') core.quit() # Adjust next trial, save results staircase.addResponse(cor) trial = { 'sub': expinfo['Subject ID'], 'group': expinfo['Group'], 'tcol': expinfo['Target Color'], 'dcol': dcol, 'ddist': step, 'tside': tside, 'resp': resp[0], 'cor': cor } log.write(trial) # ISI core.wait(1) # Clean up log.close() staircase.saveAsPickle('{}_jnd'.format(expinfo['Subject ID']))