wolffd@0
|
1 function [DAT,H1]=openbdf(FILENAME)
|
wolffd@0
|
2 % EDF=openedf(FILENAME)
|
wolffd@0
|
3 % Opens an EDF File (European Data Format for Biosignals) in MATLAB (R)
|
wolffd@0
|
4 % <A HREF="http://www.medfac.leidenuniv.nl/neurology/knf/kemp/edf.htm">About EDF</A>
|
wolffd@0
|
5
|
wolffd@0
|
6 % Copyright (C) 1997-1998 by Alois Schloegl
|
wolffd@0
|
7 % a.schloegl@ieee.org
|
wolffd@0
|
8 % Ver 2.20 18.Aug.1998
|
wolffd@0
|
9 % Ver 2.21 10.Oct.1998
|
wolffd@0
|
10 % Ver 2.30 5.Nov.1998
|
wolffd@0
|
11 %
|
wolffd@0
|
12 % For use under Octave define the following function
|
wolffd@0
|
13 % function s=upper(s); s=toupper(s); end;
|
wolffd@0
|
14
|
wolffd@0
|
15 % V2.12 Warning for missing Header information
|
wolffd@0
|
16 % V2.20 EDF.AS.* changed
|
wolffd@0
|
17 % V2.30 EDF.T0 made Y2K compatible until Year 2090
|
wolffd@0
|
18
|
wolffd@0
|
19 % This program is free software; you can redistribute it and/or
|
wolffd@0
|
20 % modify it under the terms of the GNU General Public License
|
wolffd@0
|
21 % as published by the Free Software Foundation; either version 2
|
wolffd@0
|
22 % of the License, or (at your option) any later version.
|
wolffd@0
|
23 %
|
wolffd@0
|
24 % This program is distributed in the hope that it will be useful,
|
wolffd@0
|
25 % but WITHOUT ANY WARRANTY; without even the implied warranty of
|
wolffd@0
|
26 % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
wolffd@0
|
27 % GNU General Public License for more details.
|
wolffd@0
|
28 %
|
wolffd@0
|
29 % You should have received a copy of the GNU General Public License
|
wolffd@0
|
30 % along with this program; if not, write to the Free Software
|
wolffd@0
|
31 % Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
wolffd@0
|
32 % Name changed Sept 6,2002 T.S. Lorig
|
wolffd@0
|
33
|
wolffd@0
|
34 SLASH='/'; % defines Seperator for Subdirectories
|
wolffd@0
|
35 BSLASH=setstr(92);
|
wolffd@0
|
36
|
wolffd@0
|
37 cname=computer;
|
wolffd@0
|
38 if cname(1:2)=='PC' SLASH=BSLASH; end;
|
wolffd@0
|
39
|
wolffd@0
|
40 fid=fopen(FILENAME,'r','ieee-le');
|
wolffd@0
|
41 if fid<0
|
wolffd@0
|
42 % fprintf(2,['Error LOADEDF: File ' FILENAME ' not found\n']);
|
wolffd@0
|
43 % Warning desactivated in MIRtoolbox
|
wolffd@0
|
44 return;
|
wolffd@0
|
45 end;
|
wolffd@0
|
46
|
wolffd@0
|
47 EDF.FILE.FID=fid;
|
wolffd@0
|
48 EDF.FILE.OPEN = 1;
|
wolffd@0
|
49 EDF.FileName = FILENAME;
|
wolffd@0
|
50
|
wolffd@0
|
51 PPos=min([max(find(FILENAME=='.')) length(FILENAME)+1]);
|
wolffd@0
|
52 SPos=max([0 find((FILENAME=='/') | (FILENAME==BSLASH))]);
|
wolffd@0
|
53 EDF.FILE.Ext = FILENAME(PPos+1:length(FILENAME));
|
wolffd@0
|
54 EDF.FILE.Name = FILENAME(SPos+1:PPos-1);
|
wolffd@0
|
55 if SPos==0
|
wolffd@0
|
56 EDF.FILE.Path = pwd;
|
wolffd@0
|
57 else
|
wolffd@0
|
58 EDF.FILE.Path = FILENAME(1:SPos-1);
|
wolffd@0
|
59 end;
|
wolffd@0
|
60 EDF.FileName = [EDF.FILE.Path SLASH EDF.FILE.Name '.' EDF.FILE.Ext];
|
wolffd@0
|
61
|
wolffd@0
|
62 H1=setstr(fread(EDF.FILE.FID,256,'char')'); %
|
wolffd@0
|
63 EDF.VERSION=H1(1:8); % 8 Byte Versionsnummer
|
wolffd@0
|
64 %if 0 fprintf(2,'LOADEDF: WARNING Version EDF Format %i',ver); end;
|
wolffd@0
|
65 EDF.PID = deblank(H1(9:88)); % 80 Byte local patient identification
|
wolffd@0
|
66 EDF.RID = deblank(H1(89:168)); % 80 Byte local recording identification
|
wolffd@0
|
67 %EDF.H.StartDate = H1(169:176); % 8 Byte
|
wolffd@0
|
68 %EDF.H.StartTime = H1(177:184); % 8 Byte
|
wolffd@0
|
69 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])) ];
|
wolffd@0
|
70
|
wolffd@0
|
71 % Y2K compatibility until year 2090
|
wolffd@0
|
72 if EDF.VERSION(1)=='0'
|
wolffd@0
|
73 if EDF.T0(1) < 91
|
wolffd@0
|
74 EDF.T0(1)=2000+EDF.T0(1);
|
wolffd@0
|
75 else
|
wolffd@0
|
76 EDF.T0(1)=1900+EDF.T0(1);
|
wolffd@0
|
77 end;
|
wolffd@0
|
78 else ;
|
wolffd@0
|
79 % in a future version, this is hopefully not needed
|
wolffd@0
|
80 end;
|
wolffd@0
|
81
|
wolffd@0
|
82 EDF.HeadLen = str2num(H1(185:192)); % 8 Byte Length of Header
|
wolffd@0
|
83 % reserved = H1(193:236); % 44 Byte
|
wolffd@0
|
84 EDF.NRec = str2num(H1(237:244)); % 8 Byte # of data records
|
wolffd@0
|
85 EDF.Dur = str2num(H1(245:252)); % 8 Byte # duration of data record in sec
|
wolffd@0
|
86 EDF.NS = str2num(H1(253:256)); % 8 Byte # of signals
|
wolffd@0
|
87
|
wolffd@0
|
88 EDF.Label = setstr(fread(EDF.FILE.FID,[16,EDF.NS],'char')');
|
wolffd@0
|
89 EDF.Transducer = setstr(fread(EDF.FILE.FID,[80,EDF.NS],'char')');
|
wolffd@0
|
90 EDF.PhysDim = setstr(fread(EDF.FILE.FID,[8,EDF.NS],'char')');
|
wolffd@0
|
91
|
wolffd@0
|
92 EDF.PhysMin= str2num(setstr(fread(EDF.FILE.FID,[8,EDF.NS],'char')'));
|
wolffd@0
|
93 EDF.PhysMax= str2num(setstr(fread(EDF.FILE.FID,[8,EDF.NS],'char')'));
|
wolffd@0
|
94 EDF.DigMin = str2num(setstr(fread(EDF.FILE.FID,[8,EDF.NS],'char')')); %
|
wolffd@0
|
95 EDF.DigMax = str2num(setstr(fread(EDF.FILE.FID,[8,EDF.NS],'char')')); %
|
wolffd@0
|
96
|
wolffd@0
|
97 % check validity of DigMin and DigMax
|
wolffd@0
|
98 if (length(EDF.DigMin) ~= EDF.NS)
|
wolffd@0
|
99 fprintf(2,'Warning OPENEDF: Failing Digital Minimum\n');
|
wolffd@0
|
100 EDF.DigMin = -(2^15)*ones(EDF.NS,1);
|
wolffd@0
|
101 end
|
wolffd@0
|
102 if (length(EDF.DigMax) ~= EDF.NS)
|
wolffd@0
|
103 fprintf(2,'Warning OPENEDF: Failing Digital Maximum\n');
|
wolffd@0
|
104 EDF.DigMax = (2^15-1)*ones(EDF.NS,1);
|
wolffd@0
|
105 end
|
wolffd@0
|
106 if (any(EDF.DigMin >= EDF.DigMax))
|
wolffd@0
|
107 fprintf(2,'Warning OPENEDF: Digital Minimum larger than Maximum\n');
|
wolffd@0
|
108 end
|
wolffd@0
|
109 % check validity of PhysMin and PhysMax
|
wolffd@0
|
110 if (length(EDF.PhysMin) ~= EDF.NS)
|
wolffd@0
|
111 fprintf(2,'Warning OPENEDF: Failing Physical Minimum\n');
|
wolffd@0
|
112 EDF.PhysMin = EDF.DigMin;
|
wolffd@0
|
113 end
|
wolffd@0
|
114 if (length(EDF.PhysMax) ~= EDF.NS)
|
wolffd@0
|
115 fprintf(2,'Warning OPENEDF: Failing Physical Maximum\n');
|
wolffd@0
|
116 EDF.PhysMax = EDF.DigMax;
|
wolffd@0
|
117 end
|
wolffd@0
|
118 if (any(EDF.PhysMin >= EDF.PhysMax))
|
wolffd@0
|
119 fprintf(2,'Warning OPENEDF: Physical Minimum larger than Maximum\n');
|
wolffd@0
|
120 EDF.PhysMin = EDF.DigMin;
|
wolffd@0
|
121 EDF.PhysMax = EDF.DigMax;
|
wolffd@0
|
122 end
|
wolffd@0
|
123 EDF.PreFilt= setstr(fread(EDF.FILE.FID,[80,EDF.NS],'char')'); %
|
wolffd@0
|
124 tmp = fread(EDF.FILE.FID,[8,EDF.NS],'char')'; % samples per data record
|
wolffd@0
|
125 EDF.SPR = str2num(setstr(tmp)); % samples per data record
|
wolffd@0
|
126
|
wolffd@0
|
127 fseek(EDF.FILE.FID,32*EDF.NS,0);
|
wolffd@0
|
128
|
wolffd@0
|
129 EDF.Cal = (EDF.PhysMax-EDF.PhysMin)./ ...
|
wolffd@0
|
130 (EDF.DigMax-EDF.DigMin);
|
wolffd@0
|
131 EDF.Off = EDF.PhysMin - EDF.Cal .* EDF.DigMin;
|
wolffd@0
|
132 tmp = find(EDF.Cal < 0);
|
wolffd@0
|
133 EDF.Cal(tmp) = ones(size(tmp));
|
wolffd@0
|
134 EDF.Off(tmp) = zeros(size(tmp));
|
wolffd@0
|
135
|
wolffd@0
|
136 EDF.Calib=[EDF.Off';(diag(EDF.Cal))];
|
wolffd@0
|
137 %EDF.Calib=sparse(diag([1; EDF.Cal]));
|
wolffd@0
|
138 %EDF.Calib(1,2:EDF.NS+1)=EDF.Off';
|
wolffd@0
|
139
|
wolffd@0
|
140 EDF.SampleRate = EDF.SPR / EDF.Dur;
|
wolffd@0
|
141
|
wolffd@0
|
142 EDF.FILE.POS = ftell(EDF.FILE.FID);
|
wolffd@0
|
143 if EDF.NRec == -1 % unknown record size, determine correct NRec
|
wolffd@0
|
144 fseek(EDF.FILE.FID, 0, 'eof');
|
wolffd@0
|
145 endpos = ftell(EDF.FILE.FID);
|
wolffd@0
|
146 EDF.NRec = floor((endpos - EDF.FILE.POS) / (sum(EDF.SPR) * 2));
|
wolffd@0
|
147 fseek(EDF.FILE.FID, EDF.FILE.POS, 'bof');
|
wolffd@0
|
148 H1(237:244)=sprintf('%-8i',EDF.NRec); % write number of records
|
wolffd@0
|
149 end;
|
wolffd@0
|
150
|
wolffd@0
|
151 EDF.Chan_Select=(EDF.SPR==max(EDF.SPR));
|
wolffd@0
|
152 for k=1:EDF.NS
|
wolffd@0
|
153 if EDF.Chan_Select(k)
|
wolffd@0
|
154 EDF.ChanTyp(k)='N';
|
wolffd@0
|
155 else
|
wolffd@0
|
156 EDF.ChanTyp(k)=' ';
|
wolffd@0
|
157 end;
|
wolffd@0
|
158 if findstr(upper(EDF.Label(k,:)),'ECG')
|
wolffd@0
|
159 EDF.ChanTyp(k)='C';
|
wolffd@0
|
160 elseif findstr(upper(EDF.Label(k,:)),'EKG')
|
wolffd@0
|
161 EDF.ChanTyp(k)='C';
|
wolffd@0
|
162 elseif findstr(upper(EDF.Label(k,:)),'EEG')
|
wolffd@0
|
163 EDF.ChanTyp(k)='E';
|
wolffd@0
|
164 elseif findstr(upper(EDF.Label(k,:)),'EOG')
|
wolffd@0
|
165 EDF.ChanTyp(k)='O';
|
wolffd@0
|
166 elseif findstr(upper(EDF.Label(k,:)),'EMG')
|
wolffd@0
|
167 EDF.ChanTyp(k)='M';
|
wolffd@0
|
168 end;
|
wolffd@0
|
169 end;
|
wolffd@0
|
170
|
wolffd@0
|
171 EDF.AS.spb = sum(EDF.SPR); % Samples per Block
|
wolffd@0
|
172 bi=[0;cumsum(EDF.SPR)];
|
wolffd@0
|
173
|
wolffd@0
|
174 idx=[];idx2=[];
|
wolffd@0
|
175 for k=1:EDF.NS,
|
wolffd@0
|
176 idx2=[idx2, (k-1)*max(EDF.SPR)+(1:EDF.SPR(k))];
|
wolffd@0
|
177 end;
|
wolffd@0
|
178 maxspr=max(EDF.SPR);
|
wolffd@0
|
179 idx3=zeros(EDF.NS*maxspr,1);
|
wolffd@0
|
180 for k=1:EDF.NS, idx3(maxspr*(k-1)+(1:maxspr))=bi(k)+ceil((1:maxspr)'/maxspr*EDF.SPR(k));end;
|
wolffd@0
|
181
|
wolffd@0
|
182 %EDF.AS.bi=bi;
|
wolffd@0
|
183 EDF.AS.IDX2=idx2;
|
wolffd@0
|
184 %EDF.AS.IDX3=idx3;
|
wolffd@0
|
185
|
wolffd@0
|
186
|
wolffd@0
|
187 DAT.Head=EDF;
|
wolffd@0
|
188 DAT.MX.ReRef=1;
|
wolffd@0
|
189
|
wolffd@0
|
190 %DAT.MX=feval('loadxcm',EDF);
|
wolffd@0
|
191
|
wolffd@0
|
192 return;
|