在后台运行定时进程(MATLAB)

问题描述 投票:0回答:1

我正在尝试在 MATLAB 中进行心理物理学实验,其中刺激的时机非常关键。我有代码来生成一个、两个和三个的序列,每个序列都会触发显示不同的刺激。显示刺激 2 时,参与者有 1 秒的时间通过按下按钮(使用 ResponsePixx 按钮盒)做出响应。

我需要每个刺激在前一个刺激之后传递 0.5 秒,这意味着对刺激 2 的响应时间与下一个刺激的传递时间重叠。所以我认为我需要以某种方式跟踪后台的按钮按下情况,同时继续提供刺激序列。

这是简化版本,只是将其简化为当前的问题:

% Create sequence of numbers
sequence = %FUNCTION OUTPUTS 1XN SEQUENCE OF ONES, TWOS, AND THREES

for iSequence = 1:length(sequence)
   
    disp(sequence(iSequence)) % Stand-in for displaying proper stimuli
    
    if sequence(iSequence) == 2
        % wait for 1 second whilst continuing display of sequence)
        % During this time, other code will run to track for participant responses
        disp("Time elapsed") 
    end
    
    pause (0.5)
    
end

我用 parfeval 做了一些测试,但没有成功 - 输出显示正确,但中断了主序列传递的时间(我假设是从并行池中获取输出的延迟,但说实话,我几乎没有并行处理的经验,所以我不确定):

delete(gcp('nocreate'))
clear 

background = parpool(1);

sequence = % createTrialSequence



for iSequence = 1:length(sequence)
    disp(sequence(iSequence))
    
    if iSequence > 1
        if sequence(iSequence - 1) == 2
            fetchOutputs(evalButton)
        end
    end
    
    if sequence(iSequence) == 2
        evalButton = parfeval(background, @trackInBackground, 1);
    end
    
    pause(0.5)
    
end

我也尝试过使用事件和侦听器,但这也会暂停序列的传递(同样,不太熟悉它们的工作原理,因此可能会丢失一些关键的东西):

clear
event = targetAppeared;
listener = trackTargetAppearance(event);

sequence = %createTrialSequence



for iSequence = 1:length(sequence)
    disp(sequence(iSequence))
    
    
    if sequence(iSequence) == 2
        event.isTarget
    end
    
    pause(0.5)
    
end


classdef targetAppeared < handle
    events
        targetEvent
    end
    methods
        function isTarget(obj)
            notify(obj, 'targetEvent')
            
        end
    end
end

classdef trackTargetAppearance < handle

    methods
        function obj = trackTargetAppearance(targetObj)
            addlistener(targetObj, 'targetEvent', @trackTargetAppearance.handleEvent)
        end
    end
    
    methods (Static)
        function handleEvent(~, ~)
            startTime = GetSecs; %get system time, from PsychToolBox
            while GetSecs < (startTime + 1)
                continue
            end
            disp("Target Response Window elapsed")
        end
    end    
end
matlab psychtoolbox
1个回答
0
投票

这是使用

timer

的潜在解决方案

请原谅由于为此构建了一个最小的 GUI 而导致的代码混乱,唯一需要关注的机制是:

  • 使用

    timer
    定期触发刺激显示/更改(特别是查看计时器的
    ExecutionMode
    选项,它可以让您调整计时器触发的规律性)

  • 当显示需要用户(定时)响应的刺激时,启动

    stopwatch

  • 当检测到用户按下按钮时,读取秒表的值并采取相应行动。


Timed response


上例代码:

function hf = TimedResponse
global sequence ;

    sequence = 1:10 ;
    hf = build_gui ;
   
end

function myTimerFcn(~,~,hfig)
global sequence ;
global responseTimer ;
persistent iseq ;

    hf = guidata(hfig) ;
    if isempty(iseq) ; iseq=1 ; end
    if iseq>numel(sequence) ; iseq=1 ; end
    
    hf.lbl.String = num2str(sequence(iseq)) ;
    
    if sequence(iseq) == 2
        responseTimer = tic ;
    end
    iseq = iseq+1 ;
end

function StartButtonPushed(src,~)
    hf = guidata(src) ;
    if strcmpi(hf.t.Running,'off')
        start(hf.t) ;
        hf.btnStart.String = 'Stop';
    else
        stop(hf.t) ;
        hf.btnStart.String = 'Start';
    end
end

function RespButtonPushed(src,~)
global responseTimer ;

    hf = guidata(src) ;
    ElapsedTime = toc(responseTimer) ;
    if ElapsedTime < 1
        hf.lblresp.ForegroundColor = 'g' ;
        hf.lblresp.String = sprintf('*** PASS *** (Time to respond to stimuli: %f seconds)',ElapsedTime) ;
    else
        hf.lblresp.ForegroundColor = 'r' ;
        hf.lblresp.String = sprintf('*** TOO LATE *** (Time to respond to stimuli: %f seconds)',ElapsedTime) ;
    end
    
end

function h = build_gui

    h.fig = figure('unit','normalized','CloseRequestFcn',@my_closereq);
    h.t = timer('Period',0.5,'ExecutionMode','fixedDelay') ;
    h.t.TimerFcn = @(e,v)myTimerFcn(e,v,h.fig) ;
  
    h.btnStart = uicontrol('Style','pushbutton','String','Start','unit','normalized','Position',[0.1 0.8 0.8 0.1],'Callback',@StartButtonPushed);
    h.lbl = uicontrol('Style','text','String','0','unit','normalized','Position',[0.1 0.4 0.8 0.3],'FontSize',36);
    h.btnResp = uicontrol('Style','pushbutton','String','Stimuli observed','unit','normalized','Position',[0.1 0.2 0.8 0.1],'Callback',@RespButtonPushed);
    h.lblresp = uicontrol('Style','text','String','','unit','normalized','Position',[0.1 0.1 0.8 0.05],'FontSize',12);

    h.seq = 1:10 ;
    guidata(h.fig,h)
end

function my_closereq(src,~)
    hf = guidata(src) ;
    disp('Deleting timer') ;
    if strcmpi(hf.t.Running,'on')
        stop(hf.t) ;
    end
    delete(hf.t) ;
    delete(hf.fig) ;
end
© www.soinside.com 2019 - 2024. All rights reserved.