0

这是我用于实验的脚本。
对象听到 3 种不同的音调,每种音调代表不同的奖励金额。所以当音 1 出现时,没有奖励,而当音 2 和 3 出现并且对象触发 时photobeam(pb_broken),将给予奖励。
问题是,有时物体在没有听到音调的情况下获得奖励,因为它们靠近光束,从而触发它,并导致它释放奖励。
我想防止这种情况发生,但我不知道该怎么做。这是我的选择:

  1. 如果在音调之前触发了光束 1(有 2 个光束),则跳过该音调,并继续进行实验(不要再次播放该音调,并在原本应该出现的时候继续下一个音调)
  2. 如果在奖励音(2 和 3)之前触发光束 1,则跳过音(如上)
  3. 如果 pb 1 坏了,则将音调延迟 1 秒,从而将所有内容延迟 1 秒,但仍以 1200 秒结束。这将是理想的情况。

这是我的代码:

clear all;

%%
% Set-up DAQ with an output and input session
global outputSession; % this will control the feeders
outputSession = daq.createSession('ni');
outputSession.addDigitalChannel('Dev2', 'Port1/Line0:1', 'OutputOnly');
outputSession.outputSingleScan([0 0]); % set everything to 0 to start

global inputSession; % this reads from the photobeams
inputSession = daq.createSession('ni');
inputSession.addDigitalChannel('Dev2', 'Port1/Line5:6', 'InputOnly');

global leverSession; % read from levers: note, scan returns 1 if not pressed, empty if pressed!
leverSession = daq.createSession('ni');
leverSession.addDigitalChannel('Dev2', 'Port1/Line2', 'InputOnly');

%% intitialize variables, draw status figure etc.
global target_rewarded; % needs to be global so functions can reset it
target_rewarded = [0 0]; % no targets (receptacles) armed to start

% track times and IDs of photobeam breaks
EventLogSize = 10000;
eventLog.pb_broken_time = nan(EventLogSize,1);
eventLog.pb_broken_id = nan(EventLogSize,1);
pb_counter = 1;

% times and IDs of feeders
eventLog.reward_time = nan(500,1);
eventLog.reward_id = nan(500,1);
reward_counter = 1;

eventLog.mistake_time = nan(500,1);
eventLog.mistake_id = nan(500,1);
mistake_counter = 1;

%%% generate trial start times %%%
sound_on = 0;
trial_count = 1;

%%% generate trial list %%%

trial_block = [1 1 2 2 3 3]; % permute block and repeat
eventLog.trial_list = [];
for iBlock = 1:50

    eventLog.trial_list = cat(2,eventLog.trial_list,trial_block(randperm(length(trial_block))));

end

%%% SET UP TIMES OF CUE (TONE) ONSET HERE
maxTrials = 500;
mean_ITI = 20;
SD_ITI = 3;

eventLog.trial_times = mean_ITI.*ones(maxTrials,1);
trial_SD = SD_ITI.*randn(maxTrials,1);
eventLog.trial_times = eventLog.trial_times + trial_SD;

eventLog.trial_times = cumsum(eventLog.trial_times);

%%% set up sounds %%%
outputID = 10; % which sound connection on computer to use

duration = 7; % in seconds
samplesPerSecond = 22050; % the bit rate of the tone
tvec = 0:1/samplesPerSecond:duration;

% 1: 2kHz tone, on/off at 10Hz
s1 = sin(2*pi*2000*tvec);
s1 = s1.*square(2*pi*10*tvec);
s1 = 0.2.*s1;

% 2: white noise
s2 = rand(size(tvec));
s2 = 0.2*((s2.*2)-1);

% 4: 8kHz tone, sinewave amplitude-modulated at 2Hz
s3 = sin(2*pi*8000*tvec);
modl = 0.5*(sin(2*pi*2*tvec)+1);
s3 = s3.*modl;

s3 = 0.5.*s3;

tone1 = audioplayer(s1, samplesPerSecond, 16, outputID);
set(tone1,'StopFcn',@reset_rewards); % set it up so that if the tone ends, rewards are reset

tone2 = audioplayer(s2, samplesPerSecond, 16, outputID);
set(tone2,'StopFcn',@reset_rewards); % set it up so that if the tone ends, rewards are reset

tone3 = audioplayer(s3, samplesPerSecond, 16, outputID);
set(tone3,'StopFcn',@reset_rewards); % set it up so that if the tone ends, rewards are reset

sound_timer = [];

%%% tone-to-pellet mapping
tone_to_pellets = [0 2 5];

correct_pb = 1; % which photobeam is rewarded
correct_feeder = 2; % which feeder to use

%%% initialize main timer and photobeam status %%%
start_timer = tic; % call as t_elapsed = toc(start_timer);
t_elapsed = 0;
max_time = 1200; % in seconds

pb_broken = [];
previous_broken = 0;

