decimateGND() - Downsamples a set of ERPs to a lower sampling rate. Useful for reducing the number of dependent variables and conserving memory. Usage: >> GND=decimateGND(GND,decfactor,method,bsln_wind,verblevel); Required Inputs: GND - A GND structure variable. To create a GND variable from Kutaslab ERP files (e.g., *.mas files) use avgs2GND.m. To do the same from EEGLAB *.set files use sets2GND.m. See Mass Univariate ERP Toolbox documentation for detailed information about the format of a GND variable. decfactor - [positive integer] The factor by which to reduce the data set. For example, if decfactor is 2, the data will have approximately half as many time points. Optional Inputs: method - ['boxcar' or 'fir'] If 'boxcar,' data are decimated with a boxcar moving average (this is the algorithm used by Kutaslab's UNIX program "avg"). If 'fir,' data are decimated using the MATLAB function decimate.m and a 30th order FIR filter. See comments in this file (decimateGND.m) for more information on how exactly decimation is done. Note, you MUST HAVE THE MATLAB SIGNAL PROCESSING TOOLBOX to use the 'fir' option. The 'boxcar' option does NOT require the signal processing toolbox {default: 'boxcar'} bsln_wind - [vector] Two element vector specifying the beginning and end (in ms) of the baseline time window (e.g., [-100 -4]). The mean amplitude across all time points within and including those times will be removed from each ERP. Data should be re-baselined after decimation, because baseline mean amplitude may no longer be zero after decimation. {default: all time points before 0} save_GND - ['yes' or 'no'] If 'yes', the GND variable will be saved to disk after the permutation test is completed and added to it. User will first be prompted to verify file name and path. {default: 'yes'} 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) Example: To convert a GND variable from 250 Hz to 125 Hz using a boxcar window: >>GND=decimateGND(GND,2); To convert a GND variable from 250 Hz to 125 Hz using a FIR anti-aliasing filter and then re-baselining the data: >>GND=decimateGND(GND,2,'fir',[-100 0]); Author: David Groppe ('boxcar' algorithm from Paul Krewski) Kutaslab, 3/2010
0001 % decimateGND() - Downsamples a set of ERPs to a lower sampling rate. 0002 % Useful for reducing the number of dependent variables and 0003 % conserving memory. 0004 % Usage: 0005 % >> GND=decimateGND(GND,decfactor,method,bsln_wind,verblevel); 0006 % 0007 % Required Inputs: 0008 % GND - A GND structure variable. To create a GND variable from 0009 % Kutaslab ERP files (e.g., *.mas files) use avgs2GND.m. To 0010 % do the same from EEGLAB *.set files use sets2GND.m. See Mass 0011 % Univariate ERP Toolbox documentation for detailed information 0012 % about the format of a GND variable. 0013 % decfactor - [positive integer] The factor by which to reduce the data 0014 % set. For example, if decfactor is 2, the data will have 0015 % approximately half as many time points. 0016 % 0017 % Optional Inputs: 0018 % method - ['boxcar' or 'fir'] If 'boxcar,' data are decimated with a 0019 % boxcar moving average (this is the algorithm used by 0020 % Kutaslab's UNIX program "avg"). If 'fir,' data are decimated 0021 % using the MATLAB function decimate.m and a 30th order FIR 0022 % filter. See comments in this file (decimateGND.m) for more 0023 % information on how exactly decimation is done. Note, you 0024 % MUST HAVE THE MATLAB SIGNAL PROCESSING TOOLBOX to use the 0025 % 'fir' option. The 'boxcar' option does NOT require the 0026 % signal processing toolbox {default: 'boxcar'} 0027 % bsln_wind - [vector] Two element vector specifying the beginning and 0028 % end (in ms) of the baseline time window (e.g., [-100 -4]). 0029 % The mean amplitude across all time points within and 0030 % including those times will be removed from each ERP. Data 0031 % should be re-baselined after decimation, because baseline 0032 % mean amplitude may no longer be zero after decimation. 0033 % {default: all time points before 0} 0034 % save_GND - ['yes' or 'no'] If 'yes', the GND variable will be 0035 % saved to disk after the permutation test is completed 0036 % and added to it. User will first be prompted to verify 0037 % file name and path. {default: 'yes'} 0038 % verblevel - An integer specifiying the amount of information you want 0039 % this function to provide about what it is doing during runtime. 0040 % Options are: 0041 % 0 - quiet, only show errors, warnings, and EEGLAB reports 0042 % 1 - stuff anyone should probably know 0043 % 2 - stuff you should know the first time you start working 0044 % with a data set {default value} 0045 % 3 - stuff that might help you debug (show all 0046 % reports) 0047 % 0048 % Example: 0049 % To convert a GND variable from 250 Hz to 125 Hz using a boxcar window: 0050 % >>GND=decimateGND(GND,2); 0051 % 0052 % To convert a GND variable from 250 Hz to 125 Hz using a FIR anti-aliasing 0053 % filter and then re-baselining the data: 0054 % >>GND=decimateGND(GND,2,'fir',[-100 0]); 0055 % 0056 % 0057 % Author: 0058 % David Groppe ('boxcar' algorithm from Paul Krewski) 0059 % Kutaslab, 3/2010 0060 0061 function GND=decimateGND(GND,decfactor,method,bsln_wind,save_GND,verblevel) 0062 0063 %%%%%%%%%%%%%%%% REVISION LOG %%%%%%%%%%%%%%%%% 0064 % 3/16/2011-Function now works when GND.cals field is empty. This field is 0065 % unique to Kutaslab data and is empty for data obtained from other labs. 0066 % Thanks to Andrew Hill for finding this bug. 0067 % 0068 % 3/23/2011-save_GND option added. 0069 % 0070 % 3/12/2013-'fir' option now works when GND.cals field is empty (bug fix on 0071 % 3/16/2011 was accidentally incomplete). Thanks to Aaron Newman for 0072 % reporting this. 0073 0074 %Notes about decimation: 0075 % -When using the 'boxcar' method, the size of the boxcar moving window is 0076 % decfactor+1. For example, if decfactor=2, each time point is replaced by 0077 % the mean of it and the immediately preceding and following time point. 0078 % Time points at the edge of the ERPs are discarded since they lack 0079 % sufficient preceding or following time points. Every other time point is 0080 % discarded. This method has the advantage that the latency of any effect 0081 % won't be distorted (i.e., data at a pre-decimated time point only effects 0082 % the data at a single post-decimated time point). The DISADVANTAGE of this 0083 % method is that moving average windows have ripply stop bands. Thus it 0084 % won't do a great job of suppressing high frequency activity (e.g., 60 Hz 0085 % and will surely result in some aliasing. Unless you have a lot of 0086 % 60 Hz or EMG in your data this might not be a significant problem since 0087 % ERPs typically have little power at those high frequencies. 0088 % I suspect that the 'fir' option could potentially shift effects a bit 0089 % in time, but I haven't verified this yet. When I tried running the 0090 % filter on an impulse (a waveform with a single non-zero value), it showed 0091 % no evidence of this. In contrast, the Chebyshev filter (decimate.m's 0092 % default filter) does spread an impulse forward and backward in time and 0093 % could distort the latency of effects. 0094 % 0095 0096 if nargin<3, 0097 method='boxcar'; 0098 else 0099 if ~(strcmpi(method,'boxcar') || strcmpi(method,'fir')), 0100 error('Arugment ''method'' needs to be ''boxcar'' or ''fir'''); 0101 end 0102 end 0103 0104 if nargin<4 0105 bsln_wind=[]; 0106 elseif ~isempty(bsln_wind), 0107 if length(bsln_wind)~=2, 0108 error('Argument bsln_wind needs to be a two element vector.'); 0109 end 0110 end 0111 0112 if nargin<5 0113 save_GND='yes'; 0114 elseif ~(strcmpi(save_GND,'yes') || strcmpi(save_GND,'no')) 0115 error('Argument save_GND needs to be ''yes'' or ''no''.'); 0116 end 0117 0118 global VERBLEVEL; 0119 if nargin<6 0120 if isempty(VERBLEVEL), 0121 VERBLEVEL=2; 0122 end 0123 else 0124 VERBLEVEL=verblevel; 0125 end 0126 0127 0128 %Erase any t-test results as they won't be valid anymore 0129 if ~isempty(GND.t_tests), 0130 %but ask first 0131 if VERBLEVEL>1, 0132 resp=[]; 0133 while ~strcmpi(resp,'y') && ~strcmpi(resp,'n') && ~strcmpi(resp,'yes') ... 0134 && ~strcmpi(resp,'no'), 0135 fprintf('These data have t-test results stored with them that won''t be accurate after the data have been decimated.\nFor this reason, they will be erased.\n'); 0136 resp=input(sprintf('Continue with decimation (t-tests will be erased)? [y or n] '),'s'); 0137 end 0138 if strcmpi('n',resp) || strcmpi('no',resp), 0139 return 0140 end 0141 fprintf('Erasing t-test results stored with these data.\n'); 0142 end 0143 GND.t_tests=[]; 0144 end 0145 0146 [n_chan, n_tpt, n_bin, n_sub]=size(GND.indiv_erps); 0147 if strcmpi(method,'boxcar') 0148 if VERBLEVEL>1, 0149 fprintf('Downsampling data by a factor of %d after low-pass filtering with a boxcar moving average.\n', ... 0150 decfactor); 0151 end 0152 0153 %decimate with moving boxcar window of length decfactor*2-1 0154 neo_n_tpt=length(decfactor:decfactor:(n_tpt-decfactor+1)); 0155 0156 %Recompute time points 0157 neo_times=zeros(1,neo_n_tpt); 0158 ct=0; 0159 for t=decfactor:decfactor:(n_tpt-decfactor+1), 0160 ct=ct+1; 0161 if ~rem(ct,10), 0162 fprintf('Now computing time point %d of %d.\n',ct,neo_n_tpt); 0163 end 0164 tstart=t-decfactor+1; 0165 tend=t+decfactor-1; 0166 neo_times(ct)=mean(GND.time_pts(tstart:tend)); 0167 for s=1:n_sub, 0168 for c=1:n_chan, 0169 for b=1:n_bin, 0170 GND.indiv_erps(c,ct,b,s)=mean(GND.indiv_erps(c,tstart:tend,b,s)); 0171 end 0172 %Cal pulses 0173 if ~isempty(GND.cals), 0174 GND.cals.indiv_cals(c,ct,s)=mean(GND.cals.indiv_cals(c,tstart:tend,s)); 0175 end 0176 end 0177 end 0178 end 0179 GND.indiv_erps=GND.indiv_erps(:,1:neo_n_tpt,:,:); 0180 if ~isempty(GND.cals), 0181 GND.cals.indiv_cals= GND.cals.indiv_cals(:,1:neo_n_tpt,:); 0182 end 0183 GND.time_pts=neo_times; 0184 else 0185 if VERBLEVEL>1, 0186 fprintf('Downsampling data by a factor of %d after low-pass filtering with a MATLAB derived FIR filter.\n', ... 0187 decfactor); 0188 end 0189 0190 %Recompute time points 0191 GND.time_pts=round(decimate(GND.time_pts,decfactor,'fir')); 0192 neo_n_tpt=length(GND.time_pts); 0193 0194 0195 %Decimate individual participant ERPs 0196 for c=1:n_chan, 0197 fprintf('Now downsampling Channel %d (%s).\n',c,GND.chanlocs(c).labels); 0198 for b=1:n_bin, 0199 for s=1:n_sub, 0200 GND.indiv_erps(c,1:neo_n_tpt,b,s)=decimate(GND.indiv_erps(c,:,b,s),decfactor,'FIR'); 0201 end 0202 end 0203 end 0204 GND.indiv_erps=GND.indiv_erps(:,1:neo_n_tpt,:,:); 0205 0206 if ~isempty(GND.cals), 0207 %Decimate cal pulse ERPs 0208 fprintf('Now downsampling cal pulses.\n'); 0209 for s=1:n_sub, 0210 for c=1:n_chan, 0211 GND.cals.indiv_cals(c,1:neo_n_tpt,s)=decimate(GND.cals.indiv_cals(c,:,s),decfactor,'FIR'); 0212 end 0213 end 0214 GND.cals.indiv_cals=GND.cals.indiv_cals(:,1:neo_n_tpt,:); 0215 end 0216 end 0217 0218 %Shrink grand fields for overwriting 0219 GND.grands=GND.grands(:,1:neo_n_tpt,:); 0220 GND.grands_stder=GND.grands_stder(:,1:neo_n_tpt,:); 0221 GND.grands_t=GND.grands_t(:,1:neo_n_tpt,:); 0222 0223 %Rebaseline individual ERPs/cal pulses and recompute grands 0224 GND=baselineGND(GND,bsln_wind); 0225 0226 %Recompute sampling rate 0227 GND.srate=GND.srate/decfactor; 0228 0229 %add comand to history 0230 n_hist=length(GND.history); 0231 if isempty(bsln_wind), 0232 GND.history{n_hist+1}=sprintf('GND=decimate(GND,%d,''%s'',[],%d);', ... 0233 decfactor,method,VERBLEVEL); 0234 else 0235 GND.history{n_hist+1}=sprintf('GND=decimate(GND,%d,''%s'',[%d %d],%d);', ... 0236 decfactor,method,bsln_wind(1),bsln_wind(2), ... 0237 VERBLEVEL); 0238 end 0239 0240 0241 GND.saved='no'; 0242 if strcmpi(save_GND,'yes'), 0243 GND=save_matmk(GND,'gui'); 0244 end