diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..628ca34 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +Data/** +Calibration Files/** \ No newline at end of file diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..b80dd73 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,10 @@ +[submodule "Protocols/Matching"] + path = Protocols/Matching + url = https://github.com/tsgouvea/BpodProtocols_Matching.git +[submodule "Protocols/FI_2AFC"] + path = Protocols/FI_2AFC + url = https://github.com/tsgouvea/BpodProtocols_FI_2AFC.git +[submodule "Protocols/Olf2AFC"] + path = Protocols/Olf2AFC + url = https://github.com/tsgouvea/BpodProtocols_Olf2AFC.git + branch = junya diff --git a/Calibration Files/LiquidCalibration.mat b/Calibration Files/LiquidCalibration.mat index b31c2a7..f08886c 100644 Binary files a/Calibration Files/LiquidCalibration.mat and b/Calibration Files/LiquidCalibration.mat differ diff --git a/Functions/Internal Functions/FindArduinoPorts.m b/Functions/Internal Functions/FindArduinoPorts.m index 8186193..c118f15 100644 --- a/Functions/Internal Functions/FindArduinoPorts.m +++ b/Functions/Internal Functions/FindArduinoPorts.m @@ -11,7 +11,20 @@ end ArduinoPorts = ArduinoPorts(1:nPorts); elseif ismac - + [trash, RawSerialPortList] = system('ls /dev/tty.usbmodem*'); + string = strtrim(RawSerialPortList); + PortStringPositions = strfind(string, '/dev/tty.usbmodem'); + nPorts = length(PortStringPositions); + CandidatePorts = cell(1,nPorts); + nGoodPorts = 0; + for x = 1:nPorts + if PortStringPositions(x)+20 <= length(string) + CandidatePort = strtrim(string(PortStringPositions(x):PortStringPositions(x)+20)); + nGoodPorts = nGoodPorts + 1; + CandidatePorts{nGoodPorts} = CandidatePort; + end + end + ArduinoPorts = CandidatePorts(1:nGoodPorts); else [trash, RawSerialPortList] = system('ls /dev/ttyACM*'); string = strtrim(RawSerialPortList); diff --git a/Protocols/FI_2AFC b/Protocols/FI_2AFC new file mode 160000 index 0000000..220128a --- /dev/null +++ b/Protocols/FI_2AFC @@ -0,0 +1 @@ +Subproject commit 220128aea1a2bf67f90b87ba75242acaccd46957 diff --git a/Protocols/Light2AFC/Light2AFC.m b/Protocols/Light2AFC/Light2AFC.m deleted file mode 100644 index 54e5f09..0000000 --- a/Protocols/Light2AFC/Light2AFC.m +++ /dev/null @@ -1,150 +0,0 @@ -%{ ----------------------------------------------------------------------------- - -This file is part of the Sanworks Bpod repository -Copyright (C) 2016 Sanworks LLC, Sound Beach, New York, USA - ----------------------------------------------------------------------------- - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, version 3. - -This program is distributed WITHOUT ANY WARRANTY and without even the -implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -%} -function Light2AFC -% This protocol is a starting point for a visual 2AFC task. -% After initiating each trial with a center-poke, -% the subject is rewarded for choosing the port that is lit. -% Written by Josh Sanders, 5/2015. -% -% SETUP -% You will need: -% - A Bpod MouseBox (or equivalent) configured with 3 ports. -% > Connect the left port in the box to Bpod Port#1. -% > Connect the center port in the box to Bpod Port#2. -% > Connect the right port in the box to Bpod Port#3. -% > Make sure the liquid calibration tables for ports 1 and 3 have -% calibration curves with several points surrounding 3ul. - -global BpodSystem - -%% Define parameters -S = BpodSystem.ProtocolSettings; % Load settings chosen in launch manager into current workspace as a struct called S -if isempty(fieldnames(S)) % If settings file was an empty struct, populate struct with default settings - S.GUI.RewardAmount = 3; %ul - S.GUI.CueDelay = 0.2; % How long the mouse must poke in the center to activate the goal port - S.GUI.ResponseTime = 5; % How long until the mouse must make a choice, or forefeit the trial - S.GUI.RewardDelay = 0; % How long the mouse must wait in the goal port for reward to be delivered - S.GUI.PunishDelay = 3; % How long the mouse must wait in the goal port for reward to be delivered -end - -% Initialize parameter GUI plugin -BpodParameterGUI('init', S); - -%% Define trials -MaxTrials = 1000; -TrialTypes = ceil(rand(1,1000)*2); -BpodSystem.Data.TrialTypes = []; % The trial type of each trial completed will be added here. - -%% Initialize plots -BpodSystem.ProtocolFigures.SideOutcomePlotFig = figure('Position', [200 200 1000 200],'name','Outcome plot','numbertitle','off', 'MenuBar', 'none', 'Resize', 'off'); -BpodSystem.GUIHandles.SideOutcomePlot = axes('Position', [.075 .3 .89 .6]); -SideOutcomePlot(BpodSystem.GUIHandles.SideOutcomePlot,'init',2-TrialTypes); -BpodNotebook('init'); - -%% Main trial loop -for currentTrial = 1:MaxTrials - S = BpodParameterGUI('sync', S); % Sync parameters with BpodParameterGUI plugin - R = GetValveTimes(S.GUI.RewardAmount, [1 3]); LeftValveTime = R(1); RightValveTime = R(2); % Update reward amounts - switch TrialTypes(currentTrial) % Determine trial-specific state matrix fields - case 1 - LeftPokeAction = 'LeftRewardDelay'; RightPokeAction = 'Punish'; StimulusOutput = {'PWM1', 255}; - case 2 - LeftPokeAction = 'Punish'; RightPokeAction = 'RightRewardDelay'; StimulusOutput = {'PWM3', 255}; - end - sma = NewStateMatrix(); % Assemble state matrix - sma = AddState(sma, 'Name', 'WaitForPoke', ... - 'Timer', 0,... - 'StateChangeConditions', {'Port2In', 'CueDelay'},... - 'OutputActions', {}); - sma = AddState(sma, 'Name', 'CueDelay', ... - 'Timer', S.GUI.CueDelay,... - 'StateChangeConditions', {'Port2Out', 'WaitForPoke', 'Tup', 'WaitForPortOut'},... - 'OutputActions', {}); - sma = AddState(sma, 'Name', 'WaitForPortOut', ... - 'Timer', 0,... - 'StateChangeConditions', {'Port2Out', 'WaitForResponse'},... - 'OutputActions', StimulusOutput); - sma = AddState(sma, 'Name', 'WaitForResponse', ... - 'Timer', S.GUI.ResponseTime,... - 'StateChangeConditions', {'Port1In', LeftPokeAction, 'Port3In', RightPokeAction, 'Tup', 'exit'},... - 'OutputActions', StimulusOutput); - sma = AddState(sma, 'Name', 'LeftRewardDelay', ... - 'Timer', S.GUI.RewardDelay,... - 'StateChangeConditions', {'Tup', 'LeftReward', 'Port1Out', 'CorrectEarlyWithdrawal'},... - 'OutputActions', {}); - sma = AddState(sma, 'Name', 'RightRewardDelay', ... - 'Timer', S.GUI.RewardDelay,... - 'StateChangeConditions', {'Tup', 'RightReward', 'Port3Out', 'CorrectEarlyWithdrawal'},... - 'OutputActions', {}); - sma = AddState(sma, 'Name', 'LeftReward', ... - 'Timer', LeftValveTime,... - 'StateChangeConditions', {'Tup', 'Drinking'},... - 'OutputActions', {'ValveState', 1}); - sma = AddState(sma, 'Name', 'RightReward', ... - 'Timer', RightValveTime,... - 'StateChangeConditions', {'Tup', 'Drinking'},... - 'OutputActions', {'ValveState', 4}); - sma = AddState(sma, 'Name', 'Drinking', ... - 'Timer', 0,... - 'StateChangeConditions', {'Port1Out', 'DrinkingGrace', 'Port3Out', 'DrinkingGrace'},... - 'OutputActions', {}); - sma = AddState(sma, 'Name', 'DrinkingGrace', ... - 'Timer', .5,... - 'StateChangeConditions', {'Tup', 'exit', 'Port1In', 'Drinking', 'Port3In', 'Drinking'},... - 'OutputActions', {}); - sma = AddState(sma, 'Name', 'Punish', ... - 'Timer', S.GUI.PunishDelay,... - 'StateChangeConditions', {'Tup', 'exit'},... - 'OutputActions', {}); - sma = AddState(sma, 'Name', 'CorrectEarlyWithdrawal', ... - 'Timer', 0,... - 'StateChangeConditions', {'Tup', 'exit'},... - 'OutputActions', {}); - SendStateMatrix(sma); - RawEvents = RunStateMatrix; - if ~isempty(fieldnames(RawEvents)) % If trial data was returned - BpodSystem.Data = AddTrialEvents(BpodSystem.Data,RawEvents); % Computes trial events from raw data - BpodSystem.Data = BpodNotebook('sync', BpodSystem.Data); % Sync with Bpod notebook plugin - BpodSystem.Data.TrialSettings(currentTrial) = S; % Adds the settings used for the current trial to the Data struct (to be saved after the trial ends) - BpodSystem.Data.TrialTypes(currentTrial) = TrialTypes(currentTrial); % Adds the trial type of the current trial to data - UpdateSideOutcomePlot(TrialTypes, BpodSystem.Data); - SaveBpodSessionData; % Saves the field BpodSystem.Data to the current data file - end - HandlePauseCondition; % Checks to see if the protocol is paused. If so, waits until user resumes. - if BpodSystem.BeingUsed == 0 - return - end -end - -function UpdateSideOutcomePlot(TrialTypes, Data) -global BpodSystem -Outcomes = zeros(1,Data.nTrials); -for x = 1:Data.nTrials - if ~isnan(Data.RawEvents.Trial{x}.States.Drinking(1)) - Outcomes(x) = 1; - elseif ~isnan(Data.RawEvents.Trial{x}.States.Punish(1)) - Outcomes(x) = 0; - elseif ~isnan(Data.RawEvents.Trial{x}.States.CorrectEarlyWithdrawal(1)) - Outcomes(x) = 2; - else - Outcomes(x) = 3; - end -end -SideOutcomePlot(BpodSystem.GUIHandles.SideOutcomePlot,'update',Data.nTrials+1,2-TrialTypes,Outcomes); diff --git a/Protocols/Matching b/Protocols/Matching new file mode 160000 index 0000000..fa7219b --- /dev/null +++ b/Protocols/Matching @@ -0,0 +1 @@ +Subproject commit fa7219b0a7030d1fdc300880c4f202cb34e216ec diff --git a/Protocols/Olf2AFC b/Protocols/Olf2AFC new file mode 160000 index 0000000..bd9b2e1 --- /dev/null +++ b/Protocols/Olf2AFC @@ -0,0 +1 @@ +Subproject commit bd9b2e111c656793654802a0f8fce498d3ee4ee2 diff --git a/Protocols/Operant/Operant.m b/Protocols/Operant/Operant.m deleted file mode 100644 index 443af66..0000000 --- a/Protocols/Operant/Operant.m +++ /dev/null @@ -1,146 +0,0 @@ -%{ ----------------------------------------------------------------------------- - -This file is part of the Sanworks Bpod repository -Copyright (C) 2016 Sanworks LLC, Sound Beach, New York, USA - ----------------------------------------------------------------------------- - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, version 3. - -This program is distributed WITHOUT ANY WARRANTY and without even the -implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -%} -function Operant -% This protocol introduces a naive mouse to water available in ports 1 and 3. -% Written by Josh Sanders, 5/2015. -% -% SETUP -% You will need: -% - A Bpod MouseBox (or equivalent) configured with 3 ports. -% - Place masking tape over the center port (Port 2). - -global BpodSystem - -%% Define parameters -S = BpodSystem.ProtocolSettings; % Load settings chosen in launch manager into current workspace as a struct called S -if isempty(fieldnames(S)) % If settings file was an empty struct, populate struct with default settings - S.GUI.CurrentBlock = 1; % Training level % 1 = Direct Delivery at both ports 2 = Poke for delivery - S.GUI.RewardAmount = 5; %ul - S.GUI.PortOutRegDelay = 0.5; % How long the mouse must remain out before poking back in -end - -% Initialize parameter GUI plugin -BpodParameterGUI('init', S); - -%% Define trials -nSinglePokeTrials = 5; % Number of trials where each poke is rewarded -nDoublePokeTrials = 5; % Number of trials requiring 2 pokes per reward -nTriplePokeTrials = 5; % Number of trials requiring 3 pokes per reward -nRandomTrials = 850; % Number of randomly interleaved single, double and triple poke trials -MaxTrials = nSinglePokeTrials+nDoublePokeTrials+nTriplePokeTrials+nRandomTrials; -TrialTypes = [ones(1,nSinglePokeTrials) ones(1,nDoublePokeTrials)*2 ones(1,nTriplePokeTrials)*3 ceil(rand(1,nRandomTrials)*3)]; -BpodSystem.Data.TrialTypes = []; % The trial type of each trial completed will be added here. - -%% Initialize plots -% TrialType Outcome Plot (displays each future trial type, and scores completed trials as correct/incorrect -BpodSystem.ProtocolFigures.OutcomePlotFig = figure('Position', [200 200 1000 200],'name','Outcome plot','numbertitle','off', 'MenuBar', 'none', 'Resize', 'off'); -BpodSystem.GUIHandles.OutcomePlot = axes('Position', [.075 .3 .89 .6]); -TrialTypeOutcomePlot(BpodSystem.GUIHandles.OutcomePlot,'init',TrialTypes); -% Bpod Notebook (to record text notes about the session or individual trials) -BpodNotebook('init'); - -%% Main trial loop -for currentTrial = 1:MaxTrials - S = BpodParameterGUI('sync', S); % Sync parameters with BpodParameterGUI plugin - R = GetValveTimes(S.GUI.RewardAmount, [1 3]); LeftValveTime = R(1); RightValveTime = R(2); % Update reward amounts - switch TrialTypes(currentTrial) % Determine trial-specific state matrix fields - case 1 - StateOnLeftPoke1 = 'LeftReward'; StateOnRightPoke1 = 'RightReward'; - StateOnLeftPoke2 = 'LeftReward'; StateOnRightPoke2 = 'RightReward'; - case 2 - StateOnLeftPoke1 = 'WaitForPokeOut1'; StateOnRightPoke1 = 'WaitForPokeOut1'; - StateOnLeftPoke2 = 'LeftReward'; StateOnRightPoke2 = 'RightReward'; - case 3 - StateOnLeftPoke1 = 'WaitForPokeOut1'; StateOnRightPoke1 = 'WaitForPokeOut1'; - StateOnLeftPoke2 = 'WaitForPokeOut2'; StateOnRightPoke2 = 'WaitForPokeOut2'; - end - sma = NewStateMatrix(); % Assemble state matrix - sma = AddState(sma, 'Name', 'WaitForPoke1', ... - 'Timer', 0,... - 'StateChangeConditions', {'Port1In', StateOnLeftPoke1, 'Port3In', StateOnRightPoke1},... - 'OutputActions', {}); - sma = AddState(sma, 'Name', 'WaitForPokeOut1', ... - 'Timer', S.GUI.PortOutRegDelay,... - 'StateChangeConditions', {'Port1Out', 'EnforcePokeOut1', 'Port3Out', 'EnforcePokeOut1'},... - 'OutputActions', {}); - sma = AddState(sma, 'Name', 'EnforcePokeOut1', ... - 'Timer', S.GUI.PortOutRegDelay,... - 'StateChangeConditions', {'Tup', 'WaitForPoke2'},... - 'OutputActions', {}); - sma = AddState(sma, 'Name', 'WaitForPoke2', ... - 'Timer', 0,... - 'StateChangeConditions', {'Port1In', StateOnLeftPoke2, 'Port3In', StateOnRightPoke2},... - 'OutputActions', {}); - sma = AddState(sma, 'Name', 'WaitForPokeOut2', ... - 'Timer', S.GUI.PortOutRegDelay,... - 'StateChangeConditions', {'Port1Out', 'EnforcePokeOut2', 'Port3Out', 'EnforcePokeOut2'},... - 'OutputActions', {}); - sma = AddState(sma, 'Name', 'EnforcePokeOut2', ... - 'Timer', S.GUI.PortOutRegDelay,... - 'StateChangeConditions', {'Tup', 'WaitForPoke3'},... - 'OutputActions', {}); - sma = AddState(sma, 'Name', 'WaitForPoke3', ... - 'Timer', 0,... - 'StateChangeConditions', {'Port1In', 'LeftReward', 'Port3In', 'RightReward'},... - 'OutputActions', {}); - sma = AddState(sma, 'Name', 'LeftReward', ... - 'Timer', LeftValveTime,... - 'StateChangeConditions', {'Tup', 'Drinking'},... - 'OutputActions', {'ValveState', 1}); - sma = AddState(sma, 'Name', 'RightReward', ... - 'Timer', RightValveTime,... - 'StateChangeConditions', {'Tup', 'Drinking'},... - 'OutputActions', {'ValveState', 4}); - sma = AddState(sma, 'Name', 'Drinking', ... - 'Timer', 10,... - 'StateChangeConditions', {'Tup', 'exit', 'Port1Out', 'ConfirmPortOut', 'Port3Out', 'ConfirmPortOut'},... - 'OutputActions', {}); - sma = AddState(sma, 'Name', 'ConfirmPortOut', ... - 'Timer', S.GUI.PortOutRegDelay,... - 'StateChangeConditions', {'Tup', 'exit', 'Port1In', 'Drinking', 'Port3In', 'Drinking'},... - 'OutputActions', {}); - SendStateMatrix(sma); - RawEvents = RunStateMatrix; - if ~isempty(fieldnames(RawEvents)) % If trial data was returned - BpodSystem.Data = AddTrialEvents(BpodSystem.Data,RawEvents); % Computes trial events from raw data - BpodSystem.Data = BpodNotebook('sync', BpodSystem.Data); % Sync with Bpod notebook plugin - BpodSystem.Data.TrialSettings(currentTrial) = S; % Adds the settings used for the current trial to the Data struct (to be saved after the trial ends) - BpodSystem.Data.TrialTypes(currentTrial) = TrialTypes(currentTrial); % Adds the trial type of the current trial to data - UpdateOutcomePlot(TrialTypes, BpodSystem.Data); - SaveBpodSessionData; % Saves the field BpodSystem.Data to the current data file - end - HandlePauseCondition; % Checks to see if the protocol is paused. If so, waits until user resumes. - if BpodSystem.BeingUsed == 0 - return - end -end - -function UpdateOutcomePlot(TrialTypes, Data) -% Determine outcomes from state data and score as the SideOutcomePlot plugin expects -global BpodSystem -Outcomes = zeros(1,Data.nTrials); -for x = 1:Data.nTrials - if ~isnan(Data.RawEvents.Trial{x}.States.Drinking(1)) - Outcomes(x) = 1; - else - Outcomes(x) = 3; - end -end -TrialTypeOutcomePlot(BpodSystem.GUIHandles.OutcomePlot,'update',Data.nTrials+1,TrialTypes,Outcomes); diff --git a/Protocols/PsychToolboxSound/PsychToolboxSound.m b/Protocols/PsychToolboxSound/PsychToolboxSound.m deleted file mode 100644 index 5040bb5..0000000 --- a/Protocols/PsychToolboxSound/PsychToolboxSound.m +++ /dev/null @@ -1,191 +0,0 @@ -%{ ----------------------------------------------------------------------------- - -This file is part of the Sanworks Bpod repository -Copyright (C) 2016 Sanworks LLC, Sound Beach, New York, USA - ----------------------------------------------------------------------------- - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, version 3. - -This program is distributed WITHOUT ANY WARRANTY and without even the -implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -%} -function PsychToolboxSound -% This protocol demonstrates a 2AFC task using PsychToolbox to generate sound stimuli. -% Subjects initialize each trial with a poke into port 2. After a delay, a tone plays. -% Subjects are rewarded for responding left for low-pitch tones, and right for high. -% Written by Josh Sanders, 4/2016 -% -% SETUP -% You will need: -% - Windows 7 or Ubuntu 14.XX with the -lowlatency package installed -% - ASUS Xonar DX 7-channel sound card installed. If using Windows, install -% the drivers from the ASUS website, and configure the latency to 1ms in the ASUS config panel. -% - PsychToolbox 3 installed -% - The Xonar DX comes with an RCA cable. Use an RCA to BNC adapter to -% connect channel 3 to one of Bpod's BNC input channels for a record of the -% exact time each sound played. - -global BpodSystem - -%% Define parameters -S = BpodSystem.ProtocolSettings; % Load settings chosen in launch manager into current workspace as a struct called S -if isempty(fieldnames(S)) % If settings file was an empty struct, populate struct with default settings - S.GUI.TrainingLevel = 2; % Configurable reward condition schemes. 'BothCorrect' rewards either side. - S.GUIMeta.TrainingLevel.Style = 'popupmenu'; % the GUIMeta field is used by the ParameterGUI plugin to customize UI objects. - S.GUIMeta.TrainingLevel.String = {'BothCorrect', '2AFC'}; - S.GUI.SoundDuration = 0.5; % Duration of sound (s) - S.GUI.SinWaveFreqLeft = 500; % Frequency of left cue - S.GUI.SinWaveFreqRight = 2000; % Frequency of right cue - S.GUI.RewardAmount = 5; % in ul - S.GUI.StimulusDelayDuration = 0; % Seconds before stimulus plays on each trial - S.GUI.TimeForResponse = 5; % Seconds after stimulus sampling for a response - S.GUI.PunishTimeoutDuration = 2; % Seconds to wait on errors before next trial can start - S.GUI.PunishSound = 1; % if 1, plays a white noise pulse on error. if 0, no sound is played. - S.GUIMeta.PunishSound.Style = 'checkbox'; - S.GUIPanels.Task = {'TrainingLevel', 'RewardAmount', 'PunishSound'}; % GUIPanels organize the parameters into groups. - S.GUIPanels.Sound = {'SinWaveFreqLeft', 'SinWaveFreqRight', 'SoundDuration'}; - S.GUIPanels.Time = {'StimulusDelayDuration', 'TimeForResponse', 'PunishTimeoutDuration'}; -end - -% Initialize parameter GUI plugin -BpodParameterGUI('init', S); - -%% Define trials -MaxTrials = 5000; -TrialTypes = ceil(rand(1,MaxTrials)*2); -BpodSystem.Data.TrialTypes = []; % The trial type of each trial completed will be added here. - -%% Initialize plots -% Side Outcome Plot -BpodSystem.ProtocolFigures.SideOutcomePlotFig = figure('Position', [200 200 1000 200],'name','Outcome plot','numbertitle','off', 'MenuBar', 'none', 'Resize', 'off'); -BpodSystem.GUIHandles.SideOutcomePlot = axes('Position', [.075 .3 .89 .6]); -SideOutcomePlot(BpodSystem.GUIHandles.SideOutcomePlot,'init',2-TrialTypes); -% Bpod Notebook (to record text notes about the session or individual trials) -BpodNotebook('init'); -% Total Reward display (online display of the total amount of liquid reward earned) -TotalRewardDisplay('init'); - -%% Define stimuli and send to sound server -SF = 192000; % Sound card sampling rate -LeftSound = GenerateSineWave(SF, S.GUI.SinWaveFreqLeft, S.GUI.SoundDuration); % Sampling freq (hz), Sine frequency (hz), duration (s) -RightSound = GenerateSineWave(SF, S.GUI.SinWaveFreqRight, S.GUI.SoundDuration); % Sampling freq (hz), Sine frequency (hz), duration (s) -PunishSound = (rand(1,SF*.5)*2) - 1; -% Generate early withdrawal sound -W1 = GenerateSineWave(SF, 1000, .5); W2 = GenerateSineWave(SF, 1200, .5); EarlyWithdrawalSound = W1+W2; -P = SF/100; Interval = P; -for x = 1:50 % Gate waveform to create pulses - EarlyWithdrawalSound(P:P+Interval) = 0; - P = P+(Interval*2); -end - -% Program sound server -PsychToolboxSoundServer('init') -PsychToolboxSoundServer('Load', 1, LeftSound); -PsychToolboxSoundServer('Load', 2, RightSound); -PsychToolboxSoundServer('Load', 3, PunishSound); -PsychToolboxSoundServer('Load', 4, EarlyWithdrawalSound); - -% Set soft code handler to trigger sounds -BpodSystem.SoftCodeHandlerFunction = 'SoftCodeHandler_PlaySound'; - -%% Main trial loop -for currentTrial = 1:MaxTrials - S = BpodParameterGUI('sync', S); % Sync parameters with BpodParameterGUI plugin - LeftSound = GenerateSineWave(SF, S.GUI.SinWaveFreqLeft, S.GUI.SoundDuration); % Sampling freq (hz), Sine frequency (hz), duration (s) - RightSound = GenerateSineWave(SF, S.GUI.SinWaveFreqRight, S.GUI.SoundDuration); % Sampling freq (hz), Sine frequency (hz), duration (s) - PsychToolboxSoundServer('Load', 1, LeftSound); - PsychToolboxSoundServer('Load', 2, RightSound); - R = GetValveTimes(S.GUI.RewardAmount, [1 3]); LeftValveTime = R(1); RightValveTime = R(2); % Update reward amounts - switch TrialTypes(currentTrial) % Determine trial-specific state matrix fields - case 1 - OutputActionArgument = {'SoftCode', 1, 'BNCState', 1}; - LeftActionState = 'Reward'; RightActionState = 'Punish'; CorrectWithdrawalEvent = 'Port1Out'; - ValveCode = 1; ValveTime = LeftValveTime; - case 2 - OutputActionArgument = {'SoftCode', 2, 'BNCState', 1}; - LeftActionState = 'Punish'; RightActionState = 'Reward'; CorrectWithdrawalEvent = 'Port3Out'; - ValveCode = 4; ValveTime = RightValveTime; - end - sma = NewStateMatrix(); % Assemble state matrix - sma = AddState(sma, 'Name', 'WaitForCenterPoke', ... - 'Timer', 0,... - 'StateChangeConditions', {'Port2In', 'Delay'},... - 'OutputActions', {}); - sma = AddState(sma, 'Name', 'Delay', ... - 'Timer', S.GUI.StimulusDelayDuration,... - 'StateChangeConditions', {'Tup', 'DeliverStimulus'},... - 'OutputActions', {}); - sma = AddState(sma, 'Name', 'DeliverStimulus', ... - 'Timer', S.GUI.SoundDuration,... - 'StateChangeConditions', {'Tup', 'WaitForResponse', 'Port2Out', 'EarlyWithdrawal'},... - 'OutputActions', OutputActionArgument); - sma = AddState(sma, 'Name', 'EarlyWithdrawal', ... - 'Timer', 0,... - 'StateChangeConditions', {'Tup', 'EarlyWithdrawalPunish'},... - 'OutputActions', {'SoftCode', 255}); - sma = AddState(sma, 'Name', 'WaitForResponse', ... - 'Timer', S.GUI.TimeForResponse,... - 'StateChangeConditions', {'Tup', 'exit', 'Port1In', LeftActionState, 'Port3In', RightActionState},... - 'OutputActions', {'PWM1', 255, 'PWM3', 255}); - sma = AddState(sma, 'Name', 'Reward', ... - 'Timer', ValveTime,... - 'StateChangeConditions', {'Tup', 'Drinking'},... - 'OutputActions', {'ValveState', ValveCode}); - sma = AddState(sma, 'Name', 'Drinking', ... - 'Timer', 10,... - 'StateChangeConditions', {'Tup', 'exit', CorrectWithdrawalEvent, 'exit'},... - 'OutputActions', {}); - sma = AddState(sma, 'Name', 'Punish', ... - 'Timer', S.GUI.PunishTimeoutDuration,... - 'StateChangeConditions', {'Tup', 'exit'},... - 'OutputActions', {'SoftCode', 3}); - sma = AddState(sma, 'Name', 'EarlyWithdrawalPunish', ... - 'Timer', S.GUI.PunishTimeoutDuration,... - 'StateChangeConditions', {'Tup', 'exit'},... - 'OutputActions', {'SoftCode', 4}); - SendStateMatrix(sma); % Send the state matrix to the Bpod device - RawEvents = RunStateMatrix; % Run the trial and return events - if ~isempty(fieldnames(RawEvents)) % If trial data was returned (i.e. if not final trial, interrupted by user) - BpodSystem.Data = AddTrialEvents(BpodSystem.Data,RawEvents); % Computes trial events from raw data - BpodSystem.Data = BpodNotebook('sync', BpodSystem.Data); % Sync with Bpod notebook plugin - BpodSystem.Data.TrialSettings(currentTrial) = S; % Adds the settings used for the current trial to the Data struct (to be saved after the trial ends) - BpodSystem.Data.TrialTypes(currentTrial) = TrialTypes(currentTrial); % Adds the trial type of the current trial to data - UpdateSideOutcomePlot(TrialTypes, BpodSystem.Data); - UpdateTotalRewardDisplay(S.GUI.RewardAmount, currentTrial); - SaveBpodSessionData; % Saves the field BpodSystem.Data to the current data file - end - HandlePauseCondition; % Checks to see if the protocol is paused. If so, waits until user resumes. - if BpodSystem.BeingUsed == 0 % If protocol was stopped, exit the loop - return - end -end - -function UpdateSideOutcomePlot(TrialTypes, Data) -% Determine outcomes from state data and score as the SideOutcomePlot plugin expects -global BpodSystem -Outcomes = zeros(1,Data.nTrials); -for x = 1:Data.nTrials - if ~isnan(Data.RawEvents.Trial{x}.States.Reward(1)) - Outcomes(x) = 1; - elseif ~isnan(Data.RawEvents.Trial{x}.States.Punish(1)) - Outcomes(x) = 0; - else - Outcomes(x) = 3; - end -end -SideOutcomePlot(BpodSystem.GUIHandles.SideOutcomePlot,'update',Data.nTrials+1,2-TrialTypes,Outcomes); - -function UpdateTotalRewardDisplay(RewardAmount, currentTrial) -% If rewarded based on the state data, update the TotalRewardDisplay -global BpodSystem - if ~isnan(BpodSystem.Data.RawEvents.Trial{currentTrial}.States.Reward(1)) - TotalRewardDisplay('add', RewardAmount); - end \ No newline at end of file diff --git a/Protocols/PsychToolboxSound/SoftCodeHandler_PlaySound.m b/Protocols/PsychToolboxSound/SoftCodeHandler_PlaySound.m deleted file mode 100644 index d3ba318..0000000 --- a/Protocols/PsychToolboxSound/SoftCodeHandler_PlaySound.m +++ /dev/null @@ -1,6 +0,0 @@ -function SoftCodeHandler_PlaySound(SoundID) -if SoundID ~= 255 - PsychToolboxSoundServer('Play', SoundID); -else - PsychToolboxSoundServer('StopAll'); -end \ No newline at end of file diff --git a/Protocols/README.md b/Protocols/README.md new file mode 100644 index 0000000..cc2d760 --- /dev/null +++ b/Protocols/README.md @@ -0,0 +1,2 @@ +# BpodProtocols +Submodule for Bpod containing protocols diff --git a/Protocols/ToneClouds4BPod/GenerateToneCloud.m b/Protocols/ToneClouds4BPod/GenerateToneCloud.m deleted file mode 100644 index 3883030..0000000 --- a/Protocols/ToneClouds4BPod/GenerateToneCloud.m +++ /dev/null @@ -1,127 +0,0 @@ -function [out, cloud, cloud_toplot] = GenerateToneCloud(rewarded, r, StimSettings) -%{ -GENERATETONECLOUD: Generates Cloud of tones - -This function is based on MakeToneCloud (written by P.Z.) which can be found in SoundSection.m -Not all features have been imported to this version. - -% To do: -error handling -%} - -%r is as defined by PZ (0 to 1), 0 meaning that the probability of target and non target freq is the same - -global BpodSystem - -nTones = StimSettings.nTones; -ToneOverlap = StimSettings.ToneOverlap; -ToneDuration = StimSettings.ToneDuration; -minFreq = StimSettings.minFreq; -maxFreq = StimSettings.maxFreq; -SamplingRate = StimSettings.SamplingRate; -nTones_noEvidence = StimSettings.Noevidence; -Volume = StimSettings.Volume; - -nFreq = StimSettings.nFreq; % Number of different frequencies to sample from -toneFreq = logspace(log10(minFreq),log10(maxFreq),nFreq); % Nfreq logly distributed -SoundCal = BpodSystem.CalibrationTables.SoundCal; -toneAtt = polyval(SoundCal(1,1).Coefficient,toneFreq)'; - -diffSPL = Volume - SoundCal(1,1).TargetSPL; -attFactor = sqrt(10.^(diffSPL./10)); - -att = toneAtt.*repmat(attFactor,nFreq,1); - -nTones_Evidence = nTones - nTones_noEvidence; % Number of tones with controlled evidence -ramp = StimSettings.ramp; % Fraction of tone duration that is used for the envelope - -seed = 1; -% if ~isnan(seed) -% rand('twister',seed); -% end - -noEvidence_ind = randi(nFreq,1,nTones_noEvidence); % Frequency indices of no evidence tones - -pTarget = (1/2+r/2); -%boundy = [nFreq/3 2/3*nFreq]; % debugging purposes - - -switch true - case strcmp(rewarded,'low') - - Evidence_ind = randi(nFreq/3,1,nTones_Evidence)+nFreq*2/3; % Fill everything with nontarget (high) - - %this gives exactly the number of tones according to the pTarget - %nTarget = round(nTones_Evidence*pTarget); % Number of tones with target frequencies - %ind_replace = randperm(nTones_Evidence); % Indices to replace with target frequencies - %Evidence_ind(ind_replace(1:nTarget))=randi(nFreq/3,1,nTarget); % Replace with target freqs (low) - - %this draws a independent random numbers for each slot - %note that the amount of slots with target freq will vary from - %trial to trial, even when the same pTarget - ind_replace = find(rand(1,nTones_Evidence) -1; - SideList = SideList(ValidTrials); - OutcomeRecord = OutcomeRecord(ValidTrials); - SidedEvidenceStrength = SidedEvidenceStrength(ValidTrials); - nTrials = sum(ValidTrials); - LeftTrials = zeros(1,nTrials); - LeftTrials((SideList == 0) & (OutcomeRecord == 1)) = 1; - LeftTrials((SideList == 0) & (OutcomeRecord == 0)) = 0; - LeftTrials((SideList == 1) & (OutcomeRecord == 1)) = 0; - LeftTrials((SideList == 1) & (OutcomeRecord == 0)) = 1; - - Xdata = BpodSystem.GUIHandles.PsychometricData(:,1); - Ydata = BpodSystem.GUIHandles.PsychometricData(:,2); - nBins = length(Xdata); - for i = 1:nBins - Ydata(i) = mean(LeftTrials(SidedEvidenceStrength==Xdata(i))); - end - - set(BpodSystem.GUIHandles.PsychometricLine, 'xdata', Xdata, 'ydata', Ydata); - BpodSystem.GUIHandles.PsychometricData(:,1) = Xdata; - BpodSystem.GUIHandles.PsychometricData(:,2) = Ydata; - set(AxesHandle,'XLim',[-1 1], 'Ylim', [0 1]); -end - -end - diff --git a/Protocols/ToneClouds4BPod/SoftCodeHandler_PlaySound.m b/Protocols/ToneClouds4BPod/SoftCodeHandler_PlaySound.m deleted file mode 100644 index d3ba318..0000000 --- a/Protocols/ToneClouds4BPod/SoftCodeHandler_PlaySound.m +++ /dev/null @@ -1,6 +0,0 @@ -function SoftCodeHandler_PlaySound(SoundID) -if SoundID ~= 255 - PsychToolboxSoundServer('Play', SoundID); -else - PsychToolboxSoundServer('StopAll'); -end \ No newline at end of file diff --git a/Protocols/ToneClouds4BPod/StimulusPlot.m b/Protocols/ToneClouds4BPod/StimulusPlot.m deleted file mode 100644 index 45fac09..0000000 --- a/Protocols/ToneClouds4BPod/StimulusPlot.m +++ /dev/null @@ -1,59 +0,0 @@ - -function StimulusPlot(AxesHandle, Action, varargin) -%% -% Plug in to Plot Stimulus -% AxesHandle = handle of axes to plot on -% Action = specific action for plot, "init" - initialize OR "update" - update plot - -%Example usage: -% StimulusPlot(AxesHandle,'init',Stimulus) - -% Fede - -%% Code Starts Here -global BpodSystem - -switch Action - case 'init' - %initialize pokes plot - - axes(AxesHandle); - - nStim = varargin{1}; - - %plot in specified axes - - for i=1:nStim - BpodSystem.GUIHandles.Stimulus(i) = line([0 0],[0 0]); - end - - BpodSystem.GUIHandles.RTline = line([0/0 0/0],[0 18],'Color',[1 0 0]); - - ylabel(AxesHandle, 'Frequency', 'FontSize', 18); - xlabel(AxesHandle, 'Time', 'FontSize', 18); - hold(AxesHandle, 'on'); - - case 'update' - - Stimulus = varargin{1}; - StimulusDetails = varargin{2}; - - for i=1:size(BpodSystem.GUIHandles.Stimulus,2) - set(BpodSystem.GUIHandles.Stimulus(i),'XData', (1:size(Stimulus,2))/1920); - set(BpodSystem.GUIHandles.Stimulus(i),'YData',Stimulus(i,:)); - if length(varargin)>2 - tDeliverStimulus = varargin{3}; - set(BpodSystem.GUIHandles.RTline,'XData',[tDeliverStimulus tDeliverStimulus]); - end - end - - set(BpodSystem.GUIHandles.StimulusPlot,'YLim',[1 18],'XLim', [1 size(Stimulus,2)]/1920); - - title_str = []; - fnames = fields(StimulusDetails); - for i=1:length(fnames) - title_str = [title_str ' ' fnames{i} ': ' num2str(StimulusDetails.(fnames{i}),'%2.2f')]; - end - set(get(BpodSystem.GUIHandles.StimulusPlot, 'Title'), 'String', title_str); -end - diff --git a/Protocols/ToneClouds4BPod/TC4B_PulsePalProgram.mat b/Protocols/ToneClouds4BPod/TC4B_PulsePalProgram.mat deleted file mode 100644 index c12206c..0000000 Binary files a/Protocols/ToneClouds4BPod/TC4B_PulsePalProgram.mat and /dev/null differ diff --git a/Protocols/ToneClouds4BPod/ToneClouds4BPod.m b/Protocols/ToneClouds4BPod/ToneClouds4BPod.m deleted file mode 100644 index 6e38af3..0000000 --- a/Protocols/ToneClouds4BPod/ToneClouds4BPod.m +++ /dev/null @@ -1,475 +0,0 @@ -function ToneClouds4BPod - -% This protocol implements ToneClouds (developed by P. Znamenskiy) on Bpod -% Based on PsychoToolboxSound (written by J.Sanders) - -% Written by F.Carnevale, 2/2015. -% Modified by J. Sanders 3/2016. - -global BpodSystem - -%% Define parameters -S = BpodSystem.ProtocolSettings; % Load settings chosen in launch manager into current workspace as a struct called S -if isempty(fieldnames(S)) % If settings file was an empty struct, populate struct with default settings - % Stimulation Parameters - S.GUI.UseStimulation = 0; - S.GUIMeta.UseStimulation.Style = 'checkbox'; - S.GUI.TrainDelay = 0.008; - S.GUI.PulseWidth = 0.001; - S.GUI.PulseInterval = 0.1; - S.GUI.StimProbability = 1; - S.GUIPanels.Stimulation = {'UseStimulation', 'TrainDelay', 'PulseWidth', 'PulseInterval', 'StimProbability'}; - - % Protocol parameters - % 1. Define parameters and values (with legacy syntax) - S.GUI.Subject = BpodSystem.GUIData.SubjectName; - S.GUI.Stage = 3; - % 2. Parameter types and meta-data (assumes "edit" style if no meta info is specified) - S.GUIMeta.Stage.Style = 'popupmenu'; - S.GUIMeta.Stage.String = {'Direct', 'NextCorrectPoke', 'OnlyCorrectPoke'}; - % Assigns each parameter to a panel on the GUI (assumes "Parameters" panel if not specified) - S.GUIPanels.Protocol = {'Subject', 'Stage'}; - - % Stimulus parameters - S.GUI.UseMiddleOctave = 1; - S.GUI.DifficultyLow = 1; - S.GUI.DifficultyHigh = 1; - S.GUI.nDifficulties = 0; - S.GUI.ToneOverlap = 0; - S.GUI.ToneDuration = 0.03; - S.GUI.SoundMaxDuration = 1; - S.GUI.NoEvidence = 0; - S.GUI.AudibleHuman = 1; - S.GUI.UseMiddleOctave = 1; - S.GUIMeta.UseMiddleOctave.Style = 'popupmenu'; - S.GUIMeta.UseMiddleOctave.String = {'no', 'yes'}; - S.GUIMeta.AudibleHuman.Style = 'checkbox'; - S.GUIPanels.StimulusSettings = {'UseMiddleOctave', 'DifficultyLow', 'DifficultyHigh', 'nDifficulties'... - 'ToneOverlap', 'ToneDuration', 'SoundMaxDuration', 'NoEvidence', 'AudibleHuman'}; - - % Reward parameters - S.GUI.RewardAmount = 2.5; - S.GUI.PunishSound = 1; - S.GUI.FreqSide = 1; - S.GUIMeta.FreqSide.Style = 'popupmenu'; - S.GUIMeta.FreqSide.String = {'LowLeft', 'LowRight'}; - S.GUIMeta.PunishSound.Style = 'checkbox'; - S.GUIPanels.RewardSettings = {'RewardAmount', 'FreqSide', 'PunishSound'}; - - % Trial structure - S.GUI.TimeForResponse = 10; - S.GUI.TimeForReversal = 5; - S.GUI.TimeoutDuration = 4; - S.GUIPanels.TrialStructure = {'TimeForResponse', 'TimeForReversal', 'TimeoutDuration'}; - - % Prestimulus delay - S.GUI.PrestimDistribution = 1; - S.GUIMeta.PrestimDistribution.Style = 'popupmenu'; - S.GUIMeta.PrestimDistribution.String = {'Delta', 'Uniform', 'Exponential'}; - S.GUI.PrestimDurationStart = 0.050; - S.GUI.PrestimDurationEnd = 0.050; - S.GUI.PrestimDurationStep = 0.050; - S.GUI.PrestimDurationNtrials = 50; - S.GUI.PrestimDurationCurrent = S.GUI.PrestimDurationStart; - S.GUIMeta.PrestimDurationCurrent.Style = 'text'; - S.GUIPanels.PrestimulusDelay = {'PrestimDistribution', 'PrestimDurationStart', 'PrestimDurationEnd',... - 'PrestimDurationStep', 'PrestimDurationNtrials', 'PrestimDurationCurrent'}; - - % Antibias - S.GUI.Antibias = 1; - S.GUIMeta.Antibias.Style = 'popupmenu'; - S.GUIMeta.Antibias.String = {'no', 'yes'}; - S.GUIPanels.Antibias = {'Antibias'}; - -end -% Set frequency range -if S.GUI.AudibleHuman - minFreq = 2000; maxFreq = 10000; -else - minFreq = 5000; maxFreq = 40000; -end -% Blank Pulse Pal Parameters -S.InitialPulsePalParameters = struct; -% Other Stimulus settings (not in the GUI) -StimulusSettings.ToneOverlap = S.GUI.ToneOverlap; -StimulusSettings.ToneDuration = S.GUI.ToneDuration; -StimulusSettings.minFreq = minFreq; -StimulusSettings.maxFreq = maxFreq; -StimulusSettings.SamplingRate = 192000; % Sound card sampling rate; -StimulusSettings.UseMiddleOctave = S.GUIMeta.UseMiddleOctave(S.GUI.UseMiddleOctave); -StimulusSettings.Noevidence = S.GUI.NoEvidence; -StimulusSettings.nFreq = 18; % Number of different frequencies to sample from -StimulusSettings.ramp = 0.005; -StimulusSettings.Volume = 60; - -%% Define trials -MaxTrials = 5000; -TrialTypes = ceil(rand(1,MaxTrials)*2); % correct side for each trial -EvidenceStrength = nan(1,MaxTrials); % evidence strength for each trial -PrestimDuration = nan(1,MaxTrials); % prestimulation delay period for each trial -Outcomes = nan(1,MaxTrials); -StimulationTrials = zeros(1,MaxTrials); -AccumulatedReward=0; - -BpodSystem.Data.TrialTypes = []; % The trial type of each trial completed will be added here. -BpodSystem.Data.EvidenceStrength = []; % The evidence strength of each trial completed will be added here. -BpodSystem.Data.PrestimDuration = []; % The evidence strength of each trial completed will be added here. -BpodSystem.Data.StimulationTrials = []; - -%% Initialize plots - -% Initialize parameter GUI plugin -BpodParameterGUI('init', S); - -% Outcome plot -BpodSystem.ProtocolFigures.OutcomePlotFig = figure('Position', [50 50 1000 163],'name','Outcome plot','numbertitle','off', 'MenuBar', 'none', 'Resize', 'off'); -BpodSystem.GUIHandles.OutcomePlot = axes('Position', [.075 .3 .89 .6]); -OutcomePlot(BpodSystem.GUIHandles.OutcomePlot,'init',2-TrialTypes); - -% Notebook -%BpodNotebook('init'); - -% Performance -% PerformancePlot(BpodSystem.GUIHandles.PerformancePlot,'init'); -SlidingWindowSize = 30; % Size of sliding window average, units = trials -TrialGroups{1} = [1]; TrialGroups{2} = [2]; % Groups of trial types to plot %correct -TrialGroupNames{1} = 'Left'; TrialGroupNames{2} = 'Right'; % Names of consecutive groups -PerformancePlot('init', TrialGroups, TrialGroupNames, SlidingWindowSize); - -% Psychometric -BpodSystem.ProtocolFigures.PsychoPlotFig = figure('Position', [50 50 400 300],'name','Pshycometric plot','numbertitle','off', 'MenuBar', 'none', 'Resize', 'off'); -BpodSystem.GUIHandles.PsychoPlot = axes('Position', [.2 .25 .75 .65]); -PsychoPlot(BpodSystem.GUIHandles.PsychoPlot,'init'); - -% Stimulus plot -%BpodSystem.ProtocolFigures.StimulusPlotFig = figure('Position', [50 50 500 300],'name','Stimulus plot','numbertitle','off', 'MenuBar', 'none', 'Resize', 'off'); -%BpodSystem.GUIHandles.StimulusPlot = axes('Position', [.15 .2 .75 .65]); -%StimulusPlot(BpodSystem.GUIHandles.StimulusPlot,'init',StimulusSettings.nFreq); - -%%% Pokes plot -state_colors = struct( ... - 'WaitForCenterPoke', [0.5 0.5 1],... - 'Delay',0.3*[1 1 1],... - 'DeliverStimulus', 0.75*[1 1 0],... - 'GoSignal',[0.5 1 1],... - 'WaitForLeftPoke',[.2,.2,1],... - 'WaitForRightPoke',[.7,.7,1],... - 'Reward',[0,1,0],... - 'Drinking',[0,0,1],... - 'Punish',[1,0,0],... - 'EarlyWithdrawal',[1,0.3,0],... - 'EarlyWithdrawalPunish',[1,0,0],... - 'WaitForResponse',0.75*[0,1,1],... - 'CorrectWithdrawalEvent',[1,0,0],... - 'exit',0.2*[1 1 1]); - -poke_colors = struct( ... - 'L', 0.6*[1 0.66 0], ... - 'C', [0 0 0], ... - 'R', 0.9*[1 0.66 0]); - -PokesPlot('init', state_colors, poke_colors); - - -%% Define stimuli and send to sound server - -SF = StimulusSettings.SamplingRate; -AttenuationFactor = .5; -PunishSound = (rand(1,SF*.5)*AttenuationFactor) - AttenuationFactor*.5; - -% Program sound server -PsychToolboxSoundServer('init') -PsychToolboxSoundServer('Load', 2, 0); -PsychToolboxSoundServer('Load', 3, PunishSound); - -% Set soft code handler to trigger sounds -BpodSystem.SoftCodeHandlerFunction = 'SoftCodeHandler_PlaySound'; - -BpodSystem.ProtocolFigures.InitialMsg = msgbox({'', ' Edit your settings and click OK when you are ready to start! ', ''},'ToneCloud Protocol...'); - -uiwait(BpodSystem.ProtocolFigures.InitialMsg); -S = BpodParameterGUI('sync', S); % Sync parameters with BpodParameterGUI plugin -UsingStimulation = 0; -if S.GUI.UseStimulation - PulsePal; - load TC4B_PulsePalProgram; - ProgramPulsePal(ParameterMatrix); - S.InitialPulsePalParameters = ParameterMatrix; - UsingStimulation = 1; -end -% Set timer for this session -SessionBirthdate = tic; - -% Control the step up of prestimulus period and stimulus duration -controlStep_Prestim = 0; % valid trial counter -tic -%% Main trial loop -for currentTrial = 1:MaxTrials - - S = BpodParameterGUI('sync', S); % Sync parameters with BpodParameterGUI plugin - - if S.GUI.UseStimulation - StimulationTrials(currentTrial) = rand < S.GUI.StimProbability; - if (~UsingStimulation) - PulsePal; - load TC4B_PulsePalProgram; - ProgramPulsePal(ParameterMatrix); - S.InitialPulsePalParameters = ParameterMatrix; - UsingStimulation = 1; - end - ProgramPulsePalParam(1, 'Phase1Duration', S.GUI.PulseWidth); - ProgramPulsePalParam(1, 'InterPulseInterval', S.GUI.PulseInterval); - ProgramPulsePalParam(1, 'PulseTrainDelay', S.GUI.TrainDelay); - if StimulationTrials(currentTrial) - ProgramPulsePalParam(1,'LinkTriggerChannel1', 1); - else - ProgramPulsePalParam(1,'LinkTriggerChannel1', 0); - end - else - if UsingStimulation - ProgramPulsePalParam(1,'LinkTriggerChannel1', 0); - UsingStimulation = 0; - end - StimulationTrials(currentTrial) = 0; - end - if S.GUI.AudibleHuman, minFreq = 200; maxFreq = 2000; else minFreq = 5000; maxFreq = 40000; end - - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - %Prestimulation Duration - - if currentTrial==1 %start from the start - S.GUI.PrestimDurationCurrent = S.GUI.PrestimDurationStart; - end - - controlStep_nRequiredValid_Prestim = S.GUI.PrestimDurationNtrials; - - if S.GUI.PrestimDurationStart controlStep_nRequiredValid_Prestim - - controlStep_Prestim = 0; %restart counter - - % step up, unless we are at the max - if S.GUI.PrestimDurationCurrent + S.GUI.PrestimDurationStep > S.GUI.PrestimDurationEnd - S.GUI.PrestimDurationCurrent = S.GUI.PrestimDurationEnd; - else - S.GUI.PrestimDurationCurrent = S.GUI.PrestimDurationCurrent + S.GUI.PrestimDurationStep; - end - end - else - S.GUI.PrestimDurationCurrent = S.GUI.PrestimDurationStart; - end - - - switch S.GUI.PrestimDistribution - case 1 - PrestimDuration(currentTrial) = S.GUI.PrestimDurationCurrent; - case 2' - PrestimDuration(currentTrial) = rand+S.GUI.PrestimDurationCurrent-0.5; - case 3 - PrestimDuration(currentTrial) = exprnd(S.GUI.PrestimDurationCurrent); - end - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - - R = BpodLiquidCalibration('GetValveTimes', S.GUI.RewardAmount, [1 3]); % Update reward amounts - LeftValveTime = R(1); RightValveTime = R(2); - - % Update stimulus settings - StimulusSettings.nTones = floor((S.GUI.SoundMaxDuration-S.GUI.ToneDuration*S.GUI.ToneOverlap)/(S.GUI.ToneDuration*(1-S.GUI.ToneOverlap))); - StimulusSettings.ToneOverlap = S.GUI.ToneOverlap; - StimulusSettings.ToneDuration = S.GUI.ToneDuration; - StimulusSettings.minFreq = minFreq; - StimulusSettings.maxFreq = maxFreq; - StimulusSettings.UseMiddleOctave = S.GUI.UseMiddleOctave(S.GUI.UseMiddleOctave); - StimulusSettings.Noevidence = S.GUI.NoEvidence; - StimulusSettings.Volume = 60; - - switch TrialTypes(currentTrial) % Determine trial-specific state matrix fields - - case 1 % Left is rewarded - if strcmp(S.GUIMeta.FreqSide.String{S.GUI.FreqSide},'LowLeft') - TargetOctave = 'low'; - else - TargetOctave = 'high'; - end - - LeftActionState = 'Reward'; - if S.GUI.Stage == 3 - RightActionState = 'Punish'; - else - RightActionState = 'WaitForLeftPoke'; - end - CorrectWithdrawalEvent = 'Port1Out'; - ValveCode = 1; ValveTime = LeftValveTime; - - case 2 % Right is rewarded - - if strcmp(S.GUIMeta.FreqSide.String{S.GUI.FreqSide},'LowRight') - TargetOctave = 'low'; - else - TargetOctave = 'high'; - end - - if S.GUI.Stage == 3 - LeftActionState = 'Punish'; - else - LeftActionState = 'WaitForRightPoke'; - end - RightActionState = 'Reward'; - CorrectWithdrawalEvent = 'Port3Out'; - ValveCode = 4; ValveTime = RightValveTime; - end - - if S.GUI.PunishSound - PsychToolboxSoundServer('Load', 3, PunishSound); - else - PsychToolboxSoundServer('Load', 3, 0); - end - - switch S.GUI.Stage - - case 1 % Training stage 1: Direct sides - Poke and collect water -% S.GUI.DifficultyLow.enable = 'off'; -% S.GUI.DifficultyHigh.enable = 'off'; -% S.GUI.nDifficulties.enable = 'off'; - S.GUI.TimeoutDuration = 0; -% S.GUI.TimeoutDuration.enable = 'off'; - EvidenceStrength(currentTrial) = 1; - StimulusStateChangeConditions = {'Tup', 'Reward'}; - PostRewardState = 'exit'; - case 2 % Training stage 2: Full task, but may switch error to correct choice - DifficultySet = [S.GUI.DifficultyLow S.GUI.DifficultyLow:(S.GUI.DifficultyHigh-S.GUI.DifficultyLow)/(S.GUI.nDifficulties-1):S.GUI.DifficultyHigh S.GUI.DifficultyHigh]; - DifficultySet = unique(DifficultySet); - EvidenceStrength(currentTrial) = DifficultySet(randi(size(DifficultySet,2))); - StimulusStateChangeConditions = {'Port2Out', 'WaitForResponse'}; - PostRewardState = 'Drinking'; - case 3 % Full task - DifficultySet = [S.GUI.DifficultyLow S.GUI.DifficultyLow:(S.GUI.DifficultyHigh-S.GUI.DifficultyLow)/(S.GUI.nDifficulties-1):S.GUI.DifficultyHigh S.GUI.DifficultyHigh]; - DifficultySet = unique(DifficultySet); - EvidenceStrength(currentTrial) = DifficultySet(randi(size(DifficultySet,2))); - StimulusStateChangeConditions = {'Port2Out', 'WaitForResponse'}; - PostRewardState = 'Drinking'; - end - - [Sound, Cloud, Cloud_toplot] = GenerateToneCloud(TargetOctave, EvidenceStrength(currentTrial), StimulusSettings); - PsychToolboxSoundServer('Load', 1, Sound); - - sma = NewStateMatrix(); % Assemble state matrix - - sma = AddState(sma, 'Name', 'WaitForCenterPoke', ... - 'Timer', 0,... - 'StateChangeConditions', {'Port2In', 'Delay'},... - 'OutputActions', {}); - sma = AddState(sma, 'Name', 'Delay', ... - 'Timer', PrestimDuration(currentTrial),... - 'StateChangeConditions', {'Tup', 'DeliverStimulus', 'Port2Out', 'EarlyWithdrawal'},... - 'OutputActions', {}); - sma = AddState(sma, 'Name', 'DeliverStimulus', ... - 'Timer', S.GUI.SoundMaxDuration,... - 'StateChangeConditions', StimulusStateChangeConditions,... - 'OutputActions', {'SoftCode', 1, 'BNCState', UsingStimulation}); - sma = AddState(sma, 'Name', 'EarlyWithdrawal', ... - 'Timer', 0,... - 'StateChangeConditions', {'Tup', 'EarlyWithdrawalPunish'},... - 'OutputActions', {'SoftCode', 255, 'BNCState', 0}); - sma = AddState(sma, 'Name', 'WaitForResponse', ... - 'Timer', S.GUI.TimeForResponse,... - 'StateChangeConditions', {'Tup', 'exit', 'Port1In', LeftActionState, 'Port3In', RightActionState},... - 'OutputActions', {'SoftCode', 255, 'BNCState', 0}); - sma = AddState(sma, 'Name', 'WaitForLeftPoke', ... - 'Timer', S.GUI.TimeForReversal,... - 'StateChangeConditions', {'Tup', 'Punish', 'Port1In', 'Reward'}, ... - 'OutputActions', {}); - sma = AddState(sma, 'Name', 'WaitForRightPoke', ... - 'Timer', S.GUI.TimeForReversal,... - 'StateChangeConditions', {'Tup', 'Punish', 'Port3In', 'Reward'}, ... - 'OutputActions', {}); - sma = AddState(sma, 'Name', 'Reward', ... - 'Timer', ValveTime,... - 'StateChangeConditions', {'Tup', PostRewardState},... - 'OutputActions', {'ValveState', ValveCode}); - sma = AddState(sma, 'Name', 'Drinking', ... - 'Timer', 10,... - 'StateChangeConditions', {CorrectWithdrawalEvent, 'exit', 'Tup', 'exit'},... - 'OutputActions', {}); - sma = AddState(sma, 'Name', 'Punish', ... - 'Timer', S.GUI.TimeoutDuration,... - 'StateChangeConditions', {'Tup', 'exit'},... - 'OutputActions', {'SoftCode', 3}); - sma = AddState(sma, 'Name', 'EarlyWithdrawalPunish', ... - 'Timer', S.GUI.TimeoutDuration,... - 'StateChangeConditions', {'Tup', 'exit'},... - 'OutputActions', {}); - - SendStateMatrix(sma); - RawEvents = RunStateMatrix; - - if ~isempty(fieldnames(RawEvents)) % If trial data was returned - BpodSystem.Data = AddTrialEvents(BpodSystem.Data,RawEvents); % Computes trial events from raw data - %BpodSystem.Data = BpodNotebook('sync', BpodSystem.Data); % Sync with Bpod notebook plugin - BpodSystem.Data.TrialSettings(currentTrial) = S; % Adds the settings used for the current trial to the Data struct (to be saved after the trial ends) - BpodSystem.Data.TrialTypes(currentTrial) = TrialTypes(currentTrial); % Adds the trial type of the current trial to data - BpodSystem.Data.EvidenceStrength(currentTrial) = EvidenceStrength(currentTrial); % Adds the evidence strength of the current trial to data - BpodSystem.Data.StimulationTrials(currentTrial) = StimulationTrials(currentTrial); - BpodSystem.Data.PrestimDuration(currentTrial) = PrestimDuration(currentTrial); % Adds the evidence strength of the current trial to data - BpodSystem.Data.StimulusSettings = StimulusSettings; % Save Stimulus settings - BpodSystem.Data.Cloud{currentTrial} = Cloud; % Saves Stimulus - - %Outcome - if ~isnan(BpodSystem.Data.RawEvents.Trial{currentTrial}.States.Reward(1)) - Outcomes(currentTrial) = 1; - AccumulatedReward = AccumulatedReward+S.GUI.RewardAmount; - controlStep_Prestim = controlStep_Prestim+1; % update because this is a valid trial - %controlStep_Sound = controlStep_Sound+1; % update because this is a valid trial - elseif ~isnan(BpodSystem.Data.RawEvents.Trial{currentTrial}.States.Punish(1)) - Outcomes(currentTrial) = 0; - controlStep_Prestim = controlStep_Prestim+1; % update because this is a valid trial - %controlStep_Sound = controlStep_Sound+1; % update because this is a valid trial - else - Outcomes(currentTrial) = -1; - end - - BpodSystem.Data.Outcomes(currentTrial) = Outcomes(currentTrial); - BpodSystem.Data.AccumulatedReward = AccumulatedReward; - UpdatePerformancePlot(TrialTypes, Outcomes,SessionBirthdate); - UpdatePsychoPlot(TrialTypes, Outcomes); - tDeliverStimulus = diff(BpodSystem.Data.RawEvents.Trial{1, 1}.States.DeliverStimulus); - %UpdateStimulusPlot(Cloud_toplot,tDeliverStimulus); - PokesPlot('update'); - if S.GUI.Antibias==2 %apply antibias - if Outcomes(currentTrial)==0 - TrialTypes(currentTrial+1)=TrialTypes(currentTrial); - end - end - UpdateOutcomePlot(TrialTypes, Outcomes); - SaveBpodSessionData; % Saves the field BpodSystem.Data to the current data file - end - if BpodSystem.BeingUsed == 0 - PsychToolboxSoundServer('close'); - return - end - -end - -function UpdateOutcomePlot(TrialTypes, Outcomes) -global BpodSystem -EvidenceStrength = BpodSystem.Data.EvidenceStrength; -nTrials = BpodSystem.Data.nTrials; -OutcomePlot(BpodSystem.GUIHandles.OutcomePlot,'update',nTrials+1,2-TrialTypes,Outcomes,EvidenceStrength); - -function UpdatePerformancePlot(TrialTypes, Outcomes,SessionBirthdate) -global BpodSystem -nTrials = BpodSystem.Data.nTrials; -%PerformancePlot(BpodSystem.GUIHandles.PerformancePlot,'update',nTrials,2-TrialTypes,Outcomes,SessionBirthdate); -PerformancePlot('update', TrialTypes, Outcomes, nTrials); - -function UpdatePsychoPlot(TrialTypes, Outcomes) -global BpodSystem -EvidenceStrength = BpodSystem.Data.EvidenceStrength; -nTrials = BpodSystem.Data.nTrials; -PsychoPlot(BpodSystem.GUIHandles.PsychoPlot, 'update',nTrials,2-TrialTypes,Outcomes,EvidenceStrength); - -function UpdateStimulusPlot(Cloud,tDeliverStimulus) -global BpodSystem -CloudDetails.EvidenceStrength = BpodSystem.Data.EvidenceStrength(end); -StimulusPlot(BpodSystem.GUIHandles.StimulusPlot,'update',Cloud,CloudDetails,tDeliverStimulus); \ No newline at end of file diff --git a/Settings Files/BpodSystemSettings.mat b/Settings Files/BpodSystemSettings.mat index 4d35bbf..d0d228f 100644 Binary files a/Settings Files/BpodSystemSettings.mat and b/Settings Files/BpodSystemSettings.mat differ