ECG-Kit 1.0

File: <base>/common/wavedet/pwavef.m (15,867 bytes)
function     [position,picon_all,picoff_all,messages]= pwavef(heasig,samp,time,position,w,intervalo,ultimo_anot,messages)
% script which identifies P wave, as well as its onset and offset
% admits 4 P wave morphologies: normal, inverted, biphasic +- and biphasic -+
% looking on the scale n=4 first and then if not found looking on the scale n=5
% scale m=3 for zero crossings
% if there is not P peak, there are not onset and offset either
% if there is no zero croosing in the scale m, look for it in scale n
%
%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
%   ultimo_anot:
%
%Output Parameters:
%   actualized parameters: position
%
% Rute Almeida 
% based on pwave.m by Juan Pablo Martínez Cortés
% Last update: Rute Almeida 07FEB2012
%
% Designed for MATLAB Version R12; tested with MATLAB Version R13
%
% Initialization of auxiliary variables
P = [];  picon=[]; picoff=[]; Pon=[]; Poff=[]; % alterado a 11/09/02
Pprima=[]; %Rute 28/06/02
picon_all=[];picoff_all=[];
% changes=[1 2 3 4 5]; % codes of the new strategies to apply % Rute 08/08/02
changes=[1 2 4 5]; % 3 look for peak on scale 3 instead of scale n

if nargin<8
    messages.warnings=[];
elseif nargin<7
    messages.errors=[messages.errors {'Fatal error in wavedet_3D\pwavef: not enough inputs.'}];
    warning(char(messages.errors(end)))
    messages.errors_desc=[messages.errors_desc 'Mandatory inputs not defined.'];
    messages.status=0;
    return
end
if ~isfield(messages,'setup'), messages.setup.wavedet=[]; end
if ~isfield(messages,'errors'), messages.errors=[]; end
if ~isfield(messages,'errors_desc'), messages.errors_desc=[]; end
if ~isfield(messages,'warnings'), messages.warnings=[]; end
if isfield(messages,'status')
    if messages.status~=1
        messages.warnings=[messages.warnings {['Initial status=' num2str(messages.status) '. status changed to 1']}];
    end
end
messages.status=1;
if isempty(heasig)
end

%%%%%% Constants and Thresholds  !!!!!!!!!!!!!!!!!!!!!!!!!
if ~isfield(messages.setup.wavedet,'umbraldetP')
    messages.setup.wavedet.umbraldetP = 0.02;%0.15;  % umbraldet*sqrt(mean(w(time(i):time(i+1),4).^2))
end
if ~isfield(messages.setup.wavedet,'umbralsig')
    messages.setup.wavedet.umbralsig = 1/8; %Rute 28/06/02 %threshold to decide if there is or not a significative P wave.
end
if ~isfield(messages.setup.wavedet,'inivent_tol_P')
    messages.setup.wavedet.inivent_tol_P  =  0.34;
end
if ~isfield(messages.setup.wavedet,'finvent_tol_P')
    messages.setup.wavedet.finvent_tol_P  =  0.05;  % 0.1 it seems to be larger
end
if ~isfield(messages.setup.wavedet,'Kpon')
    messages.setup.wavedet.Kpon = 2;% 3 ;         
end
if ~isfield(messages.setup.wavedet,'Kpoff')
    messages.setup.wavedet.Kpoff=  1.1;         % 1.35;
end

if ~isfield(messages.setup.wavedet,'P_bound_tol')
    messages.setup.wavedet.P_bound_tol=0.1;%sec
end
if ~isfield(messages.setup.wavedet,'min_vent_P')
    messages.setup.wavedet.min_vent_P=0.1;%sec
end

