PsychoPy中的可变试验条件

时间:2015-08-27 16:54:35

标签: python psychopy

我在Builder视图中使用PsychoPy版本1.82.01。 我对Python的了解仍然非常有限。我遇到了一个包含任务的障碍,并希望得到社区的任何建议!

任务是这样的:

主题首先呈现两个目标三角形:一个指向左侧,一个指向右侧。指示受试者在发现这些目标中的任何一个时按下相应的左或右箭头键。

Excel条件文件的示例如下所示:

angle_01    angle_02    angle_03    angle_04    corrAns
   0           45          135        180        none
  315          45          135        180        none
  315         225          135        180        none
  270         225          135        180        left
   0          225          135        180        none

**然后向受试者呈现4个三角形的阵列。我在Builder中创建了这4个三角形。每个三角形设置为持续1秒。每个三角形的方向由条件文件确定 - 三角形1方向字段设置为“angle_01”,三角形2方向设置为“angle_02”,依此类推。因此,如果您可以在上面的代码段中看到,我在条件文件中创建了每一行,以便每秒只有一个三角形更改其方向。当其中一个三角形像这样变化时,它被称为“分心器移位”。

在这些分心者转移之后,其中一个三角形移动到“目标”位置(指向左或右,90或270度),此时该人意味着用按键响应。这是“目标转变”。我有Excel条件文件中指定的所有三角形的方向。为了简单起见,我现在把这个集合作为一个顺序循环,具有固定数量的分心器移位。

然而,我的最终目标是在每次试验中在目标转变之前进行可变数量的牵引器移位,并且在进行下一次试验之前,每次试验以固定十字架结束。我很难搞清楚使用什么代码来实现这一目标。我开始让循环随机地通过条件文件,但结果是每个三角形在每个代表处改变其方向(而不是一次只改变一个)。我是以错误的方式解决了这个问题吗?完整代码粘贴在下面。

谢谢!

#!/usr/bin/env python2
# -*- coding: utf-8 -*-
"""
This experiment was created using PsychoPy2 Experiment Builder (v1.82.01), Thu Aug 27 10:56:53 2015
If you publish work using this script please cite the relevant PsychoPy publications
  Peirce, JW (2007) PsychoPy - Psychophysics software in Python. Journal of Neuroscience Methods, 162(1-2), 8-13.
  Peirce, JW (2009) Generating stimuli for neuroscience using PsychoPy. Frontiers in Neuroinformatics, 2:10. doi: 10.3389/neuro.11.010.2008
"""

from __future__ import division  # so that 1/3=0.333 instead of 1/3=0
from psychopy import visual, core, data, event, logging, sound, gui
from psychopy.constants import *  # things like STARTED, FINISHED
import numpy as np  # whole numpy lib is available, prepend 'np.'
from numpy import sin, cos, tan, log, log10, pi, average, sqrt, std, deg2rad, rad2deg, linspace, asarray
from numpy.random import random, randint, normal, shuffle
import os  # handy system and path functions

# Ensure that relative paths start from the same directory as this script
_thisDir = os.path.dirname(os.path.abspath(__file__))
os.chdir(_thisDir)

# Store info about the experiment session
expName = 'simultaneous_04'  # from the Builder filename that created this script
expInfo = {u'session': u'001', u'participant': u''}
dlg = gui.DlgFromDict(dictionary=expInfo, title=expName)
if dlg.OK == False: core.quit()  # user pressed cancel
expInfo['date'] = data.getDateStr()  # add a simple timestamp
expInfo['expName'] = expName

# Data file name stem = absolute path + name; later add .psyexp, .csv, .log, etc
filename = _thisDir + os.sep + 'data/%s_%s_%s' %(expInfo['participant'], expName, expInfo['date'])

# An ExperimentHandler isn't essential but helps with data saving
thisExp = data.ExperimentHandler(name=expName, version='',
    extraInfo=expInfo, runtimeInfo=None,
    originPath=None,
    savePickle=True, saveWideText=True,
    dataFileName=filename)
