Coastlines/sdfopen.m

1282 lines
56 KiB
Matlab
Raw Permalink Blame History

% sdfopen() - Opens EDF/GDF/SDF files for reading and writing. The EDF format is specified
% in [1], GDF in [2]. SDF is the SIESTA convention (see [3], pp.8-9); SDF uses
% the EDF format.
% Usage:
% >> EDF = sdfopen(Filename,'r' [,CHAN]); % prepare to read CHAN channels
% >> EDF = sdfopen(Filename,'r' [,CHAN [,MODE [,TSR]]]); % all arguments
% % then
% >> [S,EDF] = sdfread(EDF, SecRead, SecStart); % reads the opened EDF data file.
% >> [S,EDF] = sdfread(EDF, Inf); % reads the whole opened EDF data file.
%
% Inputs:
% CHAN - [int vector] Specifies the channel(s) to read. Else, a re-referencing
% matrix. [Default|0 -> read all channels].
% MODE -
%
% 'UCAL' [Default mode] Indicates that no calibration (re-scaling) to physical dim.
% is performed. Outputs are 16-bit integers.
%
% 'SIESTA' - Indicates that channels #1-#6 are re-referenced to (M1+M2)/2
% (Note: 'UCAL' overrides 'SIESTA')
% 'AFIR' - Indicates that Adaptive FIR filtering is used for ECG removal.
% Implements Adaptive FIR filtering for ECG removal in EDF/GDF-tb.
% based on the algorithm of Mikko Koivuluoma <k7320@cs.tut.fi>
% A delay of EDF.AFIR.delay number of samples has to be considered.
% 'SIESTA+AFIR' - Does both.
% 'RAW' - One column represents one EDF-block
% 'Notch50Hz' - Implements a simple FIR-notch filter at 50 Hz
% 'RECG' - Implements ECG minimization with regression analysis
% 'TECG' - Implements ECG minimization with template removal (test status)
% 'HPF0.0Hz' - Implements a high-pass filter (with zero at z=+1, i.e. a differentiator).
% In this case, a notch-filter and/or sub-sampling is recommended.
% 'TAUx.yS' - Compensates time-constant of x.y seconds
% 'EOG[hvr]' - Produces HEOG, VEOG and/or REOG output (CHAN not considered)
% 'OVERFLOW' - Performs overflow detection
% 'Units_Blocks' - Requests the EDF-field arguments to SDFREAD in blocks
% [default is seconds]
% TSR - [optional] The target (re)sampling rate. Currently, only downsampling
% from 256 Hz or 200 Hz to 100 Hz is supported. The details are described
% in the appendix of [4].
%
% Outputs:
% EDF - data structure read from the input file header.
% EDF.ErrNo ~= 0 Indicates that an error occurred
% 1: First 8 bytes are not '0 ', violating the EDF spec.
% 2: Invalid date (unable to guess correct date)
% 4: Incorrect date information (later than current date)
% 16: Incorrect filesize: Header information does not match actual size
% EDF.FILE.FID = -1 indicates that file has not been opened
% (for compatibility with former versions).
% EDF.WarnNo ~=0 Indicates EDF structure problems
% 1: ascii(0) in 1st header
% 2: ascii(0) in 2nd header
% 4: invalid SPR
% 4: invalid samples_per_record-values
% 8: date not in EDF-format (tries to guess correct date, see also E2)
% 16: invalid number_of-channels-value
% 32: invalid value of the EDF header length
% 64: invalid value of block_duration
% 128: Polarity of #7 probably inverted
%
% Example:
% To open an EDF/SDF file for writing:
% >> [EDF] = sdfopen(EDF,'w') % or equivalently
% >> [EDF] = sdfopen(EDF.FileName,'w',EDF.Dur,EDF.SampleRate);
%
% Note: Fields EDF.FileName, EDF.NS, EDF.Dur and EDF.EDF.SampleRate must be defined.
%
% Author: (C) 1997-2002 by Alois Schloegl, 15 Jun 2002 #0.85, (Header reworked for
% EEGLAB format, Arnaud Delorme and Scott Makeig, 27 Dec 2002)
%
% See also: fopen, SDFREAD, SDFWRITE, SDFCLOSE, SDFSEEK, SDFREWIND, SDFTELL, SDFEOF
% References:
% [1] Bob Kemp, Alpo V<>rri, Agostinho C. Rosa, Kim D. Nielsen and John Gade.
% A simple format for exchange of digitized polygraphic recordings.
% Electroencephalography and Clinical Neurophysiology, 82 (1992) 391-393.
% See also: http://www.medfac.leidenuniv.nl/neurology/knf/kemp/edf/edf_spec.htm
%
% [2] Alois Schl<68>gl, Oliver Filz, Herbert Ramoser, Gert Pfurtscheller.
% GDF - A GENERAL DATAFORMAT FOR BIOSIGNALS
% Technical Report, Department for Medical Informatics,
% Universtity of Technology, Graz (1999)
% See also: http://www-dpmi.tu-graz.ac.at/~schloegl/matlab/eeg/gdf4/tr_gdf.ps
%
% [3] The SIESTA recording protocol.
% See http://www.ai.univie.ac.at/siesta/protocol.html
% and http://www.ai.univie.ac.at/siesta/protocol.rtf
%
% [4] Alois Schl<68>gl
% The electroencephalogram and the adaptive autoregressive model: theory and applications.
% (ISBN 3-8265-7640-3) Shaker Verlag, Aachen, Germany.
% See also: "http://www.shaker.de/Online-Gesamtkatalog/Details.idc?ISBN=3-8265-7640-3"
% Testing state
%
% (1) reads header information and writes the header; can be used to check SDFOPEN or for correcting headerinformation
% EDF=sdfopen(EDF,'r+'); EDF=sdfclose(EDF);
%
% (2a) Minimal requirements for opening an EDF-File
% EDF.FileName='file.edf'; % define filename
% EDF.NS = 5; % fix number of channels
% EDF=sdfopen(EDF,'w');
% write file
% define header somewhen before
% EDF=sdfclose(EDF); % writes the corrected header information
%
% (2b) Minimal requirements for opening an EDF-File
% EDF=sdfopen('file.edf','w',N); % N number of channels
% .. do anything, e.g define header
% EDF=sdfopen(EDF,'w+'); % writes Header information
% This program is free software; you can redistribute it and/or
% modify it under the terms of the GNU General Public License
% as published by the Free Software Foundation; either version 2
% of the License, or (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program; if not, write to the Free Software
% Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
function [EDF,H1,h2]=sdfopen(arg1,arg2,arg3,arg4,arg5,arg6)
INFO='(C) 1997-2002 by Alois Schloegl, 15 Jun 2002 #0.85';
% a.schloegl@ieee.org
% Version 0.85
if nargin<2, arg2='r';end;
if 1,exist('OCTAVE_VERSION');
EDF.AS.Method='sdfopen';
mfilename=EDF.AS.Method;
else
EDF.AS.Method=mfilename;
end;
EDF.AS.Method=[EDF.AS.Method '-' arg2];
EDF.AS.Date=fix(clock);
EDF.AS.Info=INFO;
EDF.AS.Ver = 0.82;
if isstruct(arg1)
EDF=arg1;
FILENAME=EDF.FileName;
else
FILENAME=arg1;
end;
H1idx=[8 80 80 8 8 8 44 8 8 4];
H2idx=[16 80 8 8 8 8 8 80 8 32];
%%%%% Define Valid Data types %%%%%%
%GDFTYPES=[0 1 2 3 4 5 6 7 16 17 255+(1:64) 511+(1:64)];
GDFTYPES=[0 1 2 3 4 5 6 7 16 17 255+[1 12 22 24] 511+[1 12 22 24]];
%%%%% Define Size for each data type %%%%%
GDFTYP_BYTE=zeros(1,512+64);
GDFTYP_BYTE(256+(1:64))=(1:64)/8;
GDFTYP_BYTE(512+(1:64))=(1:64)/8;
GDFTYP_BYTE(1:18)=[1 1 1 2 2 4 4 8 8 4 8 0 0 0 0 0 4 8]';
%EDF.GDFTYP.TEXT={'char','int8','uint8','int16','uint16','int32','uint32','int64','uint64','float32','float64'};
%GDFTYP_BYTE=[1 1 1 2 2 4 4 8 8 4 8 0 0 0 0 0 4 8]';
%GDFTYPES=[0 1 2 3 4 5 6 7 16 17];
EDF.ErrNo = 0;
%%%%%%% ============= READ ===========%%%%%%%%%%%%
if (strcmp(arg2,'r') | strcmp(arg2,'r+'))
[EDF.FILE.FID,MESSAGE]=fopen(FILENAME,arg2,'ieee-le');
%EDF.FILE.FID=fid;
EDF.FILE.stderr=2;
if EDF.FILE.FID<0
%fprintf(EDF.FILE.stderr,'Error GDFOPEN: %s %s\n',MESSAGE,FILENAME);
H1=MESSAGE; H2=FILENAME;
EDF.ErrNo = [32,EDF.ErrNo];
return;
end;
if (arg2=='r')
EDF.FILE.OPEN = 1;
elseif (arg2=='r+')
EDF.FILE.OPEN = 2;
end;
EDF.FileName = FILENAME;
PPos=min([max(find(FILENAME=='.')) length(FILENAME)+1]);
SPos=max([0 find(FILENAME==filesep)]);
EDF.FILE.Ext = FILENAME(PPos+1:length(FILENAME));
EDF.FILE.Name = FILENAME(SPos+1:PPos-1);
if SPos==0
EDF.FILE.Path = pwd;
else
EDF.FILE.Path = FILENAME(1:SPos-1);
end;
EDF.FileName = [EDF.FILE.Path filesep EDF.FILE.Name '.' EDF.FILE.Ext];
%%% Read Fixed Header %%%
[tmp,count]=fread(EDF.FILE.FID,184,'uchar'); %
if count<184
EDF.ErrNo = [64,EDF.ErrNo];
return;
end;
H1=setstr(tmp'); %
EDF.VERSION=H1(1:8); % 8 Byte Versionsnummer
if ~(strcmp(EDF.VERSION,'0 ') | strcmp(EDF.VERSION(1:3),'GDF'))
EDF.ErrNo = [1,EDF.ErrNo];
if ~strcmp(EDF.VERSION(1:3),' '); % if not a scoring file,
% return;
end;
end;
EDF.PID = deblank(H1(9:88)); % 80 Byte local patient identification
EDF.RID = deblank(H1(89:168)); % 80 Byte local recording identification
IsGDF=strcmp(EDF.VERSION(1:3),'GDF');
if IsGDF
%EDF.T0=[str2num(H1(168+[1:4])) str2num(H1(168+[5 6])) str2num(H1(168+[7 8])) str2num(H1(168+[9 10])) str2num(H1(168+[11 12])) str2num(H1(168+[13:16]))/100 ];
if 1, % if strcmp(EDF.VERSION(4:8),' 0.12');
% Note: in future versions the date format might change.
EDF.T0(1) = str2num( H1(168 + [ 1:4]));
EDF.T0(2) = str2num( H1(168 + [ 5 6]));
EDF.T0(3) = str2num( H1(168 + [ 7 8]));
EDF.T0(4) = str2num( H1(168 + [ 9 10]));
EDF.T0(5) = str2num( H1(168 + [11 12]));
EDF.T0(6) = str2num( H1(168 + [13:16]))/100;
end;
if str2num(EDF.VERSION(4:8))<0.12
tmp = setstr(fread(EDF.FILE.FID,8,'uchar')'); % 8 Byte Length of Header
EDF.HeadLen = str2num(tmp); % 8 Byte Length of Header
else
EDF.HeadLen = fread(EDF.FILE.FID,1,'int64'); % 8 Byte Length of Header
end;
EDF.reserved1 = fread(EDF.FILE.FID,8+8+8+20,'uchar'); % 44 Byte reserved
EDF.NRec = fread(EDF.FILE.FID,1,'int64'); % 8 Byte # of data records
if strcmp(EDF.VERSION(4:8),' 0.10')
EDF.Dur = fread(EDF.FILE.FID,1,'float64'); % 8 Byte # duration of data record in sec
else
tmp = fread(EDF.FILE.FID,2,'uint32'); % 8 Byte # duration of data record in sec
EDF.Dur = tmp(1)./tmp(2);
end;
EDF.NS = fread(EDF.FILE.FID,1,'uint32'); % 4 Byte # of signals
else
if exist('OCTAVE_VERSION')>=5
tmp=(find((toascii(H1)<32) | (toascii(H1)>126))); %%% snytax for OCTAVE
else
tmp=(find((H1<32) | (H1>126))); %%% syntax for Matlab
end;
if ~isempty(tmp) %%%%% not EDF because filled out with ASCII(0) - should be spaces
%H1(tmp)=32;
EDF.ErrNo=[1025,EDF.ErrNo];
end;
%EDF.T0=[str2num(H1(168+[7 8])) str2num(H1(168+[4 5])) str2num(H1(168+[1 2])) str2num(H1(168+[9 10])) str2num(H1(168+[12 13])) str2num(H1(168+[15 16])) ];
EDF.T0 = zeros(1,6);
ErrT0=0;
tmp = str2num( H1(168 + [ 7 8]));
if ~isempty(tmp), EDF.T0(1) = tmp; else ErrT0 = 1; end;
tmp = str2num( H1(168 + [ 4 5]));
if ~isempty(tmp), EDF.T0(2) = tmp; else ErrT0 = 1; end;
tmp = str2num( H1(168 + [ 1 2]));
if ~isempty(tmp), EDF.T0(3) = tmp; else ErrT0 = 1; end;
tmp = str2num( H1(168 + [ 9 10]));
if ~isempty(tmp), EDF.T0(4) = tmp; else ErrT0 = 1; end;
tmp = str2num( H1(168 + [12 13]));
if ~isempty(tmp), EDF.T0(5) = tmp; else ErrT0 = 1; end;
tmp = str2num( H1(168 + [15 16]));
if ~isempty(tmp), EDF.T0(6) = tmp; else ErrT0 = 1; end;
if any(EDF.T0~=fix(EDF.T0)); ErrT0=1; end;
if ErrT0,
ErrT0=0;
EDF.ErrNo = [1032,EDF.ErrNo];
tmp = H1(168 + [1:8]);
for k = [3 2 1],
%fprintf(1,'\n zz%szz \n',tmp);
[tmp1,tmp] = strtok(tmp,' :./-');
tmp1 = str2num([tmp1,' ']);
if isempty(tmp1)
ErrT0 = ErrT0 | 1;
else
EDF.T0(k) = tmp1;
end;
end;
tmp = H1(168 + [9:16]);
for k = [4 5 6],
[tmp1,tmp] = strtok(tmp,' :./-');
tmp1=str2num([tmp1,' ']);
if isempty(tmp1)
ErrT0 = ErrT0 | 1;
else
EDF.T0(k) = tmp1;
end;
end;
if ErrT0
EDF.ErrNo = [2,EDF.ErrNo];
end;
else
% Y2K compatibility until year 2084
if EDF.T0(1) < 85 % for biomedical data recorded in the 1950's and converted to EDF
EDF.T0(1) = 2000+EDF.T0(1);
elseif EDF.T0(1) < 100
EDF.T0(1) = 1900+EDF.T0(1);
%else % already corrected, do not change
end;
end;
H1(185:256)=setstr(fread(EDF.FILE.FID,256-184,'uchar')'); %
EDF.HeadLen = str2num(H1(185:192)); % 8 Bytes Length of Header
EDF.reserved1=H1(193:136); % 44 Bytes reserved
EDF.NRec = str2num(H1(237:244)); % 8 Bytes # of data records
EDF.Dur = str2num(H1(245:252)); % 8 Bytes # duration of data record in sec
EDF.NS = str2num(H1(253:256)); % 4 Bytes # of signals
EDF.AS.H1 = H1; % for debugging the EDF Header
end;
if isempty(EDF.NS) %%%%% not EDF because filled out with ASCII(0) - should be spaces
fprintf(EDF.FILE.stderr, 'Warning SDFOPEN: invalid NS-value in header of %s\n',EDF.FileName);
EDF.ErrNo=[1040,EDF.ErrNo];
EDF.NS=1;
end;
if isempty(EDF.HeadLen) %%%%% not EDF because filled out with ASCII(0) - should be spaces
EDF.ErrNo=[1056,EDF.ErrNo];
EDF.HeadLen=256*(1+EDF.NS);
end;
if any(~isempty(EDF.reserved1)) %%%%% not EDF because filled out with ASCII(0) - should be spaces
fprintf(2, 'Warning SDFOPEN: 44bytes-reserved-field of fixed header is not empty in %s\n',EDF.FILE.Name);
%EDF.ErrNo=[1057,EDF.ErrNo];
end;
if isempty(EDF.NRec) %%%%% not EDF because filled out with ASCII(0) - should be spaces
EDF.ErrNo=[1027,EDF.ErrNo];
EDF.NRec = -1;
end;
if isempty(EDF.Dur) %%%%% not EDF because filled out with ASCII(0) - should be spaces
EDF.ErrNo=[1088,EDF.ErrNo];
EDF.Dur=30;
else
if ~IsGDF,
if (EDF.Dur>1) & (EDF.Dur~=fix(EDF.Dur)), % Blockduration must be in seconds or subsecond range
EDF.ErrNo=[1088,EDF.ErrNo];
end;
end;
end;
if any(EDF.T0>[2084 12 31 24 59 59]) | any(EDF.T0<[1985 1 1 0 0 0])
EDF.ErrNo = [4, EDF.ErrNo];
end;
%%% Read variable Header %%%
if ~IsGDF
idx1=cumsum([0 H2idx]);
idx2=EDF.NS*idx1;
h2=zeros(EDF.NS,256);
[H2,count]=fread(EDF.FILE.FID,EDF.NS*256,'uchar');
if count < EDF.NS*256
EDF.ErrNo=[8,EDF.ErrNo];
return;
end;
%tmp=find((H2<32) | (H2>126)); % would confirm
tmp = find((H2<32) | ((H2>126) & (H2~=255) & (H2~=181)& (H2~=230)));
if ~isempty(tmp) %%%%% not EDF because filled out with ASCII(0) - should be spaces
H2(tmp) = 32;
EDF.ErrNo = [1026,EDF.ErrNo];
end;
for k=1:length(H2idx);
%disp([k size(H2) idx2(k) idx2(k+1) H2idx(k)]);
h2(:,idx1(k)+1:idx1(k+1))=reshape(H2(idx2(k)+1:idx2(k+1)),H2idx(k),EDF.NS)';
end;
%size(h2),
h2=setstr(h2);
%(h2(:,idx1(9)+1:idx1(10))),
%abs(h2(:,idx1(9)+1:idx1(10))),
EDF.Label = h2(:,idx1(1)+1:idx1(2));
EDF.Transducer = h2(:,idx1(2)+1:idx1(3));
EDF.PhysDim = h2(:,idx1(3)+1:idx1(4));
EDF.PhysMin = str2num(h2(:,idx1(4)+1:idx1(5)));
EDF.PhysMax = str2num(h2(:,idx1(5)+1:idx1(6)));
EDF.DigMin = str2num(h2(:,idx1(6)+1:idx1(7)));
EDF.DigMax = str2num(h2(:,idx1(7)+1:idx1(8)));
EDF.PreFilt = h2(:,idx1(8)+1:idx1(9));
EDF.SPR = str2num(h2(:,idx1(9)+1:idx1(10)));
%EDF.reserved = h2(:,idx1(10)+1:idx1(11));
EDF.GDFTYP = 3*ones(1,EDF.NS); % datatype
if isempty(EDF.SPR),
fprintf(EDF.FILE.stderr, 'Warning SDFOPEN: invalid SPR-value in header of %s\n',EDF.FileName);
EDF.SPR=ones(EDF.NS,1);
EDF.ErrNo=[1028,EDF.ErrNo];
end;
else
fseek(EDF.FILE.FID,256,'bof');
EDF.Label = setstr(fread(EDF.FILE.FID,[16,EDF.NS],'uchar')');
EDF.Transducer = setstr(fread(EDF.FILE.FID,[80,EDF.NS],'uchar')');
EDF.PhysDim = setstr(fread(EDF.FILE.FID,[ 8,EDF.NS],'uchar')');
% EDF.AS.GDF.TEXT = EDF.GDFTYP.TEXT;
EDF.PhysMin = fread(EDF.FILE.FID,[EDF.NS,1],'float64');
EDF.PhysMax = fread(EDF.FILE.FID,[EDF.NS,1],'float64');
EDF.DigMin = fread(EDF.FILE.FID,[EDF.NS,1],'int64');
EDF.DigMax = fread(EDF.FILE.FID,[EDF.NS,1],'int64');
EDF.PreFilt = setstr(fread(EDF.FILE.FID,[80,EDF.NS],'uchar')'); %
EDF.SPR = fread(EDF.FILE.FID,[ 1,EDF.NS],'uint32')'; % samples per data record
EDF.GDFTYP = fread(EDF.FILE.FID,[ 1,EDF.NS],'uint32'); % datatype
% fread(EDF.FILE.FID,[32,EDF.NS],'uchar')'; % datatype
end;
% EDF=gdfcheck(EDF,1);
if any(EDF.PhysMax==EDF.PhysMin), EDF.ErrNo=[1029,EDF.ErrNo]; end;
if any(EDF.DigMax ==EDF.DigMin ), EDF.ErrNo=[1030,EDF.ErrNo]; end;
EDF.Cal = (EDF.PhysMax-EDF.PhysMin)./(EDF.DigMax-EDF.DigMin);
EDF.Off = EDF.PhysMin - EDF.Cal .* EDF.DigMin;
EDF.Calib=[EDF.Off';(diag(EDF.Cal))];
EDF.SampleRate = EDF.SPR / EDF.Dur;
EDF.AS.spb = sum(EDF.SPR); % Samples per Block
EDF.AS.bi = [0;cumsum(EDF.SPR)];
EDF.AS.BPR = ceil(EDF.SPR.*GDFTYP_BYTE(EDF.GDFTYP+1)');
EDF.AS.SAMECHANTYP = all(EDF.AS.BPR == (EDF.SPR.*GDFTYP_BYTE(EDF.GDFTYP+1)')) & all(EDF.GDFTYP(:)==EDF.GDFTYP(1));
EDF.AS.GDFbi = [0;cumsum(ceil(EDF.SPR.*GDFTYP_BYTE(EDF.GDFTYP+1)'))];
EDF.AS.bpb = sum(ceil(EDF.SPR.*GDFTYP_BYTE(EDF.GDFTYP+1)')); % Bytes per Block
EDF.AS.startrec = 0;
EDF.AS.numrec = 0;
EDF.FILE.POS = 0;
status = fseek(EDF.FILE.FID, 0, 'eof');
EDF.AS.endpos = ftell(EDF.FILE.FID);
fseek(EDF.FILE.FID, EDF.HeadLen, 'bof');
%[status EDF.AS.endpos EDF.HeadLen EDF.AS.bpb EDF.NRec]
if EDF.NRec == -1 % unknown record size, determine correct NRec
EDF.NRec = floor((EDF.AS.endpos - EDF.HeadLen) / EDF.AS.bpb);
elseif EDF.NRec ~= ((EDF.AS.endpos - EDF.HeadLen) / EDF.AS.bpb);
EDF.ErrNo=[16,EDF.ErrNo];
% EDF.NRec = floor((EDF.AS.endpos - EDF.HeadLen) / EDF.AS.bpb);
end;
% if Channelselect, ReReferenzing and Resampling
% Overflowcheck, Adaptive FIR
% Layer 4
%if nargin<3 %%%%% Channel Selection
if nargin <3 %else
arg3=0;
end;
EDF.SIE.ChanSelect = 1:EDF.NS;
EDF.SIE.InChanSelect = 1:EDF.NS;
EDF.SIE.RR=1;
EDF.SIE.RS=0; %exist('arg5')==1; if EDF.SIE.RS, EDF.SIE.RS==(arg5>0); end;
EDF.SIE.TH=0; %(exist('arg6')==1);
EDF.SIE.RAW=0;
EDF.SIE.REGC=0;
EDF.SIE.TECG=0;
EDF.SIE.AFIR=0;
EDF.SIE.FILT=0;
EDF.SIE.TimeUnits_Seconds=1;
EDF.AS.MAXSPR=max(EDF.SPR(EDF.SIE.ChanSelect)); % Layer 3 defines EDF.AS.MAXSPR in GDFREAD
EDF.SIE.ReRefMx=eye(EDF.NS);
EDF.SIE.REG=eye(EDF.NS);
EDF.SIE.ReRefMx = EDF.SIE.ReRefMx(:,EDF.SIE.ChanSelect);
EDF.Calib=EDF.Calib*EDF.SIE.REG*EDF.SIE.ReRefMx;
%if nargin>2 %%%%% Channel Selection
EDF.SIE.REG=eye(EDF.NS);
if arg3==0
EDF.SIE.ChanSelect = 1:EDF.NS;
EDF.SIE.InChanSelect = 1:EDF.NS;
EDF.SIE.ReRefMx = eye(EDF.NS);
else
[nr,nc]=size(arg3);
if all([nr,nc]>1), % Re-referencing
EDF.SIE.ReRefMx = [[arg3 zeros(size(arg3,1),EDF.NS-size(arg3,2))]; zeros(EDF.NS-size(arg3,1),EDF.NS)];
EDF.SIE.InChanSelect = find(any(EDF.SIE.ReRefMx'));
EDF.SIE.ChanSelect = find(any(EDF.SIE.ReRefMx));
if nargin>3
% fprintf(EDF.FILE.stderr,'Error SDFOPEN: Rereferenzing does not work correctly with %s (more than 3 input arguments)\n',arg4);
end;
else
EDF.SIE.ChanSelect = arg3; %full(sparse(1,arg3(:),1,1,EDF.NS));
EDF.SIE.InChanSelect = arg3;
EDF.SIE.ReRefMx = eye(EDF.NS);
end;
end;
if (exist('sedfchk')==2),
EDF=sedfchk(EDF); % corrects incorrect Header information.
end;
%EDF.SIE.CS=1;
EDF.SIE.RR=1;
EDF.SIE.RS=exist('arg5')==1; if EDF.SIE.RS, EDF.SIE.RS==(arg5>0); end;
EDF.SIE.TH=0; %(exist('arg6')==1);
EDF.SIE.RAW=0;
EDF.SIE.REGC=0;
EDF.SIE.TECG=0;
EDF.SIE.AFIR=0;
EDF.SIE.FILT=0;
EDF.AS.MAXSPR=max(EDF.SPR(EDF.SIE.ChanSelect)); % Layer 3 defines EDF.AS.MAXSPR in GDFREAD
EDF.SIE.REG=eye(EDF.NS);
%elseif nargin>3 %%%%% RE-REFERENCING
if nargin>3
if ~isempty(findstr(upper(arg4),'SIESTA'))
EDF.SIE.ReRefMx = eye(EDF.NS);% speye(EDF.NS);
EDF.SIE.ReRefMx(7,1:6)=[1 1 1 -1 -1 -1]/2;
EDF.SIE.TH=1;
% calculate (In)ChanSelect based on ReRefMatrix
EDF.SIE.InChanSelect = find(any(EDF.SIE.ReRefMx'));
EDF.SIE.ChanSelect = find(any(EDF.SIE.ReRefMx));
end;
if ~isempty(findstr(upper(arg4),'EOG'))
tmp=findstr(upper(arg4),'EOG');
tmp=lower(strtok(arg4(tmp:length(arg4)),' +'));
EDF.SIE.ReRefMx = sparse(EDF.NS,EDF.NS);% speye(EDF.NS);
if any(tmp=='h'); EDF.SIE.ReRefMx(8:9,1)=[ 1 -1 ]'; end;
if any(tmp=='v'); EDF.SIE.ReRefMx(1:9,2)=[ 1 0 0 1 0 0 1 -1 -1]';end;
if any(tmp=='r'); EDF.SIE.ReRefMx(3:9,3)=[ 1 0 0 1 2 -2 -2]'/2; end;
%EDF.SIE.TH=1;
% calculate (In)ChanSelect based on ReRefMatrix
EDF.SIE.InChanSelect = find(any(EDF.SIE.ReRefMx'));
EDF.SIE.ChanSelect = find(any(EDF.SIE.ReRefMx));
end;
if ~isempty(findstr(upper(arg4),'UCAL'))
%EDF.SIE.ReRefMx = speye(EDF.NS); % OVERRIDES 'SIESTA' and 'REGRESS_ECG'
EDF.SIE.RR = 0;
end;
if ~isempty(findstr(upper(arg4),'RAW'))
EDF.SIE.RAW = 1;
end;
if ~isempty(findstr(upper(arg4),'OVERFLOW'))
EDF.SIE.TH = 1;
end;
if ~isempty(findstr(upper(arg4),'FailingElectrodeDetector'))
EDF.SIE.FED = 1;
EDF.SIE.TH = 2;
end;
if ~isempty(findstr(upper(arg4),'ECG')), % identify ECG channel for some ECG artifact processing method
if ~isempty(findstr(upper(arg4),'SIESTA'))
channel1=12;
%channel2=1:9;
M=zeros(EDF.NS,1);M(channel1)=1;
end
if isfield(EDF,'ChanTyp')
M=upper(char(EDF.ChanTyp(channel1)))=='C';
channel1=find(M);
M=(upper(char(EDF.ChanTyp))=='E' | upper(char(EDF.ChanTyp))=='O' );
%channel2=find(M);
else
channel1=12;
%channel2=1:9;
M=zeros(EDF.NS,1);M(channel1)=1;
end;
end;
if ~isempty(findstr(upper(arg4),'RECG'))
EDF.SIE.REGC = 1;
if all(EDF.SIE.InChanSelect~=channel1)
EDF.SIE.InChanSelect=[EDF.SIE.InChanSelect channel1];
end;
end;
if ~isempty(findstr(upper(arg4),'TECG'))
fprintf(EDF.FILE.stderr,'SDFOPEN: status of TECG Mode: alpha test passed\n');
%%%% TECG - ToDo
% - optimize window
if exist([lower(EDF.FILE.Name) 'ECG.mat']);
if exist('OCTAVE_VERSION')==5
load(file_in_loadpath([lower(EDF.FILE.Name) 'ECG.mat']));
else
load([lower(EDF.FILE.Name) 'ECG.mat']);
end;
if isstruct(QRS)
EDF.SIE.TECG = 1;
%%% EDF.AS.MAXSPR=size(QRS.Templates,1)/3;
EDF.AS.MAXSPR=max(EDF.AS.MAXSPR,EDF.SPR(channel1));
else
fprintf(EDF.FILE.stderr,'WARNING SDFOPEN: %s invalid for TECG\n',[ lower(EDF.FILE.Name) 'ECG.mat']);
end;
else
fprintf(EDF.FILE.stderr,'WARNING SDFOPEN: %s not found\t (needed for Mode=TECG)\n',[lower(EDF.FILE.Name) 'ECG.mat']);
end;
end;
if ~isempty(findstr(upper(arg4),'AFIR'))
% Implements Adaptive FIR filtering for ECG removal in EDF/GDF-tb.
% based on the Algorithm of Mikko Koivuluoma <k7320@cs.tut.fi>
% channel2 determines which channels should be corrected with AFIR
%EDF = sdf_afir(EDF,12,channel2);
channel2=EDF.SIE.ChanSelect;
fprintf(EDF.FILE.stderr,'Warning SDFOPEN: option AFIR still buggy\n');
if isempty(find(channel2))
EDF.SIE.AFIR=0;
else
EDF.SIE.AFIR=1;
EDF.AFIR.channel2=channel2;
EDF.AFIR.alfa=0.01;
EDF.AFIR.gamma=1e-32;
EDF.AFIR.delay = ceil(0.05*EDF.AS.MAXSPR/EDF.Dur);
EDF.AFIR.nord = EDF.AFIR.delay+EDF.AS.MAXSPR/EDF.Dur;
EDF.AFIR.nC = length(EDF.AFIR.channel2);
EDF.AFIR.w = zeros(EDF.AFIR.nC, max(EDF.AFIR.nord));
EDF.AFIR.x = zeros(1, EDF.AFIR.nord);
EDF.AFIR.d = zeros(EDF.AFIR.delay, EDF.AFIR.nC);
channel1=12;
if isfield(EDF,'ChanTyp')
if upper(char(EDF.ChanTyp(channel1)))=='C';
EDF.AFIR.channel1 = channel1;
else
EDF.AFIR.channel1 = find(EDF.ChanTyp=='C');
fprintf(EDF.FILE.stderr,'Warning %s: #%i is not an ECG channel, %i used instead\n' ,filename,channel1,EDF.AFIR.channel1);
end;
else
EDF.AFIR.channel1 = channel1;
end;
if all(EDF.SIE.InChanSelect~=channel1)
EDF.SIE.InChanSelect=[EDF.SIE.InChanSelect channel1];
end;
end;
end;
if isempty(findstr(upper(arg4),'NOTCH50'))
EDF.Filter.A=1;
EDF.Filter.B=1;
else
EDF.SIE.FILT=1;
EDF.Filter.A=1;
EDF.Filter.B=1;
%if all(EDF.SampleRate(EDF.SIE.ChanSelect)==100)
if EDF.AS.MAXSPR/EDF.Dur==100
EDF.Filter.B=[1 1]/2;
%elseif all(EDF.SampleRate(EDF.SIE.ChanSelect)==200)
elseif EDF.AS.MAXSPR/EDF.Dur==200
EDF.Filter.B=[1 1 1 1]/4;
%elseif all(EDF.SampleRate(EDF.SIE.ChanSelect)==256)
elseif EDF.AS.MAXSPR/EDF.Dur==400
EDF.Filter.B=ones(1,8)/8;
%elseif all(EDF.SampleRate(EDF.SIE.ChanSelect)==256)
elseif EDF.AS.MAXSPR/EDF.Dur==256
EDF.Filter.B=poly([exp([-1 1 -2 2]*2*pi*i*50/256)]); %max(EDF.SampleRate(EDF.SIE.ChanSelect)))]);
EDF.Filter.B=EDF.Filter.B/sum(EDF.Filter.B);
else
fprintf(EDF.FILE.stderr,'Warning SDFOPEN: 50Hz Notch does not fit\n');
end;
end;
if ~isempty(findstr(upper(arg4),'NOTCH60'))
fprintf(EDF.FILE.stderr,'Warning SDFOPEN: option NOTCH60 not implemented yet.\n');
end;
if ~isempty(findstr(upper(arg4),'HPF')), % high pass filtering
if EDF.SIE.FILT==0; EDF.Filter.B=1; end;
EDF.SIE.FILT=1;
EDF.Filter.A=1;
end;
if ~isempty(findstr(upper(arg4),'HPF0.0Hz')), % high pass filtering
EDF.Filter.B=conv([1 -1], EDF.Filter.B);
elseif ~isempty(findstr(upper(arg4),'TAU')), % high pass filtering / compensate time constant
tmp=findstr(upper(arg4),'TAU');
TAU=strtok(upper(arg4(tmp:length(arg4))),'S');
tau=str2num(TAU);
if isempty(tau)
fprintf(EDF.FILE.stderr,'Warning SDFOPEN: invalid tau-value.\n');
else
EDF.Filter.B=conv([1 (EDF.Dur/EDF.AS.MAXSPR/tau-1)], EDF.Filter.B);
end;
%%%% example 'HPF_1.0Hz_Hamming', % high pass filtering
elseif ~isempty(findstr(upper(arg4),'HPF')), % high pass filtering
tmp=findstr(upper(arg4),'HPF');
FilterArg0=arg4(tmp+4:length(arg4));
%[tmp,FilterArg0]=strtok(arg4,'_');
[FilterArg1,FilterArg2]=strtok(FilterArg0,'_');
[FilterArg2,FilterArg3]=strtok(FilterArg2,'_');
tmp=findstr(FilterArg1,'Hz');
F0=str2num(FilterArg1(1:tmp-1));
B=feval(FilterArg2,F0*EDF.AS.MAXSPR/EDF.Dur);
B=B/sum(B);
B(ceil(length(B)/2))=(B(ceil(length(B)/2)))-1;
EDF.Filter.B=conv(-B, EDF.Filter.B);
end;
if ~isempty(findstr(upper(arg4),'UNITS_BLOCK'))
EDF.SIE.TimeUnits_Seconds=0;
end;
end; % end nargin >3
if EDF.SIE.FILT==1;
EDF.Filter.Z=[];
for k=1:length(EDF.SIE.ChanSelect),
[tmp,EDF.Filter.Z(:,k)]=filter(EDF.Filter.B,EDF.Filter.A,zeros(length(EDF.Filter.B+1),1));
end;
EDF.FilterOVG.Z=EDF.Filter.Z;
end;
if EDF.SIE.REGC
FN=[lower(EDF.FILE.Name) 'cov.mat'];
if exist(FN)~=2
fprintf(EDF.FILE.stderr,'Warning %s: Covariance-file %s not found.\n',EDF.AS.Method,FN);
EDF.SIE.REGC=0;
else
if exist('OCTAVE_VERSION')==5
load(file_in_loadpath(FN));
else
load(FN);
end;
if exist('XC') == 1
%EDF.SIE.COV = tmp.XC;
%[N,MU,COV,Corr]=decovm(XC);
N=size(XC,2);
COV=(XC(2:N,2:N)/XC(1,1)-XC(2:N,1)*XC(1,2:N)/XC(1,1)^2);
%clear tmp;
%cov = diag(EDF.Cal)*COV*diag(EDF.Cal);
mcov = M'*diag(EDF.Cal)*COV*diag(EDF.Cal);
%mcov(~())=0;
EDF.SIE.REG = eye(EDF.NS) - M*((mcov*M)\(mcov));
EDF.SIE.REG(channel1,channel1) = 1; % do not remove the regressed channels
%mcov, EDF.SIE.REG,
else
fprintf(EDF.FILE.stderr,'Error %s: Regression Coefficients for ECG minimization not available.\n',EDF.AS.Method);
end;
end;
end;
if EDF.SIE.TECG == 1;
% define channels that should be corrected
if isfield(QRS,'Version')
OutChanSelect=[1:11 13:EDF.NS];
if EDF.SIE.REGC % correct templates
QRS.Templates=QRS.Templates*EDF.SIE.REG;
fprintf(EDF.FILE.stderr,'Warning SDFOPEN: Mode TECG+RECG not tested\n');
end;
if QRS.Version~=2
fprintf(EDF.FILE.stderr,'Warning SDFOPEN Mode TECG: undefined QRS-version\n');
end;
else
%OutChanSelect=find(EDF.ChanTyp=='E' | EDF.ChanTyp=='O');
OutChanSelect=[1:9 ];
if any(EDF.SIE.ChanSelect>10)
fprintf(EDF.FILE.stderr,'Warning SDFOPEN: Mode TECG: Only #1-#9 are corrected\n');
end;
if EDF.SIE.REGC, % correct the templates
QRS.Templates=QRS.Templates*EDF.SIE.REG([1:9 12],[1:9 12]);
fprintf(EDF.FILE.stderr,'Warning SDFOPEN: Mode TECG+RECG not tested\n');
end;
end;
fs = EDF.SPR(12)/EDF.Dur;
QRS.Templates=detrend(QRS.Templates,0); %remove mean
EDF.TECG.idx = [(QRS.Index-fs/2-1) (EDF.NRec+1)*EDF.SPR(12)]; %include terminating element
EDF.TECG.idxidx = 1; %pointer to next index
% initialize if any spike is detected before first window
pulse = zeros(length(QRS.Templates),1);
Index=[];
while EDF.TECG.idx(EDF.TECG.idxidx) < 1,
Index=[Index EDF.TECG.idx(EDF.TECG.idxidx)-EDF.AS.startrec*EDF.SPR(12)];
EDF.TECG.idxidx=EDF.TECG.idxidx+1;
end;
if ~isempty(Index)
pulse(Index+length(QRS.Templates)) = 1;
end;
for i=1:length(EDF.SIE.InChanSelect),
k=find(OutChanSelect==EDF.SIE.InChanSelect(i));
if isempty(k)
EDF.TECG.QRStemp(:,i) = zeros(fs,1);
else
EDF.TECG.QRStemp(:,i) = QRS.Templates(0.5*fs:1.5*fs-1,k).*hanning(fs);
end;
[tmp,EDF.TECG.Z(:,i)] = filter(EDF.TECG.QRStemp(:,i),1,pulse);
end;
end; % if EDF.SIE.TECG==1
%syms Fp1 Fp2 M1 M2 O2 O1 A1 A2 C3 C4
for k=EDF.SIE.ChanSelect,
%fprintf(1,'#%i: ',k);
tmp=find(EDF.SIE.ReRefMx(:,k))';
if EDF.SIE.ReRefMx(tmp(1),k)==1,
x=EDF.Label(tmp(1),:);
else
x=sprintf('%3.1f*%s',EDF.SIE.ReRefMx(tmp(1),k),deblank(EDF.Label(tmp(1),:)));
end;
for l=2:length(tmp), L=tmp(l);
if (EDF.SPR(tmp(l-1),:)~=EDF.SPR(tmp(l),:))
fprintf(EDF.FILE.stderr,'Warning %s: SampleRate Mismatch in "%s", channel #%i and #%i\n',upper(EDF.AS.Method),EDF.FILE.Name,tmp(l-1),tmp(l));
end;
if ~strcmp(EDF.PhysDim(tmp(l-1),:),EDF.PhysDim(tmp(l),:))
fprintf(EDF.FILE.stderr,'Warning %s: Dimension Mismatch in "%s", channel #%i and #%i\n',upper(EDF.AS.Method),EDF.FILE.Name,tmp(l-1),tmp(l));
end;
if ~strcmp(EDF.Transducer(tmp(l-1),:),EDF.Transducer(tmp(l),:))
fprintf(EDF.FILE.stderr,'Warning %s: Transducer Mismatch in "%s", channel #%i and #%i\n',upper(EDF.AS.Method),EDF.FILE.Name,tmp(l-1),tmp(l));
end;
if ~strcmp(EDF.PreFilt(tmp(l-1),:),EDF.PreFilt(tmp(l),:))
fprintf(EDF.FILE.stderr,'Warning %s: PreFiltering Mismatch in "%s", channel #%i and #%i\n',upper(EDF.AS.Method),EDF.FILE.Name,tmp(l-1),tmp(l));
end;
x=[x sprintf('+(%3.1f)*(%s)',EDF.SIE.ReRefMx(tmp(l),k),deblank(EDF.Label(tmp(l),:)))];
end;
EDF.Label(k,1:length(x))=x; %char(sym(x))
end;
%Label,
EDF.SIE.ReRefMx = EDF.SIE.ReRefMx(:,EDF.SIE.ChanSelect);
if exist('OCTAVE_VERSION')>=5,
EDF.Calib = (EDF.Calib*EDF.SIE.REG*EDF.SIE.ReRefMx); % important to be sparse, otherwise overflow-check does not work correctly.
fprintf(EDF.FILE.stderr,'Warning SDFOPEN: Overflow Check does not work without SPARSE\n');
else
EDF.Calib = sparse(EDF.Calib*EDF.SIE.REG*EDF.SIE.ReRefMx); % important to be sparse, otherwise overflow-check does not work correctly.
end;
if 1, % ??? not sure, whether it has any advantage
EDF.PhysDim = EDF.PhysDim(EDF.SIE.ChanSelect,:);
EDF.PreFilt = EDF.PreFilt(EDF.SIE.ChanSelect,:);
EDF.Transducer = EDF.Transducer(EDF.SIE.ChanSelect,:);
end;
if EDF.SIE.RS,
tmp = EDF.AS.MAXSPR/EDF.Dur;
if arg5==0
%arg5 = max(EDF.SPR(EDF.SIE.ChanSelect))/EDF.Dur;
elseif ~rem(tmp,arg5); % The target sampling rate must divide the source sampling rate
EDF.SIE.RS = 1;
tmp=tmp/arg5;
EDF.SIE.T = ones(tmp,1)/tmp;
elseif arg5==100; % Currently, only the target sampling rate of 100Hz are supported.
EDF.SIE.RS=1;
tmp=EDF.AS.MAXSPR/EDF.Dur;
if exist('OCTAVE_VERSION')
load resample_matrix4octave.mat T256100 T200100;
else
load('resample_matrix');
end;
if 1,
if tmp==400,
EDF.SIE.T=ones(4,1)/4;
elseif tmp==256,
EDF.SIE.T=T256100;
elseif tmp==200,
EDF.SIE.T=T200100;
elseif tmp==100,
EDF.SIE.T=1;
else
fprintf('Warning %s-READ: sampling rates should be equal\n',upper(EDF.AS.Method));
end;
else
tmp=EDF.SPR(EDF.SIE.ChanSelect)/EDF.Dur;
if all((tmp==256) | (tmp<100))
EDF.SIE.RS = 1;
%tmp=load(RSMN,'T256100');
EDF.SIE.T = T256100;
elseif all((tmp==400) | (tmp<100))
EDF.SIE.RS = 1;
EDF.SIE.T = ones(4,1)/4;
elseif all((tmp==200) | (tmp<100))
EDF.SIE.RS = 1;
%tmp=load(RSMN,'T200100');
EDF.SIE.T = T200100;
elseif all(tmp==100)
%EDF.SIE.T=load('resample_matrix','T100100');
EDF.SIE.RS=0;
else
EDF.SIE.RS=0;
fprintf('Warning %s-READ: sampling rates should be equal\n',upper(EDF.AS.Method));
end;
end;
else
fprintf(EDF.FILE.stderr,'Error %s-READ: invalid target sampling rate of %i Hz\n',upper(EDF.AS.Method),arg5);
EDF.SIE.RS=0;
EDF.ErrNo=[EDF.ErrNo,];
%EDF=sdfclose(EDF);
%return;
end;
end;
FN=[lower(EDF.FILE.Name), 'th.mat'];
if exist(FN)~=2,
if EDF.SIE.TH, % && ~exist('OCTAVE_VERSION'),
fprintf(EDF.FILE.stderr,'Warning %s: THRESHOLD-file %s not found.\n',EDF.AS.Method,FN);
EDF.SIE.TH=0;
end;
else
if exist('OCTAVE_VERSION')==5
tmp=load(file_in_loadpath(FN));
else
tmp=load(FN);
end;
if isfield(tmp,'TRESHOLD')
EDF.SIE.THRESHOLD = tmp.TRESHOLD;
%else
%fprintf(EDF.FILE.stderr,'Error %s: TRESHOLD''s not found.\n',EDF.AS.Method);
end;
end;
if EDF.SIE.TH>1, % Failing electrode detector
fprintf(2,'Warning SDFOPEN: FED not implemented yet\n');
for k=1:length(InChanSelect),K=InChanSelect(k);
%for k=1:EDF.NS,
% [y1,EDF.Block.z1{k}] = filter([1 -1], 1, zeros(EDF.SPR(K)/EDF.Dur,1));
% [y2,EDF.Block.z2{k}] = filter(ones(1,EDF.SPR(K)/EDF.Dur)/(EDF.SPR(K)/EDF.Dur),1,zeros(EDF.SPR(K)/EDF.Dur,1));
% [y3,EDF.Block.z3{k}] = filter(ones(1,EDF.SPR(K)/EDF.Dur)/(EDF.SPR(K)/EDF.Dur),1,zeros(EDF.SPR(K)/EDF.Dur,1));
end;
end;
% Initialization of Bufferblock for random access (without EDF-blocklimits) of data
if ~EDF.SIE.RAW & EDF.SIE.TimeUnits_Seconds
EDF.Block.number=[0 0 0 0]; %Actual Blocknumber, start and end time of loaded block, diff(EDF.Block.number(1:2))==0 denotes no block is loaded;
% EDF.Blcok.number(3:4) indicate start and end of the returned data, [units]=samples.
EDF.Block.data=[];
EDF.Block.dataOFCHK=[];
end;
%end; % end of SDFOPEN-READ
%%%%%%% ============= WRITE ===========%%%%%%%%%%%%
elseif (arg2=='w') | (arg2=='w+')
% fprintf(EDF.FILE.stderr,'error EDFOPEN: write mode not possible.\n');
H1=[]; H2=[];
% return;
EDF.SIE.RAW = 0;
if ~isstruct(arg1) % if arg1 is the filename
EDF.FileName=arg1;
if nargin<3
tmp=input('SDFOPEN: list of samplerates for each channel? ');
EDF.SampleRate = tmp(:);
else
EDF.SampleRate=arg3;
end;
EDF.NS=length(EDF.SampleRate);
if nargin<4
tmp=input('SDFOPEN: Duration of one block in seconds: ');
EDF.Dur = tmp;
EDF.SPR=EDF.Dur*EDF.SampleRate;
else
if ~isempty(findstr(upper(arg4),'RAW'))
EDF.SIE.RAW = 1;
else
EDF.Dur = arg4;
EDF.SPR=EDF.Dur*EDF.SampleRate;
end;
end;
end;
FILENAME=EDF.FileName;
if (arg2=='w')
[fid,MESSAGE]=fopen(FILENAME,'w','ieee-le');
elseif (arg2=='w+') % may be called only by SDFCLOSE
if EDF.FILE.OPEN==2
[fid,MESSAGE]=fopen(FILENAME,'r+','ieee-le');
else
fprintf(EDF.FILE.stderr,'Error SDFOPEN-W+: Cannot open %s for write access\n',FILENAME);
return;
end;
end;
if fid<0
%fprintf(EDF.FILE.stderr,'Error EDFOPEN: %s\n',MESSAGE);
H1=MESSAGE;H2=[];
EDF.ErrNo = EDF.ErrNo + 32;
fprintf(EDF.FILE.stderr,'Error SDFOPEN-W: Could not open %s \n',FILENAME);
return;
end;
EDF.FILE.FID = fid;
EDF.FILE.OPEN = 2;
%%%% generate optional parameters
PPos=min([max(find(FILENAME=='.')) length(FILENAME)+1]);
SPos=max([0 find(FILENAME==filesep)]);
EDF.FILE.Ext = FILENAME(PPos+1:length(FILENAME));
EDF.FILE.Name = FILENAME(SPos+1:PPos-1);
if SPos==0
EDF.FILE.Path = pwd;
else
EDF.FILE.Path = FILENAME(1:SPos-1);
end;
EDF.FileName = [EDF.FILE.Path filesep EDF.FILE.Name '.' EDF.FILE.Ext];
% Check all fields of Header1
if ~isfield(EDF,'VERSION')
fprintf('Warning SDFOPEN-W: EDF.VERSION not defined; default=EDF assumed\n');
EDF.VERSION='0 '; % default EDF-format
%EDF.ErrNo = EDF.ErrNo + 128;
%fclose(EDF.FILE.FID); return;
end;
IsGDF=strcmp(upper(EDF.VERSION(1:3)),'GDF');
if ~IsGDF
EDF.VERSION = '0 ';
fprintf(EDF.FILE.stderr,'\nData are stored with integer16.\nMeasures for minimizing round-off errors have been taken.\nDespite, overflow and round off errors may occur.\n');
if sum(EDF.SPR)>61440/2;
fprintf(EDF.FILE.stderr,'\nWarning SDFOPEN: One block exceeds 61440 bytes.\n')
end;
else
EDF.VERSION = 'GDF 0.12';
end;
if ~isfield(EDF,'PID')
fprintf(EDF.FILE.stderr,'Warning SDFOPEN-W: EDF.PID not defined\n');
EDF.PID=setstr(32+zeros(1,80));
end;
if ~isfield(EDF,'RID')
fprintf(EDF.FILE.stderr,'Warning SDFOPEN-W: EDF.RID not defined\n');
EDF.RID=setstr(32+zeros(1,80));
end;
if ~isfield(EDF,'T0')
EDF.T0=zeros(1,6);
fprintf(EDF.FILE.stderr,'Warning SDFOPEN-W: EDF.T0 not defined\n');
end;
if ~isfield(EDF,'reserved1')
EDF.reserved1=char(ones(1,44)*32);
else
tmp=min(8,size(EDF.reserved1,2));
EDF.reserved1=[EDF.reserved1(1,1:tmp) 32+zeros(1,44-tmp)];
end;
if ~isfield(EDF,'NRec')
EDF.NRec=-1;
end;
if ~isfield(EDF,'Dur')
fprintf('Warning SDFOPEN-W: EDF.Dur not defined\n');
EDF.Dur=NaN;
EDF.ErrNo = EDF.ErrNo + 128;
fclose(EDF.FILE.FID); return;
end;
if ~isfield(EDF,'NS')
EDF.ERROR = sprintf('Error SDFOPEN-W: EDF.NS not defined\n');
EDF.ErrNo = EDF.ErrNo + 128;
fclose(EDF.FILE.FID); return;
end;
% Check all fields of Header2
if ~isfield(EDF,'Label')
EDF.Label=setstr(32+zeros(EDF.NS,16));
fprintf(EDF.FILE.stderr,'Warning SDFOPEN-W: EDF.Label not defined\n');
else
tmp=min(16,size(EDF.Label,2));
EDF.Label=[EDF.Label(1:EDF.NS,1:tmp) 32+zeros(EDF.NS,16-tmp)];
end;
if ~isfield(EDF,'Transducer')
EDF.Transducer=setstr(32+zeros(EDF.NS,80));
else
tmp=min(80,size(EDF.Transducer,2));
EDF.Transducer=[EDF.Transducer(1:EDF.NS,1:tmp) 32+zeros(EDF.NS,80-tmp)];
end;
if ~isfield(EDF,'PreFilt')
EDF.PreFilt=setstr(32+zeros(EDF.NS,80));
else
tmp=min(80,size(EDF.PreFilt,2));
EDF.PreFilt=[EDF.PreFilt(1:EDF.NS,1:tmp) 32+zeros(EDF.NS,80-tmp)];
end;
if ~isfield(EDF,'PhysDim')
EDF.PhysDim=setstr(32+zeros(EDF.NS,8));
fprintf(EDF.FILE.stderr,'Warning SDFOPEN-W: EDF.PhysDim not defined\n');
else
tmp=min(8,size(EDF.PhysDim,2));
EDF.PhysDim=[EDF.PhysDim(1:EDF.NS,1:tmp) 32+zeros(EDF.NS,8-tmp)];
end;
if ~isfield(EDF,'PhysMin')
fprintf(EDF.FILE.stderr,'Warning SDFOPEN-W: EDF.PhysMin not defined\n');
EDF.PhysMin=repmat(nan,EDF.NS,1);
%EDF.ERROR = sprintf('Error SDFOPEN-W: EDF.PhysMax not defined\n');
%EDF.ErrNo = EDF.ErrNo + 128;
%fclose(EDF.FILE.FID); return;
else
EDF.PhysMin=EDF.PhysMin(1:EDF.NS);
end;
if ~isfield(EDF,'PhysMax')
fprintf('Warning SDFOPEN-W: EDF.PhysMax not defined\n');
EDF.PhysMax=repmat(nan,EDF.NS,1);
%EDF.ERROR = sprintf('Error SDFOPEN-W: EDF.PhysMax not defined\n');
%EDF.ErrNo = EDF.ErrNo + 128;
%fclose(EDF.FILE.FID); return;
else
EDF.PhysMax=EDF.PhysMax(1:EDF.NS);
end;
if ~isfield(EDF,'DigMin')
fprintf(EDF.FILE.stderr,'Warning SDFOPEN-W: EDF.DigMin not defined\n');
EDF.DigMin=repmat(nan,EDF.NS,1);
%EDF.ERROR = sprintf('Error SDFOPEN-W: EDF.DigMax not defined\n');
%EDF.ErrNo = EDF.ErrNo + 128;
%fclose(EDF.FILE.FID); return;
else
EDF.DigMin=EDF.DigMin(1:EDF.NS);
end;
if ~isfield(EDF,'DigMax')
fprintf('Warning SDFOPEN-W: EDF.DigMax not defined\n');
EDF.DigMax=repmat(nan,EDF.NS,1);
%EDF.ERROR = sprintf('Error SDFOPEN-W: EDF.DigMax not defined\n');
%EDF.ErrNo = EDF.ErrNo + 128;
%fclose(EDF.FILE.FID); return;
else
EDF.DigMax=EDF.DigMax(1:EDF.NS);
end;
if ~isfield(EDF,'SPR')
fprintf('Warning SDFOPEN-W: EDF.SPR not defined\n');
EDF.SPR=repmat(nan,EDF.NS,1);
EDF.ERROR = sprintf('Error SDFOPEN-W: EDF.SPR not defined\n');
EDF.ErrNo = EDF.ErrNo + 128;
fclose(EDF.FILE.FID); return;
else
EDF.SPR=reshape(EDF.SPR(1:EDF.NS),EDF.NS,1);
end;
if IsGDF
if ~isfield(EDF,'GDFTPY')
EDF.ERROR = sprintf('Error SDFOPEN-W: EDF.GDFTYP not defined\n');
EDF.ErrNo = EDF.ErrNo + 128;
fclose(EDF.FILE.FID); return;
else
EDF.GDFTYP=EDF.GDFTYP(1:EDF.NS);
end;
else
EDF.GDFTYP=3+zeros(1,EDF.NS);
end;
%%%%%% generate Header 1, first 256 bytes
EDF.HeadLen=(EDF.NS+1)*256;
H1=setstr(32*ones(1,256));
H1(1:8)=EDF.VERSION; %sprintf('%08i',EDF.VERSION); % 8 Byte Versionsnummer
H1( 8+(1:length(EDF.PID)))=EDF.PID;
H1(88+(1:length(EDF.RID)))=EDF.RID;
%H1(185:192)=sprintf('%-8i',EDF.HeadLen);
if IsGDF
H1(168+(1:16))=sprintf('%04i%02i%02i%02i%02i%02i%02i',floor(EDF.T0),rem(EDF.T0(6),1));
fwrite(fid,H1(1:184),'uchar');
fwrite(fid,EDF.HeadLen,'int64');
fwrite(fid,ones(8,1)*32,'byte'); % EP_ID=ones(8,1)*32;
fwrite(fid,ones(8,1)*32,'byte'); % Lab_ID=ones(8,1)*32;
fwrite(fid,ones(8,1)*32,'byte'); % T_ID=ones(8,1)*32;
fwrite(fid,ones(20,1)*32,'byte'); %
fwrite(fid,EDF.NRec,'int64');
%fwrite(fid,EDF.Dur,'float64');
[n,d]=rat(EDF.Dur); fwrite(fid,[n d], 'uint32');
fwrite(fid,EDF.NS,'uint32');
else
H1(168+(1:16))=sprintf('%02i.%02i.%02i%02i:%02i:%02i',rem(EDF.T0([3 2 1 4 5 6]),100));
H1(185:192)=sprintf('%-8i',EDF.HeadLen);
H1(193:236)=EDF.reserved1;
H1(237:244)=sprintf('%-8i',EDF.NRec);
H1(245:252)=sprintf('%-8i',EDF.Dur);
H1(253:256)=sprintf('%-4i',EDF.NS);
H1(find(H1==0))=32;
fwrite(fid,H1,'uchar');
end;
%%%%%% generate Header 2, NS*256 bytes
if ~IsGDF;
sPhysMin=32+zeros(EDF.NS,8);
sPhysMax=32+zeros(EDF.NS,8);
for k=1:EDF.NS,
tmp=sprintf('%-8g',EDF.PhysMin(k));
lt=length(tmp);
if lt<9
sPhysMin(k,1:lt)=tmp;
else
if any(upper(tmp)=='E') | find(tmp=='.')>8,
fprintf(EDF.FILE.stderr,'Error SDFOPEN-W: PhysMin(%i) does not fit into header\n', k);
else
sPhysMin(k,:)=tmp(1:8);
end;
end;
tmp=sprintf('%-8g',EDF.PhysMax(k));
lt=length(tmp);
if lt<9
sPhysMax(k,1:lt)=tmp;
else
if any(upper(tmp)=='E') | find(tmp=='.')>8,
fprintf(EDF.FILE.stderr,'Error SDFOPEN-W: PhysMin(%i) does not fit into header\n', k);
else
sPhysMax(k,:)=tmp(1:8);
end;
end;
end;
sPhysMin=reshape(sprintf('%-8.1f',EDF.PhysMin)',8,EDF.NS)';
sPhysMax=reshape(sprintf('%-8.1f',EDF.PhysMax)',8,EDF.NS)';
idx1=cumsum([0 H2idx]);
idx2=EDF.NS*idx1;
h2=setstr(32*ones(EDF.NS,256));
size(h2);
h2(:,idx1(1)+1:idx1(2))=EDF.Label;
h2(:,idx1(2)+1:idx1(3))=EDF.Transducer;
h2(:,idx1(3)+1:idx1(4))=EDF.PhysDim;
%h2(:,idx1(4)+1:idx1(5))=sPhysMin;
%h2(:,idx1(5)+1:idx1(6))=sPhysMax;
h2(:,idx1(4)+1:idx1(5))=sPhysMin;
h2(:,idx1(5)+1:idx1(6))=sPhysMax;
h2(:,idx1(6)+1:idx1(7))=reshape(sprintf('%-8i',EDF.DigMin)',8,EDF.NS)';
h2(:,idx1(7)+1:idx1(8))=reshape(sprintf('%-8i',EDF.DigMax)',8,EDF.NS)';
h2(:,idx1(8)+1:idx1(9))=EDF.PreFilt;
h2(:,idx1(9)+1:idx1(10))=reshape(sprintf('%-8i',EDF.SPR)',8,EDF.NS)';
h2(h2==0)=32;
for k=1:length(H2idx);
fwrite(fid,h2(:,idx1(k)+1:idx1(k+1))','uchar');
end;
else
fwrite(fid, EDF.Label','16*uchar');
fwrite(fid, EDF.Transducer','80*uchar');
fwrite(fid, EDF.PhysDim','8*uchar');
fwrite(fid, EDF.PhysMin,'float64');
fwrite(fid, EDF.PhysMax,'float64');
fwrite(fid, EDF.DigMin,'int64');
fwrite(fid, EDF.DigMax,'int64');
fwrite(fid, EDF.PreFilt','80*uchar');
fwrite(fid, EDF.SPR,'uint32');
fwrite(fid, EDF.GDFTYP,'uint32');
fprintf(fid,'%c',32*ones(32,EDF.NS));
end;
tmp = ftell(EDF.FILE.FID);
if tmp ~= (256 * (EDF.NS+1))
fprintf(1,'Warning %s-WRITE: incorrect header length %i bytes\n',upper(EDF.AS.Method),tmp);
%else fprintf(1,'sdfopen in write mode: header info stored correctly\n');
end;
EDF.AS.spb = sum(EDF.SPR); % Samples per Block
11,
EDF.AS.bi = [0;cumsum(EDF.SPR)];
EDF.AS.BPR = ceil(EDF.SPR.*GDFTYP_BYTE(EDF.GDFTYP+1)');
EDF.AS.SAMECHANTYP = all(EDF.AS.BPR == (EDF.SPR.*GDFTYP_BYTE(EDF.GDFTYP+1)')) & all(EDF.GDFTYP(:)~=EDF.GDFTYP(1));
%EDF.AS.GDFbi= [0;cumsum(EDF.AS.BPR)];
EDF.AS.GDFbi = [0;cumsum(ceil(EDF.SPR.*GDFTYP_BYTE(EDF.GDFTYP+1)'))];
EDF.AS.bpb = sum(ceil(EDF.SPR.*GDFTYP_BYTE(EDF.GDFTYP+1)')); % Bytes per Block
EDF.AS.startrec = 0;
EDF.AS.numrec = 0;
EDF.FILE.POS = 0;
else % if arg2 is not 'r' or 'w'
fprintf(EDF.FILE.stderr,'Warning %s: Incorrect 2nd argument. Argument2 must be ''r'' or ''w''\n',upper(EDF.AS.Method));
end;
if EDF.ErrNo>0
fprintf(EDF.FILE.stderr,'ERROR %i SDFOPEN\n',EDF.ErrNo);
end;