基于Psychopy的语音感知实验操作示例

PsychoPy 是一个功能强大的工具,用于创建和运行心理学实验。它提供了直观的图形用户界面(Builder)和灵活的编程环境(Coder),使得无论是没有编程经验的初学者,还是需要高级控制的研究者,都能够方便地设计复杂的实验。本文将介绍PsychoPy的主要页面及其功能,并且给出一个基于Psychopy的语音感知实验操作示例。

页面介绍

1. 启动PsychoPy

当你启动PsychoPy时,会看到以下界面:

  • Builder视图:用于图形化地创建实验。
  • Coder视图:用于编写自定义代码。
  • Runner视图:用于运行和监控实验。

默认情况下,PsychoPy会打开Builder视图。

2. Builder视图

Builder视图是PsychoPy的核心功能区,提供了一个直观的图形化界面,用户可以通过拖放组件来设计实验。

2.1 工具栏

工具栏提供了一些常用功能的快捷方式。

image-ifya.png

2.2 流程(Flow)

image-wewv.png

流程区域显示实验的整体结构,通过将例程或循环 拖放到流程中,用户可以设置实验的顺序和循环。每个例程代表实验中的一个步骤或阶段。

2.3 例程编辑器(Routine Editor)

例程编辑器用于设计每个实验阶段的具体内容。用户可以在例程中添加各种刺激和响应组件,例如文本、图片、声音、键盘响应等。每个组件都有详细的属性设置,可以精确控制其显示和行为。

3. 主要组件介绍

PsychoPy的Builder视图提供了多种组件,用于创建不同类型的实验内容。以下是一些常用组件的介绍:

  • 文本组件(Text)用于在屏幕上显示文本。
  • 图片组件(Image)用于在屏幕上显示图片。
  • 声音组件(Sound)用于播放声音。
  • 键盘响应组件(Keyboard)用于记录参与者的按键响应。
  • 代码组件(Code)用于设置一些复杂的实验逻辑。

这些组件一般都涉及以下基础设置:
名称(Name):组件的名称,用于在代码和其他设置中引用该组件。

  • 起始时间(Start)
  • 时间(s):组件开始的时间,以秒为单位。
  • 结束时间(Stop)
  • 持续时间(s):组件的持续时间。
    在此处不展开叙述各个组件的特性设置,在后文操作步骤中会详细叙述。

屏幕单位

在PsychoPy中,坐标系统的设置取决于你选择的单位和实验的需求。PsychoPy支持多种单位系统,包括像素('pix')、归一化('norm')、高度('height')和度('deg')等,每种单位系统对坐标的解释都有所不同。下面是关于这些单位系统及其坐标设置的一些详细信息:

  1. 像素 ('pix'):

    • 这是最直接的单位,坐标原点在窗口中心,向右和向上为正方向。例如,一个1920x1080的窗口中,原点为(0, 0),右上角为(960, 540)。
  2. 归一化 ('norm'):

    • 在这个单位系统中,坐标原点同样位于窗口中心,但每个轴的范围从-1到1,不论窗口的实际尺寸。例如,右上角的坐标是(1, 1),左下角是(-1, -1)。
  3. 高度 ('height')⭐:

    • 这个单位基于窗口的高度,保持高度为1单位,宽度根据窗口比例自动调整。原点位于窗口中心,顶部中心坐标为(0, 0.5)。
  4. 度 ('deg'):

    • 用于视觉实验,假设观察者位于屏幕的正中央,屏幕距离适当。单位是视觉角度,常用于视觉刺激的呈现。

设置坐标时,你可以根据实验的设计和需要选择最合适的单位。例如,如果你正在做一个视觉搜索任务,可能会使用'pix'或'deg'单位以获得更精确的控制。一般来说,使用height或norm对不同屏幕的兼容性最好。

使用 normheight作为单位时,字符高度设置为0.05表示字符高度为屏幕高度的5%。norm单位通常用于定义相对于屏幕尺寸的位置和尺寸,使得实验在不同分辨率下具有一致的比例。

更改默认单位

如果你需要更改默认单位,可以按照以下步骤操作:

  1. 在PsychoPy Builder中:

    • 打开实验设置(Experiment Settings)。

    image-ntaf.png

  • 在“通用” 选项卡中,你可以找到“Units” 设置。

  • 从下拉菜单中选择所需的单位,本案例选择 height

    image-gtka.png

收集参与者信息

