1 function [HDR] =
save2gdf(arg1,arg2,arg3);
2 % SAVE2GDF loads EEG data and saves it in GDF format
3 % It has been tested with data of the following formats:
4 % Physiobank, BKR, CNT (Neurscan), EDF,
6 % HDR =
save2gdf(sourcefile [, destfile [, option]]);
11 % see also: SLOAD, SOPEN, SREAD, SCLOSE, SWRITE
14 % sourcefile sourcefile wildcards are allowed
15 % destfile destination file in BKR format
16 %
if destfile is empty or a directory, sourcefile but with extension .bkr is used.
20 % gain Gain factor
for unscaled EEG data (e.g. old Matlab files)
21 %
'removeDC' removes mean
22 %
'autoscale k:l' uses only channels from k to l
for scaling
23 %
'detrend k:l' channels from k to l are detrended with an FIR-highpass filter.
24 %
'PhysMax=XXX' uses a fixed scaling factor; might be important
for concanating BKR files
25 % +XXX and -XXX correspond to the maximum and minimum physical value, resp.
26 % You can concanate several options by separating with space, komma or semicolon
28 % HDR Header, HDR.FileName must contain target filename
31 % This program is free software; you can redistribute it and/or
32 % modify it under the terms of the GNU General Public License
33 % as published by the Free Software Foundation; either version 3
34 % of the License, or (at your option) any later version.
37 % $Id:
save2gdf.m 2997 2012-06-18 15:15:49Z schloegl $
38 % Copyright (C) 2003-2005,2007,2008 by Alois Schloegl <a.schloegl@ieee.org>
39 % This file is part of the biosig project http:
50 if nargin<2, arg2=[]; end;
56 inpath = fileparts(arg1);
57 infile = dir(arg1); % input file
59 fprintf(2,
'ERROR SAVE2GDF: file %s not found.\n',arg1);
63 elseif isstruct(arg1) & isnumeric(arg2),
66 else %
if isstruct(arg1) & isnumeric(arg2),
67 fprintf(2,
'Error SAVE2GDF: invalid input arguments\n');
72 %HDR.FileName = destfile; % Assign Filename
74 if HDR.NS==size(data,2),
76 elseif HDR.NS==size(data,1),
77 warning('data is transposed\n');
79 elseif HDR.NS==size(data,2)+1,
80 HDR.NS = size(data,2);
81 %warning('data is transposed\n');
84 fprintf(2,'HDR.NS=%i is not equal to number of data columns %i\n',HDR.NS,size(data,2));
88 HDR.NS = size(data,2); % number of channels
91 % THRESHOLD, GDFTYP -> Phys/Dig/Min/Max
92 if isa(data,'single') & strncmp(version,'6',1)
96 if isfield(HDR,'THRESHOLD')
97 HDR.DigMax = HDR.THRESHOLD(1:HDR.NS,2)';
98 HDR.DigMin = HDR.THRESHOLD(1:HDR.NS,1)';
100 else %if ~isfield(HDR,'THRESHOLD')
101 fprintf(2,'Warning SAVE2GDF: no THRESHOLD value provided - automated overflow detection not supported\n');
103 HDR.DigMax = max(data,[],1);
104 HDR.DigMin = min(data,[],1);
109 if ~isfield(HDR,'VERSION');
112 % HDR.FLAG.UCAL = 0; % data is de-calibrated, no rescaling within SWRITE
114 if strcmp(HDR.TYPE,'EVENT')
115 HDR.SampleRate = HDR.EVENT.SampleRate;
116 elseif isfield(HDR,'GDFTYP')
117 if any((HDR.GDFTYP>=16) & (HDR.GDFTYP<=18))
118 if (HDR.VERSION < 1.90)
121 HDR.PhysMax = [1,HDR.DigMax]*HDR.Calib;
122 HDR.PhysMin = [1,HDR.DigMin]*HDR.Calib;
123 data = (data - repmat(HDR.DigMin(:)',size(data,1),1));
124 data = data * diag((digmax-digmin)./HDR.Cal) + digmin;
125 HDR.DigMin(:) = digmin;
126 HDR.DigMax(:) = digmax;
127 HDR.Cal = (HDR.PhysMax-HDR.PhysMin)./(HDR.DigMax-HDR.DigMin);
128 HDR.Off = HDR.PhysMin - HDR.Cal .* HDR.DigMin;
129 HDR.Calib = [HDR.Off;diag(HDR.Cal)];
134 HDR.PhysMax = [1,HDR.DigMax]*HDR.Calib;
135 HDR.PhysMin = [1,HDR.DigMin]*HDR.Calib;
136 %bits = ceil(log2(max(HDR.DigMax-HDR.DigMin+1))/8)*8; % allows int8, int16, int24, int32, etc.
137 bits1 = ceil(log2(HDR.DigMax-HDR.DigMin+1));
138 [datatyp,limits,datatypes] =
gdfdatatype(HDR.GDFTYP);
139 bits = log2(limits(:,2)-limits(:,1)+1);
140 fprintf(1,'SAVE2GDF: %i bits needed, %i bits used for file %s\n',max(bits1),max(bits),HDR.FileName);
143 % re-scale data to account for the scaling factor in the header
144 %HIS = histo3(data); save HIS HIS
148 tmp(tmp<8*eps) = NaN;
154 bits = ceil(log2(max(digmax-digmin+1))); % allows any bit-depth
155 if (min(dQ)<1) & (HDR.VERSION>1.9), GDFTYP = 16; % float32
156 elseif min(dQ)<1, GDFTYP = 5; % int32
157 elseif bits==8, GDFTYP = 1; % int8
158 elseif bits==16, GDFTYP = 3; % int16
159 elseif bits==32, GDFTYP = 5; % int32
160 elseif bits==64, GDFTYP = 7; % int64
161 elseif ~isempty(bits); GDFTYP = 255+bits; % intN
162 else GDFTYP = 3; % int8
166 if length(HDR.GDFTYP)==HDR.NS,
167 elseif length(HDR.GDFTYP)==1,
168 HDR.GDFTYP = HDR.GDFTYP*ones(1,HDR.NS); % int16
173 [datatyp,limits,datatypes] =
gdfdatatype(HDR.GDFTYP);
175 % here, the data is forced to a different data type
176 % this is useful if data is
float
177 % this can cause round-off errors
178 HDR.DigMin = limits(:,1)';
179 HDR.DigMax = limits(:,2)';
180 HDR.FLAG.UCAL = 0; % data is calibrated, rescaling within SWRITE
183 % here, the data is of integer type
184 % no round of errors occur.
187 while any(digmin'<limits(:,1)),
188 c = 2^ceil(log2(max(limits(:,1)-digmin')))
193 while any(digmax'>limits(:,2)),
194 c = 2^ceil(log2(max(digmax'-limits(:,2))))
199 while any(digmin'<limits(:,1)),
200 c = 2^ceil(log2(max(limits(:,1)-digmin')))
208 HDR.DigMax = digmax; %limits(:,2); %*ones(1,HDR.NS);
209 HDR.DigMin = digmin; %limits(:,1); %*ones(1,HDR.NS);
211 %fprintf(1,'Warning SAVE2GDF: overflow detection not implemented, yet.\n');
213 if isfield(HDR,'Calib') & ~isfield(HDR,'PhysMax');
214 HDR.PhysMax = [1,HDR.DigMax]*HDR.Calib;
215 HDR.PhysMin = [1,HDR.DigMin]*HDR.Calib;
219 if ~isfield(HDR,'Dur');
220 HDR.Dur = 1/HDR.SampleRate;
224 %% [HDR.PhysMax;HDR.PhysMin;HDR.DigMax;HDR.DigMin;max(data);min(data)],
226 HDR =
sopen(HDR,'w');
228 fprintf(1,'Error SAVE2GDF: couldnot open file %s.\n',HDR.FileName);
233 HDR =
swrite(HDR,data(:,1:HDR.NS)); % WRITE GDF FILE
240 [y1,H2]=
sload(HDR.FileName,0,'UCAL','OFF');
241 d2 = [ones(size(data,1),1),data]*H2.Calib;
242 if all(all((d2==y1) | (isnan(d2) & isnan(y1)))),
243 fprintf(2,'SAVE2GDF: saving file %s OK.\n',HDR.FileName);
245 fprintf(2,'SAVE2GDF: file %s saved. Maximum relative roundoff error is %f.\n',HDR.FileName, max(max((d2-y1)./(abs(d2)+abs(y1)))) );
248 fprintf(2,'Error SAVE2GDF: saving file %s failed\n',HDR.FileName);
256 fid = fopen('MM.mmm','w+');
257 fprintf(fid,'%%%%MatrixMarket matrix coordinate real general\n');
258 fprintf(fid,'%% generated (C) 2009 by Alois Schloegl\n');
259 fprintf(fid,'%% selecting channels\n');
260 fprintf(fid,'%i %i %i\n',size(gain),length(V));
262 fprintf(fid,'%2i %2i %f\n',I(k),J(k),V(k));
266 for k=1:length(infile);
267 filename = fullfile(inpath,infile(k).name);
268 [pf,fn,ext] = fileparts(filename);
271 %[data,HDR] =
sload(filename);
272 HDR =
sopen(filename,'r',0);
274 fprintf(2,'Error SAVE2GDF: file %s not found\n',filename);
278 HDR.FLAG.OVERFLOWDETECTION = 0;
279 [data,HDR] =
sread(HDR,inf);
281 if isfield(HDR,'EDF')
282 if isfield(HDR.EDF,'Annotations')
283 if ~isempty(HDR.EDF.Annotations)
284 fprintf(2,'Warning SAVE2GDF: Annotations in EDF+ are not fully supported.\n');
288 if ~isfield(HDR,'DigMax'),
289 HDR.DigMax = max(data,[],1);
291 if ~isfield(HDR,'DigMin'),
292 HDR.DigMin = min(data,[],1);
294 if ~isfield(HDR,'DigMin'),
295 HDR.PhysMax = [1,HDR.DigMax]*HDR.Calib;
297 if ~isfield(HDR,'DigMin'),
298 HDR.PhysMin = [1,HDR.DigMin]*HDR.Calib;
300 if ~isfield(HDR,'NS'),
301 warning(['number of channels undefined in ',filename]);
302 HDR.NS = size(data,2);
305 if isempty(outfile), % default destination directory
306 ix = max(find(filename=='.'));
307 HDR.FileName = [HDR.FILE.Name,'.gdf']; % destination directory is current working directory
308 elseif isdir(outfile), % output file
309 HDR.FILE.Path = outfile;
310 HDR.FileName = fullfile(outfile,[HDR.FILE.Name,'.gdf']);
312 [HDR.FILE.Path,HDR.FILE.Name,Ext] = fileparts(outfile);
313 HDR.FileName = fullfile(HDR.FILE.Path,[HDR.FILE.Name,Ext]);