0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057 function [scale_fact, used_cal_ids]=cont_data_calibrate(crwfile,logfile,bdffile,use_chanlocs,params)
0058
0059 global VERBLEVEL
0060
0061
0062 VerbReport(' ',1,VERBLEVEL);
0063
0064
0065
0066
0067 srate=erpio2('get_srate',crwfile);
0068
0069 VerbReport(sprintf('Creating temporary ascii version of logfile %s',logfile),1,VERBLEVEL);
0070
0071 asci_cmnd='rm -f temp.asci';
0072 unix(asci_cmnd);
0073 asci_cmnd=sprintf('log2asci %s temp.asci -d %d',logfile,srate);
0074 [s, w]=unix(asci_cmnd);
0075 if s~=0,
0076 disp('Could not create ascii version of logfile using log2asci.');
0077 error('According to log2asci: %s',w);
0078 end
0079 asciilogfile='temp.asci';
0080 tempascii=1;
0081 VerbReport(sprintf('Getting log information from %s', asciilogfile), 1, VERBLEVEL);
0082
0083
0084 log_info=import_entire_log(asciilogfile);
0085
0086
0087 if tempascii,
0088 VerbReport(sprintf('Removing temporary ascii version of logfile.'),1,VERBLEVEL);
0089 asci_cmnd='rm -f temp.asci';
0090 [s, w]=unix(asci_cmnd);
0091 if s~=0,
0092 disp('Could not remove ascii version of logfile: temp.asci.');
0093 error('According to rm: %s',w);
0094 end
0095 end
0096
0097
0098 [cc_bounds, cc_bounds_codes]=parse_log_by_cc(log_info);
0099
0100
0101
0102 n_chans=erpio2('get_nchans',crwfile);
0103 errstring=erpio2('get_errstr');
0104 if ~isempty(errstring),
0105 error(errstring);
0106 end
0107
0108 crw_chanlabels=cell(1,n_chans);
0109 for c=1:n_chans,
0110 chan_label=erpio2('get_chandes',crwfile,c-1);
0111 errstring=erpio2('get_errstr');
0112 if ~isempty(errstring),
0113 error(errstring);
0114 end
0115 crw_chanlabels{c}=chan_label;
0116 end
0117
0118
0119 n_chanloc_chans=length(use_chanlocs);
0120 chanloc_labels=cell(1,n_chanloc_chans);
0121 crwfile2chanloc_ids=zeros(1,n_chans);
0122 for a=1:n_chanloc_chans,
0123 chanloc_labels{a}=use_chanlocs(a).labels;
0124 [in_crw_file, id]=ismember(chanloc_labels{a},crw_chanlabels);
0125 if ~in_crw_file,
0126 error('The cal pulse crw file %s does not have a channel for EEG variable channel %s.', ...
0127 crwfile,chanloc_labels{a});
0128 end
0129 crwfile2chanloc_ids(id)=a;
0130 end
0131
0132
0133
0134 cont_data=[];
0135 eventcodes=[];
0136 timestamps=[];
0137 n_cc_bounds=size(cc_bounds,1);
0138 for a=1:n_cc_bounds,
0139 if ~cc_bounds_codes(a)
0140
0141 [cont_dataTEMP, eventcodesTEMP, timestampsTEMP]=erpio2('get_cdata', ...
0142 crwfile,'event',cc_bounds(a,1)-1,cc_bounds(a,2)-1,0);
0143
0144
0145 cont_data=[cont_data cont_dataTEMP];
0146 eventcodes=[eventcodes eventcodesTEMP];
0147 timestamps=[timestamps timestampsTEMP];
0148 end
0149 end
0150 clear cont_dataTEMP eventcodesTEMP timestampsTEMP
0151
0152
0153
0154 use_chans=find(crwfile2chanloc_ids>0);
0155 cont_data=cont_data(use_chans,:);
0156
0157 cont_data=cont_data(crwfile2chanloc_ids(use_chans),:);
0158
0159
0160
0161
0162
0163 [blf_info, bin_LongDesc, blffile, blf_evnum, rtfile, cal_bin, cond_LongDesc, bin_CondCode]= ...
0164 import_blf(bdffile,logfile,srate,[]);
0165
0166
0167
0168
0169 [n_chan, n_tpts]=size(cont_data);
0170 bndry_times_in_ms=1000*log_info(log_info(:,2)==-16384,5);
0171 cal_blf_ids=find(blf_info(:,cal_bin+1));
0172 cal_log_ids=blf_evnum(cal_blf_ids);
0173
0174
0175 n_cal_ids=length(cal_log_ids);
0176 diff=zeros(n_chan,n_cal_ids);
0177 pulse_log_ids=zeros(1,n_cal_ids);
0178 pulse_ct=0;
0179 if VERBLEVEL>1,
0180 fprintf('Searching data for cal pulses (i.e., items in Bin %d). Cal pulses found: ',cal_bin);
0181 end
0182
0183 back_step=floor((params.cal_npts-1)/2);
0184 fwd_step=ceil((params.cal_npts-1)/2);
0185 for a=cal_log_ids,
0186 if (VERBLEVEL>1) && ~mod(pulse_ct,50),
0187 fprintf('%d ',pulse_ct);
0188 end
0189
0190
0191 log_id=a+1;
0192
0193
0194 event_time=1000*log_info(log_id,5);
0195 pre_cntr_id=find_tpt(event_time+params.low_cursor,timestamps);
0196 post_cntr_id=find_tpt(event_time+params.hi_cursor,timestamps);
0197
0198
0199
0200
0201
0202 if (pre_cntr_id-back_step)<1,
0203 watchit(sprintf('Cal pulse #%d is too close to boundary to be used.',find(cal_log_ids==a)));
0204 elseif (post_cntr_id+fwd_step)>n_tpts,
0205 watchit(sprintf('Cal pulse #%d is too close to boundary to be used.',find(cal_log_ids==a)));
0206 else
0207 min_time_needed=timestamps(pre_cntr_id-back_step);
0208 max_time_needed=timestamps(post_cntr_id+fwd_step);
0209 if sum( (bndry_times_in_ms>=min_time_needed).*(bndry_times_in_ms<=max_time_needed))
0210 watchit(sprintf('Cal pulse #%d is too close to boundary to be used.',find(cal_log_ids==a)));
0211 else
0212
0213 mn_prepulse=mean(cont_data(:,(pre_cntr_id-back_step):(pre_cntr_id+fwd_step)),2);
0214 mn_postpulse=mean(cont_data(:,(post_cntr_id-back_step):(post_cntr_id+fwd_step)),2);
0215
0216
0217 pulse_ct=pulse_ct+1;
0218 diff(:,pulse_ct)=mn_postpulse-mn_prepulse;
0219 pulse_log_ids(pulse_ct)=a+1;
0220 end
0221 end
0222 end
0223
0224 if VERBLEVEL>1
0225 fprintf('\n');
0226 end
0227
0228
0229
0230
0231 if pulse_ct==0,
0232 error('No calibration pulses found. Cal pulses are events with a condition code of 0 that fall in a bin according to the specified bdf/blf file.');
0233 end
0234
0235
0236
0237
0238
0239 VerbReport(sprintf(['cont_data_calibrate: converting raw A/D to calibrated' ...
0240 ' uV with the following parameters']),1,VERBLEVEL);
0241 VerbReport(sprintf('# of time points in mean windows: %d',params.cal_npts),1,VERBLEVEL);
0242 VerbReport(sprintf('pre-pulse time window center (in msec): %d',params.low_cursor),1,VERBLEVEL);
0243 VerbReport(sprintf('post-pulse time window center (in msec): %d',params.hi_cursor),1,VERBLEVEL);
0244 VerbReport(sprintf('cal pulse amplitude: %d uV',params.cal_amp),1,VERBLEVEL);
0245 if params.cal_polarity==1,
0246 VerbReport('cal pulse polarity: positive',1, ...
0247 VERBLEVEL);
0248 elseif params.cal_polarity==-1,
0249 VerbReport('cal pulse polarity: negative',1, ...
0250 VERBLEVEL);
0251 else
0252 error('cal_polarity must be 1 or -1');
0253 end
0254 VerbReport(sprintf('Percent of extreme pulses to trim: %d',params.trm_pcnt),VERBLEVEL);
0255
0256
0257
0258
0259
0260
0261 VerbReport(sprintf('Averaging cal pulses'),2,VERBLEVEL);
0262
0263 [diff srt_id]=sort(diff(:,1:pulse_ct)');
0264 cut_pls=round((params.trm_pcnt*pulse_ct)/200);
0265
0266 nUse=length(cut_pls+1:pulse_ct-cut_pls);
0267 true_trm_pcnt=100*(1-nUse/pulse_ct)/2;
0268 VerbReport(sprintf('Removing max %.2f percent and min %.2f percent of pulses', ...
0269 true_trm_pcnt,true_trm_pcnt),2,VERBLEVEL);
0270
0271
0272 useamps=diff(cut_pls+1:pulse_ct-cut_pls,:);
0273 scale_fact=params.cal_polarity*mean(useamps)';
0274 scale_fact=params.cal_amp./scale_fact;
0275
0276
0277 used_cal_ids=zeros(n_chan,nUse);
0278 for dg=1:n_chan,
0279 used_cal_ids(dg,:)=srt_id(cut_pls+1:pulse_ct-cut_pls,dg)';
0280 end
0281
0282
0283
0284
0285 if params.cal_plot_opt
0286 if params.cal_plot_avg,
0287 n_subplot=5;
0288 else
0289 n_subplot=4;
0290 end
0291
0292
0293 show_prepulse=100;
0294 show_postpulse=700;
0295
0296
0297
0298
0299
0300 show_pulse_ct=1;
0301 show_prepulse_tpt=[];
0302 tme=-show_prepulse:1000/srate:show_postpulse;
0303 n_show_tpts=length(tme);
0304 while show_pulse_ct<=pulse_ct,
0305 a=pulse_log_ids(show_pulse_ct);
0306 event_time=1000*log_info(a,5);
0307 show_prepulse_tpt=find_tpt(event_time-show_prepulse,timestamps);
0308 show_postpulse_tpt=find_tpt(event_time+show_postpulse,timestamps);
0309 if length(show_prepulse_tpt:show_postpulse_tpt)~=n_show_tpts
0310 watchit(sprintf('Used pulse #%d is too close to boundary to plot.',show_pulse_ct));
0311 show_prepulse_tpt=[];
0312 else
0313 break;
0314 end
0315 show_pulse_ct=show_pulse_ct+1;
0316 end
0317 if isempty(show_prepulse_tpt)
0318 error('Could not plot a cal pulse. They are all too close to log file boundaries.');
0319 end
0320 firstpulse=cont_data(:,show_prepulse_tpt:show_postpulse_tpt);
0321
0322
0323 show_pulse_ct=pulse_ct;
0324 show_prepulse_tpt=[];
0325 while show_pulse_ct>=1,
0326 a=pulse_log_ids(show_pulse_ct);
0327 event_time=1000*log_info(a,5);
0328 show_prepulse_tpt=find_tpt(event_time-show_prepulse,timestamps);
0329 show_postpulse_tpt=find_tpt(event_time+show_postpulse,timestamps);
0330 if length(show_prepulse_tpt:show_postpulse_tpt)~=n_show_tpts
0331 watchit(sprintf('Used pulse #%d is too close to boundary to plot.',show_pulse_ct));
0332 show_prepulse_tpt=[];
0333 else
0334 break;
0335 end
0336 show_pulse_ct=show_pulse_ct-1;
0337 end
0338 if isempty(show_prepulse_tpt)
0339 error('Could not plot a cal pulse. They are all too close to log file boundaries.');
0340 end
0341 lastpulse=cont_data(:,show_prepulse_tpt:show_postpulse_tpt);
0342
0343 figure;
0344 subplot(n_subplot,1,1);
0345 plot(tme,firstpulse');
0346 h=title('First Cal Pulse (Uncalibrated)');
0347 set(h,'fontsize',14,'fontweight','bold');
0348 hold on;
0349 v=axis;
0350 axis([tme(1) tme(end) v(3:4)]);
0351 h=plot([0 0],v(3:4),'k');
0352 set(h,'linewidth',3);
0353 h=xlabel('Time (ms)');
0354 set(gca,'ygrid','on');
0355 set(h,'fontsize',14);
0356
0357 subplot(n_subplot,1,2);
0358 plot(tme,lastpulse');
0359 h=title('Last Cal Pulse (Uncalibrated)');
0360 set(h,'fontsize',14,'fontweight','bold');
0361 hold on;
0362 v=axis;
0363 axis([tme(1) tme(end) v(3:4)]);
0364 h=plot([0 0],v(3:4),'k');
0365 set(h,'linewidth',3);
0366 set(gca,'ygrid','on');
0367 h=xlabel('Time (ms)');
0368 set(h,'fontsize',14);
0369
0370
0371 subplot(n_subplot,1,3);
0372 boxplot(diff.*repmat(scale_fact',pulse_ct,1));
0373 set(gca,'ygrid','on','xtick',1:n_chan,'xticklabel',1:n_chan);
0374 hh=xlabel({' ','Electrode Number'});
0375 ylabel('Microvolts');
0376 h=title('Boxplots of All Pulses (Calibrated)');
0377 set(h,'fontsize',14,'fontweight','bold');
0378
0379
0380 subplot(n_subplot,1,4);
0381 boxplot(useamps.*repmat(scale_fact',nUse,1));
0382 set(gca,'ygrid','on','xtick',1:n_chan,'xticklabel',1:n_chan);
0383 hh2=xlabel({' ','Electrode Number'});
0384
0385
0386 ylabel('Microvolts');
0387 h=title(['Boxplots of ' num2str(200*cut_pls/pulse_ct,3) ' Percent Trimmed Pulses (Calibrated)']);
0388 set(h,'fontsize',14,'fontweight','bold');
0389
0390 if params.cal_plot_avg,
0391
0392 fprintf('Computing average used cal pulse (i.e., excluding trimmed pulses).\n');
0393 cal_erp=zeros(n_chan,n_show_tpts);
0394 cal_erp_ct=zeros(n_chan,1);
0395 for c=1:n_chan
0396 fprintf('Channel %d of %d.\n',c,n_chan);
0397 for b=1:nUse,
0398 a=pulse_log_ids(used_cal_ids(c,b));
0399
0400
0401 event_time=1000*log_info(a,5);
0402 start_tpt=find_tpt(event_time-show_prepulse,timestamps);
0403 stop_tpt=find_tpt(event_time+show_postpulse,timestamps);
0404 if length(start_tpt:stop_tpt)~=n_show_tpts,
0405 watchit(sprintf('Pulse %d, Channel %d cannot be included in average since plotting epoch duration extends beyond recording boundaries.', ...
0406 b,c));
0407 else
0408 cal_erp(c,:)=cal_erp(c,:)+cont_data(c,start_tpt:stop_tpt);
0409 cal_erp_ct(c)=cal_erp_ct(c)+1;
0410 end
0411 end
0412 end
0413
0414 cal_erp=cal_erp./repmat(cal_erp_ct./scale_fact,1,n_show_tpts);
0415
0416 center_tpt=find_tpt(params.low_cursor,tme);
0417 bsln_start_tpt=center_tpt-floor((params.cal_npts-1)/2);
0418 bsln_stop_tpt=center_tpt+ceil((params.cal_npts-1)/2);
0419 bsln_mn=mean(cal_erp(:,bsln_start_tpt:bsln_stop_tpt),2);
0420 cal_erp=cal_erp-repmat(bsln_mn,1,n_show_tpts);
0421
0422
0423 subplot(n_subplot,1,5);
0424 plot(tme,cal_erp');
0425 h=title('Average of Used Cal Pulse (Baselined, Trimmed, Calibrated)');
0426 set(h,'fontsize',14,'fontweight','bold');
0427 hold on;
0428 v=axis;
0429 axis([tme(1) tme(end) v(3:4)]);
0430 h=plot([0 0],v(3:4),'k');
0431 set(h,'linewidth',3);
0432 set(gca,'ygrid','on');
0433 h=xlabel('Time (ms)');
0434 set(h,'fontsize',14);
0435 end
0436 end