之前讲过利用双 buffers 来快速呈现图像的原理。Psychtoolbox 采用 VBL Synchronization 的方式实现对图像呈现时间的精确控制。
这一次,主要说下这个方法在实验程序中的实现。
上次的练习中,是在屏幕的中间呈现了一个灰色的圆点,现在要求一秒后呈现一个红色的圆点。
有一些时间控制类的函数可以做到,但是 PTB 推荐采用指定在哪一帧翻转的方式来实现。
举例如下:
先做一些准备工作
sca;
close all;
clearvars;
PsychDefaultSetup(2);
screen = max(Screen('Screens'));
white = WhiteIndex(screen);
grey = white / 2;
% 下面 打开一个窗口,颜色设为白色
[win, rect] = PsychImaging('OpenWindow', screen, white);
% 获取每帧间的时间差
ifi = Screen('GetFlipInterval', win);
注意上面的例子中,通过 Screen('GetFlipInterval')
获取了显示器的刷新时间,一般来说,液晶显示器的刷新率为 60 hz ,可以据此估算,ifi 的值约为16.67 ms.
接下来,画一个灰色的圆点:
Screen( 'FillOval', win, grey, [ 1260, 700, 1300, 740] );
vbl = Screen('Flip', win);
这次,与上次的例子中,有一个不太一样的地方, " Flip " 之后,返回了一个值给 vbl. 这里,vbl 相当于一个标记,它标记了 " Flip " 动作完成的时间点。
大家查看下帮助,可以看到 Screen('Flip')
还可以传入更多的参数,其中 "when" 参数是这个任务的核心。when 可以指Flip 动作的翻转时间。
画了一个灰色的圆点以后,随着 Flip 动作,原先的灰色圆点也随之被清除。
现在画一个红色的圆点:
Screen( 'FillOval', win, [255 0 0], [ 1260, 700, 1300, 740]);
接着指定它在何时翻转。
Screen('Flip', win, vbl + (1 / ifi - 0.5) * ifi);
简单解释下它的原理:
先看这个式子: ( 1 / ifi - 0.5 ) * ifi
,它可以理解为 第 "1 / ifi + 1" 帧之后执行翻转动作。1 是指 1 秒,因为我们前面指定了 1 秒钟以后变为红色的点。
有点奇怪啊,为什么第"1 / ifi + 1" 之后执行翻转动作,在计算的时候要减 0.5 呢?这是因为执行程序需要时间,写成 " 1/ifi +1 "的话,程序有可能稍微滞后一些,这样就错过了那一帧的翻转,就变成了更之后的一帧进行翻转,这会带来误差。
为了避免这样的误差,如果需要在哪一帧翻转,就提前半帧执行动作,这样就可以保证它一定会在那一帧进行翻转。请结合教程13理解一下。
但是程序内部,它不是按照帧来完成动作的,它仍然是按照计时的。所以需要将帧转换成为时间。
所以 when 参数就变成了 "vbl + ( 1 / ifi - 0.5 ) * ifi" ,意味着在vbl 之后 ( 1 / ifi - 0.5 ) * ifi 时间执行翻转动作。