/
wavedet.m
361 lines (312 loc) · 13.5 KB
/
wavedet.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
function position = wavedet(sigdir,headir,matdir,ecgnr,ft,anot,lead,t,qrs_flag,anot_fmt,aname,dirann)
%function position = mainwav(sigdir, headir, matdir, ecgnr, ft, anot, lead, t)
%Significant ECG points detector based on wavelet approach %Syntaxis:
%Input Parameters:
% sigdir: directory of the original signal
% headir: directory of the header file
% matdir: output directory
% ecgnr: string with the name of the record to analyze
% ft: format file: 0 for MIT header 1 for LUND header 2 for a mat file
% without header.
% anot: name of the annotation output file
% lead: scalar with the lead number to analyze (1,2, ...) (only one lead)
% t=[tbegin tend]: time vector with initial and sample to analyze
% qrs_flag: External (1) or internal (0) QRS detector
% anot_fmt: in case of external QRS detector, format of annotation file:
% aname: annotation file name with QRS marks
% dirann: directory with external annotation file
%Output Parameters:
% position: struct vector with the detected points
% The analysis loop has an overlapping structure. The number of samples
% processed is large and there are an overlap at the beginning and another
% at the end. The first one is necessary because: a) the first l4-1 samples
% are always incorrectly filtered b) To align the signals, as the filters
% have different lengths, we must discard some samples. c) The algorithms
% must have some possibility of turning back.
% The second overlap is mainly because of the alignment, as the filters have
% different delays.
% Juan Pablo Martínez Cortés
% 1/3/2006 option ft=2 was added from wavedetplus.
%%%%%alteraçoes para estudar a importancia do limiar de regularidade %%%%%%%
%%%%%% Rute 04/09/02
global regularity
regularity.time=[];
regularity.amp2=[];
regularity.amp3=[];
regularity.amp4=[];
regularity.alphalinha=[];
regularity.alpha1=[];
regularity.alpha2=[];
regularity.alpha3=[];
regularity.alpha4=[]; %%%%% para incluir a escala 5 %% Rute 22/05/02
regularity.thalpha1=[];
regularity.thalpha2=[];
regularity.thalpha3=[];
regularity.th2=[];
regularity.th3=[];
regularity.th4=[];
regularity.thlinha=[];
regularity.escolhidos=[];
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
warning off
ultimo_anot=1;
timeoffset=0;
leadsfile = [];
nsamp = 2^16; % Number of samples per excerpt for the WT
if ft==0 % MIT format files
if isunix, %%%%%%% Rute 13/03/02
sep = '/';
else sep = '\'; %%%%%%% Rute 13/03/02
end %%%%%%% Rute 13/03/02
heasig = readheader([headir sep ecgnr '.hea']);
%%%%%%%%%%%%%% ANA PARA BIOPAC %%%%%%%%%%%%%%%%%%%%%%
if isfield(heasig,'spf')
heasig.freq=heasig.freq*heasig.spf(lead);
heasig.nsamp=heasig.nsamp*heasig.spf(lead);
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
if (heasig.fmt(lead)==16) || (heasig.fmt(lead)==212) || (heasig.fmt(lead)==61)
formato = num2str(heasig.fmt(lead));
else
error('This format is not supported by the program')
end
for kk=1:heasig.nsig
leadsfile(kk)=strcmp(heasig.fname(lead,:),heasig.fname(kk,:));
end
leadsfile = cumsum(leadsfile);
leadinfile = leadsfile(lead); % this is necessary when there are leads in different files. e.g. ptbdb database JP 2006
nsiginfile = leadsfile(end);
if strcmp(formato,'16')||strcmp(formato,'61'),
% fid = fopen([sigdir ecgnr '.dat'],'rb');
% if fid == -1,
fid = fopen([sigdir heasig.fname(lead,:)],'rb');
% end
fseek(fid,0,-1); % Rewind the file
if strcmp(heasig.fname(lead,1),'_'), % Siemens card recordings with MIT-type header
timeoffset=512;
fseek (fid, timeoffset,-1); % offset
end
end
elseif ft==1 % LUND format files
hdsig=gethdsig(sigdir,ecgnr); % Reading header information
heasig = hdsig2heasig(hdsig);
freq = heasig.freq;
elseif ft==2 % data in a Matlab file
aux=[sigdir ecgnr];
load ([aux '.mat'])
heasig.nsamp=length(sinal);
heasig.freq=fa;
freq = heasig.freq;
if exist('gain','var')
heasig.gain=gain;
else
heasig.gain=200; % When heasig.gain = 0 => default 200
end
else
error('Format ft should be 0, 1 or 2')
end
heasig.gain(heasig.gain==0)=200; % When heasig.gain = 0 => default 200
if nargin >=8,
t=[max(t(1),1) min(heasig.nsamp,t(2))];
else
qrs_flag=0;% default value was missing 01/04/02 Rute
t=[1 heasig.nsamp];
end
% Reading of external QRS annotation file if qrs_flag
if qrs_flag==1 % The QRS fiducial point is read from external annotator
switch (anot_fmt);
case 0 % MIT annotation file
if exist([dirann ecgnr '.' aname],'file')
s=readannot([dirann ecgnr '.' aname],t);
s=isqrs(s,heasig,t);
ext_anot=s.time';
else error('QRS annotation file not found');
end
case 1 % mat file
if exist([dirann aname '.mat'],'file')
s=load ([dirann aname]);
kk=getfield(s);
eval(['ext_anot=s.' kk ';']);
else error('QRS annotation file not found');
end
otherwise
error('Bad annotation format for external QRS annotation file');
end
end
inisamp = t(1);
endsamp = 0;
timeqrs = [];
lastqrs = 1;
if qrs_flag==0 % estimated maximum number of beats
maxlength = (t(2)-t(1))/heasig.freq*2;
else maxlength=length(ext_anot);
end
%if qrs_flag==1,
% sel=find(ext_anot<heasig.freq);
% if ~isempty(sel)
% ext_anot(sel)=[];
% maxlength= length(ext_anot);
% end
%end
nanvec = nan*ones(1,maxlength);
position=struct('Pon',nanvec,'P',nanvec,'Poff',nanvec,'QRSon',nanvec,...
'Q',nanvec,'R',nanvec,'Fiducial',nanvec,'qrs',zeros(1,maxlength),...
'Rprima',nanvec,'S',nanvec,'QRSoff',nanvec,'Ton',nanvec,'T',nanvec,...
'Tprima', nanvec,'Toff',nanvec,'Ttipo',nanvec);
if qrs_flag==1, position.qrs=ext_anot; end
numlatdet = 0; % Number of detected beats until now
[q1,q2,q3,q4,q5] = qspfilt5(heasig.freq); % WT equivalent filters %%%%% para incluir a escala 5 %% Rute 22/05/02
l1=length(q1);l2=length(q2);l3=length(q3);l4=length(q4);
d1=floor((l1-1)/2);d2=floor((l2-1)/2);
d3=floor((l3-1)/2);d4=floor((l4-1)/2);
l5=length(q5);d5=floor((l5-1)/2); %%%%% para incluir a escala 5 %% Rute 22/05/02
begoverlap = l5+2*heasig.freq; % l5 + 2 sec. %%%%% passa a ser em relaçao a escala 5 %% Rute 22/05/02
endoverlap = d5; %%%%% passa a ser em relaçao a escala 5 %% Rute 22/05/02
% The two seconds overlap makes sure that the last/first beat
% are completely within the excerpt processed
samp=1; %freq; %Initialization of samp (1 sec)
while ((endsamp+1) < t(2))
firstnewsamp = samp(end); % last sample analyzed
endsamp = min(inisamp + nsamp -1,t(2));
if ft==0 % MIT format
if strcmp(formato,'212'), % !!!!! Different formats (heasig)
sig = rdsign212([sigdir ecgnr '.dat'],nsiginfile,inisamp, endsamp); % I changed heasig.nsig by nsiginfile ---> see above JP2006
elseif strcmp(formato,'16')|strcmp(formato,'61'),
%%%%%%%%%%%%%% ANA PARA BIOPAC %%%%%%%%%%%%%%%%%%%%%%
if isfield(heasig,'spf')
if(~isempty(heasig.spf) & find(heasig.spf ~= 1) )
agrupacion = sum(heasig.spf);
% ecg = zeros(heasig.nsig,heasig.nsamp*(max(heasig.spf)));
end
fid = fopen([sigdir ecgnr '.ecg'],'rb');
% fid = fopen([prmBrowse.ecgdir prmBrowse.ecgnr],'rb');
if(length(find(heasig.fmt == 16)) == heasig.nsig)
%fseek(fid,agrupacion*(inisamp-1)*2,'bof');
fseek(fid,agrupacion*round((inisamp-1)/heasig.spf(lead))*2,'bof');
x = fread(fid,[agrupacion (endsamp-inisamp+1)/heasig.spf(lead)], 'int16');
ini_pos_lead = sum(heasig.spf(1:lead))-heasig.spf(lead)+1;
end_pos_lead = sum(heasig.spf(1:lead));
sig = reshape(x(ini_pos_lead:end_pos_lead,:),[],1);
% Para no tener que cambiar el codigo
sig=[zeros(length(sig),leadinfile-1) sig];
clear('x')
end
fclose('all');
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
else
fseek(fid, timeoffset+2*(inisamp-1)*nsiginfile, -1); % Locate the pointer
sig = fread(fid,[nsiginfile endsamp-inisamp+1] ,'int16')';
end
if (strcmp(computer,'SOL2')&strcmp(formato,'16'))|(~strcmp(computer,'SOL2')&strcmp(formato,'61')),
sig=swap16(sig);
end
end
sig = sig(:,leadinfile); % Only selected lead. --> JP 2006 I changed lead by leainfile... see at the top
if exist('heasig','var') && isfield(heasig,'units')
if upper(heasig.units(lead))=='MV'
sig = (sig - heasig.adczero(lead))/heasig.gain(lead)*1e3; % conversion to microV
elseif upper(heasig.units(lead))=='V'
sig = (sig - heasig.adczero(lead))/heasig.gain(lead)*1e6; % conversion to microV
else
sig = (sig - heasig.adczero(lead))/heasig.gain(lead);
end
else
sig = (sig - heasig.adczero(lead))/heasig.gain(lead)*1e3; % conversion to microV
end
% sig = (sig - heasig.adczero(lead))/heasig.gain(lead)*1e3; % conversion to microV
elseif ft==1 % LUND format
sig=getsig(sigdir,ecgnr,[inisamp,endsamp],lead)';
%sig=sig/5; % Mejor en uV JP
elseif ft==2 % data in a Matlab file
sig=sinal(lead,inisamp:endsamp)';
end
wt = wavt5(sig',q1,q2,q3,q4,q5); % WT equivalent filtering % 22/05/02 Rute including scale 5
wt=wt(l5:end,1:5); % Remove "incorrect" samples
samp = (inisamp + l5 -1):endsamp-d5;
% First l5-1 samples are not correctly filtered (border effect)
% Last d5 samples are discarded in order to alineate all the
% filtered signals, taking into acount the filter delays
% Synchronizing filtered signals at different scales
w = zeros(size(wt,1)-d5,5);
w(:,5) = wt(d5+1:end,5);
w(:,4) = wt(d4+1:end+d4-d5,4);
w(:,3) = wt(d3+1:end+d3-d5,3);
w(:,2) = wt(d2+1:end+d2-d5,2);
w(:,1) = wt(d1+1:end+d1-d5,1);
sig=sig(l5:end-d5); % piece of signal processed in this iteration
clear wt;
% Initialization of the thresholds for QRS detection (eps)
eps= 0.5*sqrt(mean(w.^2));
eps(4) = eps(4)*2;
if qrs_flag==0 % The QRS fiducial point is calculated with wavedet
%fiducial_altera_novo; % uso de Criterios alternativos para selecao de candidatos a QRS % Rute 4/9/02
fiducial; % Detection of fiducial point % 22/05/02 Rute including scale 5 % 07/06/02 Rute exclui escala5
else % The QRS fiducial point is read from external annotator
first = max(firstnewsamp-ceil(heasig.freq), samp(1)-1+ceil(heasig.freq*0.050));
% first is calculated according with the first lines of fiducial JP
sel=find(position.qrs>=first & position.qrs<=samp(end));
time=position.qrs(sel)-samp(1)+1;
% If the P-wave is not in the present segment, discard the beat, because the
% the beat should have been detected in the last segment.
if abs(samp(time(1)) - lastqrs)< 0.275*heasig.freq,
time(1)=[]; sel(1)=[]; % In order not to repeat beats
end
if (length(sig)-time(end) < 0.45*heasig.freq),
time(end)=[]; sel(end)=[];
end
% If last beat's T-wave is not in 'sig', the beat is detected in next one
if time(1)-0.35*heasig.freq<=0, time(1)=[]; sel(1)=[]; end
timeqrs = [timeqrs samp(time)]; % QRS times
lastqrs = samp(time(end));
intervalo = [sel(1) sel(end)]; %%%%%%
% numeration of the beats processed in this segment
%keyboard
end
if ~isempty(time)
%% Individual wave detection %%
qrswave;
%%%%%%%%%%%%%%%% caso em que rr tem dimensao inferior ao necessario
if length(time)>1 %%%%%%%%%%%%%%%%introduzido a 17/05/02 Rute
twave, %%%%%%%% 07/06/0 Rute including scale 5
end %%%%%%%%%%%%%%%%introduzido a 17/05/02 Rute
pwave;
% Last annotated position
if ~isnan(position.Toff(intervalo(2))),
ultimo_anot = position.Toff(intervalo(2));
elseif ~isnan(position.Tprima(intervalo(2))),
ultimo_anot = position.Tprima(intervalo(2));
elseif ~isnan(position.T(intervalo(2))),
ultimo_anot = position.T(intervalo(2));
elseif ~isnan(position.QRSoff(intervalo(2))),
ultimo_anot = position.QRSoff(intervalo(2));
else
ultimo_anot = position.qrs(intervalo(2));
end
end
inisamp = endsamp+2-endoverlap-begoverlap;
end
% Remove void annotations at the end
aux = find (position.qrs == 0);
position.Pon(aux)=[];
position.P(aux)=[];
position.Poff(aux)=[];
position.QRSon(aux)=[];
position.Q(aux)=[];
position.R(aux)=[];
position.Fiducial(aux)=[];
position.qrs(aux)=[];
position.Rprima(aux)=[];
position.S(aux)=[];
position.QRSoff(aux)=[];
position.Ton(aux)=[];
position.T(aux)=[];
position.Tprima(aux)=[];
position.Toff(aux)=[];
position.Ttipo(aux)=[];
annstruct = pos2ann(position);
if ~isempty(position.qrs)
writeannot ([matdir ecgnr '.' anot 's' num2str(lead)], annstruct); % mexfile, faster!
end
%escribeanot(fann,position,anot,lead, ecgnr, freq, matdir, 'anot');
fclose('all');
clear global regularity