设置实验信息对话框

  1. 打开实验设置

    • 在PsychoPy Builder模式中,点击顶部菜单栏中的“实验设置”按钮(齿轮图标)。

    image-gpgi.png

  2. 添加实验信息字段

  • 在弹出的对话框中,找到“实验信息”部分。

  • 在“Field”列中添加需要收集的信息字段名称,例如“sex”(性别)和“age”(年龄)。

  • 在“默认”列中可以设置默认值或者留空。

    image-mdhc.png

配置实验信息字段

  1. 性别字段设置

    • 在“Field”中添加sex,表示需要收集被试的性别。
    • 默认值可以留空。
  2. 年龄字段设置

    • 在“Field”中添加age,表示需要收集被试的年龄。
    • 默认值同样可以留空。

实操:一个辨认实验的预实验流程

本实验旨在研究参与者在不同刺激条件下的反应时间。实验流程包括指示页面、凝视点显示、实验刺激呈现和反馈阶段。以下是实验各个步骤的详细描述。

流程概述

image-fkes.png

  1. Instruction 1 (指示页面)
    • 参与者首先看到一段指示文字,解释实验任务并指导他们按空格键开始实验。
    • 这个阶段使用了文本刺激(instruction_1)和键盘响应(key_intro_start)来控制实验开始。
  2. Fixation Point (注视点)
    • 在每个实验试次开始前,屏幕中央会显示一个凝视点“+”,确保参与者的注意力集中。
    • 这个阶段持续2秒左右,包含一个声音提示(beep),视觉凝视点(fixation)和一个预实验声音(sound_pre)。
  3. Pre-experiment Trials (预实验试次)
    • 在正式实验开始前,参与者会进行一些预实验试次,以熟悉实验流程和任务。
    • 这一阶段包括两个文本刺激(leftText_prerightText_pre)分别显示在屏幕的左侧和右侧,以及一个键盘响应(practice_resp)来记录参与者的反应。
    • 代码组件(code_pre)用于计算和评估参与者的反应时间,并生成反馈信息。
  4. Feedback (反馈)
    • 每个试次结束后,参与者会收到基于其反应时间的反馈。
    • 反馈阶段持续1秒,通过文本刺激(feedback)呈现反馈信息,会显示“按键太慢了”或“很棒”
  5. familiar_check
    • 询问参与者是否已经熟悉流程了流程,如果参与者已经熟悉,则继续后面的实验,如果不熟悉,则继续进行预实验循环。

详细步骤

1.创建新的实验

  1. 打开PsychoPy。
  2. 创建一个新的实验文件,可以命名为 demo.psyexp

2.创建说明页面

  1. Flow 标签下,点击 插入例程 按钮,命名为 instruction1
  2. instruction1 例程中,添加一个文本刺激(Text)和一个键盘响应(Keyboard)。

image-jded.png

  • 文本刺激的基础设置

    image-zmrw.png

  • 名称: instruction_1

  • 文本: "(自行设置你的实验介绍)……如果准备好了,请按空格键开始,开始练习。"

  • 起始: 0.0

  • 终止-持续时间: 设置为空白(空白表示持续到按键响应为止)
    文本刺激的布局设置

    image-iaqz.png

  • 位置[x, y] (Position [x, y]): 这里显示的值是 (-0.5, 0),表示刺激在屏幕上的横纵坐标位置。横坐标 (x) 为 -0.5,表示相对于屏幕中心向左移动0.5个单位。纵坐标 (y) 为 0,表示不在垂直方向上移动。单位取决于 “Spatial units” 设定。

  • Spatial units: 这里的选项为 “从实验设置 ”,表示位置的单位是根据实验的全局设置来决定的。常见单位有像素 (pixels)、度 (degrees)、norm (标准化坐标) 等。

  • 朝向 (Orientation): 这里的值为 0,表示刺激没有旋转,即保持初始方向。

  • 换行宽度 (Wrap width): 这里的值为 0.5,通常用于文本刺激,表示文本在屏幕上换行的宽度。

  • 翻转(镜像)(Flip): 这里的选项为 “None”,表示不对刺激进行镜像翻转。
    后文各种组件的“布局”设置与此相同,后文中不再详细解释。

  • 键盘响应:

    image-seov.png

  • Name: key_intro_start

  • Start: 0.0

  • Force end of Routine: 勾选,表示操作后就结束该例程,进入下个页面

  • 允许的按键:'space',即空格键。