#save a log file for detail verbose info
logFile = logging.LogFile(filename+'.log', level=logging.EXP)
logging.console.setLevel(logging.WARNING)  # this outputs to the screen, not a file

endExpNow = False  # flag for 'escape' or other condition => quit the exp

# Start Code - component code to be run before the window creation

# Setup the Window
win = visual.Window(size=(1366, 768), fullscr=True, screen=0, allowGUI=False, allowStencil=False,
    monitor='testMonitor', color=[-1,-1,-1], colorSpace='rgb',
    blendMode='avg', useFBO=True,
    )
# store frame rate of monitor if we can measure it successfully
expInfo['frameRate']=win.getActualFrameRate()
if expInfo['frameRate']!=None:
    frameDur = 1.0/round(expInfo['frameRate'])
else:
    frameDur = 1.0/60.0 # couldn't get a reliable measure so guess

# Initialize components for Routine "Target_Presentation"
Target_PresentationClock = core.Clock()
target_triangle = visual.ShapeStim(win=win, name='target_triangle',units='cm', 
    vertices = [[-[5.5,5.89][0]/2.0,-[5.5,5.89][1]/2.0], [+[5.5,5.89][0]/2.0,-[5.5,5.89][1]/2.0], [0,[5.5,5.89][1]/2.0]],
    ori=1.0, pos=[-7, 3],
    lineWidth=1, lineColor=[1,1,1], lineColorSpace='rgb',
    fillColor=[1,1,1], fillColorSpace='rgb',
    opacity=1,depth=0.0, 
interpolate=True)
text_4 = visual.TextStim(win=win, ori=0, name='text_4',
    text='Press the LEFT ARROW key when you spot the triangle pointing to the left.\n\nPress the RIGHT ARROW key when you spot the triangle pointing to the right.\n\nPress the spacebar when you are ready to begin.',    font='Arial',
    pos=[0,-0.5], height=0.08, wrapWidth=None,
    color='white', colorSpace='rgb', opacity=1,
    depth=-1.0)
target_triangle_02 = visual.ShapeStim(win=win, name='target_triangle_02',units='cm', 
    vertices = [[-[5.5,5.89][0]/2.0,-[5.5,5.89][1]/2.0], [+[5.5,5.89][0]/2.0,-[5.5,5.89][1]/2.0], [0,[5.5,5.89][1]/2.0]],
    ori=90, pos=[7,3],
    lineWidth=1, lineColor=[1,1,1], lineColorSpace='rgb',
    fillColor=[1,1,1], fillColorSpace='rgb',
    opacity=1,depth=-2.0, 
interpolate=True)
text_5 = visual.TextStim(win=win, ori=0, name='text_5',
    text='or',    font='Arial',
    pos=[0, 0.25], height=0.1, wrapWidth=None,
    color='white', colorSpace='rgb', opacity=1,
    depth=-3.0)

# Initialize components for Routine "Start_Fixation_Cross"
Start_Fixation_CrossClock = core.Clock()
text_2 = visual.TextStim(win=win, ori=0, name='text_2',
    text='+',    font='Arial',
    pos=[0, 0], height=0.1, wrapWidth=None,
    color='white', colorSpace='rgb', opacity=1,
    depth=0.0)

# Initialize components for Routine "Trial"
TrialClock = core.Clock()


