ECG-Kit 1.0

File: <base>/common/wavedet/wavedet.m (13,816 bytes)
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