3.创建注视点页面

Flow 标签下,点击 插入例程 按钮,命名为 Fixation_point

添加“beep”组件

  1. 在右侧页面选择“Sound组件”。

image-owif.png

  1. 将新添加的声音组件命名为“beep”。

  2. 设置“beep”组件的属性:

    image-dcvb.png

  • 名称(Name):组件的名称“beep”。
  • 起始时间(Start)
    • 时间(s):在本例中,beep组件从0秒开始。
  • 结束时间(Stop)
    • 持续时间(s):在本例中,beep组件持续1秒。
  • 声音:设置声音的频率或选择声音文件。在本例中,输入200,即输入一个200 Hz的声音。
  • 同步屏幕开始(Sync start with screen):勾选后,声音组件将与屏幕刷新同步开始,从而提高实验结果的准确性和一致性。

添加“sound_pre”组件

  1. 在右侧页面选择“Sound组件”。

image-xlhx.png

  1. 将新添加的声音组件命名为“sound_pre”。
  2. 设置“sound_pre”组件的属性:

image-bdzl.png

  • 起始(s):1.1
  • 持续(s):1.2
  • 声音文件:$sound(需要在循环中的条件文件中定义这些变量,见后文)。
  • 勾选“Sync start with screen”选项。

添加“fixation”组件

  1. 在右侧页面选择“Polygon组件”。

image-zamp.png

  1. 将新添加的图形组件命名为“fixation”。
  2. 设置“fixation”组件的属性:

image-akmf.png

  • 起始时间(s):0.0
  • 持续时间(s):2.3,这里的数值和音频长度有关。
  • 形状:组件的形状,可以选择十字(Cross)、圆点(Dot)等。在本例中,选择的是十字。

例程概览

image-naxd.png

4.创建预实验例程

Flow 标签下,点击 插入例程 按钮,命名为 Pre_experiment

添加“leftText_pre”组件和“rightText_pre”组件:

  1. 在右侧页面选择“Text组件”。

  2. 将新添加两个文本组件,分别命名为“leftText_pre”和“rightText_pre”。

  3. 设置它们的属性:

    image-oqhj.png

    image-acag.png

  • 名称(Name):组件的名称,。
  • 起始时间(Start Time):0.0 秒。
  • 持续时间(Duration)
  • 文本内容(Text):$text1 和 text2(需要在循环中的条件文件中定义这些变量,见后文)。

添加“practice_resp”组件:

  1. 在右侧页面选择“Keyboard组件”。
  2. 设置它的属性:

image-oxtz.png

  • 名称(Name):practice_resp,
  • 起始时间(Start Time):0.0 秒。
  • 持续时间(Duration):设置为空。
  • 允许的按键(Allowed keys):'f', 'j'。
  • 结束例程(Force end routine):勾选后,当按下允许的按键时,例程将结束。

添加代码组件

  1. 添加“code_pre”组件:
    • 在右侧页面选择“Code”

    • 将新添加的代码组件命名为“code_pre”。

    • 在“结束例程(End routine)”选项卡中,输入以下代码以检查响应时间并设置反馈文本:

      image-buny.png

# 检查practice_resp.rt是否为列表
if isinstance(practice_resp.rt, list):
    rt = practice_resp.rt[0]  # 获取第一个反应时间
else:
    rt = practice_resp.rt  # 直接使用反应时间

# 检查反应时间是否小于或等于4秒
if rt is not None and rt <= 4.0:
    feedback_text = "很棒" #变量feedback_text会在后面的feedback页面中引用。
else:
    feedback_text = "太慢了"

例程概览

image-ilyg.png

5.创建feedback页面

  1. Flow 标签下,点击 插入例程 按钮,命名为 feedback

  2. 在右侧页面选择“Text组件”。

  3. 设置属性:

    image-xabd.png

例程概览

image-rbto.png

6.创建小循环trials_pre

Flow 标签下,点击 插入循环 按钮,命名为 trials_pre,包括以下内容:

image-hrsh.png

