【问题标题】:Matlab Psychtoolbox fprintf error with multiple keypresses within a trialMatlab Psychtoolbox fprintf 在试验中出现多个按键错误
【发布时间】:2019-03-13 09:34:56
【问题描述】:

我有一个实验,收集按键(“x”或“n”)和响应时间以响应刺激显示。如果参与者在每次试验中按下任一按钮一次,则实验运行良好。但是,如果他们反复按下键盘或按住一个键,它往往会崩溃。 (我和孩子一起工作,即使我们要求他们不要这样做,这种情况仍然会经常发生)。

崩溃时出现的错误是:

没有为“单元”输入定义函数。

实验错误(第 682 行)

fprintf(dataFile, formatString, SJNB, Date, Age, block, trial, trialFaceLabel, trialLoadLabel, Target, keyStroke, tStart, keyTime, Correct, RT, FaceGen);

虽然它说“没有为“单元”输入定义函数”(这与 this 帖子有关),但这个函数似乎在所有其他时间都能正常工作,所以我看不出它只是没有正确定义。只有当连续按下太多按键时(例如,如果按键被按住),才会发生此错误。

我可以进行哪些更改以确保实验稳健且不会崩溃,即使每次试验有多个按键?任何帮助,将不胜感激。

我已包含以下代码。

以下是一些附加信息,以防有用:

  • 在实验之前,有一个练习循环,它的设置方式非常相似,但有两个主要区别:1) 显示在屏幕上的刺激不同,2) 未记录按键.这个循环似乎永远不会崩溃。

  • 崩溃后,按键响应会打印到命令行。

  • 我看过其他类似的帖子,例如@ 987654322@ post,但据我了解,我编写的按键循环也应该在按下键后立即退出 - 所以我不确定为什么我的工作方式不同。

下面的代码都包含在一个实验循环中。它正在做的是: 1)搜索按键 2)根据按键计算响应时间 3)如果响应不正确,发出哔哔声 4)打印到文件(这是在试用结束之前)(这是错误引用的行)

            %searching for keypress
            timedout = false;
            pressed = 0;
            %while pressed < 1;

            while ~timedout && ~pressed

                [keyIsDown, keyTime, keyCode] = KbCheck;

                if keyIsDown && ((keyTime-tStart) < max_stimulus_shown)
                    keyStroke = KbName(keyCode);
                    if any(strcmpi(keyStroke,leftKey)) || any(strcmpi(keyStroke,rightKey)) %|| any(strcmpi(keyStroke,exitKey))
                        pressed = 1;
                        WaitSecs(remainer-(keyTime-stimulus_shown));
                        break;
                    elseif any(strcmpi(keyStroke,exitKey))
                    disp('*** Experiment terminated ***');
                        break;
                        sca;
                    end
                elseif ((keyTime-tStart) > max_stimulus_shown)
                keyStroke = 'None';
                timedout = true;
                RT = 0;
                Correct = 0;
                pressed = 2; % 2 = not pressed
                KbQueueStop(); 
                end
            end 

            %calculate response times
            if pressed == 1 && (~timedout)
            RT = round((keyTime-tStart)*1000); % RT in ms
            if any(strcmpi(keyStroke,leftKey)) % pressed left (X)
                if any(strcmpi(Target, 'X')) % target was an X
                    Correct = 1;
                else % target was X, but pressed right (N)
                    Correct = 0;
                end
            elseif any(strcmpi(keyStroke,rightKey)) % they pressed right 
                if any(strcmpi(Target, 'N')) % target was an N
                    Correct = 1;
                else % target was N, but pressed right
                    Correct = 0;
                end
            elseif any(strcmpi(keyStroke,exitKey))
                disp('ESC');
                break;
            end
            end

            Screen('TextSize',Screen_wid, star_size);
            DrawFormattedText(Screen_wid, '.', 'center', 'center');
            WaitSecs(feedback);
            Screen('Flip', Screen_wid);

            %say when to beep                
            if Correct == 0 && ~timedout
            PsychPortAudio('Start', pahandle, repetitions, startCue, waitForDeviceStart);
            WaitSecs(remainer-beepLengthSecs);
            elseif Correct == 0 && timedout
            PsychPortAudio('Start', pahandle, repetitions, startCue, waitForDeviceStart);
            Screen('TextSize',Screen_wid, text_size);
            DrawFormattedText(Screen_wid, 'missed trial', 'center', 'center');
            Screen('Flip', Screen_wid);
            WaitSecs(beepLengthSecs+feedback);
            elseif Correct == 1
            WaitSecs(remainer+beepLengthSecs);
            end

            %WaitSecs(stimulus_shown); %stimulus shown for 0.2 seconds
            Screen('Flip', Screen_wid);

            dataFile = fopen(dataFileName, 'a');                               
            fprintf(dataFile, formatString, SJNB, Date, Age, block, trial, trialFaceLabel, trialLoadLabel, Target, keyStroke, tStart, keyTime, Correct, RT, FaceGen);
            fclose(dataFile);   

