Permalink
Cannot retrieve contributors at this time
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
olfStim/buildSmell.m
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
442 lines (374 sloc)
19.6 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function buildSmell(instruction,olfactometerOdors,trialOdor,trialNum,stimProtocol,protocolSpecificInfo,varargin) | |
% buildSmell(instruction,trialOdor,trialNum,stimProtocol,protocolSpecificInfo,varargin) creates or | |
% updates the smell structure. | |
% The smell structure contains the relevant information about every trial | |
% for odor presentation. However it does not contain accurate timing | |
% information. | |
% | |
% Instruction: | |
% - 'setUp' | |
% - 'update': assumes there is a gui | |
% - 'updateFields' | |
% | |
% stimProtocol does not have to be given as an input argument. If | |
% buildSmell is called from the stimulation protocol m-file, the function | |
% can extract the name of the protocol and write it into the smell | |
% structure. | |
% | |
% Possible fields to update in 'updateFields' option: | |
% - 'trialOdor': will update all fields from the trial odor | |
% - 'maxFlowRateMfc': no property value necessary. | |
% - 'trialNum': no propertyValue necessary. | |
% - 'stimProtocol': no propertyValue necessary. | |
% - 'time': no propertyValue necessary. | |
% - 'notes': no propertyValue necessary. Will extract notes | |
% automatically from gui. | |
% - 'log': no propertyValue necessary. Will extract the log messages | |
% for the previous trial from the gui. | |
% - 'olfactometerInstructions': no propertyValue necessary. Will | |
% extract instructions automatically from gui. | |
% - 'protocolSpecificInfo': no propertyValue necessary. | |
% - 'sessionInstructions' - Is extracted from the gui. If we're in | |
% olfStimSriptMode you have to provide the sessionInstructions | |
% structure after 'sessionInstructions' option | |
% - 'scientist' - Is extracted from the gui. If we're in | |
% olfStimSriptMode you have to provide the sessionInstructions | |
% structure after 'scientist' option | |
% - 'animalName' - Is extracted from the gui. If we're in | |
% olfStimSriptMode you have to provide the animalName | |
% structure after 'sessionInstructions' option | |
% - 'interTrialInterval' - Is extracted from the gui. If we're in | |
% olfStimSriptMode you have to provide the animalName | |
% structure after 'interTrialInterval' option | |
% - 'io' : If no property value is provided, this option will pull the | |
% current io variable from the appdata. | |
% - 'olfactometerID': No property value necessary, will probe | |
% olfactometer. | |
% | |
% NOTICE: If you want to add a new field to smell, remember to check: | |
% - If the new field will be populated during a trial with information | |
% about a trial, or in general if there's a for loop somewhere populating | |
% it incrementally, remember to append the | |
% removeHistoricalTrialDataFromSmell.m to clear the contents of the field. | |
% Otherwise if there's old data in the fields there might be problems | |
% overwriting them in a manualSessionProgramming stimulation protocol session. | |
% | |
% | |
% | |
% TO DO: | |
% - check whether it's possible to "lock" the structure of smell. ie no new | |
% fields are allowed to be added after the structure is once defined when | |
% calling buildSmell('update'). | |
% - Write the numbers which will be output as 8-bit digital timestamps to | |
% the recording software for each valve and for each trial into the smell structure. | |
% - Document for every field of smell, in which step of an olfactory | |
% session it should be populated, updated etc. | |
% | |
% lorenzpammer 2011/09 | |
global smell | |
global olfactometerInstructions | |
global olfStimScriptMode | |
smellVersion = '0.1'; % version of smell structure | |
%% Import function packages | |
% Import all utility functions | |
import protocolUtilities.* | |
%% Check whether inputs are correct | |
if nargin < 1 | |
error('No instruction defined.') | |
elseif strcmp('setUp',instruction) && nargin < 3 | |
trialOdor = []; | |
trialNum = []; | |
%stimProtocol = dbstack; | |
%stimProtocol = stimProtocol(2).file(1:end-2); % | |
stimProtocol = []; | |
protocolSpecificInfo =[]; | |
elseif ~isempty(strmatch('update',instruction)) && nargin<3 | |
error('For updating smell structure, trial odor information is necessary.') | |
elseif ~isempty(strmatch('update',instruction)) && nargin<4 | |
error('For updating smell structure, trial number is necessary.') | |
elseif ~isempty(strmatch('update',instruction)) && nargin<5 | |
stimProtocol = dbstack; % dbstack gives the function call stack, which function called the present function | |
stimProtocol = stimProtocol(2).file(1:end-2); % | |
elseif ~isempty(strmatch('update',instruction)) && nargin<6 | |
protocolSpecificInfo = []; % if no data is handed to the function for protocolSpecific Information this is set empty. | |
end | |
if nargin < 6 | |
protocolSpecificInfo =[]; | |
end | |
%% Set up smell structure | |
if strcmp(instruction,'setUp') | |
smell = setUpSmellStructure(smell, olfactometerOdors, stimProtocol,protocolSpecificInfo,smellVersion); | |
end | |
%% Update all relevant elements of smell structure for the current trial | |
% | |
if strcmp(instruction,'update') | |
smell = updateSmellStructure(smell, trialOdor,trialNum,stimProtocol,protocolSpecificInfo,smellVersion); | |
end | |
%% Update a defined set of parameters in smell. | |
if strcmp(instruction,'updateFields') | |
smell = updateFields(smell,trialOdor,trialNum,stimProtocol,protocolSpecificInfo,smellVersion,varargin); | |
end | |
end | |
function smell = setUpSmellStructure(smell, olfactometerOdors, stimProtocol,protocolSpecificInfo,smellVersion) | |
%global olfactometerOdors | |
global olfactometerInstructions | |
global olfStimTestMode | |
% Extract the gui handle structure from the appdata of the figure: | |
h=appdataManager('olfStimGui','get','h'); | |
%% Import function packages | |
% Import all utility functions | |
import protocolUtilities.* | |
%% | |
% Basic information about the current trial | |
smell.olfactometerOdors = olfactometerOdors; % structure containing information which odors are loaded into olfactometer | |
smell.version = smellVersion; % Define here which version of the smell structure was used - if anything has to change in the future downstream algorithms know what to do. | |
% Get the maximum flow rate of the mass flow controllers from the olfactometer | |
% If more than two MFCs are conntected, this code has to be adapted: | |
usedSlaves = find([smell.olfactometerOdors.slave.used]); | |
for i = usedSlaves | |
if ~olfStimTestMode | |
olfactometerH = olfactometerAccess.connect(false); | |
[smell.olfactometerSettings.slave(i).maxFlowRateMfcAir, ~] = olfactometerAccess.getMaxFlowRateMfc(false, olfactometerH, i,1); % in liters/minute probably 1.5 | |
[smell.olfactometerSettings.slave(i).maxFlowRateMfcNitrogen,~] = olfactometerAccess.getMaxFlowRateMfc(false, olfactometerH, i,2); % in liters/minute probably 0.1 | |
% Field for storing information about LASOM (firmware, etc.) | |
smell.olfactometerSettings.olfactometerID = olfactometerAccess.getID(false,olfactometerH); | |
release(olfactometerH); | |
else % if we're in the test mode write some default values into the olfactometerSettings. Otherwise downstream code will break. | |
smell.olfactometerSettings.slave(i).maxFlowRateMfcAir = 1.5; | |
smell.olfactometerSettings.slave(i).maxFlowRateMfcNitrogen = 0.1; | |
smell.olfactometerSettings.olfactometerID = []; | |
end | |
end | |
odorFields = fields(olfactometerOdors.sessionOdors(1)); | |
smell.trial(1) = cell2struct(cell(length(odorFields),1),odorFields,1); % all fields for each used odor are written to the smell structure: odorName,iupacName,CASNumber,producingCompany,odorantPurity,state,odorantDilution,dilutedIn,concentrationAtPresentation,inflectionPointResponseCurve,slave,vial,mixture,sessionOdorNumber | |
smell.trial(1).isSequence = []; % Whether multiple different odors are presented sequentially within one trial. | |
smell.trial(1).trialNum = []; % Trial number in the current session | |
smell.trial(1).stimProtocol = []; % which stimulation protocol was used for this session | |
smell.trial(1).time = []; % time at time of start of a new trial (not the time of actual odor presentation) | |
% smell.trial(1).interTrialInterval = 0; % First trial has a intertrial-interval of 0 seconds. | |
smell.trial(1).notes = []; % Notes that are taken during the session will be saved here. Every trial the notes are extracted from the field and written into this field in form of a string.\ | |
smell.trial(1).flowRateMfcAir = []; % Field contains the target flow rate for the air mass flow controller | |
smell.trial(1).flowRateMfcN = []; % Field contains the target flow rate for the Nitrogen mass flow controller | |
smell.trial(1).log = []; % field for storing log messages | |
% User defined times to instruct the olfactometer. | |
% olfactometerInstructions structure is handled by | |
% olfactometerSettings.m function | |
smell.trial(1).olfactometerInstructions = olfactometerInstructions; | |
% User defined settings for the current session. sessionInstructions | |
% structure is produced by sessionSettings.m and written into the | |
% appdata of the gui. | |
sessionSettings(h,'setUpStructure'); % Create structure and write into appdata | |
% Extract the sessionInstructions structure from the appdata of the figure: | |
sessionInstructions=appdataManager('olfStimGui','get','sessionInstructions'); | |
smell.trial(1).sessionInstructions = sessionInstructions; | |
% Field for storing the event log from the LASOM after the execution of | |
% the trial: | |
smell.trial(1).olfactometerEventLog.flowRateMfcAir = []; | |
smell.trial(1).olfactometerEventLog.flowRateMfcN = []; | |
% Field for storing the osq file (olfactometer sequencer script) for each | |
% trial: | |
smell.trial(1).trialOsqFile = []; | |
% Set up the structure containing information about I/O io (triggers, timestamps, etc.). | |
smell.trial(1).io = ioControl.ioConfiguration; | |
% Here any information specific for the current protocol can be dumped | |
smell.trial(1).protocolSpecificInfo = []; | |
end | |
function smell = updateSmellStructure(smell,trialOdor,trialNum,stimProtocol,protocolSpecificInfo,smellVersion) | |
global olfactometerInstructions | |
% Extract the gui handle structure from the appdata of the figure: | |
h=appdataManager('olfStimGui','get','h'); | |
%% Import function packages | |
% Import all utility functions | |
import protocolUtilities.* | |
%% Update the relevant fields for the current trial | |
smell.version = smellVersion; % Define which version of the smell structure was used - if anything has to change in the future downstream algorithms know what to do. | |
smell.trial(trialNum).odorName = []; % to set up a new struct array (1xtrialNum) | |
% Find out how to extract information which function called buildSmell | |
trialOdorFields = fields(trialOdor); % get name of fields in trialOdor (also present in smell | |
% update first couple of fields (same as in trialOdor) with the data for the current trial. | |
for i = 1 : length(trialOdorFields) | |
smell.trial(trialNum) = setfield(smell.trial(trialNum),trialOdorFields{i},getfield(trialOdor,trialOdorFields{i})); | |
end | |
if iscell(smell.trial(trialNum).odorName) && length(smell.trial(trialNum).odorName) > 1 | |
smell.trial(trialNum).isSequence = true; | |
else | |
smell.trial(trialNum).isSequence = false; | |
end | |
smell.trial(trialNum).trialNum = trialNum; | |
smell.trial(trialNum).stimProtocol = stimProtocol; | |
smell.trial(trialNum).time = clock; % This only gives an approximate time, as the odor might be presented to the animal multiple seconds later. | |
smell.trial(trialNum).protocolSpecificInfo = protocolSpecificInfo; | |
% Only extract notes from gui if we're not in scripting mode: | |
%if isempty(olfStimScriptMode) | |
smell.trial(trialNum).notes = protocolUtilities.notes.extract(h); % extract the notes | |
%end | |
if trialNum > 1 | |
% Extract the log messages for the last trial, because at the time of | |
% calling update smell the current trial hasn't even started yet. | |
smell.trial(trialNum-1).log = protocolUtilities.logWindow.extract(1); | |
end | |
% olfactometerInstructions structure is updated in the | |
% olfactometerSettings function prior to calling build smell. Now write | |
% the updated instructions into the smell structure. | |
smell.trial(trialNum).olfactometerInstructions = olfactometerInstructions; | |
% sessionInstructions structure is updated in the | |
% sessionSettings function prior to calling build smell. Now write | |
% the updated instructions into the smell structure. | |
sessionSettings(h,'get'); % Create structure and write into appdata | |
% Extract the sessionInstructions structure from the appdata of the figure: | |
sessionInstructions=appdataManager('olfStimGui','get','sessionInstructions'); | |
smell.trial(trialNum).sessionInstructions = sessionInstructions; | |
% The list of I/O actions can be updated from the gui. If the user updated | |
% some actions, the io variable in the appdata will be updated. Pull the | |
% current io variable from the appdata and update the io field in | |
% smell.trial(trialNum): | |
smell.trial(trialNum).io = appdataManager('olfStimGui','get','io'); | |
end | |
function smell = updateFields(smell,trialOdor,trialNum,stimProtocol,protocolSpecificInfo,smellVersion,fieldsToUpdate) | |
%global olfactometerOdors | |
global olfactometerInstructions | |
global olfStimTestMode | |
global olfStimScriptMode | |
% Extract the gui handle structure from the appdata of the figure: | |
h=appdataManager('olfStimGui','get','h'); | |
%% Import function packages | |
% Import all utility functions | |
import protocolUtilities.* | |
%% Update smell version | |
% Define here which version of the smell structure was used - if anything has to change in the future downstream algorithms know what to do. | |
smell.version = smellVersion; | |
%% Update the fields specified in varargin | |
% varargin includes the information in the form | |
% 'PropertyName','PropertyValue' | |
if any(strcmpi('trialOdor',fieldsToUpdate)) | |
smell.trial(trialNum).odorName = []; % to set up a new struct array (1xtrialNum) | |
% Find out how to extract information which function called buildSmell | |
trialOdorFields = fields(trialOdor); % get name of fields in trialOdor (also present in smell | |
% update first couple of fields (same as in trialOdor) with the data for the current trial. | |
for i = 1 : length(trialOdorFields) | |
smell.trial(trialNum) = setfield(smell.trial(trialNum),trialOdorFields{i},getfield(trialOdor,trialOdorFields{i})); | |
end | |
end | |
if any(strcmpi('trialNum',fieldsToUpdate)) | |
smell.trial(trialNum).trialNum = trialNum; | |
end | |
if any(strcmpi('stimProtocol',fieldsToUpdate)) | |
smell.trial(trialNum).stimProtocol = stimProtocol; | |
end | |
if any(strcmpi('time',fieldsToUpdate)) | |
smell.trial(trialNum).time = clock; % This only gives an approximate time, as the odor might be presented to the animal multiple seconds later. | |
end | |
if any(strcmpi('notes',fieldsToUpdate)) | |
% Extract the notes from the gui | |
smell.trial(trialNum).notes = protocolUtilities.notes.extract(h); % extract the notes | |
end | |
if any(strcmpi('log',fieldsToUpdate)) && trialNum > 1 | |
% Extract the log messages from the gui for the last trial, because at | |
% the time of calling update smell the current trial hasn't even started yet. | |
smell.trial(trialNum-1).log = protocolUtilities.logWindow.extract(1); | |
end | |
if any(strcmpi('olfactometerInstructions',fieldsToUpdate)) | |
smell.trial(trialNum).olfactometerInstructions = olfactometerInstructions; | |
end | |
if any(strcmpi('protocolSpecificInfo',fieldsToUpdate)) | |
smell.trial(trialNum).protocolSpecificInfo = protocolSpecificInfo; | |
end | |
if any(strcmpi('sessionInstructions',fieldsToUpdate)) | |
if isempty(olfStimScriptMode) | |
% sessionInstructions structure is updated in the | |
% sessionSettings function prior to calling build smell. Now write | |
% the updated instructions into the smell structure. | |
sessionSettings(h,'get'); % Create structure and write into appdata | |
% Extract the sessionInstructions structure from the appdata of the figure: | |
sessionInstructions=appdataManager('olfStimGui','get','sessionInstructions'); | |
else | |
index = find(strcmp('sessionInstructions',fieldsToUpdate)); | |
sessionInstructions=fieldsToUpdate{index+1}; | |
end | |
smell.trial(trialNum).sessionInstructions = sessionInstructions; | |
end | |
if any(strcmpi('scientist',fieldsToUpdate)) | |
if isempty(olfStimScriptMode) | |
% sessionInstructions structure is updated in the | |
% sessionSettings function prior to calling build smell. Now write | |
% the updated instructions into the smell structure. | |
sessionSettings(h,'get'); % Create structure and write into appdata | |
% Extract the sessionInstructions structure from the appdata of the figure: | |
sessionInstructions=appdataManager('olfStimGui','get','sessionInstructions'); | |
index = strmatch('scientist', {sessionInstructions.name}); | |
smell.trial(trialNum).sessionInstructions(index).value = sessionInstructions(index).value; | |
else | |
index = find(strcmp('scientist',fieldsToUpdate)); | |
smell.trial(trialNum).sessionInstructions(index).value = fieldsToUpdate{index+1}; | |
end | |
end | |
if any(strcmpi('animalName',fieldsToUpdate)) | |
if isempty(olfStimScriptMode) | |
% sessionInstructions structure is updated in the | |
% sessionSettings function prior to calling build smell. Now write | |
% the updated instructions into the smell structure. | |
sessionSettings(h,'get'); % Create structure and write into appdata | |
% Extract the sessionInstructions structure from the appdata of the figure: | |
sessionInstructions=appdataManager('olfStimGui','get','sessionInstructions'); | |
index = strmatch('animalName', {sessionInstructions.name}); | |
smell.trial(trialNum).sessionInstructions(index).value = sessionInstructions(index).value; | |
else | |
index = find(strcmp('animalName',fieldsToUpdate)); | |
smell.trial(trialNum).sessionInstructions(index).value = fieldsToUpdate{index+1}; | |
end | |
end | |
if any(strcmpi('interTrialInterval',fieldsToUpdate)) | |
if ~olfStimScriptMode | |
sessionSettings(h,'get'); % Create structure and write into appdata | |
% Extract the sessionInstructions structure from the appdata of the figure: | |
sessionInstructions=appdataManager('olfStimGui','get','sessionInstructions'); | |
index = strmatch('interTrialInterval', {sessionInstructions.name}); | |
smell.trial(trialNum).sessionInstructions(index).value = sessionInstructions(index).value; | |
else | |
index = find(strcmp('animalName',fieldsToUpdate)); % This should give an error. Why is nothing happening? | |
smell.trial(trialNum).sessionInstructions(index).value = fieldsToUpdate{index+1}; | |
end | |
end | |
if any(strcmpi('maxFlowRateMfc',fieldsToUpdate)) | |
% Get the maximum flow rate of the mass flow controllers from the olfactometer | |
% If more than two MFCs are conntected, this code has to be adapted: | |
usedSlaves = find([smell.olfactometerOdors.slave.used]); | |
for i = usedSlaves | |
if ~olfStimTestMode | |
olfactometerH = olfactometerAccess.connect(false); | |
[smell.olfactometerSettings.slave(i).maxFlowRateMfcAir, ~] = olfactometerAccess.getMaxFlowRateMfc(false, olfactometerH, i,1); % in liters/minute probably 1.5 | |
[smell.olfactometerSettings.slave(i).maxFlowRateMfcNitrogen,~] = olfactometerAccess.getMaxFlowRateMfc(false, olfactometerH, i,2); % in liters/minute probably 0.1 | |
release(olfactometerH); | |
else | |
smell.olfactometerSettings.slave(i).maxFlowRateMfcAir = 1.5; | |
smell.olfactometerSettings.slave(i).maxFlowRateMfcNitrogen = 0.1; | |
end | |
end | |
end | |
if any(strcmpi('olfactometerID',fieldsToUpdate)) | |
% Field for storing information about LASOM (firmware, etc.)\ | |
if ~olfStimTestMode | |
olfactometerH = olfactometerAccess.connect(false); | |
smell.olfactometerSettings.olfactometerID = olfactometerAccess.getID(false,olfactometerH); | |
release(olfactometerH); | |
else | |
smell.olfactometerSettings.olfactometerID = ''; | |
end | |
end | |
if any(strcmpi('io',fieldsToUpdate)) | |
if isempty(olfStimScriptMode) | |
index = find(strcmp('io',fieldsToUpdate)); | |
try | |
io = fieldsToUpdate{index+1}; | |
if ~isstruct(io) | |
error('jump to catch') | |
end | |
catch | |
io = appdataManager('olfStimGui','get','io'); | |
end | |
else | |
io = olfStimConfiguration('io','structure'); | |
end | |
smell.trial(trialNum).io = io; | |
end | |
end |