1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
|
"""measure your JND in orientation using a staircase method"""
from psychopy import core, visual, gui, data, event
from psychopy.tools.filetools import fromFile, toFile
import numpy, random
try: # try to get a previous parameters file
expInfo = fromFile('lastParams.pickle')
except: # if not there then use a default set
expInfo = {'observer':'jwp', 'refOrientation':0}
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()
# display instructions and wait
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 %.1f deg probe." %expInfo['refOrientation'])
message1.draw()
message2.draw()
fixation.draw()
win.flip()#to show our newly drawn 'stimuli'
#pause until there's a keypress
event.waitKeys()
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)
foil.setPos([-5*targetSide, 0])
target.setPos([5*targetSide, 0]) # in other location
# set orientation of probe
foil.setOri(expInfo['refOrientation'] + thisIncrement)
# draw all stimuli
foil.draw()
target.draw()
fixation.draw()
win.flip()
# wait 500ms; but use a loop of x frames for more accurate timing
core.wait(0.5)
# blank screen
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
# add the data to the staircase so it can calculate the next level
staircase.addData(thisResp)
dataFile.write('%i,%.3f,%i\n' %(targetSide, thisIncrement, thisResp))
core.wait(1)
# staircase has ended
dataFile.close()
staircase.saveAsPickle(fileName) # special python binary file to save all the info
# give some output to user in the command line in the output window
print('reversals:')
print(staircase.reversalIntensities)
approxThreshold = numpy.average(staircase.reversalIntensities[-6:])
print('mean of final 6 reversals = %.3f' % (approxThreshold))
# give some on-screen feedback
feedback1 = visual.TextStim(
win, pos=[0,+3],
text='mean of final 6 reversals = %.3f' % (approxThreshold))
feedback1.draw()
fixation.draw()
win.flip()
event.waitKeys() # wait for participant to respond
win.close()
core.quit()
|