ECG-Kit 1.0

File: <base>/common/wavedet/qrswavef.m (41,147 bytes)
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<NASGU>
    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<NASGU>
        % 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<AND2> % 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)<umbral1a*dermax) %#ok<OR2>   % 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)<umbral2a*dermax), %#ok<OR2> % 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)<umbral1p*dermax),     %#ok<OR2>    % 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)<umbral2p*dermax),  %#ok<OR2> % 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<AND2> % 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<AND2> % 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<AND2> % 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<AND2> % 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)<umbral1a*dermax)%#ok<OR2>
                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)<umbral2a*dermax), %#ok<OR2>
                        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)<umbral1p*dermax), %#ok<OR2>
                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)<umbral2p*dermax), %#ok<OR2>
                        zpp=[];
                    elseif(isempty(ppostzpp))
                        zpp=[];
                    end
                end
            end
        end
        
        if (isempty(zaa)) & (qrs-za)>farza*(messages.setup.wavedet.freq), %#ok<AND2> %changed from 0.16 MAY2011
            za = [];   % Si 1º onda m
        end
        if ~isempty(zaa) & (za - zaa)> farzaa*(messages.setup.wavedet.freq), %#ok<AND2> %changed from 0.08 MAY2011
            zaa=[];
        end
        
        if isempty(zpp) & (zp-qrs)>farzp*(messages.setup.wavedet.freq),%#ok<AND2> %changed from 0.13 MAY2011
            zp = [];
        end
        if ~isempty(zpp) & (zpp-zp)>farzpp*(messages.setup.wavedet.freq) %#ok<AND2> %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<AND2>
        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<AND2> %!!!!!!!!!
        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<AND2>
        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<AND2>
        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<AGROW>
    qrspicoffset=[qrspicoffset picoffset]; %#ok<AGROW>
    
   
    
    %%%%% 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<AGROW>
    end
    if ~isempty(S)
        aux=[aux find(WT_zc(:,i)==S,1)]; %#ok<AGROW>
    end
    if ~isempty(Rprima)
        aux=[aux find(WT_zc(:,i)==Rprima,1) aux]; %#ok<AGROW>
    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<ASGLU>
    [m,im]=min(auxaux); %#ok<ASGLU>
    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