Hi,
So I have an experiment which records BOTH the onset of stimuli (currently relative to the trial) AND keyboard inputs (reaction time). The reaction time has been built in the builder with the presentation of stimuli a mix between inputted code and builder. The loop consists of 2 routines (fixation and trial), the first being a simple fixation target presented for 1 second using the routineTimer code. The second routine consists of a presented arithmetic sum with coinciding flashing squares.
The problem is this, the presentation of the stimuli is recorded relative to the start of the second routine Trial. The reaction time is recorded to what appears to be the start of the loop. Looking at reaction time code, it records name.clock.getTime(), however the name.clock is not defined anywhere previously. I can only assume it is encapsulated in the BuilderKeyResponse which the builder view uses to generate keyboard responses. Further I cannot get a clock to start from the start of a loop to match the reaction time clock. The difference between the two is 2 seconds, and the reaction time clock is accurate, there are definite 2 seconds between start of the loop and first stimuli presentation.
I have attempted to put any clock at the beginning of the 1st routine and it is about a second off, as it is when placed in the loop statement. The only way I have matched the reaction time clock is by using the global.Clock, for some reason this records the same start time, but I cannot reset it for each loop in the right place making it not possible to compare. When trying to alter the reaction time clocks, very strange things happen, if using the global.Clock for both stimuli and reaction time for some bizarre reason the original 2 second gaps returns. I can get them to match if I replace the default clock in the reaction time statements with ‘t’ and use a clock at the start of the loop for the stimuli.
This creates a situation where the reaction time reduces by 1 second and the stimuli increase by 1 second. I attach the code below, I’ve included a lot as the key areas are over several large sections.
# Create some handy timers
globalClock = core.Clock() # to track the time since experiment started
routineTimer = core.CountdownTimer() # to track time remaining of each (non-slip) routine
# ------Prepare to start Routine "setup_and_instructions"-------
t = 0
setup_and_instructionsClock.reset() # clock
frameN = -1
continueRoutine = True
# update component parameters for each repeat
key_resp_2 = event.BuilderKeyResponse()
# keep track of which components have finished
setup_and_instructionsComponents = [text_2, key_resp_2]
for thisComponent in setup_and_instructionsComponents:
if hasattr(thisComponent, 'status'):
thisComponent.status = NOT_STARTED
# -------Start Routine "setup_and_instructions"-------
while continueRoutine:
# get current time
t = setup_and_instructionsClock.getTime()
frameN = frameN + 1 # number of completed frames (so 0 is the first frame)
# update/draw components on each frame
# *text_2* updates
if t >= 0.0 and text_2.status == NOT_STARTED:
# keep track of start time/frame for later
text_2.tStart = t
text_2.frameNStart = frameN # exact frame index
text_2.setAutoDraw(True)
# *key_resp_2* updates
if t >= 0.0 and key_resp_2.status == NOT_STARTED:
# keep track of start time/frame for later
key_resp_2.tStart = t
key_resp_2.frameNStart = frameN # exact frame index
key_resp_2.status = STARTED
# keyboard checking is just starting
win.callOnFlip(key_resp_2.clock.reset) # t=0 on next screen flip
event.clearEvents(eventType='keyboard')
if key_resp_2.status == STARTED:
theseKeys = event.getKeys(keyList=['space'])
# check for quit:
if "escape" in theseKeys:
endExpNow = True
if len(theseKeys) > 0: # at least one key was pressed
key_resp_2.keys = theseKeys[-1] # just the last key pressed
key_resp_2.rt = key_resp_2.clock.getTime()
# a response ends the routine
continueRoutine = False
# 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 setup_and_instructionsComponents:
if hasattr(thisComponent, "status") and thisComponent.status != FINISHED:
continueRoutine = True
break # at least one component has not yet finished
# check for quit (the Esc key)
if endExpNow or event.getKeys(keyList=["escape"]):
core.quit()
# refresh the screen
if continueRoutine: # don't flip if this routine is over or we'll get a blank screen
win.flip()
# -------Ending Routine "setup_and_instructions"-------
for thisComponent in setup_and_instructionsComponents:
if hasattr(thisComponent, "setAutoDraw"):
thisComponent.setAutoDraw(False)
# check responses
if key_resp_2.keys in ['', [], None]: # No response was made
key_resp_2.keys=None
thisExp.addData('key_resp_2.keys',key_resp_2.keys)
if key_resp_2.keys != None: # we had a response
thisExp.addData('key_resp_2.rt', key_resp_2.rt)
thisExp.nextEntry()
# the Routine "setup_and_instructions" was not non-slip safe, so reset the non-slip timer
routineTimer.reset()
# set up handler to look after randomisation of conditions etc
trials = data.TrialHandler(nReps=1, method='random',
extraInfo=expInfo, originPath=-1,
trialList=data.importConditions('ConduciveA.xlsx'),
seed=None, name='trials')
thisExp.addLoop(trials) # add the loop to the experiment
thisTrial = trials.trialList[0] # so we can initialise stimuli with some values
# abbreviate parameter names if possible (e.g. rgb = thisTrial.rgb)
if thisTrial != None:
for paramName in thisTrial.keys():
exec(paramName + '= thisTrial.' + paramName)
for thisTrial in trials:
currentLoop = trials
# abbreviate parameter names if possible (e.g. rgb = thisTrial.rgb)
if thisTrial != None:
for paramName in thisTrial.keys():
exec(paramName + '= thisTrial.' + paramName)
# ------Prepare to start Routine "Fixation_2"-------
t = 0
Fixation_2Clock.reset() # clock
frameN = -1
continueRoutine = True
routineTimer.add(1.000000)
# update component parameters for each repeat
trialsrun += 1
# keep track of which components have finished
Fixation_2Components = [Fixation]
for thisComponent in Fixation_2Components:
if hasattr(thisComponent, 'status'):
thisComponent.status = NOT_STARTED
# -------Start Routine "Fixation_2"-------
while continueRoutine and routineTimer.getTime() > 0:
# get current time
t = Fixation_2Clock.getTime()
frameN = frameN + 1 # number of completed frames (so 0 is the first frame)
# update/draw components on each frame
# *Fixation* updates
if t >= 0.0 and Fixation.status == NOT_STARTED:
# keep track of start time/frame for later
Fixation.tStart = t
Fixation.frameNStart = frameN # exact frame index
Fixation.setAutoDraw(True)
frameRemains = 0.0 + 1- win.monitorFramePeriod * 0.75 # most of one frame period left
if Fixation.status == STARTED and t >= frameRemains:
Fixation.setAutoDraw(False)
# 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 Fixation_2Components:
if hasattr(thisComponent, "status") and thisComponent.status != FINISHED:
continueRoutine = True
break # at least one component has not yet finished
# check for quit (the Esc key)
if endExpNow or event.getKeys(keyList=["escape"]):
core.quit()
# refresh the screen
if continueRoutine: # don't flip if this routine is over or we'll get a blank screen
win.flip()
# -------Ending Routine "Fixation_2"-------
for thisComponent in Fixation_2Components:
if hasattr(thisComponent, "setAutoDraw"):
thisComponent.setAutoDraw(False)
# ------Prepare to start Routine "trial"-------
t = 0
trialClock.reset() # clock
frameN = -1
continueRoutine = True
# update component parameters for each repeat
stimulus = [UL, UM, UR, BL, BM, BR]
continuerout = 1
framenum = 0
Arithmetic.setText(Conducive)
solved_arithmetic = event.BuilderKeyResponse()
N_back_detect = event.BuilderKeyResponse()
arith_ans = event.BuilderKeyResponse()
experimenter_ends = event.BuilderKeyResponse()
# keep track of which components have finished
trialComponents = [UL, UM, UR, BL, BM, BR, Arithmetic, solved_arithmetic, N_back_detect, arith_ans, experimenter_ends]
for thisComponent in trialComponents:
if hasattr(thisComponent, 'status'):
thisComponent.status = NOT_STARTED
# -------Start Routine "trial"-------
while continueRoutine:
# get current time
t = trialClock.getTime()
frameN = frameN + 1 # number of completed frames (so 0 is the first frame)
# update/draw components on each frame
# *UL* updates
if t >= 0.0 and UL.status == NOT_STARTED:
# keep track of start time/frame for later
UL.tStart = t
UL.frameNStart = frameN # exact frame index
UL.setAutoDraw(True)
# *UM* updates
if t >= 0.0 and UM.status == NOT_STARTED:
# keep track of start time/frame for later
UM.tStart = t
UM.frameNStart = frameN # exact frame index
UM.setAutoDraw(True)
# *UR* updates
if t >= 0.0 and UR.status == NOT_STARTED:
# keep track of start time/frame for later
UR.tStart = t
UR.frameNStart = frameN # exact frame index
UR.setAutoDraw(True)
# *BL* updates
if t >= 0.0 and BL.status == NOT_STARTED:
# keep track of start time/frame for later
BL.tStart = t
BL.frameNStart = frameN # exact frame index
BL.setAutoDraw(True)
# *BM* updates
if t >= 0.0 and BM.status == NOT_STARTED:
# keep track of start time/frame for later
BM.tStart = t
BM.frameNStart = frameN # exact frame index
BM.setAutoDraw(True)
# *BR* updates
if t >= 0.0 and BR.status == NOT_STARTED:
# keep track of start time/frame for later
BR.tStart = t
BR.frameNStart = frameN # exact frame index
BR.setAutoDraw(True)
if frameN == 0:
flasher = 0
ExLog = [] #create blank list to record ordered stimulus / time pairs for presentation changes
#when forcing 1-back or 2-back contingencies (e.g. after 6 stimuli). Have to record time or else contingency statement won't work.
StimLog = [] # create a blank list of flasher-name/time pairs for sending to excel file
if frameN > 0 and frameN < 10 and frameN %2 > 0: #getting all of the odd frames between 1 and 9
flasher = random.choice(stimulus)
flasher.setColor([1.0, -1.0, -1.0], colorSpace='rgb')
#when flasher gets assigned a random stimulus, append list (with the chosen stimulus as the first element and corresponding time as the second element) to the Experiment log list.
ExLog.append([flasher,t])
StimLog.append([flasher.name,t]) # flahser.name = 'UL, BR etc'. Flasher.name can be sent to excel file, flasher cannot.
time.sleep(1)
if frameN > 0 and frameN < 11 and frameN %2 == 0: #get all even framesbetween 1 and 10. Doesn't record anything about forcing flasher to go white
flasher.setColor([1.0, 1.0, 1.0], colorSpace='rgb')
time.sleep(1)
#Code to identify whether 6th trial needs to be forced or not
if frameN == 10:
fcheck = False # variable to say whether 1 or 2 back event has happened
for i in range(len(ExLog)-1): #length of Exlog is 4 (python starts at zero). There are 5 items in ExLog, the 5th item
#cannot be evaluated because 6th hasn't been defined. So for the 4 items do the check.
if ExLog[i][0] == ExLog[i+1][0]:#for each flasher.name, ignoring time, is the same as the one that follows, fcheck is true
fcheck = True
if frameN == 11: #contingency for the 6th stimulus
if fcheck == True:# if detection event has happened, continue at random as normal
flasher = random.choice(stimulus)
flasher.setColor([1.0, -1.0, -1.0], colorSpace='rgb')
#when flasher gets assigned a random stimulus, append list (with the chosen stimulus as the first element and corresponding time as the second element) to the Experiment log list.
ExLog.append([flasher,t])
StimLog.append([flasher.name,t]) # flahser.name = 'UL, BR etc'. Flasher.name can be sent to excel file, flasher cannot.
time.sleep(1)
else:
flasher = ExLog[4][0] #if detection event hasn't happened, take the 5th stimulus presented and flash it again
flasher.setColor([1.0, -1.0, -1.0], colorSpace='rgb')
#when flasher gets assigned a random stimulus, append list (with the chosen stimulus as the first element and corresponding time as the second element) to the Experiment log list.
ExLog.append([flasher,t])
StimLog.append([flasher.name,t]) # flahser.name = 'UL, BR etc'. Flasher.name can be sent to excel file, flasher cannot.
time.sleep(1)
# After the fcheck period, continue the routine as normal
if frameN > 11 and frameN %2 == 0: #get all even framesbetween 1 and 10. Doesn't record anything about forcing flasher to go white
flasher.setColor([1.0, 1.0, 1.0], colorSpace='rgb')
time.sleep(1)
if frameN > 11 and frameN %2 > 0: #getting all of the odd frames between 1 and 9
flasher = random.choice(stimulus)
flasher.setColor([1.0, -1.0, -1.0], colorSpace='rgb')
#when flasher gets assigned a random stimulus, append list (with the chosen stimulus as the first element and corresponding time as the second element) to the Experiment log list.
ExLog.append([flasher,t])
StimLog.append([flasher.name,t]) # flahser.name = 'UL, BR etc'. Flasher.name can be sent to excel file, flasher cannot.
time.sleep(1)
# *Arithmetic* updates
if frameN >= 3 and Arithmetic.status == NOT_STARTED:
# keep track of start time/frame for later
Arithmetic.tStart = t
Arithmetic.frameNStart = frameN # exact frame index
Arithmetic.setAutoDraw(True)
# *solved_arithmetic* updates
if t >= 0.0 and solved_arithmetic.status == NOT_STARTED:
# keep track of start time/frame for later
solved_arithmetic.tStart = t
solved_arithmetic.frameNStart = frameN # exact frame index
solved_arithmetic.status = STARTED
# keyboard checking is just starting
win.callOnFlip(solved_arithmetic.clock.reset) # t=0 on next screen flip
event.clearEvents(eventType='keyboard')
if solved_arithmetic.status == STARTED:
theseKeys = event.getKeys(keyList=['space'])
# check for quit:
if "escape" in theseKeys:
endExpNow = True
if len(theseKeys) > 0: # at least one key was pressed
solved_arithmetic.keys = theseKeys[-1] # just the last key pressed
solved_arithmetic.rt = solved_arithmetic.clock.getTime()
# *N_back_detect* updates
if t >= 0.0 and N_back_detect.status == NOT_STARTED:
# keep track of start time/frame for later
N_back_detect.tStart = t
N_back_detect.frameNStart = frameN # exact frame index
N_back_detect.status = STARTED
# keyboard checking is just starting
win.callOnFlip(N_back_detect.clock.reset) # t=0 on next screen flip
event.clearEvents(eventType='keyboard')
if N_back_detect.status == STARTED:
theseKeys = event.getKeys(keyList=['backspace'])
# check for quit:
if "escape" in theseKeys:
endExpNow = True
if len(theseKeys) > 0: # at least one key was pressed
N_back_detect.keys.extend(theseKeys) # storing all keys
N_back_detect.rt.append(N_back_detect.clock.getTime())
# *arith_ans* updates
if t >= 0.0 and arith_ans.status == NOT_STARTED:
# keep track of start time/frame for later
arith_ans.tStart = t
arith_ans.frameNStart = frameN # exact frame index
arith_ans.status = STARTED
# keyboard checking is just starting
win.callOnFlip(arith_ans.clock.reset) # t=0 on next screen flip
event.clearEvents(eventType='keyboard')
if arith_ans.status == STARTED:
theseKeys = event.getKeys(keyList=['num_1', 'num_2', 'num_3', 'num_4', 'num_5', 'num_6', 'num_7', 'num_8', 'num_9', 'num_0'])
# check for quit:
if "escape" in theseKeys:
endExpNow = True
if len(theseKeys) > 0: # at least one key was pressed
arith_ans.keys.extend(theseKeys) # storing all keys
arith_ans.rt.append(arith_ans.clock.getTime())
# *experimenter_ends* updates
if t >= 0.0 and experimenter_ends.status == NOT_STARTED:
# keep track of start time/frame for later
experimenter_ends.tStart = t
experimenter_ends.frameNStart = frameN # exact frame index
experimenter_ends.status = STARTED
# keyboard checking is just starting
win.callOnFlip(experimenter_ends.clock.reset) # t=0 on next screen flip
event.clearEvents(eventType='keyboard')
if experimenter_ends.status == STARTED:
theseKeys = event.getKeys(keyList=['enter', 'return'])
# check for quit:
if "escape" in theseKeys:
endExpNow = True
if len(theseKeys) > 0: # at least one key was pressed
experimenter_ends.keys = theseKeys[-1] # just the last key pressed
experimenter_ends.rt = experimenter_ends.clock.getTime()
# a response ends the routine
continueRoutine = False
# 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
# check for quit (the Esc key)
if endExpNow or event.getKeys(keyList=["escape"]):
core.quit()
# refresh the screen
if continueRoutine: # don't flip if this routine is over or we'll get a blank screen
win.flip()