【问题讨论】:

  • 您对上述fprintf 方法的输入很可能是一个元胞数组,您必须找出哪一个,因为这只有在整个上下文中才有可能。当持续按下键时,可能收集按键的变量之一变成一个元胞数组,但当短时间按下键时,它是一个单一的值!?

标签: matlab psychtoolbox


【解决方案1】:

函数KbName 通过键码向量 (key_name = KbName([21 22])) 或逻辑向量返回键输入的名称字符串,如 KbCheck 返回的那样。

如果只提供 key / 为 True,则以字符串形式返回。但是,如果同时按下多个键,则会以字符串元胞数组的形式返回。

例如,看输出:

% for key name consistency across operating systems
KbName('UnifyKeyNames')

% one key
KbName(21)

ans =

r

% more than one key
KbName([21 22])

ans =

  1×2 cell array

    'r'    's'

您的问题是,当同时按下多个键时(关于键检查循环),keyStroke 是一个包含被按下键的元胞数组。您似乎在大部分代码中都在适当地处理元胞数组,但对 fprintf 的调用除外,它需要一个字符串,而不是字符串元胞数组。

如果要保存所有按下的键的记录,可以将字符串元胞数组转换为单个字符串,并在元素之间使用分隔符,例如在调用 fprintf 之前添加以下行:

if iscell(keyStroke)
    keyStroke = strjoin(keyStroke, '_');
end

但是,请记住,您可能希望更改实验逻辑以拒绝按下两个键的试验,或者以不同于单键响应的方式处理它们。您当前优先使用“左”键,换句话说,如果参与者按下了左键并且目标是“X”,则试验将被标记为正确,即使也按下了右键。相反,如果参与者按下了左键并且目标是“N”,则试验将被标记为不正确,即使也按下了右键。

【讨论】:

  • 谢谢,这很有帮助!我添加了您建议的行。我还添加了一个新的输出变量,指示 keyStroke 何时是一个单元格(即同时按下了多个键),以便我可以从分析中丢弃这些试验。
  • 顺便说一句,这让我开始思考——如果我能识别出参与者通常何时随机按下按钮,那实际上会更好,因为这表明他们根本没有对刺激做出真正的反应,所以应该被丢弃。根据您的建议,我将能够排除他们同时按下两个键的试验,但如果他们交替按下按钮,这将在结果中看起来像是一个有效的响应。
  • 你知道有没有办法做到这一点?如果有一种方法可以在试用过程中记录所有按键,我似乎认为这是可能的。但是,我不确定这是否可能基于 Kb 函数。我还在考虑你提到的逻辑变化——但上述变化似乎已经解决了崩溃问题! :)
  • 您是正确的,在您当前的代码中,如果参与者在试验中连续按下两个按钮,则第一次按下按钮将使“按下”变量为真,并且在试验中进一步按键不会t 被收集。通常,随机响应是在参与者级别处理的,基本上如果整体性能处于某个阈值接近机会,则排除该参与者的所有数据但是,您也可以在试验中记录多个按键(我将在随后的评论)。
  • 基本上您想要做的是,在您现在注册按键后不要停止轮询,而是将每个按键添加到该试验的向量或单元阵列中。为促进这一点,在检测到每个按键后,还要添加对 KbReleaseWait() 的调用,这将防止一次按键错误地检测到多个按键,例如,如果参与者按住一个键。
猜你喜欢
  • 2016-07-30
  • 1970-01-01
  • 2017-07-20
  • 1970-01-01
  • 2011-04-19
  • 1970-01-01
  • 2013-12-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多