image-rcwx.png

  • 名称(Name):用于指定该循环的名称,方便在代码和其他设置中引用该循环。
    • 示例:trials_pre
  • 循环类型(Loop type):用于选择循环的类型,有以下选项:
    • 顺序(sequential):按顺序进行循环。
    • 随机(random):随机选择条件进行循环。
    • 完全随机(fullRandom):每次完全随机选择条件。
    • 本例选择random
  • Is Trials(in trials):用于指定该循环是否为试验循环。勾选后,PsychoPy会将该循环视为试验循环,每一行条件对应一个试验。
    • 示例:勾选
  • 循环次数(Number of repeats):用于设置循环应重复的次数,本例输入1次,因为是预实验阶段,只是让被试熟悉步骤,不需要循环很多次。
  • 选择行(Selected rows):用于指定要选择的行。可以输入特定的行号或行号范围。如果为空,则选择所有行。如输入 0:5 表示选择第0到第4行。
  • 随机种子(Random seed):用于设置随机种子,确保实验的随机选择可以重复。如果为空,则每次运行实验时随机选择会不同。
  • 条件(Conditions):用于选择包含实验条件的文件。通常是一个Excel文件或CSV文件,其中每一行定义了一组试验条件。本案例填写的是lib/condition/pre_experiment1.xlsx

本案例的条件文件 pre_experiment1.xlsx,其中包含以下列:

image-xtuk.png

  • text1:左侧文本的内容,所以leftText_pre填入$text1
  • text2:右侧文本的内容,所以rightText_pre填入$text2
  • sound:声音文件的路径,所以sound_pre里填入了$sound。并且可以观察到,sound里面是声音文件的路径,而且使用了相对路径
  • sound_type:声音类型(这一列没有用到,和本次实验无关。但是最终数据文件导出的时候也会随之导出,有时候这样做可以减少后期分类的工作量。)

关于相对路径

在之前的步骤中,我们会发现条件文件和声音文件都使用了lib文件夹,这里涉及相对路径的格式,也就是引用的文件的路径是相对于你保存的 .psyexp 实验文件所在的目录的
这是本案例项目文件结构:

image-hfca.png

可以发现lib和psyexp文件是同级的,此时就可以直接引用类似lib/sound/a10.wav的格式。普遍来说,相对路径有如下格式:

  1. 当前目录:使用相对路径中的.表示当前目录,此处的.可以省略。
    • 示例:./filename.xlsx
  2. 子目录:如果文件在当前目录的子目录中,使用相对路径从当前目录指向子目录,此处的.可以省略,本案例就是这种情况。
    • 示例:./subdir/filename.xlsx
  3. 父目录:使用相对路径中的..表示上一级目录,可以用来访问上一级目录。
    • 示例:../filename.xlsx(上一级目录中的文件)
    • 示例:../subdir/filename.xlsx(上一级目录的子目录中的文件)
  4. 多层目录:可以组合多个相对路径符号访问多层目录。
    • 示例:../../subdir/filename.xlsx(上两级目录中的子目录中的文件)

使用相对路径的好处是它提高了实验的可移植性,无论是在不同的计算机上还是在不同的文件系统结构中,实验文件都可以正确找到所需的资源文件。确保你的相对路径是基于你的 .psyexp 文件所在的目录的相对位置。

7.添加熟悉度检查例程

Flow 标签下,点击 插入例程 按钮,命名为 familiar_check

添加“key_resp_check”组件
  1. 在PsychoPy的时间轴中,右键点击选择“添加”->“键盘响应组件”。
  2. 将新添加的键盘响应组件命名为“key_resp_check”。
  3. 设置“key_resp_check”组件的属性:

image-ezjr.png

  • 名称(Name):key_resp_check
  • 起始时间(Start Time):0.0 秒。
  • 持续时间(Duration):保持默认值,表示组件在整个例程中都有效。
  • 允许的按键(Allowed keys):'y', 'n'。
  • 结束例程(Force end routine)不勾选,以便根据代码组件的判断来结束例程。
添加“text”组件
  1. 在PsychoPy的时间轴中,右键点击选择“添加”->“文本组件”。

  2. 将新添加的文本组件命名为“text”。

  3. 设置“text”组件的属性:

    image-gfwr.png

  • 名称(Name):text
  • 起始时间(Start Time):0.0 秒。组件开始的时间,以秒为单位。
  • 持续时间(Duration):保持默认值,表示组件在整个例程中都显示。
  • 文本内容(Text)
你是否已经熟悉按键操作? 如果要再练习一遍,请按N。 如果开始正式实验,请按Y。
添加“code_familiar_check”代码组件
  1. 在PsychoPy的时间轴中,右键点击选择“添加”->“代码组件”。

  2. 将新添加的代码组件命名为“code_familiar_check”。

  3. 在“每帧(Each Frame)”选项卡中,输入以下代码以检查按键响应并设置循环控制:

    image-yveg.png

