Home > matlabmk > sets2GNDclocs.m

sets2GNDclocs

PURPOSE ^

sets2GND() - Create a Mass Univariate ERP Toolbox GND struct variable from a set of

SYNOPSIS ^

function GND=sets2GND(gui_infiles_or_tmplt,varargin)

DESCRIPTION ^

 sets2GND() - Create a Mass Univariate ERP Toolbox GND struct variable from a set of
              EEGLAB *.set files

 Usage:
  >> GND=sets2GND(gui_infiles_or_tmplt,varargin);

 Required Inputs:
   gui_infiles_or_tmplt - ['gui', a cell array of strings, or a string template]
                          If 'gui', a GUI is created that allows you to select
                          which set files to import (this is probably the
                          easiest way to import files).  If a cell array of
                          of strings, each element of the cell array should
                          contain the filename of an EEGLAB set file (e.g.,
                          {'visodbl01.set','visodbl02.set'}.  Otherwise, this
                          input should be a filename template (i.e., a string with
                          # where the subject number should be--'visodbl#.set').
                          If you provide a template, you must use the option
                          'sub_ids' (see below) to specify the ID numbers of
                          each subject. Include the files' path unless the files
                          are in the current working directory.


 Optional Inputs:
   sub_ids          - [integer vector] A set of integers specifying the
                      subject ID numbers to include in the grand average.
                      Only necessary if a filename template is given as
                      the input to gui_infiles_or_tmplt.

   bsln             - [vector or NaN] A pair of numbers (in milliseconds)
                      specifying the start and end times of the ERP baseline
                      window or NaN.  If NaN, data are not baselined.  
                      Otherwise, the mean voltage in the baseline window 
                      will be removed from each ERP. {default: use all time
                      points before time 0}.

   use_bins         - [integer vector] A set of integers specifying which
                      bins to import into MATLAB.  If not specified, all
                      bins will be imported. Note, if you import only a
                      subset of bins, the bin numberings will start at 1
                      and run to the number you've imported (i.e., they may
                      differ from the bin numbers in the set files.
                      {default: import all bins}

   exclude_chans    - A cell array of channel labels to exclude from the
                      importation (e.g., {'A2','lle','rhe'}). You cannot
                      use both this option and 'include_chans' (below).{default:
                      not used, import all channels}

   include_chans    - A cell array specifying a subset of channel labels to import
                      (e.g., {'Fz','Cz','Pz'}).  All other channels will
                      be ignored. You cannot use both this option and
                      'exclude_chans' (above). {default: not used, import
                      all channels}

   exp_name         - [string] Name of the experiment. {default: 'An
                      Experiment'}

   out_fname        - [string] Filename to save GND variable to.  If empty
                      (i.e., not specified), a GUI will be created to prompt
                      you for a filename. If the string 'no save', the GND
                      variable will not be saved to disk. If no file
                      extension is given '.GND' will be added to the
                      filename. {default: not specified}
   force_chanlocs   - ['y' or 'n'] If 'y', the chanlocs information from
                      the first set file will be used for all subsequent 
                      files. {default: 'n'}

   verblevel        - An integer specifiying the amount of information you want
                      this function to provide about what it is doing during runtime.
                       Options are:
                        0 - quiet, only show errors, warnings, and EEGLAB reports
                        1 - stuff anyone should probably know
                        2 - stuff you should know the first time you start working
                            with a data set {default value}
                        3 - stuff that might help you debug (show all
                            reports)

 Output:
   GND  - Struct variable containing grand averages, individual subject
          ERPs, mass univariate t-test results and more.


 Global Variables:
   VERBLEVEL - Mass Univariate ERP Toolbox level of verbosity (i.e., tells 
               functions how much to report about what they're doing during
               runtime) set by the optional function argument 'verblevel'

 Notes:
 -This function expects the EEG variable to have information about bins
 stored in it.  More specifically, there needs to be (1) an EEG.bindesc
 field that contains a text description of each bin and (2) epochs of data
 labeled as bin types (e.g., 'bin1').  Bin types are stored in the field
 EEG.epoch(#).eventtype.  Use the function bin_info2EEG.m to add bin
 information to an EEG variable.

 -ICs labeled as artifacts will be removed from the data before ERPs are
 formed.  This is done by the function remove_artifact_ics.m.  IC labeling
 can be done via EEGLAB or MATLABmk functions/conventions.  If both
 conventions appear in the EEG variable, only MATLABmk IC labels will be used.

 -This function is not yet compatible with ERPLAB's conventions for
 storing bin information.

 -The GND fields odelay, cals, indiv_bin_raw_ct, and condesc are specific 
 to Kutaslab data. Other labs should be able to ignore them (though 
 indiv_bin_raw_ct is used by ERPLAB processed data as well.

 Author:
 David Groppe
 Kutaslab, 7/2010

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SUBFUNCTIONS ^

SOURCE CODE ^

0001 % sets2GND() - Create a Mass Univariate ERP Toolbox GND struct variable from a set of
0002 %              EEGLAB *.set files
0003 %
0004 % Usage:
0005 %  >> GND=sets2GND(gui_infiles_or_tmplt,varargin);
0006 %
0007 % Required Inputs:
0008 %   gui_infiles_or_tmplt - ['gui', a cell array of strings, or a string template]
0009 %                          If 'gui', a GUI is created that allows you to select
0010 %                          which set files to import (this is probably the
0011 %                          easiest way to import files).  If a cell array of
0012 %                          of strings, each element of the cell array should
0013 %                          contain the filename of an EEGLAB set file (e.g.,
0014 %                          {'visodbl01.set','visodbl02.set'}.  Otherwise, this
0015 %                          input should be a filename template (i.e., a string with
0016 %                          # where the subject number should be--'visodbl#.set').
0017 %                          If you provide a template, you must use the option
0018 %                          'sub_ids' (see below) to specify the ID numbers of
0019 %                          each subject. Include the files' path unless the files
0020 %                          are in the current working directory.
0021 %
0022 %
0023 % Optional Inputs:
0024 %   sub_ids          - [integer vector] A set of integers specifying the
0025 %                      subject ID numbers to include in the grand average.
0026 %                      Only necessary if a filename template is given as
0027 %                      the input to gui_infiles_or_tmplt.
0028 %
0029 %   bsln             - [vector or NaN] A pair of numbers (in milliseconds)
0030 %                      specifying the start and end times of the ERP baseline
0031 %                      window or NaN.  If NaN, data are not baselined.
0032 %                      Otherwise, the mean voltage in the baseline window
0033 %                      will be removed from each ERP. {default: use all time
0034 %                      points before time 0}.
0035 %
0036 %   use_bins         - [integer vector] A set of integers specifying which
0037 %                      bins to import into MATLAB.  If not specified, all
0038 %                      bins will be imported. Note, if you import only a
0039 %                      subset of bins, the bin numberings will start at 1
0040 %                      and run to the number you've imported (i.e., they may
0041 %                      differ from the bin numbers in the set files.
0042 %                      {default: import all bins}
0043 %
0044 %   exclude_chans    - A cell array of channel labels to exclude from the
0045 %                      importation (e.g., {'A2','lle','rhe'}). You cannot
0046 %                      use both this option and 'include_chans' (below).{default:
0047 %                      not used, import all channels}
0048 %
0049 %   include_chans    - A cell array specifying a subset of channel labels to import
0050 %                      (e.g., {'Fz','Cz','Pz'}).  All other channels will
0051 %                      be ignored. You cannot use both this option and
0052 %                      'exclude_chans' (above). {default: not used, import
0053 %                      all channels}
0054 %
0055 %   exp_name         - [string] Name of the experiment. {default: 'An
0056 %                      Experiment'}
0057 %
0058 %   out_fname        - [string] Filename to save GND variable to.  If empty
0059 %                      (i.e., not specified), a GUI will be created to prompt
0060 %                      you for a filename. If the string 'no save', the GND
0061 %                      variable will not be saved to disk. If no file
0062 %                      extension is given '.GND' will be added to the
0063 %                      filename. {default: not specified}
0064 %   force_chanlocs   - ['y' or 'n'] If 'y', the chanlocs information from
0065 %                      the first set file will be used for all subsequent
0066 %                      files. {default: 'n'}
0067 %
0068 %   verblevel        - An integer specifiying the amount of information you want
0069 %                      this function to provide about what it is doing during runtime.
0070 %                       Options are:
0071 %                        0 - quiet, only show errors, warnings, and EEGLAB reports
0072 %                        1 - stuff anyone should probably know
0073 %                        2 - stuff you should know the first time you start working
0074 %                            with a data set {default value}
0075 %                        3 - stuff that might help you debug (show all
0076 %                            reports)
0077 %
0078 % Output:
0079 %   GND  - Struct variable containing grand averages, individual subject
0080 %          ERPs, mass univariate t-test results and more.
0081 %
0082 %
0083 % Global Variables:
0084 %   VERBLEVEL - Mass Univariate ERP Toolbox level of verbosity (i.e., tells
0085 %               functions how much to report about what they're doing during
0086 %               runtime) set by the optional function argument 'verblevel'
0087 %
0088 % Notes:
0089 % -This function expects the EEG variable to have information about bins
0090 % stored in it.  More specifically, there needs to be (1) an EEG.bindesc
0091 % field that contains a text description of each bin and (2) epochs of data
0092 % labeled as bin types (e.g., 'bin1').  Bin types are stored in the field
0093 % EEG.epoch(#).eventtype.  Use the function bin_info2EEG.m to add bin
0094 % information to an EEG variable.
0095 %
0096 % -ICs labeled as artifacts will be removed from the data before ERPs are
0097 % formed.  This is done by the function remove_artifact_ics.m.  IC labeling
0098 % can be done via EEGLAB or MATLABmk functions/conventions.  If both
0099 % conventions appear in the EEG variable, only MATLABmk IC labels will be used.
0100 %
0101 % -This function is not yet compatible with ERPLAB's conventions for
0102 % storing bin information.
0103 %
0104 % -The GND fields odelay, cals, indiv_bin_raw_ct, and condesc are specific
0105 % to Kutaslab data. Other labs should be able to ignore them (though
0106 % indiv_bin_raw_ct is used by ERPLAB processed data as well.
0107 %
0108 % Author:
0109 % David Groppe
0110 % Kutaslab, 7/2010
0111 
0112 %%%%%%%%%%%%%%%% Revision History  %%%%%%%%%%%%%%%%%
0113 % 10/31/2010: 'use_bin' option fixed and problem with reshaping data when no
0114 % ICs are labeled as artifacts fixed-TPU
0115 %
0116 % 11/2/2010: Can now deal with condition codes for Kutaslab data (before it
0117 % assumed that all bins had a condition code of 1)
0118 %
0119 % 11/3/2010: Function now checks to make sure GND file can be written to
0120 % disk before attempting to do so.  Code courtesy of Tom Urbach.
0121 %
0122 % 11/14/2010: 'include_chans' option now reports if function could not find
0123 % a channel the user wished to include. 'include' & 'exclude' options made
0124 % case insensitive
0125 %
0126 % 12/9/2010: 'rawtrials_per_bin' recorded keeping wasn't working if only a
0127 % subset of possible bins were imported.  Works now.
0128 %
0129 % 12/15/2010: 'locfiles' optional input removed.  It wasn't doing anything.
0130 %
0131 % 4/4/2011: Made compatible with Windows.
0132 %
0133 % 8/23/2012: NaN now a possible value for bsln to avoid any baselining
0134 %
0135 % 3/12/2013: If you provide a GND variable filename, program no longer
0136 % asks user if s/he wants to save the file. Thanks to Aaron Newman for the
0137 % suggestion.
0138 
0139 %%%%%%%%%%%%%%%% Future Work  %%%%%%%%%%%%%%%%%
0140 %
0141 % Could make function able to read ERPLAB bin information in set files
0142 %
0143 % Add odelay for Kutaslab?  Currently GND.odelay=[];
0144 %
0145 % GND.indiv_traits=[]; <-make import option for this (i.e., function
0146 % should be able to import this info from text file)
0147 %
0148 % Make import option for GND.indiv_traits this (i.e., sets2GND.m should be able to import
0149 % this info from text file)
0150 
0151 function GND=sets2GND(gui_infiles_or_tmplt,varargin)
0152 
0153 p=inputParser;
0154 p.addRequired('gui_infiles_or_tmplt',@(x) ischar(x) || iscell(x));
0155 p.addParamValue('sub_ids',[],@isnumeric);
0156 p.addParamValue('bsln',[],@(x) sum(isnan(x)) || (isnumeric(x) && length(x)==2));
0157 p.addParamValue('exp_name','An Experiment',@ischar);
0158 p.addParamValue('use_bins',[],@isnumeric);
0159 p.addParamValue('exclude_chans',[],@(x) ischar(x) || iscell(x));
0160 p.addParamValue('include_chans',[],@(x) ischar(x) || iscell(x));
0161 p.addParamValue('out_fname',[],@ischar);
0162 p.addParamValue('force_chanlocs',[],@ischar);
0163 p.addParamValue('verblevel',[],@(x) isnumeric(x) && (length(x)==1));
0164 p.parse(gui_infiles_or_tmplt,varargin{:});
0165 
0166 global EEG
0167 global VERBLEVEL;
0168 
0169 if isempty(p.Results.verblevel),
0170     if isempty(VERBLEVEL),
0171         VERBLEVEL=2;
0172     end
0173 else
0174     VERBLEVEL=p.Results.verblevel;
0175 end
0176 
0177 
0178 %% Figure out which channels to ignore if any
0179 %But first make sure exclude & include options were not both used.
0180 if ~isempty(p.Results.include_chans) && ~isempty(p.Results.exclude_chans)
0181     error('You cannot use BOTH ''include_chans'' and ''exclude_chans'' options.');
0182 end
0183 if ischar(p.Results.exclude_chans),
0184     exclude_chans{1}=p.Results.exclude_chans;
0185 elseif isempty(p.Results.exclude_chans)
0186     exclude_chans=[];
0187 else
0188     exclude_chans=p.Results.exclude_chans;
0189 end
0190 if ischar(p.Results.include_chans),
0191     include_chans{1}=p.Results.include_chans;
0192 elseif isempty(p.Results.include_chans)
0193     include_chans=[];
0194 else
0195     include_chans=p.Results.include_chans;
0196 end
0197 
0198 
0199 %%  Select files for loading
0200 if strcmpi(gui_infiles_or_tmplt,'GUI'),
0201     loading=1;
0202     infiles=[];
0203     while loading,
0204         [neofname, inpath]=uigetfile({'*.set','*.set files'; ...
0205             '*.*','All Files (*.*)'},'EEGLAB set Files to Import','MultiSelect','on');
0206         if ischar(neofname),
0207             clear infname;
0208             infname{1}=neofname; %make it a cell array for consistent syntax below
0209         else
0210             infname=neofname;
0211         end
0212         if ~inpath,
0213             if isempty(infiles),
0214                 fprintf('File selection cancelled.  Aborting sets2GND.\n');
0215                 GND=[];
0216                 return;
0217             else
0218                 loading=0;
0219             end
0220         else
0221             if isempty(infiles),
0222                 infiles=cell(1,length(infname)); %preallocate mem
0223                 for a=1:length(infname),
0224                     infiles{a}=[inpath infname{a}];
0225                 end
0226             else
0227                 n_files=length(infiles);
0228                 ct=0;
0229                 for a=(n_files+1):(n_files+length(infname)),
0230                     ct=ct+1;
0231                     infiles{a}=[inpath infname{ct}];
0232                 end
0233             end
0234             % trigger GUI to see if user wants to load more
0235             resp=questdlg('Do you want to load more files?',...
0236                 'OUTPUT','Yes','No','Yes');
0237             if strcmpi(resp,'No'),
0238                 loading=0;
0239             end
0240         end
0241     end
0242 elseif iscell(p.Results.gui_infiles_or_tmplt)
0243     infiles=p.Results.gui_infiles_or_tmplt;
0244 else
0245     if isempty(p.Results.sub_ids)
0246         error('If gui_infiles_or_tmplt is a string filename template, you must specify the subject numbers with the argument ''sub_ids''.');
0247     elseif ~ismember('#',p.Results.gui_infiles_or_tmplt),
0248         error('The filename template %s needs to contain a # to indicate where the subject numbers go (e.g., odbl#.nrm).', ...
0249             p.Results.gui_infiles_or_tmplt);
0250     else
0251         lb_id=find(p.Results.gui_infiles_or_tmplt=='#');
0252         prefix=p.Results.gui_infiles_or_tmplt(1:(lb_id(1)-1)); %indexing lb_id by 1 in case there are multiple pound signs
0253         postfix=p.Results.gui_infiles_or_tmplt((lb_id(1)+1):end);
0254         n_infiles=length(p.Results.sub_ids);
0255         infiles=cell(1,n_infiles);
0256         for s=1:n_infiles,
0257             no_pad=[prefix num2str(p.Results.sub_ids(s)) postfix];
0258             if p.Results.sub_ids(s)<10,
0259                 padded=[prefix num2str(p.Results.sub_ids(s),'%.2d') postfix];
0260                 if ismac || isunix
0261                     %Mac or Unix OS
0262                     [sP wP]=unix(['ls ' padded]); %if sp==0, then the file exists, need wP argument so that it isn't automatically displayed in command window
0263                     [sNP wNP]=unix(['ls ' no_pad]); %Need wP argument so that it isn't automatically displayed in command window
0264                     if ~sP
0265                         if ~sNP,
0266                             error('You have a file named %s and one named %s.  I don''t know which one to load!\n', ...
0267                                 padded,no_pad);
0268                         else
0269                             infiles{s}=padded;
0270                         end
0271                     else
0272                         infiles{s}=no_pad;
0273                     end
0274                 else
0275                     %Must be a PC
0276                     infiles{s}=no_pad;
0277                 end
0278             else
0279                 infiles{s}=no_pad;
0280             end
0281         end
0282     end
0283 end
0284 
0285 %Get rid of any redundant input files
0286 infiles=unique(infiles);
0287 n_infiles=length(infiles);
0288 
0289 
0290 %% Load first data set and draft GND fields
0291 EEG=pop_loadset(infiles{1});
0292 EEG_var_check(EEG,infiles{1});
0293 
0294 if universal_yes(p.Results.force_chanlocs)
0295     unvsl_chanlocs=EEG.chanlocs;
0296 else
0297     unvsl_chanlocs=[];
0298 end
0299 
0300 [n_EEG_chans, n_pts, n_epochs]=size(EEG.data);
0301 if ~isempty(exclude_chans),
0302     use_chans=zeros(1,n_EEG_chans);
0303     ex_ct=0;
0304     for a=1:n_EEG_chans,
0305         if ~ismember_ci(EEG.chanlocs(a).labels,exclude_chans)
0306             use_chans(a)=1;
0307         else
0308             ex_ct=ex_ct+1;
0309             ex_labels{ex_ct}=EEG.chanlocs(a).labels;
0310         end
0311     end
0312     n_chans=sum(use_chans);
0313     use_chans=find(use_chans==1);
0314     
0315     if VERBLEVEL>1,
0316         missed=setdiff_ci(exclude_chans,ex_labels);
0317         n_missed=length(missed);
0318         if n_missed,
0319             if n_missed==1,
0320                 msg=sprintf('I attempted to exclude the following channel, but it was not found:');
0321             else
0322                 msg=sprintf('I attempted to exclude the following channels, but they were not found:');
0323             end
0324             for a=1:n_missed,
0325                 msg=[msg ' ' missed{a}];
0326             end
0327             watchit(msg);
0328         end
0329     end
0330 elseif ~isempty(include_chans),
0331     use_chans=zeros(1,n_EEG_chans);
0332     in_ct=0;
0333     for a=1:n_EEG_chans,
0334         if ismember_ci(EEG.chanlocs(a).labels,include_chans)
0335             use_chans(a)=1;
0336             in_ct=in_ct+1;
0337             in_labels{in_ct}=EEG.chanlocs(a).labels;
0338         end
0339     end
0340     n_chans=sum(use_chans);
0341     use_chans=find(use_chans==1);
0342     
0343     if VERBLEVEL>1,
0344         missed=setdiff_ci(include_chans,in_labels);
0345         n_missed=length(missed);
0346         if n_missed,
0347             if n_missed==1,
0348                 msg=sprintf('I attempted to include the following channel, but it was not found:');
0349             else
0350                 msg=sprintf('I attempted to include the following channels, but they were not found:');
0351             end
0352             for a=1:n_missed,
0353                 msg=[msg ' ' missed{a}];
0354             end
0355             watchit(msg);
0356         end
0357     end
0358 else
0359     n_chans=n_EEG_chans;
0360     use_chans=1:n_chans;
0361 end
0362 
0363 n_EEG_bins=length(EEG.bindesc);
0364 if isempty(p.Results.use_bins),
0365     use_bins=1:n_EEG_bins;
0366     n_bins=n_EEG_bins;
0367 else
0368     %modicum of error checking
0369     if min(p.Results.use_bins)<1,
0370         error('You cannot request to import bins with indices less than 1 (e.g., "Bin -1").');
0371     elseif length(unique(p.Results.use_bins)) ~= length(p.Results.use_bins)  % TPU checking for duplicate bin numbers in use_bins
0372         error('You cannot request to import duplicate bins\n');              % TPU
0373     elseif max(p.Results.use_bins)>n_EEG_bins,
0374         error('File %s only has %d bins, but you''ve requested to import Bin %d.\n', ...
0375             infiles{1},n_EEG_bins,max(p.Results.use_bins));
0376     end
0377     use_bins=p.Results.use_bins;
0378     n_bins=length(use_bins);
0379 end
0380 %initialize cell array for keeping track of used urevents
0381 used_urevents=cell(n_infiles,n_bins); %at most there will be n_infiles subjects
0382 
0383 GND.exp_desc=p.Results.exp_name;
0384 GND.filename=[];
0385 GND.filepath=[];
0386 GND.saved='no';
0387 GND.grands=zeros(n_chans,n_pts,n_bins)*NaN;
0388 GND.grands_stder=GND.grands;
0389 GND.grands_t=GND.grands;
0390 GND.sub_ct=zeros(1,n_bins);
0391 GND.chanlocs=EEG.chanlocs(use_chans);
0392 GND.bin_info=[];
0393 if isfield(EEG,'condesc'),
0394     for b=1:n_bins,
0395         GND.bin_info(b).bindesc=EEG.bindesc{use_bins(b)};
0396         GND.bin_info(b).condcode=EEG.binccodes(use_bins(b));
0397     end
0398     GND.condesc=EEG.condesc;
0399 else
0400     for b=1:n_bins,
0401         GND.bin_info(b).bindesc=EEG.bindesc{use_bins(b)};
0402         GND.bin_info(b).condcode=1; %Not Kutaslab data, so condition codes aren't important
0403     end
0404     
0405     %Note, Kutaslab data won't have condition descriptors
0406     GND.condesc{1}='Experiment (not cal pulses)';
0407 end
0408 GND.time_pts=EEG.times;
0409 if isempty(p.Results.bsln)
0410     %use all time points before 0 or first time point
0411     GND.bsln_wind(1)=EEG.times(1);
0412     ids=find(EEG.times<0);
0413     if isempty(ids)
0414         GND.bsln_wind(2)=EEG.times(1);
0415     else
0416         GND.bsln_wind(2)=EEG.times(max(ids));
0417     end
0418 else
0419     GND.bsln_wind=p.Results.bsln;
0420 end
0421 GND.odelay=[];
0422 GND.srate=EEG.srate;
0423 GND.indiv_fnames=infiles;
0424 if isempty(EEG.subject),
0425     if VERBLEVEL,
0426         fprintf('Set file, %s, does not have a subject name. I will use the filename as the subject''s name.\n', ...
0427             infiles{1});
0428     end
0429     GND.indiv_subnames{1}=infiles{1};
0430 else
0431     GND.indiv_subnames{1}=EEG.subject;
0432 end
0433 GND.indiv_traits=[];
0434 GND.indiv_bin_ct=zeros(n_infiles,n_bins);
0435 if isfield(EEG,'rawtrials_per_bin'),
0436     GND.indiv_bin_raw_ct=zeros(n_infiles,n_bins);
0437 else
0438     GND.indiv_bin_raw_ct=zeros(n_infiles,n_bins)*NaN; %This field is only relevant to Kutaslab data.  It keeps track of how many trials there were before artifact rejection.
0439 end
0440 GND.indiv_erps=zeros(n_chans,n_pts,n_bins,n_infiles);
0441 GND.indiv_art_ics=[];
0442 if isfield(EEG,'cal_info'),
0443     %This field is only relevant to Kutaslab data.
0444     cal_size=size(EEG.cal_info.erps);
0445     GND.cals.indiv_cals=zeros(n_chans,cal_size(2),n_infiles);
0446     GND.cals.indiv_cal_ct=zeros(1,n_infiles);
0447     GND.cals.grand_cals=zeros(cal_size);
0448     GND.cals.caldesc='cal pulses';
0449     GND.cals.condcode=0;
0450     GND.cals.condesc='calibration';
0451     cal_info_present=1;
0452 else
0453     cal_info_present=0;
0454     GND.cals=[];
0455 end
0456 GND.history=[];
0457 GND.t_tests=[];
0458 
0459 %% Loop through set files
0460 sub_ct=1;
0461 for filenum=1:n_infiles,
0462     new_sub=1; %Assume data from this subject has not been already loaded, until we learn otherwise (This is to deal with the fact that data from the same participant may be distributed among multiple set files)
0463     if filenum>1,
0464         global EEG; %this needs to be done to be compatible with EEGLAB (which stores EEG globally)
0465         if VERBLEVEL,
0466             fprintf('\n\n');
0467         end
0468         EEG=pop_loadset(infiles{filenum});
0469         if ~isempty(unvsl_chanlocs)
0470             EEG.chanlocs=unvsl_chanlocs;
0471         end
0472         
0473         %collect sub names
0474         if isempty(EEG.subject),
0475             if VERBLEVEL,
0476                 fprintf('Set file, %s, does not have a subject name. I will use the filename as the subject''s name.\n', ...
0477                     infiles{filenum});
0478             end
0479             sub_name=infiles{filenum};
0480         else
0481             sub_name=EEG.subject;
0482         end
0483         ur_sub_id=0;
0484         for old_sub=1:sub_ct,
0485             if strcmpi(GND.indiv_subnames{old_sub},sub_name),
0486                 ur_sub_id=old_sub;
0487                 if VERBLEVEL
0488                     fprintf('Set file, %s, will be appended to data already loaded from Subject %s.\n', ...
0489                         infiles{filenum},GND.indiv_subnames{old_sub});
0490                 end
0491                 new_sub=0;
0492                 break;
0493             end
0494         end
0495         if ~ur_sub_id,
0496             sub_ct=sub_ct+1;
0497             sub=sub_ct;
0498             GND.indiv_subnames{sub}=sub_name;
0499         else
0500             sub=ur_sub_id;
0501         end
0502         
0503         EEG_var_check(EEG,infiles{filenum});
0504         
0505         [n_EEG_chans2, n_pts2, n_epochs]=size(EEG.data);
0506         n_EEG_bins2=length(EEG.bindesc);
0507         
0508         %Figure out which channels to use
0509         if ~isempty(exclude_chans),
0510             use_chans=zeros(1,n_EEG_chans2);
0511             ex_ct=0;
0512             ex_labels=[];
0513             for a=1:n_EEG_chans2,
0514                 if ~ismember_ci(EEG.chanlocs(a).labels,exclude_chans)
0515                     use_chans(a)=1;
0516                 else
0517                     ex_ct=ex_ct+1;
0518                     ex_labels{ex_ct}=EEG.chanlocs(a).labels;
0519                 end
0520             end
0521             n_chans2=sum(use_chans);
0522             use_chans=find(use_chans==1);
0523             
0524             if VERBLEVEL>1,
0525                 missed=setdiff_ci(exclude_chans,ex_labels);
0526                 n_missed=length(missed);
0527                 if n_missed,
0528                     if n_missed==1,
0529                         msg=sprintf('I attempted to exclude the following channel, but it was not found:');
0530                     else
0531                         msg=sprintf('I attempted to exclude the following channels, but they were not found:');
0532                     end
0533                     for a=1:n_missed,
0534                         msg=[msg ' ' missed{a}];
0535                     end
0536                     watchit(msg);
0537                 end
0538             end
0539         elseif ~isempty(include_chans),
0540             use_chans=zeros(1,n_EEG_chans2);
0541             in_ct=0;
0542             in_labels=[];
0543             for a=1:n_EEG_chans2,
0544                 if ismember_ci(EEG.chanlocs(a).labels,include_chans)
0545                     use_chans(a)=1;
0546                     in_ct=in_ct+1;
0547                     in_labels{in_ct}=EEG.chanlocs(a).labels;
0548                 end
0549             end
0550             n_chans2=sum(use_chans);
0551             use_chans=find(use_chans==1);
0552             
0553             if VERBLEVEL>1,
0554                 missed=setdiff_ci(include_chans,in_labels);
0555                 n_missed=length(missed);
0556                 if n_missed,
0557                     if n_missed==1,
0558                         msg=sprintf('I attempted to include the following channel, but it was not found:');
0559                     else
0560                         msg=sprintf('I attempted to include the following channels, but they were not found:');
0561                     end
0562                     for a=1:n_missed,
0563                         msg=[msg ' ' missed{a}];
0564                     end
0565                     watchit(msg);
0566                 end
0567             end
0568         else
0569             n_chans2=n_EEG_chans2;
0570             use_chans=1:n_chans2;
0571         end
0572         
0573         %Check for consistency with GND
0574         if EEG.srate~=GND.srate,
0575             error('File %s has a different sampling rate than file %s.\n', ...
0576                 infiles{1},infiles{filenum});
0577         end
0578         if n_chans2~=n_chans,
0579             error('File %s has a different number of channels to import than file %s.\n', ...
0580                 infiles{1},infiles{filenum});
0581         end
0582         if n_pts2~=n_pts,
0583             error('File %s has a different number of time points than file %s.\n', ...
0584                 infiles{1},infiles{filenum});
0585         end
0586         if ~min(EEG.times==GND.time_pts),
0587             error('The epochs in file %s begin and end at different times than file %s.\n', ...
0588                 infiles{1},infiles{filenum});
0589         end
0590         if isempty(p.Results.use_bins),
0591             if n_EEG_bins2~=n_bins,
0592                 error('File %s has a different number of bins than file %s.\n', ...
0593                     infiles{1},infiles{filenum});
0594             end
0595         else
0596             if max(p.Results.use_bins)>n_EEG_bins2,
0597                 error('File %s only has %d bins, but you''ve requested to import Bin %d.\n', ...
0598                     infiles{filenum},n_EEG_bins2,max(p.Results.use_bins));
0599             end
0600         end
0601         if isfield(EEG,'condesc'),
0602             newfile_condesc=EEG.condesc;
0603         else
0604             newfile_condesc{1}='Experiment (not cal pulses)';
0605         end
0606         if ~isequal(GND.condesc,newfile_condesc),
0607             error('The condition code descriptor (EEG.condesc) in file %s is not the same as that in previous files.\n', ...
0608                 infiles{filenum});
0609         end
0610         bin_ct=0;
0611         for b=use_bins,
0612             bin_ct=bin_ct+1;
0613             if ~strcmpi(GND.bin_info(bin_ct).bindesc,EEG.bindesc{b}),
0614                 error('The #%d imported bin in file %s is different than that of file %s.\n', ...
0615                     b,infiles{1},infiles{filenum});
0616             end
0617         end
0618         try
0619             [fs1, fs2, er]=comp_struct_quiet(GND.chanlocs,EEG.chanlocs(use_chans));
0620         catch
0621             error('File %s''s imported channel location information differs from that of file %s.\n', ...
0622                 infiles{1},infiles{filenum});
0623         end
0624         if ~isempty(er),
0625             error('File %s''s imported channel location information differs from that of file %s.\n', ...
0626                 infiles{1},infiles{filenum});
0627         end
0628     else
0629         sub=sub_ct; %for first set file, sub=1 (since sub_ct=1)
0630     end
0631     
0632     %Remove ICs labeled as artifacts
0633     fldnames=fieldnames(EEG);
0634     art_ics=[];
0635     ics_removed=0;
0636     if sum(EEG.reject.gcompreject),
0637         ics_removed=1;
0638     else
0639         for fn=1:length(fldnames),
0640             if strcmpi(fldnames{fn},'iclabels'),
0641                 ics_removed=1;
0642                 break;
0643             end
0644         end
0645     end
0646     if ics_removed,
0647         art_ics=remove_artifact_ics(GND.bsln_wind);
0648     end
0649     GND.indiv_art_ics{filenum}=art_ics;
0650     
0651     %baseline data (if not already baselined by ics_removed)
0652     if isnan(GND.bsln_wind)
0653         fprintf('NOT baselining data.\n');
0654     elseif ~isempty(GND.bsln_wind) && ~ics_removed,
0655         bsln_pts(1)=find_tpt(GND.bsln_wind(1),EEG.times);
0656         bsln_pts(2)=find_tpt(GND.bsln_wind(2),EEG.times);
0657         if VERBLEVEL>=2,
0658             fprintf('Baselining data by removing mean EEG between %d and %d ms (time points %d and %d).\n', ...
0659                 GND.bsln_wind(1),GND.bsln_wind(2),bsln_pts(1),bsln_pts(2));
0660         end
0661         
0662         EEG.data=rmbase(EEG.data,n_pts,bsln_pts(1):bsln_pts(2));
0663         EEG.data=reshape(EEG.data,n_EEG_chans,n_pts,n_epochs);
0664         
0665     end
0666     
0667     
0668     %Compute ERPs, use GND.indiv_erps as a running sum
0669     for a=1:n_epochs,
0670         for b=1:length(EEG.epoch(a).eventtype),
0671             if (length(EEG.epoch(a).eventtype{b})>2) && strcmpi(EEG.epoch(a).eventtype{b}(1:3),'bin')
0672                 bin=str2num(EEG.epoch(a).eventtype{b}(4:end));
0673                 if ismember(bin,use_bins) && ~index_cellarray_or_vector(EEG.epoch(a).eventlatency,b,VERBLEVEL),
0674                     
0675                     % BEGIN TPU
0676                     binind=find(use_bins==bin);  % lookup dimension of array to load
0677                     if (length(binind)>1) % die if duplicate bins ... this should be caught earlier
0678                         error('ERROR sets2GND.m Duplicate bins in use_bins');
0679                     end
0680                     % END TPU
0681                     
0682                     %only consider events with epoch latency of 0
0683                     new_event=1;
0684                     urevent=index_cellarray_or_vector(EEG.epoch(a).eventurevent,b,VERBLEVEL);
0685                     if ~new_sub,
0686                         %check to see if event has already been used for
0687                         %this bin
0688                         if ismember(urevent,used_urevents{sub,binind}), % TPU
0689                             if VERBLEVEL>1,
0690                                 fprintf('Epoch %d has already been added to Bin %d for Subject %s.\n', ...
0691                                     a,bin,GND.indiv_subnames{sub});
0692                             end
0693                             new_event=0;
0694                         end
0695                     end
0696                     if new_event,
0697                         GND.indiv_erps(:,:,binind,sub)=GND.indiv_erps(:,:,binind,sub)+EEG.data(use_chans,:,a); % TPU bin->binind
0698                         GND.indiv_bin_ct(sub,binind)=GND.indiv_bin_ct(sub,binind)+1;   % TPU bin->binind
0699                         used_urevents{sub,binind}=[used_urevents{sub,binind} urevent]; % TPU bin->binind
0700                     end
0701                 end
0702             end
0703         end
0704     end
0705     
0706     if isfield(EEG,'rawtrials_per_bin'),
0707         %Again, this field is only relevant to Kutaslab data.  It keeps
0708         %track of how many trials there were before artifact rejection.
0709         GND.indiv_bin_raw_ct(sub,:)=GND.indiv_bin_raw_ct(sub,:)+EEG.rawtrials_per_bin(use_bins);
0710     end
0711     
0712     if isfield(EEG,'cal_info')
0713         %Again, this field is only relevant to Kutaslab data.
0714         %Note, I assume that even if a single participant's data are
0715         %distributed among multiple set files, EEG.cal_info is the same in
0716         %all the set files.
0717         GND.cals.indiv_cals(use_chans,:,sub)=EEG.cal_info.erps(use_chans,:);
0718         GND.cals.indiv_cal_ct(sub)=EEG.cal_info.npulse_used;
0719         GND.cals.caldesc='cal pulses';
0720         GND.cals.condcode=0;
0721         GND.cals.condesc='calibration';
0722         cal_info_present=1;
0723     end
0724     
0725     clear global EEG; %make sure it's not saved since ICs might have been removed
0726 end %filenum loop
0727 
0728 
0729 %remove unused elements of GND variable (if any), because there are fewer
0730 %subjects than set files
0731 GND.indiv_bin_ct=GND.indiv_bin_ct(1:sub_ct,:);
0732 GND.indiv_bin_raw_ct=GND.indiv_bin_raw_ct(1:sub_ct,:);
0733 GND.indiv_erps=GND.indiv_erps(:,:,:,1:sub_ct);
0734 if cal_info_present,
0735     GND.cals.indiv_cals(:,:,1:sub_ct)=GND.cals.indiv_cals(:,:,1:sub_ct);
0736     GND.cals.indiv_cal_ct=GND.cals.indiv_cal_ct(1:sub_ct);
0737 end
0738 
0739 %turn running sums into means
0740 for sub=1:sub_ct,
0741     if VERBLEVEL>1
0742         fprintf('\nTrials per bin for Subject %s:\n',GND.indiv_subnames{sub});
0743     end
0744     for b=1:n_bins,
0745         bin_ct=GND.indiv_bin_ct(sub,b);
0746         if bin_ct,
0747             if VERBLEVEL>1,
0748                 fprintf('Bin %d (%s): %d trials\n',b,GND.bin_info(b).bindesc,bin_ct);
0749             end
0750             GND.indiv_erps(:,:,b,sub)=GND.indiv_erps(:,:,b,sub)/bin_ct;
0751             GND.sub_ct(b)=GND.sub_ct(b)+1;
0752         else
0753             watchit(sprintf('Subject %s has no epochs that fall into bin %d.',GND.indiv_subnames{sub},b));
0754             GND.indiv_erps(:,:,b,sub)=GND.indiv_erps(:,:,b,sub)*NaN;
0755         end
0756     end
0757 end
0758 
0759 %Baseline individual ERPs/cal pulses and compute grands
0760 if VERBLEVEL>1,
0761     fprintf('\n\n'); %add a couple lines between between counts and baselining info
0762 end
0763 GND=baselineGND(GND,GND.bsln_wind);% This line actually computes the grand average ERPs. It doesn't just baseline them.
0764 
0765 
0766 %Compute grand average cal pulses (if individual subject cal pulses present)
0767 if cal_info_present,
0768     GND.cals.grand_cals=mean(GND.cals.indiv_cals,3);
0769 end
0770 
0771 %% Save GND variable
0772 if isempty(p.Results.out_fname),
0773     %Create GUI
0774     [jname, jpath]=uiputfile({'*.GND','*.GND files'; ...
0775         '*','All files'},'Save GND variable as:','untitled.GND');
0776     if ~jpath,
0777         fprintf('Output filename selection cancelled.  GND variable NOT saved to disk.\n');
0778     else
0779         %test to make sure file can be created
0780         isW=isWriteable([jpath jname]);
0781         if isW,
0782             GND=save_matmk(GND,jname,jpath,1); % 1 means that user won't be asked again about saving file
0783         else
0784             fprintf('GND file could not be saved, but should still exist in MATLAB workspace.');
0785         end
0786     end
0787 elseif ~strcmpi(p.Results.out_fname,'no save'),
0788     [jpath, jname]=pathNname(p.Results.out_fname);
0789     %Add .GND extension if no extension given
0790     if ~ismember('.',jname),
0791         jname=[jname '.GND'];
0792     end
0793     fprintf('Saving GND variable as %s\n',[jpath jname]);
0794     force=1;
0795     GND=save_matmk(GND,jname,jpath,force);
0796 end
0797 
0798 function EEG_var_check(EEG,fname)
0799 
0800 if isempty(EEG.epoch),
0801     error('File %s stores continuous EEG data. You need to convert the data into epochs.',fname);
0802 elseif ~isfield(EEG,'bindesc'),
0803     error('The variable stored in file %s does not contain a bin descriptor. You need to apply bin_info2EEG.m to it.',fname);
0804 end
0805 
0806 function value=index_cellarray_or_vector(cellarray_or_vector,index,VERBLEVEL)
0807 
0808 if index>length(cellarray_or_vector),
0809     %This if statement is necessary for compatibility with Kutaslab .set
0810     %files, which can have multiple types per epoch but typically only a
0811     %single latency value
0812     index=length(cellarray_or_vector);
0813     if VERBLEVEL>2,
0814         fprintf('EEG.epoch(#).eventtype index exceeds EEG.epoch(#).latency index.  I will simply use the last element of EEG.epoch(#).latency.\n');
0815     end
0816 end
0817 
0818 if iscell(cellarray_or_vector),
0819     value=cellarray_or_vector{index};
0820 else
0821     value=cellarray_or_vector(index);
0822 end
0823 
0824 %%%%%%%% END OF MAIN FUNCTION %%%%%%%
0825 
0826 
0827 function isW = isWriteable(inFile)
0828 % Function checks to make sure "inFile" can be written to disk. "inFile" is
0829 % not modified by the function.
0830 %
0831 % Author: Tom Urbach
0832 %
0833 
0834 isW = 0;
0835 [fid, message] = fopen(inFile,'a+');
0836 if (fid ~= -1)
0837     isW = 1;
0838     fclose(fid);
0839 else
0840     fprintf('Error opening %s: %s\n', inFile, message);
0841 end
0842 
0843 
0844 
0845 function yesno=ismember_ci(str,str_array)
0846 % function yesno=ismember_ci(str,str_array)
0847 % A case insensitive version of ismember.m but just for strings
0848 %
0849 % Inputs:
0850 %  str       - a string
0851 %  str_array - a cell array of strings
0852 %
0853 % Outputs:
0854 %  yesno - 1 if str is a member of str_array.  0 otherwise.  Comparison is
0855 %          not case sensitive.
0856 
0857 yesno=0;
0858 n_str=length(str_array);
0859 
0860 for a=1:n_str,
0861     if strcmpi(str,str_array{a})
0862         yesno=1;
0863         break;
0864     end
0865 end
0866 
0867 
0868 
0869 function dif_str=setdiff_ci(superset,subset)
0870 %function dif_str=setdiff_ci(superset,subset)
0871 %
0872 % Inputs:
0873 %   superset - an cell array of strings
0874 %   subset   - an cell array of strings
0875 %
0876 % Outputs:
0877 %   dif_str - a cell array of the strings that are in superset but NOT
0878 %             subset. Comparison is not case sensitive.
0879 %
0880 
0881 n_super=length(superset);
0882 n_sub=length(subset);
0883 dif_ct=0;
0884 dif_str=[];
0885 for a=1:n_super,
0886     found=0;
0887     for b=1:n_sub,
0888         if strcmpi(superset{a},subset{b}),
0889             found=1;
0890             break
0891         end
0892     end
0893     if ~found,
0894         dif_ct=dif_ct+1;
0895         dif_str{dif_ct}=superset{a};
0896     end
0897 end

Generated on Tue 10-May-2016 16:37:45 by m2html © 2005