1 引言
分享一下如何使用MATLAB中的心理学工具箱(Psychtoolbox,PTB)编写一个完整的心理学实验。一般而言,任何行为实验都可以按照本文的框架来编写。
今天要编写的例子是一个很简单的按键判断的实验,只有一个block,block里有五个trial。每个trial的流程图如下。首先呈现一个500~1200ms的注视点,然后随机出现左箭头或右箭头,被试需要根据出现的刺激按方向键反应,如果500ms之内按键则记录反应时、正确率等信息,并且箭头消失,否则箭头会呈现500ms的时间后自动消失,最后是300ms的空屏。
2 实验程序的编写
2.1 创建文件夹、构建程序的基本框架
首先新建一个文件夹,将来的实验程序文件都放在这个文件夹中,这样子管理起来比较方便。我的叫“My_Psych_exp”,注意MATLAB读取文件时有一些命名规范,一般采用英文命名即可,单词与单词之间用首字母大写或下划线来区分。
在MATLAB左边的面板点击进入刚刚创建的文件夹,新建一个叫“exp_example”的文件夹,在该文件夹中通过快捷键Ctrl+N新建一个脚本。
开头输入如下三行代码。clear是清除所有变量,clc是清除命令行窗口的代码,sca相当于Screen('CloseAll'),即关闭PTB里所有打开的窗口。
clear;
clc;
sca;
接下来输入如下代码。
try
HideCursor;
catch
ShowCursor;
sca;
psychrethrow(psychlasterror);
end
编写实验程序时推荐采用这种“try……catch……end”的框架,实验的主要代码就放在try和catch中间,这样万一出现错误,就会执行catch之后的语句。
我们一般做行为实验时都是通过按键反应,鼠标指针是隐藏起来的,因此可以在一开始使用HideCursor隐藏鼠标指针,同时在catch部分写上ShowCursor,这样程序出错时鼠标指针就会显示出来。而sca会关闭窗口,psychrethrow(psychlasterror)则会在命令行窗口告诉我们出错的代码的位置。
2.2 创建数据表格
现在,让我们来看看整个实验程序最重要的部分:数据。
在MATLAB中,我们的数据都储存在变量中,虽然可以直接将这些变量保存为“mat”格式的文件,并在MATLAB中处理这些数据,但最好还是将实验数据统一整理并导出为外部文件,以便将来进行查阅和统计分析。
在这个例子中,我们想要收集的信息有:被试的基本信息(包括被试编号、性别、年龄和利手)、注视点呈现时间、箭头刺激的朝向、反应按键、反应时、正确率。并且这个实验总共有5个trial。因此预期的数据矩阵的格式如下(为了方便理解,添加了表头)。
在实验过程中,我们需要时不时地从这么一个矩阵中读写信息,例如将被试的反应按键记录到矩阵中,然后在计算正确率的时候再将这一信息读取出来使用。为此,我们先创建一个名为“data”的cell矩阵,矩阵的大小就按照我们预期的要求。之所以使用cell,是因为我们的数据信息同时包含了数值和字符串。现在,让我们将下面这段代码添加至“try……”的后面。
% Create a cell array to save data
data = cell(5,9);
2.3 收集被试的基本信息
在开始实验前,我们还需要收集被试的基本信息。
使用过E-Prime的同学应该知道,E-Prime运行实验程序时,会出现一些收集被试的基本信息的对话框。在MATLAB中,我们同样可以采用对话框的方式来收集被试的信息。
% Obtain some information of experiment
prompt = {'Subject Number','Gender[1 = m, 2 = f]','Age','Handeness[1 = left, 2 = right]'};
title = 'Exp infor'; % The title of the dialog box
definput = {'','','',''}; % Default input value(s)
% Using inputdlg() to obtain information and save it to cell array
data(1:5, 1:4) = repmat(inputdlg(prompt,title,[1, 50],definput)', 5, 1);
这里用到了MATLAB自带的inputdlg函数,其作用是打开一个收集用户输入的对话框,并将输入的信息赋给一个变量(在这里就是赋给我们刚刚创建的cell矩阵啦)。至于inputdlg中的参数,prompt是对需要输入的信息的提示,title就是对话框标题,“[1, 50]”是输入框的维度,表示对话框的高度为一个字符,长度为50个字符。如果需要增加、减少想要收集的信息,则在prompt这个变量里添加/删除一下就可以了。
接着,我们将收集到的信息,通过'(英文的单引号,效果是将行变列、将列变行)进行转置,并通过repmat函数复制5次后,写入我们刚刚创建的数据矩阵中。先让我们看一下最终的效果。
其实这些信息只需要一行就够了,我这么做只是为了美观一点……
2.4 打开窗口
继续在try部分添加下面这些代码。代码的作用是打开一个窗口(这个窗口便是我们呈现实验刺激的地方),同时我们还设置了一些所需的参数。
HideCursor;
% Open a black backgound window
[w, wrect] = Screen('OpenWindow', 0, [0, 0, 0]);
% Define the center coordinates
[x_center, y_center] = RectCenter(wrect);
% Measure the vertical refresh rate of the monitor
ifi = Screen('GetFlipInterval', w);
% Text font and text color
Screen('TextFont', w, 'Simhei');
Screen('TextSize', w, 65);
接下来解释一下各行代码。
Screen('OpenWindow')的作用是打开一个窗口,我们将这个窗口命名为“w”,“wrect”返回的值是窗口的分辨率,0是显示器的编号,第一个显示器的编号是0,后面依次是1、2、3……,当存在多个显示器时,