# Each Frame - 选项卡中的代码

# 检查按键响应
keys = key_resp_check.getKeys(['y', 'n'])

# 如果有响应
if keys:
    if 'y' in [key.name for key in keys]:  # 'y'表示熟悉
        trials_familiar.finished = True  # 结束大循环
    else:
        trials_familiar.finished = False  # 继续大循环
    continueRoutine = False  # 结束当前例程
例程概览

image-hqwh.png

大循环

在 PsychoPy Builder 中设置一个外部大循环,包含上文中的预实验循环trials_pre和熟悉度检查familiar_check。即在小循环结束后,进入熟悉度检查阶段,判断是否熟悉操作,如果不熟悉则继续大循环,否则退出大循环并继续后续实验。
Flow 标签下,点击 插入循环 按钮,创建外部大循环 trials_familiar

  • 包含 trials_pre里的各个例程 和 familiar_check

image-jqxt.png

  • 设置 nReps 为一个很大的数(例如 100)。

image-pkgt.png

步骤7:运行实验

  1. 在菜单栏中选择 Run -> Run Experiment 或按快捷键 Ctrl+R(Windows)或 Cmd+R(Mac)。
  2. 实验会开始运行,将看到文本指示、凝视点、实验刺激和反馈。

总结

通过以上步骤,我们创建了一个简单的PsychoPy实验,包含指令页面、凝视点、实验刺激和反馈页面,可以根据实验需求进行进一步扩展和修改。

进阶技巧

音频结束后立刻结束routine(音频长度未知)

在PsychoPy中,要实现音频播放完毕后自动跳转到下一个routine,你需要在当前routine的最后一个组件中设置结束条件为"音频结束"。具体步骤如下:

  1. 选择音频组件:在你的routine中选择最后一个音频组件(假设是sound_pre)。
  2. 设置音频结束
    • Duration (s)栏中,不填任何数值。
    • Stop栏中选择Duration,然后填写音频的实际持续时间。如果你想直接通过音频的结束事件来控制,你可以使用condition,并设置条件为sound_pre.status == FINISHED

如果你的音频组件没有明确的持续时间,可以按以下步骤设置:

  1. 在代码组件中设置音频结束条件
    • 添加一个代码组件到routine的最后。

    • 在代码组件的Each Frame标签中,添加以下代码:

      if sound_pre.status == FINISHED:
          continueRoutine = False
      

这段代码会在每一帧检查sound_pre音频是否播放结束,如果结束则跳转到下一个routine。

  1. Experiment Settings中设置End Routine
    • 打开Experiment Settings,在End Routine选项中确保勾选了Force end of Routine on component finish

只需确保sound_pre的播放时间和routine的总时间一致,这样在音频播放结束后即可自动跳转。

如果音频长度是未知的,并且需要在 sound_e1 播放结束后立即播放 sound_e2,可以使用 Python 代码来动态控制这些组件的播放和停止。以下是如何实现的步骤:

  1. 在 routine 中,添加一个 Code 组件。
  2. 在 Code 组件中,选择 "Each Frame" 选项卡。
  3. 输入以下代码:
if t >= sound_e1.status == FINISHED and not sound_e2_played:
    sound_e2.play()
    sound_e2_played = True

# 停止整个 routine
if sound_e2.status == FINISHED:
    continueRoutine = False
  1. 在 "Begin Routine" 选项卡中,初始化 sound_e2_played 变量:
sound_e2_played = False

上述代码解释:

  • 在每一帧(Each Frame)中,检查 sound_e1 是否已经播放结束(sound_e1.status == FINISHED)。
  • 如果 sound_e1 播放结束且 sound_e2 尚未播放,则播放 sound_e2 并将 sound_e2_played 设置为 True
  • 如果 sound_e2 播放结束(sound_e2.status == FINISHED),则将 continueRoutine 设置为 False,从而结束这个 routine。

通过这种方式,可以确保在 sound_e1 播放结束后立即播放 sound_e2,并在 sound_e2 播放结束后结束这个 routine。


基于Psychopy的语音感知实验操作示例
http://whxblog.com//archives/edbf7db2-8b8e-4fa0-b62a-5f3fff6cc660
作者
W
发布于
2024年06月01日
许可协议