umbraldetP=messages.setup.wavedet.umbraldetP; %#ok<NASGU>  It is used in pwave_task1 script
umbralsig=messages.setup.wavedet.umbralsig;
Kpon= messages.setup.wavedet.Kpon;
Kpoff=messages.setup.wavedet.Kpoff;

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%for i = 1:length(time)
if ~isempty(intervalo)
    for i = 1:length(unique(intervalo(1):intervalo(end)))
        maxapos=[];
        minapos=[];
        minppos=[];
        maxppos=[];
        % First know (or guess) were is the QRS onset for this beat    

        if ~isnan(position.QRSon(i+intervalo(1)-1)) && (position.QRSon(i+intervalo(1)-1)-samp(1)+1)<time(i)
            qrson = position.QRSon(i+intervalo(1)-1)-samp(1)+1;
        else
            qrson = time(i) - round(messages.setup.wavedet.finvent_tol_P*messages.setup.wavedet.freq);
        end

        %inivent = round(0.2*messages.setup.wavedet.freq);
        inivent = round(messages.setup.wavedet.inivent_tol_P*messages.setup.wavedet.freq);
        if (i-1+intervalo(1)-1)>1,   % Protection, window to begin after Toff of last beat
            if ~isnan(position.Toff(i-1+intervalo(1)-1)),
                inivent = min(inivent, qrson-(position.Toff(i-1+intervalo(1)-1)-samp(1)+1));
            elseif ~isnan(position.T(i-1+intervalo(1)-1)),                          % Rute 28/01/03
                inivent = min(inivent, qrson-(position.T(i-1+intervalo(1)-1)-samp(1)+1));       % Rute 28/01/03
            elseif ~isnan(position.QRSoff(i-1+intervalo(1)-1)),                     % Rute 28/01/03
                inivent = min(inivent, qrson-(position.QRSoff(i-1+intervalo(1)-1)-samp(1)+1));  % Rute 28/01/03
            else                                                % Rute 28/01/03
                inivent = min(inivent, round(qrson-(position.qrs(i-1+intervalo(1)-1)-samp(1)+1)));     % Rute 8/10/08
            end
        end 
       finvent = round(messages.setup.wavedet.finvent_tol_P*messages.setup.wavedet.freq);
        ultimo_anot = ultimo_anot - samp(1)+1;
        % last anotation of the previous segment can overlap with the present one
        if (i==1 && ultimo_anot>=1),   % Protection in case it is the first beat
            begwin = round(max([1 qrson-inivent+1 ultimo_anot+1]));
        else
            begwin = round(max(1, qrson-inivent+1));
        end
        endwin =  round(max(1,qrson- finvent+1)); %27SEP2011
        if endwin-begwin>=messages.setup.wavedet.min_vent_P*messages.setup.wavedet.freq; %27SEP2011
            n=4;    % We work at scale 4 first
            pwave_task1 % subtask finding extreme points and deciding if there is wave is the scale n
            if ~hay_onda,   % look in the scale 5
                n=5;
                pwave_task1 % subtask finding extreme points and deciding if there is wave is the scale n
            end
        else
            hay_onda=0;
        end
        % deciding the morphology and marking the peak(s), onset and offset on the scale n
        if hay_onda && (sum(changes==2)==1 || n==4)

            if sum(changes==3)==1
                m=3; % zero crossings in the m scale
            else
                m=n; % zero crossings in the m=n scale
            end
            if sum(changes==1)==1%%%%%look for other significant extreme points - biphasic P waves %%%%%%%%%%%Rute 28/06/02
                if absmax>absmin % look for a minimum in opposite side to absmin
                    if maxpos < minpos, % look for a minimum before maxpos
                        minapos = begwin + modmax(w(begwin+1:maxpos,n),2,0,-1); % minimum of minima
                        [minaim ind] = min(w(minapos,n));
                        minapos = minapos(ind);
                        if abs(minaim)<umbralsig*absmax; % non significant
                            minapos=[];
                        end
                    else %look for a minimum after maxpos
                        minppos = maxpos + modmax(w(maxpos+1:endwin,n),2,0,-1); % minimum of minima
                        [minpim ind] = min(w(minppos,n));
                        minppos = minppos(ind);
                        if abs(minpim)<umbralsig*absmax % non significant
                            minppos=[];
                        end
                    end
                else % look for a maximum in opposite side to absmax
                    if minpos<maxpos, % look for a maximum before minpos
                        maxapos = begwin + modmax(w(begwin+1:minpos,n),2,0,1); % maximum of maxima
                        [maxaim ind] = max(w(maxapos,n));
                        maxapos = maxapos(ind);
                        if abs(maxaim)<umbralsig*absmin % non significant
                            maxapos=[];
                        end
                    else % look for a maximum after minpos
                        maxppos = minpos + modmax(w(minpos+1:endwin,n),2,0,1);% maximum of maxima
                        [maxpim ind] = max(w(maxppos,n));
                        maxppos = maxppos(ind);
                        if abs(maxpim)<umbralsig*absmin  % non significant
                            maxppos=[];
                        end
                    end
                end
            end
            %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%Rute 28/06/02
            if isempty(maxapos)&& isempty(minapos)&&isempty(maxppos)&& isempty(minppos) %Rute 28/06/02
                if maxpos < minpos %normal P wave
                    Ptipo=1;
                    if minpos - maxpos >2,
                        ind = zerocros(w(maxpos:minpos,m));   % First zero crossing after maxpos
                        if isempty(ind) && sum(changes==5)==1 % look in  the n scale %Rute 29/07/02
                            ind = zerocros(w(maxpos:minpos,n));
                        end
                        P = maxpos + ind -1;
                        picon = maxpos;                       % For detecting onset and offset
                        picoff = minpos;
                    else %Rute 28/06/02
                       messages.warnings=[messages.warnings {'unknown case: unable to classify P wave'}];   
                    end
                else  %inverted P wave
                    Ptipo=0;
                    if maxpos -minpos >2,
                        ind = zerocros(w(minpos:maxpos,m));   % First zero crossing after minpos
                        if isempty(ind) && sum(changes==5)==1 % look in  the n scale %Rute 29/07/02
                            ind = zerocros(w(minpos:maxpos,n));
                        end
                        P = minpos + ind -1;
                        picon = minpos;                       % For detecting onset and offset
                        picoff = maxpos;
                    else %Rute 28/06/02
                       messages.warnings=[messages.warnings {'unknown case: unable to classify P wave'}];  
                    end
                end
                %%%%%%%%%%%%%%%%%%%%%%%%%%%% Rute 22/07/02 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
            elseif ~isempty(maxapos)|| ~isempty(maxppos) % P bifasica + -
                Ptipo=4;
                [extra]= sort([minpos maxpos maxapos maxppos]);
                if extra(2)-extra(1) >2,
                    ind = zerocros(w(extra(1):extra(2),m));   % First zero crossing after picon
                    if isempty(ind) && sum(changes==5)==1 % look in  the n scale %Rute 29/07/02
                        ind = zerocros(w(extra(1):extra(2),n));
                    end
                    P = extra(1) + ind -1;
                    picon=extra(1); % For detecting onset, offset
                else
                       messages.warnings=[messages.warnings {'unknown case: unable to classify P wave'}];  
                end
                if extra(3)-extra(2) >2,
                    ind = zerocros(w(extra(2):extra(3),m));   % First zero crossing after extra
                    if isempty(ind) && sum(changes==5)==1 % look in  the n scale %Rute 29/07/02
                        ind = zerocros(w(extra(2):extra(3),n));
                    end
                    Pprima = extra(2) + ind -1;
                    picoff=extra(3); % For detecting onset, offset
                else %Rute 28/06/02
                       messages.warnings=[messages.warnings {'unknown case: unable to classify P wave'}];  
                end
            elseif ~isempty(minapos)|| ~isempty(minppos) % P bifasica - +
                Ptipo=5;
                [extra]= sort([minpos maxpos minapos minppos]); % For detecting onset, offset and intermediate extreme
                if extra(2)-extra(1) >2,
                    ind = zerocros(w(extra(1):extra(2),m));   % First zero crossing after picon
                    if isempty(ind) && sum(changes==5)==1 % look in  the n scale %Rute 29/07/02
                        ind = zerocros(w(extra(1):extra(2),n));
                    end
                    P = extra(1) + ind -1;
                    picon=extra(1); % For detecting onset, offset
                else %Rute 28/06/02
                       messages.warnings=[messages.warnings {'unknown case: unable to classify P wave'}];  
                end
                if extra(3)-extra(2) >2,
                    ind = zerocros(w(extra(2):extra(3),m));   % First zero crossing after extra
                    if isempty(ind) && sum(changes==5)==1 % look in  the n scale %Rute 29/07/02
                        ind = zerocros(w(extra(2):extra(3),n));
                    end
                    Pprima = extra(2) + ind -1;
                    picoff=extra(3); % For detecting onset, offset
                else %Rute 28/06/02
                       messages.warnings=[messages.warnings {'unknown case: unable to classify P wave'}];  
                end
            else
                messages.warnings=[messages.warnings {'unknown case: unable to classify P wave'}];  
                Ptipo=NaN;
            end  %%%%%%%%%%%%%%%%%%%%%%%%%%%% Rute 22/07/02 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
            % P wave onset and offset detection
            if ~isempty(picon),
                Pon = searchon (picon, w(max(begwin,picon-round(messages.setup.wavedet.P_bound_tol*messages.setup.wavedet.freq)):picon,n), Kpon);
            end
            if ~isempty(picoff),
                Poff=searchoff(picoff, w(picoff:min(picoff+round(messages.setup.wavedet.P_bound_tol*messages.setup.wavedet.freq),endwin),n), Kpoff);
            end
            if isempty(P)&& sum(changes==4)==1
                Pon=[];Poff=[];P=[]; % Rute 25/07/02
            end
            if (isempty(Pon) || isempty(Poff)),
                Pon=[];Poff=[];P=[]; %  Why?!!!!!!!!!
            end
            maxapos=[]; maxppos=[];minapos=[];minppos=[];  %#ok<NASGU>
            maxpos=[]; minpos=[];
        else
            maxpos=[]; minpos=[];
        end
        % If maxima too small or too separated, there is no P wave
        % Filling the structure with positions
        if isempty(Pon), Pon = NaN; end;
        if isempty(Poff), Poff = NaN; end;
        if isempty(P), Ptipo=NaN; end;
        if isempty(P), P=NaN; n=NaN; end;
        if isempty(Pprima), Pprima=NaN; end; % Rute 22/07/02
        if isempty(picoff), picoff=NaN; end; % Rute 23/02/10
        if isempty(picon), picon=NaN; end; % Rute 23/02/10
        pos.Pon(i) = Pon;
        pos.Poff(i) = Poff;
        pos.P(i) = P;
        pos.Pprima(i) = Pprima; % Rute 22/07/02
        picon_all=[picon_all picon]; %#ok<AGROW>
        picoff_all=[picoff_all picoff]; %#ok<AGROW>
        P = [];  picon=[]; picoff=[]; Pon=[]; Poff=[];
        Pprima=[];% Rute 22/07/02
        pos.Pscale(i) = n;
        pos.Ptipo(i)=Ptipo;
    end

    if exist('pos','var')
        position.Pon(intervalo(1):intervalo(2)) = pos.Pon+samp(1)-1;
        position.Poff(intervalo(1):intervalo(2))=  pos.Poff+samp(1)-1;
        position.P(intervalo(1):intervalo(2)) = pos.P+samp(1)-1;
        position.Pprima(intervalo(1):intervalo(2)) = pos.Pprima+samp(1)-1; % Rute 22/07/02
        position.Pscale(intervalo(1):intervalo(2)) = pos.Pscale; % Rute 22/07/02
        position.Ptipo(intervalo(1):intervalo(2)) = pos.Ptipo; % Rute 22/07/02
    elseif ~isempty(intervalo)
        position.Pon(intervalo(1):intervalo(2)) = NaN;
        position.Poff(intervalo(1):intervalo(2))=  NaN;
        position.P(intervalo(1):intervalo(2)) = NaN;
        position.Pprima(intervalo(1):intervalo(2)) = NaN; % Rute 22/07/02
        position.Pscale(intervalo(1):intervalo(2)) =NaN;
        position.Ptipo(intervalo(1):intervalo(2))=NaN;
    end
end