function [position,qrspiconset,qrspicoffset,messages]= qrswavef(heasig,samp,time,position,w,intervalo,messages) % script which identifies q,r or s waves in each beat. % % Untill the end, all indexes are referred to sig and w, % i.e. they are not global indexes but referred to the present segment. % %Input Parameters: % heasig: struct vector with header information % samp: samples included in the current excerpt (borders excluded) % time: QRS times in inedexes refering the interval included in the current excerpt (borders excluded) % position: struct vector with the detected points % w: matrix with WT scales 1 to 5 % intervalo: numeration of the beats processed in this segment % messages.setup.wavedet.Kron,Kroff,Kq,Ks,umbral,umbral1p,umbral1a,umbral2a,umbral2p,QRS_window (optional): parameters % messages.setup.wavedet.QRS_wtol_paa,QRS_wtol_za,QRS_wtol_pantza,QRS_wtol_ppp,QRS_wtol_zp,QRS_wtol_ppostzp (optional): parameters % messages.setup.wavedet.farza,farzaa,farzpp,QRSon_window,QRSoff_window, (optional): parameters % messages.setup.wavedet.firstwaverestriction,Qwaverestriction,Rwaverestriction,Rprimarestriction1,Rprimarestriction2,Srestriction1,Srestriction2 (optional): parameters % % %Output Parameters: % qrspiconset: first relevant slope associated to each QRS complex (WT extrema) % qrspicoffset: last relevant slope associated to each QRS complex (WT extrema) % actualized parameters: position % %Parameters details and default values: %relative thresholds with respect to dermax to decide if other absolute maximum lines are significative: equation 3.14 R Almeida PhD thesis %messages.setup.wavedet.Kron = 20; %messages.setup.wavedet.Kroff = 14; %messages.setup.wavedet.Kq = 15; %messages.setup.wavedet.Ks = 8; % S offset (Proyeuto de Mapi) . 2.5 3 5 8; % %messages.setup.wavedet.umbral = 0.2; % relative threshold respecto to dermax to decide if waves posterior to qrs are significative: equation 3.13 R Almeida PhD thesis %messages.setup.wavedet.umbral1p = 0.09; %relative threshold respecto to dermax to decide if waves anterior to qrs are significative: equation 3.13 R Almeida PhD thesis %messages.setup.wavedet.umbral1a=0.06; % relative threshold respecto to dermax to decide if waves anterior to qrs are significative: equation 3.13 R Almeida PhD thesis %messages.setup.wavedet.umbral2a=0.15; % same as umbral1a but second peak in bifasic waves %messages.setup.wavedet.umbral2p=0.18; % same as umbral1p but second peak in bifasic waves %messages.setup.wavedet.QRS_window=0.1; % half length of the initial delineation window for QRS : equation 3.12 PhD thesis %messages.setup.wavedet.QRS_wtol_paa=0.07;% search window length for paa (peak before pa) to find main wave cracks %messages.setup.wavedet.QRS_wtol_za=0.08;% search window length for za (zero before pa) %messages.setup.wavedet.QRS_wtol_pantza=0.08; search window length for za(zero before pa) and zaa (zero before pantza) %messages.setup.wavedet.QRS_wtol_ppp=0.13;% search window length for ppp (peak after pp) %messages.setup.wavedet.QRS_wtol_zp=0.13;% search window length for za (zero before pa) and search window length for zpp ( zero after zp) %messages.setup.wavedet.QRS_wtol_ppostzp=0.08;%half length of the search window for ppostzp (peak after zp) %messages.setup.wavedet.farza=0.16;%maximum time allowed bewteen za and qrs %messages.setup.wavedet.farzaa=0.16;%maximum time allowed bewteen zaa and za %messages.setup.wavedet.farzp=0.16;%maximum time allowed bewteen zp and qrs %messages.setup.wavedet.farzpp=0.16;%maximum time allowed bewteen zp and zpp %messages.setup.wavedet.QRSon_window=0.08; %search window length for QRS on %messages.setup.wavedet.QRSoff_window=0.08; %search window length for QRS end %messages.setup.wavedet.firstwaverestriction=0.12;%If qrs onset differs more than 120 ms of qrs the first not main wave is excluded and qrs onset searched again %messages.setup.wavedet.Qwaverestriction=0.05;%If qrs onset differs more than 5 ms from Q wave, the Q wave is excluded and qrs onset searched again %messages.setup.wavedet.Rwaverestriction=0.08;%If qrs onset differs more than 8 ms from a first wave R, the R wave is excluded and qrs onset searched again %messages.setup.wavedet.Rprimarestriction1=0.12;%If qrs onset differs more than 120 ms of qrs the last not main wave Rprima is excluded and qrs onset searched again %messages.setup.wavedet.Rprimarestriction2=0.05;%If qrs onset differs more than 5 ms from the last not main wave Rprima, R prima is excluded and qrs onset searched again %messages.setup.wavedet.Srestriction1=0.27;%If qrs onset differs more than 270 ms of qrs the last not main wave S wave is excluded and qrs onset searched again %messages.setup.wavedet.Srestriction2=0.15;%If qrs onset differs more than 150 ms from the last not main wave S, S wave is excluded and qrs onset searched again % % Last update: Rute Almeida 07FEB2012 % % Designed for MATLAB Version R12; tested with MATLAB Version R13 if nargin<7 || ~isfield(messages,'setup') || ~isfield(messages.setup,'wavedet')% 27JUN2011 messages.setup.wavedet=[]; end if ~isfield(messages.setup.wavedet,'Kron') messages.setup.wavedet.Kron = 20;% 3.5 5 8 10 15 20! end if ~isfield(messages.setup.wavedet,'Kroff') messages.setup.wavedet.Kroff = 14; end if ~isfield(messages.setup.wavedet,'Kq')% Q onset, antiguo Kq==1; 2 2.5 3.5 5 10 15! messages.setup.wavedet.Kq = 15; end if ~isfield(messages.setup.wavedet,'Ks') messages.setup.wavedet.Ks = 8; % S offset (Proyeuto de Mapi) . 2.5 3 5 8; end if ~isfield(messages.setup.wavedet,'umbral') messages.setup.wavedet.umbral = 0.2; % relative threshold respecto to dermax to decide if waves paa and ppp are significative end if ~isfield(messages.setup.wavedet,'umbral1p') messages.setup.wavedet.umbral1p = 0.09; % relative threshold respecto to dermax to decide if waves posterior to qrs are significative: equation 3.13 R Almeida PhD thesis end if ~isfield(messages.setup.wavedet,'umbral1a') messages.setup.wavedet.umbral1a=0.06; % relative threshold respecto to dermax to decide if waves anterior to qrs are significative: equation 3.13 R Almeida PhD thesis end if ~isfield(messages.setup.wavedet,'umbral2a') messages.setup.wavedet.umbral2a=0.15; % significativas. % anterior 0.15 --0.20 end if ~isfield(messages.setup.wavedet,'umbral2p') % anterior 0.14 -- 0.09 messages.setup.wavedet.umbral2p=0.18; end if ~isfield(messages.setup.wavedet,'QRS_window') % half length of the initial delineation window for QRS : equation 3.12 PhD thesis messages.setup.wavedet.QRS_window=0.1; % same as QRS_wtol_ppostzp_crack corresponding to % half length of the search window for ppostzz crack protection end if ~isfield(messages.setup.wavedet,'QRS_wtol_paa') % search window length for paa (peak before pa) to find main wave cracks messages.setup.wavedet.QRS_wtol_paa=0.07; end if ~isfield(messages.setup.wavedet,'QRS_wtol_za') % search window length for za (zero before pa) messages.setup.wavedet.QRS_wtol_za=0.08; end if ~isfield(messages.setup.wavedet,'QRS_wtol_pantza') %half length of the search window for pantza (peak before za) messages.setup.wavedet.QRS_wtol_pantza=0.08; % same as QRS_wtol_pantzaa and QRS_wtol_pantza_crack corresponding to % half length of the search window for pantzaa and crack protection % same as and QRS_wtol_zaa corresponding to search window length for zaa (zero before pantza) end if ~isfield(messages.setup.wavedet,'QRS_wtol_ppp') % search window length for ppp (peak after pp) messages.setup.wavedet.QRS_wtol_ppp=0.13; end if ~isfield(messages.setup.wavedet,'QRS_wtol_zp') % search window length for za (zero before pa) messages.setup.wavedet.QRS_wtol_zp=0.13; % same as QRS_wtol_zpp corresponding to to search window length for zpp ( zero after zp) end if ~isfield(messages.setup.wavedet,'QRS_wtol_ppostzp') %half length of the search window for ppostzp (peak after zp) messages.setup.wavedet.QRS_wtol_ppostzp=0.08; end if ~isfield(messages.setup.wavedet,'farza') %maximum time allowed bewteen za and qrs messages.setup.wavedet.farza=0.16; end if ~isfield(messages.setup.wavedet,'farzaa') %maximum time allowed bewteen zaa and za messages.setup.wavedet.farzaa=0.16; end if ~isfield(messages.setup.wavedet,'farzp') %maximum time allowed bewteen zp and qrs messages.setup.wavedet.farzp=0.16; end if ~isfield(messages.setup.wavedet,'farzpp') %maximum time allowed bewteen zp and qrs messages.setup.wavedet.farzpp=0.16; end if ~isfield(messages.setup.wavedet,'QRSon_window') %search window length for QRS on messages.setup.wavedet.QRSon_window=0.08; end if ~isfield(messages.setup.wavedet,'QRSoff_window') %search window length for QRS off messages.setup.wavedet.QRSoff_window=0.08; end if ~isfield(messages.setup.wavedet,'firstwaverestriction') messages.setup.wavedet.firstwaverestriction=0.12; %If qrs onset differs more than 120 ms of qrs the first not main wave is excluded and qrs onset searched again end if ~isfield(messages.setup.wavedet,'Qwaverestriction') messages.setup.wavedet.Qwaverestriction=0.05; %If qrs onset differs more than 5 ms from Q wave, the Q wave is excluded and qrs onset searched again end if ~isfield(messages.setup.wavedet,'Rwaverestriction') messages.setup.wavedet.Rwaverestriction=0.08; %If qrs onset differs more than 8 ms from a first wave R, the R wave is excluded and qrs onset searched again end if ~isfield(messages.setup.wavedet,'Rprimarestriction1') messages.setup.wavedet.Rprimarestriction1=0.12; %If qrs onset differs more than 120 ms of qrs the last not main wave Rprima is excluded and qrs onset searched again end if ~isfield(messages.setup.wavedet,'Rprimarestriction2') messages.setup.wavedet.Rprimarestriction2=0.05; %If qrs onset differs more than 5 ms from the last not main wave Rprima, R prima is excluded and qrs onset searched again end if ~isfield(messages.setup.wavedet,'Srestriction1') messages.setup.wavedet.Srestriction1=0.27; %If qrs onset differs more than 270 ms of qrs the last not main wave S wave is excluded and qrs onset searched again end if ~isfield(messages.setup.wavedet,'Srestriction2') messages.setup.wavedet.Srestriction2=0.15; %If qrs onset differs more than 150 ms from the last not main wave S, S wave is excluded and qrs onset searched again end %%%%%%%%%%%%%%%%%%%%% Parameters !!!!!!!!!!!!!!!%%%%%%%%%%%% QRS_window=messages.setup.wavedet.QRS_window; QRSon_window=messages.setup.wavedet.QRSon_window; QRSoff_window=messages.setup.wavedet.QRSoff_window; QRS_wtol_paa=messages.setup.wavedet.QRS_wtol_paa; QRS_wtol_za=messages.setup.wavedet.QRS_wtol_za; QRS_wtol_pantza=messages.setup.wavedet.QRS_wtol_pantza; QRS_wtol_pantza_crack=QRS_wtol_pantza; QRS_wtol_zaa=QRS_wtol_pantza; QRS_wtol_pantzaa=QRS_wtol_pantza; QRS_wtol_ppp=messages.setup.wavedet.QRS_wtol_ppp; QRS_wtol_zp=messages.setup.wavedet.QRS_wtol_zp; QRS_wtol_ppostzp=messages.setup.wavedet.QRS_wtol_ppostzp; QRS_wtol_ppostzp_crack=messages.setup.wavedet.QRS_window; QRS_wtol_zpp=QRS_wtol_zp; QRS_wtol_ppostzpp=QRS_wtol_ppostzp; farza=messages.setup.wavedet.farza; farzaa=messages.setup.wavedet.farzaa; farzp=messages.setup.wavedet.farzp; farzpp=messages.setup.wavedet.farzpp; firstwaverestriction=messages.setup.wavedet.firstwaverestriction; Qwaverestriction=messages.setup.wavedet.Qwaverestriction; Rwaverestriction=messages.setup.wavedet.Rwaverestriction; Rprimarestriction1=messages.setup.wavedet.Rprimarestriction1; Rprimarestriction2=messages.setup.wavedet.Rprimarestriction1; Srestriction1=messages.setup.wavedet.Srestriction1; Srestriction2=messages.setup.wavedet.Srestriction2; umbral=messages.setup.wavedet.umbral; umbral1p = messages.setup.wavedet.umbral1p; umbral1a= messages.setup.wavedet.umbral1a; umbral2a = messages.setup.wavedet.umbral2a; umbral2p = messages.setup.wavedet.umbral2p; Kron=messages.setup.wavedet.Kron; Kroff=messages.setup.wavedet.Kroff; Kq=messages.setup.wavedet.Kq; Ks=messages.setup.wavedet.Ks; % Si a primera u a zaguera onda ye a R. 2.5 3 5 8 14 % antiguo 2.5 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% if isempty(heasig) end % Structure for the present segment of the signal (sig) times referred to % begining of the present segment. pos=struct('Pon',[],'P',[],'Poff',[],'QRSon',[],'Q',[],'R',[],'Fiducial',[],'qrs',[],'Rprima',[],'S',[],'QRSoff',[],'Ton',[],'T',[],'Tprima',[],'Toff',[],'Ttipo',[],'QRSpa',[],'QRSpp',[]); % After processing all the excerpt,pos is transferred to the struct position. qrspiconset=[]; qrspicoffset=[]; WT_extrema=NaN*ones(6,length(time)); WT_zc=NaN*ones(5,length(time)); pos_extrema=NaN*ones(6,length(time)); for i = 1:length(time), qrs = time(i); R=[];Q=[];S=[];Rprima=[]; za=[];zaa=[];zp=[]; zpp=[]; %#ok dermax = max(abs(w(max(qrs-round(QRS_window*(messages.setup.wavedet.freq)),1):min(size(w,1),qrs+round(QRS_window*(messages.setup.wavedet.freq))),2))); pa = picant(w(max(qrs-round(QRS_window*(messages.setup.wavedet.freq)),1):qrs,2),qrs); % first peak before detected qrs position at scale 2 pp = picpost(w(qrs:min(size(w,1),qrs+round(QRS_window*(messages.setup.wavedet.freq))),2),qrs); % first peak after detected qrs position at scale 2 apa = w(pa,2); % Amplitudes of pa and pp at scale 2 app = w(pp,2); % If there is a crack at scale 1 but not at scale 2, it is possible that % pa and pp have the same sign. if (sign(apa)==sign(app)), % In that case... paux =modmax(w(pp+1:min(pp+round(QRS_window*(messages.setup.wavedet.freq)),size(w,1)),2),2,0,-sign(app)); if paux, pp2 = pp + paux(1); else pp2= []; app2=0; end %#ok % If there is the next 100 ms some modulus maximum of the contrary sign of app paux=modmax(flipud(w(max(1,pa-round(QRS_wtol_paa*(messages.setup.wavedet.freq))):pa-1,2)),2,0,-sign(apa)); if paux, pa2 = pp - paux(1); else pa2=[]; end % If there is the next 70 ms some modulus maximum of the contrary sign of apa if isempty(pp2), if isempty(pa2), % Nothing else pa = pa2; apa = w(pa2,2); end else if isempty(pa2), pp = pp2; app = w(pp2,2); else if abs(w(pp2,2))> abs(w(pa2,2)), pp = pp2; app = w(pp2,2); else pa = pa2; apa = w(pa2,2); end end end % So, we take the peak with greater absolute value !!!!!!!!!!!!!!!!!!!!!!!!!!!! % Not coherent with the PFC!!!!!!!!!!!!!!!!!! % Think in which conditions the condition holds % and what happens if there is no peak ?? Solucionado esto último end % Next peaks before pa and after pp paa = modmax(flipud(w(max(1,pa-round(QRS_wtol_paa*(messages.setup.wavedet.freq))):pa-1,2)),2,umbral*dermax,sign(w(pa,2))); ppp = modmax(w(pp+1:fix(min(pp+round(QRS_wtol_ppp*(messages.setup.wavedet.freq)),size(w,1))),2),2,umbral*dermax,sign(w(pp,2))); % Protection against R-waves with cracks if ~isempty(paa), paa = pa - paa(end); pa = paa; apa = max(w(paa,2),apa); end if ~isempty(ppp), ppp = pp + ppp(end); pp = ppp; app = max(app,w(ppp,2)); end % depending of the signs of apa and app we can know if the detected qrs position % corresponded to a positive or a negative wave. if (apa>0 & app<0), %#ok % qrs is positive qRs, Rsr, rsR. ind = zerocros(flipud(w(max(1,pa-round(QRS_wtol_za*(messages.setup.wavedet.freq))):pa-1,1))); za = pa -ind; % previous zero if ~isempty(za), % search for the first negative peak before za (and thus, before the positive peak pa) % paux= modmax(flipud(w(za-0.08*(messages.setup.wavedet.freq):za,2)),2,0,-1); % %%RUTE: can give error in i=1 if za < 0.08*(messages.setup.wavedet.freq) %%24Mar06 paux= modmax(flipud(w(max(1,za-round(QRS_wtol_pantza*(messages.setup.wavedet.freq))):za,2)),2,0,-1); if paux, pantza = za - paux(1)+1; else pantza = []; end apantza = w(pantza,2); % p ant za = peak anterior to za ; % a p ant za = amplitude of the peak anterior to za % Protection against waves with cracks % If there is another peak of the same sign as pantza just before it, take it as the position of % the peak, and as amplitude, the maximum of the two. %paux =modmax(flipud(w(pantza-round(0.05*(messages.setup.wavedet.freq)):pantza-1,2)),2,umbral2a*dermax,sign(w(pantza,2))); % %%RUTE: can give error in i=1 if pantza < 0.08*(messages.setup.wavedet.freq) %%24Mar06 %paux %=modmax(flipud(w(max(1,pantza-round(0.05*(messages.setup.wavedet.freq))):pantza-1,2)),2,umbral2a*dermax,sign(w(pantza,2))); % parameter changed form 0.08 to 0.05 ?!?!? when? Why paux =modmax(flipud(w(max(1,pantza-round(QRS_wtol_pantza_crack*(messages.setup.wavedet.freq))):pantza-1,2)),2,umbral2a*dermax,sign(w(pantza,2))); if ~isempty(paux) paux = pantza -paux(end); pantza = paux; apantza = sign(w(paux,2))*max(abs(apantza), abs(w(paux,2))); end if (apantza>0)|(abs(apantza) % If apantza is a little peak, forget it and za za = []; elseif (isempty(pantza)) za =[]; end if ~isempty(za), % If we are interested in the zero crossing "za" % Search for the zero crossign before "za", called "zaa" %ind = zerocros(flipud(w(pantza-0.08*(messages.setup.wavedet.freq):pantza-1,1))); %%RUTE: can give error in i=1 if pantza < 0.08*(messages.setup.wavedet.freq) %%14Mar06 ind = zerocros(flipud(w(max(1,pantza-round(QRS_wtol_zaa*(messages.setup.wavedet.freq))):pantza-1,1))); %%RUTE: %14Mar06 zaa = pantza-ind; if ~isempty(zaa), paux= modmax(flipud(w(max(1,zaa-round(QRS_wtol_pantzaa*(messages.setup.wavedet.freq))):zaa,2)),2,0,+1); % Search positive peak before "zaa" if paux, pantzaa = zaa - paux(1)+1; else pantzaa = []; end apantzaa = w(pantzaa,2); % Amplitude of the peak anterior to zaa: apantzaa if (apantzaa<0)|(abs(apantzaa) % If little, forget it and zaa zaa=[]; elseif(isempty(pantzaa)) zaa=[]; end end end end %%%%%%%%%%%%% now the same, but after pp (pico posterior) %%%%%%%%%%%%%%%%%% ind = zerocros(w(pp+1:min(size(w,1),pp+round(QRS_wtol_zp*(messages.setup.wavedet.freq))),1)); % Search zero after pp (zp) zp = pp + ind; if ~isempty(zp), paux= modmax(w(zp:min(size(w,1),zp+round(QRS_wtol_ppostzp*(messages.setup.wavedet.freq))),2),2,0,+1); % Search peak after zp (ppostzp) if paux, ppostzp = zp + paux(1)-1; else ppostzp = []; end appostzp = w(ppostzp,2); % Amplitude of ppostzp at scale 2 % Protection against waves with cracks % If there is another peak of the same sign as ppostzp just after it, take it as the position of % the peak, and as amplitude, the maximum of the two. paux =modmax(w(ppostzp+1:min(size(w,1),ppostzp+round(QRS_wtol_ppostzp_crack*(messages.setup.wavedet.freq))),2),2,umbral2p*dermax,sign(w(ppostzp,2))); if ~isempty(paux) paux = ppostzp + paux(end); ppostzp = paux; appostzp = sign(w(paux,2))* max(abs(appostzp), abs(w(paux,2))); end if (appostzp<0)|(abs(appostzp) % if peak is not large enough zp=[]; % forget it and zp elseif isempty(ppostzp), zp=[]; end if ~isempty(zp), % else, search zero crossing after it ind = zerocros(w(ppostzp+1:min(size(w,1),ppostzp+round(QRS_wtol_zpp*(messages.setup.wavedet.freq))),1)); zpp = ppostzp + ind; if ~isempty(zpp), % and next peak after zero crossing paux= modmax(w(zpp:min(size(w,1),zpp+round(QRS_wtol_ppostzpp*(messages.setup.wavedet.freq))),2),2,0,-1); if paux, ppostzpp = zpp + paux(1)-1; else ppostzpp = []; end appostzpp = w(ppostzpp,2); if (appostzpp>0)|(abs(appostzpp) % If not large enough, forget it zpp=[]; elseif(isempty(ppostzpp)) zpp=[]; end end end end if (isempty(zaa))& (qrs-za)>round(farza*(messages.setup.wavedet.freq)), %#ok % farza changed from 0.08 MAY2011 za = []; % If first zero in the wavelet before qrs is too far from QRS end % forget it if ~isempty(zaa) & (za - zaa)>round( farzaa*(messages.setup.wavedet.freq)),%#ok % farza changed from 0.16 MAY2011 zaa=[]; % If zaa is too far from za, forget it end if isempty(zpp) & (zp-qrs)>round(farzp*(messages.setup.wavedet.freq)),%#ok % farza changed from 0.16 MAY2011 zp = []; % If zp is too far from qrs, forget it end if ~isempty(zpp) & (zpp-zp)>round(farzpp*(messages.setup.wavedet.freq)) %#ok % farza changed from 0.16 MAY2011 zpp = []; % if zpp is too far from zpp forget it end % wave label asignation if isempty(za), % No waves before qrs (which is positive) R=qrs; S=zp; Rprima=zpp; % RSR' or RS or R %2AGO2011 elseif isempty(zp), % if some wave before qrs but not waves after if ~isempty(zaa), % if there are two waves befor qrs R=zaa; S=za; Rprima = qrs; % RSR' else % if only one wave before qrs Q=za; R=qrs; % QR end else % if there are waves before and after qrs if (~isempty(zpp))&&(~isempty(zaa)) % if there are two waves before and two waves after if (abs(apantzaa)>abs(appostzpp)),% Forget the smaller of the two extreme waves zpp=[]; else zaa=[]; end end % Now there are no more than 4 possible waves if ~isempty(zpp)&&(isempty(zaa)), % if we have one wave before and two after if abs(appostzpp)>abs(apantza), % if the second after is bigger than the one before R = qrs; S = zp; Rprima = zpp; % RSR' else % if the one before is bigger than the second after Q = za; R = qrs; S=zp; % QRS end elseif ~isempty(zaa)&& isempty(zpp), % if there are two waves before and one after if abs(apantzaa)>abs(appostzp), % ... R=zaa; S=za; Rprima=qrs; % RSR' else Q=za; R=qrs; S=zp; % QRS end elseif za~=qrs && zp~=qrs % else = if there are one wave before and one after qrs Q=za; R=qrs; S=zp; % QRS else %MAR06;2012 if za==qrs %%%%% strange case R==Q??? if apantza<0 Q=za; R=zp; else R=za; S=zp; end else if appostzp<0 R=qrs; S=zp; else Q=qrs; R=zp; end end end end % We begin again in case the qrs peak is negative: the process is similar else % Negative QRS: Qrs qrS QS % ind = zerocros(flipud(w(max(1,pa-round(QRS_wtol_za*(messages.setup.wavedet.freq))):pa-1,1))); za = pa -ind; % previous zero. za: zero anterior if ~isempty(za), %paux= modmax(flipud(w(za-0.08*(messages.setup.wavedet.freq):za,2)),2,0,+1); %RUTE: can give error in i=1 if za < 0.08*(messages.setup.wavedet.freq) paux= modmax(flipud(w(max(1,za-round(QRS_wtol_pantza*(messages.setup.wavedet.freq))):za,2)),2,0,+1); if paux, pantza = za - paux(1)+1; else pantza = []; end apantza = w(pantza,2); % Protection against waves with cracks %paux=modmax(flipud(w(max(1,pantza-round(0.05*(messages.setup.wavedet.freq))):pantza-1,2)),2,umbral2a*dermax,sign(w(pantza,2))); % 0.05 why, when it was changed? paux =modmax(flipud(w(max(1,pantza-round(QRS_wtol_pantza_crack*(messages.setup.wavedet.freq))):pantza-1,2)),2,umbral2a*dermax,sign(w(pantza,2))); if ~isempty(paux) paux = pantza -paux(end); pantza = paux; apantza = sign(w(paux,2))*max(abs(apantza), abs(w(paux,2))); end if (apantza<0)|(abs(apantza) za = []; elseif isempty(pantza), za = []; end if ~isempty(za), % ind = zerocros(flipud(w(pantza-0.08*(messages.setup.wavedet.freq):pantza-1,1))); %%RUTE: can give error in i=1 if pantza < 0.08*(messages.setup.wavedet.freq) ind = zerocros(flipud(w(max(1,pantza-round(QRS_wtol_zaa*(messages.setup.wavedet.freq))):pantza-1,1))); %%RUTE: %07 Abri06 zaa = pantza-ind; if ~isempty(zaa), paux= modmax(flipud(w(max(1,zaa-round(QRS_wtol_pantzaa*(messages.setup.wavedet.freq))):zaa,2)),2,0,-1); if paux, pantzaa = zaa - paux(1)+1; else pantzaa = []; end apantzaa = w(pantzaa,2); if (apantzaa>0)|(abs(apantzaa) zaa=[]; elseif(isempty(pantzaa)) zaa=[]; end end end end ind = zerocros(w(pp+1:min(size(w,1),pp+round(QRS_wtol_zp*(messages.setup.wavedet.freq))),2)); if ~isempty(pp) && ~isempty(ind) %2JUL2011 zp = pp + ind; end if ~isempty(zp), paux= modmax(w(zp:min(size(w,1),zp+round(QRS_wtol_ppostzp*(messages.setup.wavedet.freq))),2),2,0,-1); if paux, ppostzp = zp + paux(1)-1; else ppostzp = []; end appostzp = w(ppostzp,2); % Protection against waves with cracks paux =modmax(w(ppostzp+1:min(size(w,1),ppostzp+round(QRS_wtol_ppostzp_crack*(messages.setup.wavedet.freq))),2),2,umbral2p*dermax,sign(w(ppostzp,2))); % estamos a ir longe de mais na busca falta protecçao para que nao entre no batimento seguinte! if ~isempty(paux) paux = ppostzp + paux(end); ppostzp = paux; appostzp = sign(w(paux,2))*max(abs(appostzp), abs(w(paux,2))); end if (appostzp>0) |(abs(appostzp) zp=[]; elseif isempty(ppostzp), zp = []; end if ~isempty(zp), ind = zerocros(w(ppostzp+1:min(size(w,1),ppostzp+round(QRS_wtol_zpp*(messages.setup.wavedet.freq))),2)); zpp = ppostzp + ind; if ~isempty(zpp), %ppostzpp = picpost(w(zpp:min(size(w,1),zpp+0.08*(messages.setup.wavedet.freq)),2),zpp); paux= modmax(w(zpp:min(size(w,1),zpp+round(QRS_wtol_ppostzpp*(messages.setup.wavedet.freq))),2),2,0,+1); if paux, ppostzpp = zpp + paux(1)-1; else ppostzpp = []; end appostzpp = w(ppostzpp,2); if (appostzpp<0) |(abs(appostzpp) zpp=[]; elseif(isempty(ppostzpp)) zpp=[]; end end end end if (isempty(zaa)) & (qrs-za)>farza*(messages.setup.wavedet.freq), %#ok %changed from 0.16 MAY2011 za = []; % Si 1º onda m end if ~isempty(zaa) & (za - zaa)> farzaa*(messages.setup.wavedet.freq), %#ok %changed from 0.08 MAY2011 zaa=[]; end if isempty(zpp) & (zp-qrs)>farzp*(messages.setup.wavedet.freq),%#ok %changed from 0.13 MAY2011 zp = []; end if ~isempty(zpp) & (zpp-zp)>farzpp*(messages.setup.wavedet.freq) %#ok %changed from 0.13 MAY2011 zpp = []; end % wave label asignation if isempty(za), % if no waves before qrs Q= qrs; R= zp; S=zpp; % (Q)RS if (isempty(zp) && isempty(zpp)), % no waves before nor after Q=[]; S=qrs; end % QS complex elseif isempty(zp), % if some wave before, but not after Q=zaa; R=za; S=qrs; % QR(S) or R(S) else % if some wave before and some wave after if (~isempty(zpp)) && (~isempty(zaa)) % if two waves before and two after if (abs(apantzaa)>abs(appostzpp)), % forget the smaller of the extreme waves zpp=[]; else zaa=[]; end end % now there are not more than 4 possible waves if ~isempty(zpp), % if 1 wave before and two after if abs(appostzpp)>abs(apantza), % if the second after greater than the wave before Q = qrs; R = zp;S = zpp; % (Q)RS else % if the wave before qrs greater than the secon wave after qrs R = za; % R(S)R' S = qrs; Rprima = zp; end elseif ~isempty(zaa), % if 2 waves before and one after if abs(apantzaa)>abs(appostzp), Q=zaa; R=za; S=qrs; % QR(S) else R=za; S=qrs; Rprima=zp; % R(S)R' end else % if 1 before and one after qrs R=za; S=qrs; Rprima=zp; % R(S)R' end end end Konset = Kq; %constants used for onset and offset detection Koffset = Ks; % Identify the first wave in the complex if ~isempty(Q), firstwave = Q; elseif ~isempty(R), firstwave =R; Konset=Kron; else firstwave = S; Konset = Kron; end % Identify the last wave in the complex if ~isempty(Rprima), lastwave = Rprima; Koffset = Kroff; elseif ~isempty(S), lastwave = S; else lastwave = R; Koffset=Kroff; end % The point of departure for detecting the onset and offset of QRS is a peak in the wavelet transform % Now we identify which peak must we use for onset and for offset of QRS if (firstwave == qrs), piconset=pa; elseif (firstwave == za), piconset=pantza; elseif (firstwave == zaa), piconset = pantzaa; else error('Imposible Condition') end if (lastwave == qrs), picoffset=pp; elseif (lastwave == zp), picoffset=ppostzp; elseif (lastwave == zpp), picoffset = ppostzpp; else error('Imposible Condition') end % Application of derivative criteria: onset of QRS % Search onset by means of a threshold in the wavelet related to the amplitude of the wavelet at the peak %qrson = searchon (piconset, w(piconset-0.08*(messages.setup.wavedet.freq):piconset,2), Konset); %%RUTE: can give error in i=1 if piconset < 0.08*(messages.setup.wavedet.freq) 14Mar06 qrson = searchon (piconset, w(max(1,piconset-round(QRSon_window*(messages.setup.wavedet.freq))):piconset,2), Konset); %14Mar06 % Protection of onsets too far from qrs % If qrs onset more than 120 ms before R wave, there is no Q wave. if (firstwave==Q)&(Q~=qrs), %#ok if ((qrs-qrson)>=firstwaverestriction*(messages.setup.wavedet.freq))||(Q-qrson>=Qwaverestriction*(messages.setup.wavedet.freq)), firstwave = R; if (firstwave == qrs), piconset=pa; elseif (firstwave == za), piconset=pantza; elseif (firstwave == zaa), piconset = pantzaa; end % New search %qrson = searchon (piconset, w(piconset-0.08*(messages.setup.wavedet.freq):piconset,2), Kron); %%RUTE: can give error in i=1 if piconset < 0.08*(messages.setup.wavedet.freq) 14Mar06 qrson = searchon (piconset, w(max(1,piconset-round(QRSon_window*(messages.setup.wavedet.freq))):piconset,2), Kron); Q = []; end end % if first wave is R and qrs onset more than firstwaverestriction w before qrs, there is no R wave. if (firstwave==R)&(lastwave~=R)& (qrs~=R), %#ok %!!!!!!!!! if ((qrs-qrson)>firstwaverestriction*(messages.setup.wavedet.freq))||(R-qrson>=Rwaverestriction*(messages.setup.wavedet.freq)), % 0.2 0.1 % 19Out09 % R = []; % 19Out09 % firstwave = S; % 19Out09 %check qrs morphology if isempty(Rprima)==1 % QS complex (S wave only) firstwave = S; R=[]; else % SRprima -> QR complex R=Rprima; Q=S; S=[]; Rprima=[]; firstwave = Q; end if (firstwave == qrs), piconset=pa; elseif (firstwave == za), piconset=pantza; elseif (firstwave == zaa), piconset = pantzaa; end %qrson = searchon (piconset, w(piconset-0.08*(messages.setup.wavedet.freq):piconset,2), Ks); %%RUTE: can give error in i=1 if piconset < 0.08*(messages.setup.wavedet.freq) 14Mar06 qrson = searchon (piconset, w(max(1,piconset-round(QRSon_window*(messages.setup.wavedet.freq))):piconset,2), Ks); %14Mar06 end end % Application of derivative criteria: offset of QRS qrsoff = searchoff (picoffset, w(picoffset:min(size(w,1),picoffset+round(QRSoff_window*(messages.setup.wavedet.freq))),2), Koffset); % Protection of offsets too far from qrs % If Rprima offset more than 120 ms after S wave, there is no Rprima wave. if (lastwave==Rprima)&(Rprima~=qrs), %#ok if ((qrsoff-qrs)>Rprimarestriction1*(messages.setup.wavedet.freq))||(qrsoff-Rprima>Rprimarestriction2*(messages.setup.wavedet.freq)), lastwave = S; if (lastwave == qrs), picoffset=pp; elseif (lastwave == zp), picoffset=ppostzp; elseif (lastwave == zpp), picoffset = ppostzpp; end qrsoff = searchoff (picoffset, w(picoffset:min(size(w,1),picoffset+round(QRSoff_window*(messages.setup.wavedet.freq))),2), Koffset); Rprima = []; end end % if S offset more than 200 ms after R wave, there is no S wave. if (lastwave==S)&(firstwave~=S)&(S~=qrs), %#ok if ((qrsoff-qrs)>Srestriction1*(messages.setup.wavedet.freq))||(qrsoff-S>Srestriction2*(messages.setup.wavedet.freq)), lastwave = R; if (lastwave == qrs), picoffset=pp; elseif (lastwave == zp), picoffset=ppostzp; elseif (lastwave == zpp), picoffset = ppostzpp; end qrsoff = searchoff (picoffset, w(picoffset:min(size(w,1),picoffset+round(QRSoff_window*(messages.setup.wavedet.freq))),2), Kroff); S = []; end end if isempty(piconset), piconset = NaN; end; % 11.03.09 if isempty(picoffset), picoffset = NaN; end;% 11.03.09 qrspiconset=[qrspiconset piconset]; %#ok qrspicoffset=[qrspicoffset picoffset]; %#ok %%%%% OUT09%%%% main positive and negative wave if exist('apantzaa','var'), if ~isempty(apantzaa), WT_extrema(1,i)=apantzaa; pos_extrema(1,i)=pantzaa;end;end if exist('apantza','var'), if ~isempty(apantza), WT_extrema(2,i)=apantza; pos_extrema(2,i)=pantza; end;end if exist('apa','var'), if ~isempty(apa), WT_extrema(3,i)=apa; pos_extrema(3,i)=pa; end;end if exist('app','var'), if ~isempty(app), WT_extrema(4,i)=app; pos_extrema(4,i)=pp; end;end if exist('appostzp','var'), if~isempty(appostzp), WT_extrema(5,i)=appostzp; pos_extrema(5,i)=ppostzp; end;end if exist('appostzpp','var'), if ~isempty(appostzpp), WT_extrema(6,i)=appostzpp; pos_extrema(6,i)=ppostzpp; end;end if exist('zaa','var'), if ~isempty(zaa), WT_zc(1,i)=zaa; end;end if exist('za','var'), if ~isempty(za), WT_zc(2,i)=za; end;end if exist('qrs','var'), if ~isempty(qrs), WT_zc(3,i)=qrs; end;end if exist('zp','var'), if ~isempty(zp), WT_zc(4,i)=zp; end;end if exist('zpp','var'), if ~isempty(zpp), WT_zc(5,i)=zpp; end;end %%%%%%%% RUTE01MAR2012 aux=[]; if ~isempty(R) aux=find(WT_zc(:,i)==R,1); end if ~isempty(Q) aux=[aux find(WT_zc(:,i)==Q,1)]; %#ok end if ~isempty(S) aux=[aux find(WT_zc(:,i)==S,1)]; %#ok end if ~isempty(Rprima) aux=[aux find(WT_zc(:,i)==Rprima,1) aux]; %#ok end auxaux=NaN(5,1); auxaux(aux)=WT_zc(aux,i); WT_zc(:,i)=auxaux; %%%%%%%%%%%%%%% A=find(~isnan(WT_zc(:,i))); auxaux= WT_extrema(A,i)-WT_extrema(A+1,i); [M,iM]=max(auxaux); %#ok [m,im]=min(auxaux); %#ok pos.QRSmainpos(i)= WT_zc(A(iM),i); pos.QRSmaininv(i)= WT_zc(A(im),i); % maximum slope locations for main wave % 2AGO2011 if ~isempty(pa) pos.QRSpa(i)=pa; else pos.QRSpa(i) = NaN; end if ~isempty(pp) pos.QRSpp(i)=pp; else pos.QRSpp(i) = NaN; end %%%%%%%%%% % Filling the structs of positions if isempty(qrson), qrson = NaN; end; if isempty(qrsoff), qrsoff = NaN; end; if isempty(R), R=NaN; end; if isempty(S), S=NaN; end; if isempty(Q), Q=NaN; end; if isempty(Rprima), Rprima=NaN; end; pos.QRSon(i)= qrson; pos.Q(i) = Q; pos.R(i) = R; pos.S(i) = S; pos.Rprima(i) = Rprima; pos.QRSoff(i) = qrsoff; pos.qrs(i) = qrs; end if ~isempty(intervalo) position.QRSon(intervalo(1):intervalo(2)) = pos.QRSon+samp(1)-1; position.Q(intervalo(1):intervalo(2)) = pos.Q+samp(1)-1; position.R(intervalo(1):intervalo(2)) = pos.R+samp(1)-1; position.S(intervalo(1):intervalo(2)) = pos.S+samp(1)-1; position.Rprima(intervalo(1):intervalo(2)) = pos.Rprima+samp(1)-1; position.QRSoff(intervalo(1):intervalo(2)) = pos.QRSoff+samp(1)-1; position.QRSmainpos(intervalo(1):intervalo(2))= pos.QRSmainpos+samp(1)-1; %28OUT09 position.QRSmaininv(intervalo(1):intervalo(2))= pos.QRSmaininv+samp(1)-1; %28OUT09 position.QRSpa(intervalo(1):intervalo(2))=pos.QRSpa+samp(1)-1;% 2AGO2011 position.QRSpp(intervalo(1):intervalo(2))=pos.QRSpp+samp(1)-1;% 2AGO2011 end