triangle_01 = visual.ShapeStim(win=win, name='triangle_01',units='cm', 
    vertices = [[-[5.5,5.89][0]/2.0,-[5.5,5.89][1]/2.0], [+[5.5,5.89][0]/2.0,-[5.5,5.89][1]/2.0], [0,[5.5,5.89][1]/2.0]],
    ori=1.0, pos=[-8.2,6.2],
    lineWidth=1, lineColor=[1,1,1], lineColorSpace='rgb',
    fillColor=[1,1,1], fillColorSpace='rgb',
    opacity=1,depth=-1.0, 
interpolate=True)
triangle_02 = visual.ShapeStim(win=win, name='triangle_02',units='cm', 
    vertices = [[-[5.5,5.89][0]/2.0,-[5.5,5.89][1]/2.0], [+[5.5,5.89][0]/2.0,-[5.5,5.89][1]/2.0], [0,[5.5,5.89][1]/2.0]],
    ori=1.0, pos=[8.2,6.2],
    lineWidth=1, lineColor=[1,1,1], lineColorSpace='rgb',
    fillColor=[1,1,1], fillColorSpace='rgb',
    opacity=1,depth=-2.0, 
interpolate=True)
triangle_03 = visual.ShapeStim(win=win, name='triangle_03',units='cm', 
    vertices = [[-[5.5,5.89][0]/2.0,-[5.5,5.89][1]/2.0], [+[5.5,5.89][0]/2.0,-[5.5,5.89][1]/2.0], [0,[5.5,5.89][1]/2.0]],
    ori=1.0, pos=[8.2,-6.2],
    lineWidth=1, lineColor=[1,1,1], lineColorSpace='rgb',
    fillColor=[1,1,1], fillColorSpace='rgb',
    opacity=1,depth=-3.0, 
interpolate=True)
triangle_04 = visual.ShapeStim(win=win, name='triangle_04',units='cm', 
    vertices = [[-[5.5,5.89][0]/2.0,-[5.5,5.89][1]/2.0], [+[5.5,5.89][0]/2.0,-[5.5,5.89][1]/2.0], [0,[5.5,5.89][1]/2.0]],
    ori=1.0, pos=[-8.2,-6.2],
    lineWidth=1, lineColor=[1,1,1], lineColorSpace='rgb',
    fillColor=[1,1,1], fillColorSpace='rgb',
    opacity=1,depth=-4.0, 
interpolate=True)