%%% make task window %%%
fs = 18;
f1_handle = figure(1);
t_handle = title('Task starting...'); set(t_handle,'FontSize',fs);

status_handle = text(0,0.8,sprintf('Correct trials %d, Incorrect trials %d',reward_counter-1,mistake_counter-1)); set(status_handle,'FontSize',fs);
axis off;

%% run task

while t_elapsed < max_time

    % update figure text,time
    set(t_handle,'String',sprintf('t %.2f, pb %d, target %s',t_elapsed,pb_broken,num2str(target_rewarded)));
    drawnow;

    t_elapsed = toc(start_timer);

    % check if any photobeams are broken
    pb_broken = pb_scan(inputSession);

    n_broken = numel(pb_broken);
    if n_broken > 0 % do something potentially

        % check
        if n_broken > 1
            disp('WARNING: multiple photobeams broken');
            pb_broken = pb_broken(1);
        end

        if pb_broken == previous_broken % no change, do nothing
            continue;
        end

        % log this: it's a new photobeam break
        eventLog.pb_broken_time(pb_counter) = t_elapsed;
        eventLog.pb_broken_id(pb_counter) = pb_broken;
        pb_counter = pb_counter + 1;

        disp(sprintf('*** Photobeam %d broken ***',pb_broken));

        if any(target_rewarded > 0) % reward active, maybe dispense pellet

            if pb_broken == correct_pb

                disp('*** CORRECT POKE ***');

                switch eventLog.trial_list(trial_count-1) % check what trial it is

                    case 1
                        disp(sprintf('Dispensed %d pellets',tone_to_pellets(1)));
                        dispensePellets(correct_feeder,tone_to_pellets(1));
                        stop(tone1);
                    case 2
                        disp(sprintf('Dispensed %d pellets',tone_to_pellets(2)));
                        dispensePellets(correct_feeder,tone_to_pellets(2));
                        stop(tone2);
                    case 3
                        disp(sprintf('Dispensed %d pellets',tone_to_pellets(3)));
                        dispensePellets(correct_feeder,tone_to_pellets(3));
                        stop(tone3);
                end

                target_rewarded = [0 0];

                eventLog.reward_time(reward_counter) = t_elapsed;
                eventLog.reward_id(reward_counter) = tone_to_pellets(eventLog.trial_list(trial_count-1));
                reward_counter = reward_counter + 1;

                disp(sprintf('Logged %d pellets rewarded',tone_to_pellets(eventLog.trial_list(trial_count-1))));

                set(status_handle,'String',sprintf('Correct trials %d, Incorrect trials %d',reward_counter-1,mistake_counter-1));

            else % wrong receptacle

                if ~poked_this_trial
                    disp('*** ACTIVE CUE, INCORRECT POKE ***');
                    mistake_counter = mistake_counter + 1;
                    poked_this_trial = 1;
                end

            end


        else % no reward active, do nothing

            disp('*** INACTIVE CUE, INCORRECT POKE ***');
            %mistake_counter = mistake_counter + 1;

        end

    end % of photobeam broken loop


    % check if a new trial (sound) is starting
    if t_elapsed > eventLog.trial_times(trial_count)

        switch eventLog.trial_list(trial_count) % check what trial it is

            case 1
                play(tone1);
                target_rewarded = [0 tone_to_pellets(1)];
            case 2
                play(tone2);
                target_rewarded = [0 tone_to_pellets(2)];
            case 3
                play(tone3);
                target_rewarded = [0 tone_to_pellets(3)];
        end
        sound_timer = tic;

        trial_count = trial_count + 1;

        poked_this_trial = 0;

        disp(sprintf('New trial started (%d pellets): updated trial count is %d',target_rewarded(2),trial_count));
    end

    % check if we need to stop sound
    if ~isempty(sound_timer) & toc(sound_timer) > duration

        switch eventLog.trial_list(trial_count - 1)

            case 1
                stop(tone1)
            case 2
                stop(tone2)
            case 3
                stop(tone3)
        end

    end

    previous_broken = pb_broken;

end % of main while loop
4

1 回答 1

0

这确实是一个无需动手就可以解决的复杂问题,而且不是编程,而是更多的实验设计问题。

您可能希望确保在开始新音调之前没有光束被中断,也许可以通过替换

 if t_elapsed > eventLog.trial_times(trial_count)

if t_elapsed > eventLog.trial_times(trial_count) & ~n_broken

在退出 if 语句并继续之前,您可以交替在 pb 阻塞检查语句的末尾添加一个 while 循环,以确保 1 秒内没有新事件发生。但是您还必须检查声音并可能在退出该循环之前终止它。

作为最后的选择,运行各种控制(我相信你正在运行),例如没有奖励的实验,应该用于检查随机障碍物的可能性。

我不确定你有什么样的限制需要保持紧张的审判时间表,但正如另一条评论提到的那样,最好记录事件的时间,但在继续新的审判之前允许系统“清除”任意时间.

于 2013-08-02T15:39:11.963 回答