TEAP (Toolbox for Emotion Analysis using Physiological Signals) doc
save2bkr.m
Go to the documentation of this file.
1 function [HDR] = save2bkr(arg1,arg2,arg3);
2 % SAVE2BKR loads EEG data and saves it in BKR format
3 % The following data formats are supported:
4 % CNT, EDF, BKR, MAT, etc. format
5 %
6 % HDR = save2bkr(sourcefile [, destfile [, option]]);
7 %
8 % HDR = eegchkhdr();
9 % HDR = save2bkr(HDR,data);
10 %
11 % sourcefile sourcefile wildcards are allowed
12 % destfile destination file in BKR format
13 % if destfile is empty or a directory, sourcefile but with extension .bkr is used.
14 % options
15 % gain Gain factor for unscaled EEG data (e.g. old Matlab files)
16 % 'removeDC' removes mean
17 % 'regressEOG k:l,m:n' removes EOG (channels m:n) from EEG (channels k:l)
18 % 'autoscale k:l' uses only channels from k to l for scaling
19 % 'detrend k:l' channels from k to l are detrended with an FIR-highpass filter.
20 % 'PhysMax=XXX' uses a fixed scaling factor; might be important for concanating BKR files
21 % +XXX and -XXX correspond to the maximum and minimum physical value, resp.
22 % You can concanate several options by separating with space, komma or semicolon
23 %
24 % HDR Header, HDR.FileName must contain target filename
25 % data data samples
26 %
27 % Examples:
28 % save2bkr('/tmp/*.cnt',[],'autoscale 5:30');
29 % converts all CNT-files from subdir /tmp/ into BKR files
30 % and saves them in the current directory
31 % save2bkr('/tmp/*.cnt','/tmp2/','autoscale 5:30, PhysMax=200');
32 % converts all CNT-files from subdir /tmp/ into BKR files
33 % and saves them in the directory /tmp2/
34 %
35 %
36 %
37 % see also: EEGCHKHDR, REGRESS_EOG, SLOAD
38 
39 % $Revision: 1.23 $
40 % $Id: save2bkr.m 2205 2009-10-27 12:18:15Z schloegl $
41 % Copyright (C) 2002-2003 by Alois Schloegl <a.schloegl@ieee.org>
42 % This is part of the BIOSIG-toolbox http://biosig.sf.net/
43 
44 % This library is free software; you can redistribute it and/or
45 % modify it under the terms of the GNU Library General Public
46 % License as published by the Free Software Foundation; either
47 % Version 2 of the License, or (at your option) any later version.
48 %
49 % This library is distributed in the hope that it will be useful,
50 % but WITHOUT ANY WARRANTY; without even the implied warranty of
51 % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
52 % Library General Public License for more details.
53 %
54 % You should have received a copy of the GNU Library General Public
55 % License along with this library; if not, write to the
56 % Free Software Foundation, Inc., 59 Temple Place - Suite 330,
57 % Boston, MA 02111-1307, USA.
58 
59 
60 FLAG_REGRESS_EOG = 0;
61 FLAG_REMOVE_DC = 0;
62 FLAG_AUTOSCALE = 0;
63 FLAG_DETREND = 0;
64 FLAG_PHYSMAX = 0;
65 FLAG_removeDrift = 0;
66 
67 chansel = 0;
68 
69 if nargin<2, arg2=[]; end;
70 
71 if nargin<3,
72  cali = NaN;
73 elseif isnumeric(arg3)
74  cali = arg3;
75 else
76  FLAG_REMOVE_DC = findstr(lower(arg3),'removedc');
77 
78  tmp = findstr(arg3,'autoscale');
79  if ~isempty(tmp);
80  [chansel,tmp] = strtok(arg3(tmp+9:length(arg3)),' ;+');
81  tmp = str2num(chansel);
82  if isempty(tmp),
83  fprintf(2,'invalid autoscale argument %s',chansel);
84  return;
85  else
86  FLAG_AUTOSCALE = 1;
87  chansel = tmp;
88  end;
89  end;
90 
91  tmp = findstr(lower(arg3),'detrend');
92  if ~isempty(tmp);
93  [chansel_dt,tmp] = strtok(arg3(tmp+7:length(arg3)),' ;,+');
94  tmp = str2num(chansel_dt);
95  if isempty(tmp),
96  fprintf(2,'invalid detrend argument %s',chansel_dt);
97  return;
98  else
99  FLAG_DETREND = 1;
100  chansel_dt = tmp;
101  end;
102  end;
103 
104  tmp = findstr(lower(arg3),'removedrift');
105  if ~isempty(tmp);
106  [chansel_dt2,tmp] = strtok(arg3(tmp+11:length(arg3)),' ;+');
107  tmp = str2num(chansel_dt2);
108  if isempty(tmp),
109  fprintf(2,'invalid RemoveDrift argument %s',chansel_dt2);
110  return;
111  else
112  FLAG_removeDrift = 1;
113  chansel_dt2 = tmp;
114  end;
115  end;
116 
117  tmp = findstr(lower(arg3),'regresseog');
118  if ~isempty(tmp);
119  [chansel_dt3,tmp] = strtok(arg3(tmp+11:length(arg3)),' ;,+');
120  [chansel_dt4,tmp] = strtok(tmp,' ;,+');
121  tmp = str2num(chansel_dt3);
122  FLAG_REGRESS_EOG = ~isempty(tmp);
123  if isempty(tmp),
124  fprintf(2,'invalid REGRESSEOG argument %s',chansel_dt3);
125  return;
126  else
127  FLAG_REGRESS_EOG = 1;
128  chansel_dt3 = tmp;
129  end;
130  tmp = str2num(chansel_dt4);
131  FLAG_REGRESS_EOG = FLAG_REGRESS_EOG * ~isempty(tmp);
132  if isempty(tmp),
133  fprintf(2,'invalid REGRESSEOG argument %s',chansel_dt4);
134  return;
135  else
136  chansel_dt4 = tmp;
137  end;
138  end;
139  tmp = findstr(lower(arg3),'physmax=');
140  if ~isempty(tmp);
141  [tmp,tmp1] = strtok(arg3(tmp+8:length(arg3)),' ;,');
142  PHYSMAX = str2num(tmp);
143  if isempty(PHYSMAX ),
144  fprintf(2,'invalid PhysMax argument %s',tmp);
145  return;
146  else
147  FLAG_PHYSMAX = 1;
148  end;
149  end;
150 end;
151 
152 if 0,
153 elseif exist(arg1,'file')
154  inpath='';
155  infile.name=arg1;
156  outfile = arg2;
157 elseif exist(arg1,'dir')
158  inpath = fileparts(arg1);
159  infile = dir(arg1); % input file
160  if isempty(infile)
161  fprintf(2,'ERROR SAVE2BKR: file %s not found.\n',arg1);
162  return;
163  end;
164  outfile = arg2;
165 elseif isstruct(arg1) & isnumeric(arg2),
166  HDR = arg1;
167  data = arg2;
168 else %if isstruct(arg1) & isnumeric(arg2),
169  fprintf(2,'Error SAVE2BKR: invalid input arguments\n');
170  return;
171 end;
172 
173 if isstruct(arg1),
174  %HDR.FileName = destfile; % Assign Filename
175  if isfield(HDR,'NS')
176  if HDR.NS==size(data,2),
177  % It's ok.
178  elseif HDR.NS==size(data,1),
179  warning('data is transposed\n');
180  data = data';
181  else
182  fprintf(2,'HDR.NS=%i is not equal number of data columns %i\n',HDR.NS,size(data,2));
183  return;
184  end;
185  else
186  HDR.NS = size(data,2); % number of channels
187  end;
188  if ~isfield(HDR,'NRec'),
189  HDR.NRec = 1; % number of trials (1 for continous data)
190  end;
191  HDR.SPR = size(data,1)/HDR.NRec; % number of samples per trial
192  %HDR.SampleRate = 100; % Sampling rate
193  %HDR.Label = hdr.Label; % Labels,
194 
195  %HDR.PhysMax = max(abs(data(:))); % Physical maximum
196  %HDR.DigMax = max(2^15-1); % Digital maximum
197  % --- !!! Previous scaling gave an error up to 6% and more !!! ---
198 
199  %HDR.Filter.LowPass = 30; % upper cutoff frequency
200  %HDR.Filter.HighPass = .5; % lower cutoff frequency
201  HDR.FLAG.REFERENCE = ' '; % reference '', 'LOC', 'COM', 'LAP', 'WGT'
202  %HDR.FLAG.REFERENCE = HDR.Recording;
203  HDR.FLAG.TRIGGERED = HDR.NRec>1; % Trigger Flag
204 
205  if FLAG_REMOVE_DC,
206  %y = center(y,1);
207  data = data - repmat(mean(data,1),size(data,1),1);
208  end;
209  if chansel == 0;
210  chansel=1:HDR.NS;
211  end;
212  tmp = data(:,chansel);
213  HDR.PhysMax = max(abs(tmp(:))); %gives max of the whole matrix
214  HDR.DigMax = 2^15-1; % maximum resulution
215  for k = 1:HDR.NS,
216  if any(k==chansel),
217  data(:,k) = data(:,k)*HDR.DigMax/HDR.PhysMax;
218  else
219  mm = max(abs(data(:,k)));
220  data(:,k) = data(:,k)*HDR.DigMax/mm;
221  end;
222  end;
223  HDR.FLAG.UCAL = 1; % data is de-calibrated, no rescaling within SWRITE
224  %HDR = eegchkhdr(HDR);
225  HDR.TYPE = 'BKR';
226 
227  HDR = sopen (HDR,'w',0); % OPEN BKR FILE
228  HDR = swrite(HDR,data); % WRITE BKR FILE
229  %fwrite(HDR.FILE.FID,data','int16'); % WRITE BKR FILE
230  HDR = sclose(HDR); % CLOSE BKR FILE
231 
232  % save Classlabels
233  if isfield(HDR,'Classlabel'),
234  fid = fopen([HDR.FileName(1:length(HDR.FileName)-4) '.par'],'wt');
235  fprintf(fid, '%i\n', HDR.Classlabel);
236  fclose(fid);
237  end;
238  if isfield(HDR,'ArtifactSelection'),
239  fid = fopen([HDR.FileName(1:length(HDR.FileName)-4) '.sel'],'w');
240  fprintf(fid, '%i\r\n', HDR.ArtifactSelection);
241  fclose(fid);
242  end;
243 
244  % final test
245  try
246  HDR = sopen(HDR.FileName,'r');
247  HDR = sclose(HDR);
248  catch
249  fprintf(2,'Error SAVE2BKR: saving file %s failed\n',HDR.FileName);
250  end;
251  return;
252 end;
253 
254 for k=1:length(infile);
255  filename = fullfile(inpath,infile(k).name);
256  [pf,fn,ext] = fileparts(filename);
257 
258  % load eeg data
259  [y,HDR] = sload(filename);
260 
261  % load classlabels if the exist
262  tmp = fullfile(HDR.FILE.Path,[HDR.FILE.Name,'.mat']);
263  if exist(tmp),
264  tmp=load(tmp);
265  if isfield(tmp,'classlabel');
266  HDR.Classlabel = tmp.classlabel;
267  end;
268  end;
269 
270  if isempty(y),
271  fprintf(2,'Error SAVE2BKR: file %s not found\n',filename);
272  return;
273  end;
274 
275  if ~isfield(HDR,'NS'),
276  warning(['number of channels undefined in ',filename]);
277  HDR.NS = size(y,2);
278  end;
279  if ~HDR.FLAG.TRIGGERED,
280  HDR.NRec = 1;
281  HDR.SPR = size(y,1);
282  end;
283  if ~isfield(HDR,'NRec'),
284  HDR.NRec = 1;
285  end;
286  if ~isfield(HDR,'SPR'),
287  HDR.SPR = size(y,1)/HDR.NRec;
288  elseif length(HDR.SPR)>1, % use just one sampling rate
289  HDR.SPR = HDR.AS.MAXSPR;
290  HDR.SampleRate = HDR.AS.MAXSPR/HDR.Dur;
291  FLAG_PHYSMAX = 1;
292  PHYSMAX = max(abs(y(:)));
293  HDR.DigMax = 2^15-1;
294  end;
295 
296  if FLAG_REGRESS_EOG,
297  fprintf(1,'\tREGRESS_EOG \n');
298  [R,y] = regress_eog(y,chansel_dt3,chansel_dt4);
299  end;
300 
301  if FLAG_REMOVE_DC,
302  fprintf(1,'\tREMOVE_DC \n');
303  y = y - repmat(mean(y,1),size(y,1),1);
304  end;
305  if FLAG_DETREND,
306  B = -ones(1,HDR.SampleRate)/HDR.SampleRate;
307  B(HDR.SampleRate/2) = B(HDR.SampleRate/2)+1;
308  HDR.Filter.B = B;
309  HDR.Filter.A = 1;
310  %HDR.Filter.B=B;%conv(-B, HDR.Filter.B);
311  Delay = length(B)/2;
312  HDR.FLAG.FILT = 1;
313  HDR.Filter.HighPass = .5;
314 
315  for k = chansel_dt,
316  tmp = filter(B,1,[y(:,k);zeros(length(B),1)]);
317  y(:,k) = tmp(Delay+1:size(y,1)+Delay);
318  end;
319  end;
320 
321  if FLAG_removeDrift,
322  B = .5*(1 - cos(2*pi*(1:4*HDR.SampleRate+1)'/(4*HDR.SampleRate+2)));
323  B = -B/sum(B);
324  B(2*HDR.SampleRate) = B(HDR.SampleRate)+1;
325 
326  B = -ones(1,HDR.SampleRate)/HDR.SampleRate;
327  B(HDR.SampleRate/2) = B(HDR.SampleRate/2)+1;
328  %B(1) = B(1)+1;
329 
330  HDR.Filter.B = B;
331  HDR.Filter.A = 1;
332  %HDR.Filter.B=B;%conv(-B, HDR.Filter.B);
333  Delay = (length(B)-1)/2;
334  HDR.FLAG.FILT = 1;
335  HDR.Filter.HighPass = .5;
336 
337  for k = chansel_dt2,
338  y(:,k) = filtfilt(B,1,y(:,k));
339  %y(:,k) = tmp(Delay+1:size(y,1)+Delay);
340  end;
341  end;
342 
343  if chansel == 0;
344  chansel=1:HDR.NS;
345  end;
346 
347  % add event channel
348  if isfield(HDR,'EVENT')
349  if ~length(HDR.EVENT.TYP),
350  elseif 0,
351  % TypeList = unique(HDR.EVENT.TYP); but ignores NaN's
352  [sY ,idx] = sort(HDR.EVENT.TYP(:));
353  TypeList = sY([1;find(diff(sY,1)>0)+1]);
354 
355  event = zeros(size(y,1),length(TypeList));
356  for k2 = 1:length(TypeList),
357  tmp = (HDR.EVENT.TYP==TypeList(k2));
358  event(HDR.EVENT.POS(tmp),k2) = HDR.EVENT.TYP(tmp);
359  end;
360  HDR.NS = HDR.NS + size(event,2);
361  y = [y, event];
362  elseif all(HDR.EVENT.TYP < 256), % only NeuroScan Events are converted into separate channels
363  K = 0; event = [];
364  for k1 = 0:7,
365  tmp = bitand(HDR.EVENT.TYP,2^k1);
366  if any(tmp),
367  K = K+1;
368  event(size(y,1),K) = 0;
369  event(HDR.EVENT.POS(tmp>0),K) = 1;
370  end;
371  end;
372  if any(sum(event,2)>1),
373  fprintf(2,'Warning SAVE2BKR: simulateneous events occur. \n');
374  end;
375  HDR.NS = HDR.NS + size(event,2);
376  y = [y, event];
377  end;
378  end;
379 
380  % re-scale data to account for the scaling factor in the header
381  HDR.DigMax = 2^15-1;
382  if FLAG_PHYSMAX,
383  HDR.PhysMax = PHYSMAX;
384  else
385  tmp = y(:,chansel);
386  HDR.PhysMax = max(abs(tmp(:))); %gives max of the whole matrix
387  end;
388  for k = 1:HDR.NS,
389  if any(k==chansel),
390  y(:,k) = y(:,k)*HDR.DigMax/HDR.PhysMax; % keep correct scaling factor
391  else
392  mm = max(abs(y(:,k)));
393  y(:,k) = y(:,k)*HDR.DigMax/mm; % scale to maximum resolution
394  end;
395  end;
396  HDR.FLAG.UCAL = 1; % data is de-calibrated, no rescaling within SWRITE
397 
398  tmp = round(HDR.PhysMax);
399  fprintf(1,'Rounding of PhysMax yields %f%% error.\n',abs((HDR.PhysMax-tmp)/tmp)*100);
400  HDR.PhysMax = tmp;
401  HDR.TYPE = 'BKR';
402  HDR.FLAG.REFERENCE = ' ';
403  HDR.FLAG.TRIGGERED = (HDR.NRec>1);
404 
405  if isempty(outfile), % default destination directory
406  ix = max(find(filename=='.'));
407  %HDR.FileName = [filename(1:ix-1),'.bkr']; % destination directory is same as source directory
408  HDR.FileName = [HDR.FILE.Name,'.bkr']; % destination directory is current working directory
409  elseif isdir(outfile), % output file
410  HDR.FILE.Path = outfile;
411  HDR.FileName = fullfile(outfile,[HDR.FILE.Name,'.bkr']);
412  else
413  [HDR.FILE.Path,HDR.FILE.Name,Ext] = fileparts(outfile);
414  HDR.FileName = fullfile(HDR.FILE.Path,[HDR.FILE.Name,Ext]);
415  end;
416  %HDR = eegchkhdr(HDR);
417 
418  HDR = sopen(HDR,'w');
419  if HDR.FILE.FID < 0,
420  fprintf(1,'Error SAVE2BKR: couldnot open file %s.\n',HDR.FileName);
421  return;
422  end;
423  % writes data
424  HDR = swrite(HDR,y(:,1:HDR.NS)); % WRITE BKR FILE
425  %count = fwrite(HDR.FILE.FID,y','short');
426  HDR = sclose(HDR);
427 
428  % save classlabels
429  if isfield(HDR,'Classlabel'),
430  if ~isempty(HDR.Classlabel),
431  fid = fopen([HDR.FileName(1:length(HDR.FileName)-4) '.par'],'w');
432  fprintf(fid, '%i\r\n', HDR.Classlabel);
433  fclose(fid);
434  end;
435  end;
436  if isfield(HDR,'ArtifactSelection'),
437  fid = fopen([HDR.FileName(1:length(HDR.FileName)-4) '.sel'],'w');
438  fprintf(fid, '%i\r\n', HDR.ArtifactSelection);
439  fclose(fid);
440  end;
441 
442  % final test
443  try
444  HDR = sopen(HDR.FileName,'r');
445  HDR = sclose(HDR);
446  catch
447  fprintf(2,'Error SAVE2BKR: saving file %s failed\n',HDR.FileName);
448  end;
449 end;
sclose
function sclose(in HDR)
save2bkr
function save2bkr(in arg1, in arg2, in arg3)
sload
function sload(in FILENAME, in varargin)
swrite
function swrite(in HDR, in data)
regress_eog
function regress_eog(in D, in ny, in nx)
sopen
function sopen(in arg1, in PERMISSION, in CHAN, in MODE, in arg5, in arg6)