# Initialize components for Routine "Ending"
EndingClock = core.Clock()
text_3 = visual.TextStim(win=win, ori=0, name='text_3',
    text='This concludes the experiment. \n\nThank you for participating!',    font='Arial',
    pos=[0, 0], height=0.1, wrapWidth=None,
    color='white', colorSpace='rgb', opacity=1,
    depth=0.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 Routine "Target_Presentation"-------
t = 0
Target_PresentationClock.reset()  # clock 
frameN = -1
# update component parameters for each repeat
target_triangle.setOri(270)
key_resp_3 = event.BuilderKeyResponse()  # create an object of type KeyResponse
key_resp_3.status = NOT_STARTED
# keep track of which components have finished
Target_PresentationComponents = []
Target_PresentationComponents.append(target_triangle)
Target_PresentationComponents.append(text_4)
Target_PresentationComponents.append(target_triangle_02)
Target_PresentationComponents.append(text_5)
Target_PresentationComponents.append(key_resp_3)
for thisComponent in Target_PresentationComponents:
    if hasattr(thisComponent, 'status'):
        thisComponent.status = NOT_STARTED

#-------Start Routine "Target_Presentation"-------
continueRoutine = True
while continueRoutine:
    # get current time
    t = Target_PresentationClock.getTime()
    frameN = frameN + 1  # number of completed frames (so 0 is the first frame)
    # update/draw components on each frame

    # *target_triangle* updates
    if t >= 0.0 and target_triangle.status == NOT_STARTED:
        # keep track of start time/frame for later
        target_triangle.tStart = t  # underestimates by a little under one frame
        target_triangle.frameNStart = frameN  # exact frame index
        target_triangle.setAutoDraw(True)

    # *text_4* updates
    if t >= 0.0 and text_4.status == NOT_STARTED:
        # keep track of start time/frame for later
        text_4.tStart = t  # underestimates by a little under one frame
        text_4.frameNStart = frameN  # exact frame index
        text_4.setAutoDraw(True)

    # *target_triangle_02* updates
    if t >= 0.0 and target_triangle_02.status == NOT_STARTED:
        # keep track of start time/frame for later
        target_triangle_02.tStart = t  # underestimates by a little under one frame
        target_triangle_02.frameNStart = frameN  # exact frame index
        target_triangle_02.setAutoDraw(True)

    # *text_5* updates
    if t >= 0.0 and text_5.status == NOT_STARTED:
        # keep track of start time/frame for later
        text_5.tStart = t  # underestimates by a little under one frame
        text_5.frameNStart = frameN  # exact frame index
        text_5.setAutoDraw(True)

    # *key_resp_3* updates
    if t >= 0.0 and key_resp_3.status == NOT_STARTED:
        # keep track of start time/frame for later
        key_resp_3.tStart = t  # underestimates by a little under one frame
        key_resp_3.frameNStart = frameN  # exact frame index
        key_resp_3.status = STARTED
        # keyboard checking is just starting
        key_resp_3.clock.reset()  # now t=0
        event.clearEvents(eventType='keyboard')
    if key_resp_3.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_3.keys = theseKeys[-1]  # just the last key pressed
            key_resp_3.rt = key_resp_3.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 Target_PresentationComponents:
        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 "Target_Presentation"-------
for thisComponent in Target_PresentationComponents:
    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()
# the Routine "Target_Presentation" was not non-slip safe, so reset the non-slip timer
routineTimer.reset()

#------Prepare to start Routine "Start_Fixation_Cross"-------
t = 0
Start_Fixation_CrossClock.reset()  # clock 
frameN = -1
routineTimer.add(1.000000)
# update component parameters for each repeat
# keep track of which components have finished
Start_Fixation_CrossComponents = []
Start_Fixation_CrossComponents.append(text_2)
for thisComponent in Start_Fixation_CrossComponents:
    if hasattr(thisComponent, 'status'):
        thisComponent.status = NOT_STARTED

#-------Start Routine "Start_Fixation_Cross"-------
continueRoutine = True
while continueRoutine and routineTimer.getTime() > 0:
    # get current time
    t = Start_Fixation_CrossClock.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  # underestimates by a little under one frame
        text_2.frameNStart = frameN  # exact frame index
        text_2.setAutoDraw(True)
    if text_2.status == STARTED and t >= (0.0 + (1.0-win.monitorFramePeriod*0.75)): #most of one frame period left
        text_2.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 Start_Fixation_CrossComponents:
        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 "Start_Fixation_Cross"-------
for thisComponent in Start_Fixation_CrossComponents:
    if hasattr(thisComponent, "setAutoDraw"):
        thisComponent.setAutoDraw(False)

# set up handler to look after randomisation of conditions etc
TrialLoop = data.TrialHandler(nReps=1, method='sequential', 
    extraInfo=expInfo, originPath=None,
    trialList=data.importConditions('distractor_conditions.xlsx'),
    seed=None, name='TrialLoop')
thisExp.addLoop(TrialLoop)  # add the loop to the experiment
thisTrialLoop = TrialLoop.trialList[0]  # so we can initialise stimuli with some values
# abbreviate parameter names if possible (e.g. rgb=thisTrialLoop.rgb)
if thisTrialLoop != None:
    for paramName in thisTrialLoop.keys():
        exec(paramName + '= thisTrialLoop.' + paramName)

for thisTrialLoop in TrialLoop:
    currentLoop = TrialLoop
    # abbreviate parameter names if possible (e.g. rgb = thisTrialLoop.rgb)
    if thisTrialLoop != None:
        for paramName in thisTrialLoop.keys():
            exec(paramName + '= thisTrialLoop.' + paramName)

    #------Prepare to start Routine "Trial"-------
    t = 0
    TrialClock.reset()  # clock 
    frameN = -1
    routineTimer.add(1.000000)
    # update component parameters for each repeat



    triangle_01.setOri(distractor_angle_01)
    triangle_02.setOri(distractor_angle_02)
    triangle_03.setOri(distractor_angle_03)
    triangle_04.setOri(distractor_angle_04)
    trial_resp = event.BuilderKeyResponse()  # create an object of type KeyResponse
    trial_resp.status = NOT_STARTED
    # keep track of which components have finished
    TrialComponents = []
    TrialComponents.append(triangle_01)
    TrialComponents.append(triangle_02)
    TrialComponents.append(triangle_03)
    TrialComponents.append(triangle_04)
    TrialComponents.append(trial_resp)
    for thisComponent in TrialComponents:
        if hasattr(thisComponent, 'status'):
            thisComponent.status = NOT_STARTED

    #-------Start Routine "Trial"-------
    continueRoutine = True
    while continueRoutine and routineTimer.getTime() > 0:
        # 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




        # *triangle_01* updates
        if t >= 0 and triangle_01.status == NOT_STARTED:
            # keep track of start time/frame for later
            triangle_01.tStart = t  # underestimates by a little under one frame
            triangle_01.frameNStart = frameN  # exact frame index
            triangle_01.setAutoDraw(True)
        if triangle_01.status == STARTED and t >= (0 + (1.0-win.monitorFramePeriod*0.75)): #most of one frame period left
            triangle_01.setAutoDraw(False)

        # *triangle_02* updates
        if t >= 0 and triangle_02.status == NOT_STARTED:
            # keep track of start time/frame for later
            triangle_02.tStart = t  # underestimates by a little under one frame
            triangle_02.frameNStart = frameN  # exact frame index
            triangle_02.setAutoDraw(True)
        if triangle_02.status == STARTED and t >= (0 + (1.0-win.monitorFramePeriod*0.75)): #most of one frame period left
            triangle_02.setAutoDraw(False)

        # *triangle_03* updates
        if t >= 0 and triangle_03.status == NOT_STARTED:
            # keep track of start time/frame for later
            triangle_03.tStart = t  # underestimates by a little under one frame
            triangle_03.frameNStart = frameN  # exact frame index
            triangle_03.setAutoDraw(True)
        if triangle_03.status == STARTED and t >= (0 + (1.0-win.monitorFramePeriod*0.75)): #most of one frame period left
            triangle_03.setAutoDraw(False)

        # *triangle_04* updates
        if t >= 0 and triangle_04.status == NOT_STARTED:
            # keep track of start time/frame for later
            triangle_04.tStart = t  # underestimates by a little under one frame
            triangle_04.frameNStart = frameN  # exact frame index
            triangle_04.setAutoDraw(True)
        if triangle_04.status == STARTED and t >= (0 + (1.0-win.monitorFramePeriod*0.75)): #most of one frame period left
            triangle_04.setAutoDraw(False)

        # *trial_resp* updates
        if t >= 0.0 and trial_resp.status == NOT_STARTED:
            # keep track of start time/frame for later
            trial_resp.tStart = t  # underestimates by a little under one frame
            trial_resp.frameNStart = frameN  # exact frame index
            trial_resp.status = STARTED
            # keyboard checking is just starting
            trial_resp.clock.reset()  # now t=0
            event.clearEvents(eventType='keyboard')
        if trial_resp.status == STARTED and t >= (0.0 + (1.0-win.monitorFramePeriod*0.75)): #most of one frame period left
            trial_resp.status = STOPPED
        if trial_resp.status == STARTED:
            theseKeys = event.getKeys(keyList=['left', 'right'])

            # check for quit:
            if "escape" in theseKeys:
                endExpNow = True
            if len(theseKeys) > 0:  # at least one key was pressed
                trial_resp.keys = theseKeys[-1]  # just the last key pressed
                trial_resp.rt = trial_resp.clock.getTime()
                # was this 'correct'?
                if (trial_resp.keys == str(corrAns)) or (trial_resp.keys == corrAns):
                    trial_resp.corr = 1
                else:
                    trial_resp.corr = 0

        # 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()

    #-------Ending Routine "Trial"-------
    for thisComponent in TrialComponents:
        if hasattr(thisComponent, "setAutoDraw"):
            thisComponent.setAutoDraw(False)

    # check responses
    if trial_resp.keys in ['', [], None]:  # No response was made
       trial_resp.keys=None
       # was no response the correct answer?!
       if str(corrAns).lower() == 'none': trial_resp.corr = 1  # correct non-response
       else: trial_resp.corr = 0  # failed to respond (incorrectly)
    # store data for TrialLoop (TrialHandler)
    TrialLoop.addData('trial_resp.keys',trial_resp.keys)
    TrialLoop.addData('trial_resp.corr', trial_resp.corr)
    if trial_resp.keys != None:  # we had a response
        TrialLoop.addData('trial_resp.rt', trial_resp.rt)
    thisExp.nextEntry()

# completed 1 repeats of 'TrialLoop'


#------Prepare to start Routine "Ending"-------
t = 0
EndingClock.reset()  # clock 
frameN = -1
routineTimer.add(3.000000)
# update component parameters for each repeat
# keep track of which components have finished
EndingComponents = []
EndingComponents.append(text_3)
for thisComponent in EndingComponents:
    if hasattr(thisComponent, 'status'):
        thisComponent.status = NOT_STARTED

#-------Start Routine "Ending"-------
continueRoutine = True
while continueRoutine and routineTimer.getTime() > 0:
    # get current time
    t = EndingClock.getTime()
    frameN = frameN + 1  # number of completed frames (so 0 is the first frame)
    # update/draw components on each frame

    # *text_3* updates
    if t >= 0.0 and text_3.status == NOT_STARTED:
        # keep track of start time/frame for later
        text_3.tStart = t  # underestimates by a little under one frame
        text_3.frameNStart = frameN  # exact frame index
        text_3.setAutoDraw(True)
    if text_3.status == STARTED and t >= (0.0 + (3.0-win.monitorFramePeriod*0.75)): #most of one frame period left
        text_3.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 EndingComponents:
        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 "Ending"-------
for thisComponent in EndingComponents:
    if hasattr(thisComponent, "setAutoDraw"):
        thisComponent.setAutoDraw(False)

win.close()
core.quit()

1 个答案:

答案 0 :(得分:0)

Excel条件文件的布局可能需要稍微更改一下。 PsychoPy的结构是将该文件中的每一行视为与试验相对应,而您目前正在跨多行传播试验。这将使得通过相应的刺激适当地存储和收集响应变得更加困难。建议你这样做:

numShifts     angle_01         angle_02
4             [0,315,315,270]  [45,45,225,225]
3             [0,45,315]        [45,45,90]
etc

然后在Builder中,在现有循环中插入一个新循环。

重要的是:取消选中“is trials”复选框。这意味着这个循环将在一次试验中多次运行,但是这个特定试验需要多次转换刺激。

让我们调用内部stimulusLoop和外部试用级循环trialLoop)。即trialLoop每次试验只运行一次,处理一行条件文件。 stimulusLoop将在试验中提取每个刺激的角度列表的每个条目。要实现此目的,请将numShift放在内循环的nReps字段中。例如给定上面的条件文件,它将在第一次试验中运行4次,在第二次试验中运行3次。

然后在每个刺激的方向领域,放置这样的东西(未经测试):

eval(angle_01)[stimulusLoop.thisN]

这样做是评估角度列表(当它被读入时,PsychoPy认为它是字符列表"[0,315,315,270]"eval()函数告诉它将它评估为Python表达式在这种情况下,它会意识到它是一个数字列表,然后我们可以将其索引以获取当前值,在这种情况下使用内部循环的当前迭代次数(stimulusLoop.thisN)。

希望这会让你开始。