Home > matlabmk > sets2GND.m

sets2GND

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}

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

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