Hi, I am building a SNR adaptive staircase whereby participants have to select the stimulus they heard (randomly chosen & then mixed with noise at different dB) using the following snippet of code: (I have bolded the staircase-relevant parts of code, the rest is just initialising the stimuli etc)
n_reversals_total = 20
threshold = []
def getstaircase(startVal):
return data.staircase.StairHandler(startVal, stepSizes=[2],
maxVal=10, minVal=-10, nDown=1, nUp=1,
nTrials=8, nReversals=n_reversals_total, stepType='lin')
#Check for key press
event.waitKeys()
Parameters_file = pd.read_csv('Parameters.csv')
Pair_list = Parameters_file.ix[1]
syllable_list = Parameters_file.ix[0]
corr_Ans_list = Parameters_file.ix[2]
Block1 = getstaircase(-10)
thisExp.addLoop(Block1) # add the loop to the experiment
#condition = Block1.currentStaircase.condition
#thisBlock1 = Block1.trialList[0] # so we can initialise stimuli with some values
# abbreviate parameter names if possible (e.g. rgb = thisBlock1.rgb)
#if thisBlock1 != None:
#for paramName in thisBlock1:
#exec('{} = thisBlock1[paramName]'.format(paramName))
for increment in Block1:
currentloop = Block1
# abbreviate parameter names if possible (e.g. rgb = thisBlock1.rgb)b
#if thisBlock1 != None:
#for paramName in thisBlock1:
#exec('{} = thisBlock1[paramName]'.format(paramName))
# ------Prepare to start Routine "Trial"-------
continueRoutine = True
# update component parameters for each repeat
trial_index = randint(6)
Pair = Pair_list[trial_index]
corrAns = corr_Ans_list[trial_index]
key_resp.keys = []
key_resp.rt = []
_key_resp_allKeys = []
text.setText(Pair
)
shuffled_syllable = syllable_list[trial_index]
level = Block1.calculateNextIntensity()
path = '/Desktop/SNR_list'
filename = os.path.join(path, str(level) +'.mat')
Stimulus = scipy.io.loadmat(filename)
Stimulus = Stimulus + shuffled_syllable
sound_1.setSound(Stimulus, hamming=True)
sound_1.setVolume(1, log=False)
# keep track of which components have finished
TrialComponents = [key_resp, text, sound_1]
for thisComponent in TrialComponents:
thisComponent.tStart = None
thisComponent.tStop = None
thisComponent.tStartRefresh = None
thisComponent.tStopRefresh = None
if hasattr(thisComponent, 'status'):
thisComponent.status = NOT_STARTED
# reset timers
t = 0
_timeToFirstFrame = win.getFutureFlipTime(clock="now")
TrialClock.reset(-_timeToFirstFrame) # t0 is time of first possible flip
frameN = -1
# -------Run Routine "Trial"-------
while continueRoutine:
# get current time
t = TrialClock.getTime()
tThisFlip = win.getFutureFlipTime(clock=TrialClock)
tThisFlipGlobal = win.getFutureFlipTime(clock=None)
frameN = frameN + 1 # number of completed frames (so 0 is the first frame)
# update/draw components on each frame
# *key_resp* updates
waitOnFlip = False
if key_resp.status == NOT_STARTED and tThisFlip >= 0.1-frameTolerance:
# keep track of start time/frame for later
key_resp.frameNStart = frameN # exact frame index
key_resp.tStart = t # local t and not account for scr refresh
key_resp.tStartRefresh = tThisFlipGlobal # on global time
win.timeOnFlip(key_resp, 'tStartRefresh') # time at next scr refresh
key_resp.status = STARTED
# keyboard checking is just starting
waitOnFlip = True
win.callOnFlip(key_resp.clock.reset) # t=0 on next screen flip
win.callOnFlip(key_resp.clearEvents, eventType='keyboard') # clear events on next screen flip
if key_resp.status == STARTED:
# is it time to stop? (based on global clock, using actual start)
if tThisFlipGlobal > key_resp.tStartRefresh + 2.5-frameTolerance:
# keep track of stop time/frame for later
key_resp.tStop = t # not accounting for scr refresh
key_resp.frameNStop = frameN # exact frame index
win.timeOnFlip(key_resp, 'tStopRefresh') # time at next scr refresh
key_resp.status = FINISHED
if key_resp.status == STARTED and not waitOnFlip:
theseKeys = key_resp.getKeys(keyList=['left', 'right'], waitRelease=False)
_key_resp_allKeys.extend(theseKeys)
if len(_key_resp_allKeys):
key_resp.keys = _key_resp_allKeys[-1].name # just the last key pressed
key_resp.rt = _key_resp_allKeys[-1].rt
# was this correct?
if (key_resp.keys == str(corrAns)) or (key_resp.keys == corrAns):
key_resp.corr = 1
else:
key_resp.corr = 0
# a response ends the routine
continueRoutine = False
# *text* updates
if text.status == NOT_STARTED and tThisFlip >= 0.0-frameTolerance:
# keep track of start time/frame for later
text.frameNStart = frameN # exact frame index
text.tStart = t # local t and not account for scr refresh
text.tStartRefresh = tThisFlipGlobal # on global time
win.timeOnFlip(text, 'tStartRefresh') # time at next scr refresh
text.setAutoDraw(True)
if text.status == STARTED:
# is it time to stop? (based on global clock, using actual start)
if tThisFlipGlobal > text.tStartRefresh + 2.5-frameTolerance:
# keep track of stop time/frame for later
text.tStop = t # not accounting for scr refresh
text.frameNStop = frameN # exact frame index
win.timeOnFlip(text, 'tStopRefresh') # time at next scr refresh
text.setAutoDraw(False)
# start/stop sound_1
if sound_1.status == NOT_STARTED and tThisFlip >= 0.1-frameTolerance:
# keep track of start time/frame for later
sound_1.frameNStart = frameN # exact frame index
sound_1.tStart = t # local t and not account for scr refresh
sound_1.tStartRefresh = tThisFlipGlobal # on global time
sound_1.play(when=win) # sync with win flip
# check for quit (typically the Esc key)
if endExpNow or defaultKeyboard.getKeys(keyList=["escape"]):
core.quit()
# check if all components have finished
if not continueRoutine: # a component has requested a forced-end of Routine
break
continueRoutine = False # will revert to True if at least one component still running
for thisComponent in TrialComponents:
if hasattr(thisComponent, "status") and thisComponent.status != FINISHED:
continueRoutine = True
break # at least one component has not yet finished
# refresh the screen
if continueRoutine: # don't flip if this routine is over or we'll get a blank screen
win.flip()
# -------Ending Routine "Trial" & adding results to staircase-------
for thisComponent in TrialComponents:
if hasattr(thisComponent, "setAutoDraw"):
thisComponent.setAutoDraw(False)
sound_1.stop()
Block1.addOtherData('sound_1.started', sound_1.tStartRefresh)
Block1.addOtherData('sound_1.stopped', sound_1.tStopRefresh)
# check response
thisResponse = None
while thisResponse is None:
allKeys = key_resp.keys
for thisKey in allKeys:
if thisKey in ['', [], None]: # No response was made
thisKey = None
elif (thisKey == str(corrAns)) or (thisKey == corrAns):
thisResponse = 1
elif (thisKey != str(corrAns)) or (thisKey != corrAns):
thisResponse = 0
Block1.addResponse(thisResponse)
Block1.addOtherData('key_resp.rt',key_resp.rt)
Block1.addOtherData('key_resp.started',key_resp.tStartRefresh)
Block1.addOtherData('key_resp.stopped',key_resp.tStopRefresh)
Block1.addOtherData('Syllable_played', shuffled_syllable)
Block1.addOtherData('SNR_played', SNR)
Block1.addOtherData('Reversal_intensities', staircase.reversalIntensities)
# store data for Block1 (TrialHandler)
threshold += np.average(Block1.reversalIntensities)
# the Routine "Trial" was not non-slip safe, so reset the non-slip timer
routineTimer.reset()
However, psychopy tells me I have an error in the function calculateNextIntensity in the following code. I am assuming that this is not actually an error in the function but a consequence of something going wrong with my staircase code but cannot figure out what it is. Thank you!
if self.data[-1] == 1: # last answer correct
# got it right
if self.currentDirection == 'up':
reversal = True
The exact error message is:
Traceback (most recent call last):
File "/Users/emilia/Desktop/Staircase/staircase_trial.py", line 1460, in <module>
level = Block1.calculateNextIntensity()
File "/Applications/PsychoPy3.app/Contents/Resources/lib/python3.6/psychopy/data/staircase.py", line 282, in calculateNextIntensity
if self.data[-1] == 1: # last answer correct
IndexError: list index out of range