TWAnalyser - A T-wave Alternans Detector 1.0.0

File: <base>/twa-mfiles/FindFiducials.m (4,368 bytes)
function Align = FindFiducials(ecg, q, s, Align)
% FindFiducials.m
% Author: Alexander Khaustov; alexander dot khaustov at gmail dot com 
% Copyright (C) 2008 St.-Petersburg Institute of Cardiological Technics (Incart), www.incart.ru
% This software is released under the terms of the GNU General
% Public License (http://www.gnu.org/copyleft/gpl.html).
% 
% finds the lead with maximum QRS amplitude, takes a beat as QRS template and finds fiducial points such that
% aligned beats have maximum cross-correlation (over Q to S or S to T interval) in the chosen
% lead against the template
%
% no attempt has been made to make this code computationally effective

global Param
q = q(1:min(length(q), length(s)));
s = s(1:min(length(q), length(s)));

leadSorted = SortLeads(ecg, q, s, Align.st);

for ilead = 1:length(leadSorted)
    Align.lead = leadSorted(ilead);

    Align.orientation = MaxFrontOrientation(ecg(:, Align.lead), q, s);

    Align.fidBase = FindFidBase(ecg(:, Align.lead), q, s, Align.orientation);


    Align.f2s = floor(median(s - Align.fidBase) + Param.stAdjIntv);   % reserve to avoid including part of QRS in ST interval computations
    Align.q2f = floor(median(Align.fidBase - q));
    Align.fid = [];
    NFailed = 0;

    Align.template = 0;
    while isempty(Align.fid)
        %    template = floor(rand * length(s)) + 1;
        Align.template = Align.template + 1;
        %disp(['template beat - ' num2str(Align.template)]);

        Align = Adjust(ecg, Align);
        if isempty(Align.fid)

            %       disp('doesn''t do...');
            NFailed = NFailed + 1;
            if (NFailed > 0.1 * length(s))
                %          disp('what a mess..');
                break;
            end;
        end;
    end;
    if (~isempty(Align.fid))
        for i = 1:length(Align.fid)
            for lead=1:size(ecg, 2)
                Align.amp(i, lead) = mean(ecg(Align.fidQRS(i) - Align.q2f : Align.fidQRS(i) + Align.f2s, lead));  % align to zero mean on QS segment
            end;
        end;
        Align = CheckLeadCorrelations(ecg, Align);
        disp(['FindFiducials: Alignment in lead ' num2str(Align.lead)]);
        break;
    end;
    disp(['FindFiducials: lead ' num2str(Align.lead) ' is too noisy or ectopic..']);
end;
return;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function leads = SortLeads(ecg, q, s, st)

NLead = size(ecg, 2);

global Param
%   QRS or T amplitudes in each lead
ptp = zeros(min(length(q), 8),NLead);
for i = 1:min(length(q), 8)
    for l = 1:NLead
        if strcmp(Param.Alignment, 'st')
            ptp(i, l) = max(ecg(s(i):s(i) + st, l)) - min(ecg(s(i):s(i) + st, l));
        else
            ptp(i, l) = max(ecg(q(i):s(i), l)) - min(ecg(q(i):s(i), l));
        end;
    end;
end;
ptpmed = zeros(1,NLead);
for i = 1:NLead
    ptpmed(i) = median(ptp(:, i));
end;

[sorted indices] = sort(ptpmed);
leads = indices(length(indices):-1:1);
return;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function Align = Adjust(ecg, Align)

global Param

qs_templ = ecg((Align.fidBase(Align.template) - Align.q2f):(Align.fidBase(Align.template) + Align.f2s), Align.lead);
st_templ = ecg((Align.fidBase(Align.template) + Align.f2s):(Align.fidBase(Align.template) + Align.f2s + Align.st), Align.lead);

[a b c d] = AdjustFiducials(ecg, Align.fidBase, Align.q2f, Align.f2s, qs_templ, Align.st, st_templ);

if ~isempty(c)
    Align.fidQRS = a;
    Align.QRScorr(:, Align.lead) = b;
    Align.fid = c;
    Align.Tcorr(:, Align.lead) = d;
    amp = mean(qs_templ);
    Align.qs_templ(:, Align.lead) = qs_templ - amp;
    Align.st_templ(:, Align.lead) = st_templ - amp;
    
    for i = 1:length(Align.fid)
        Align.valid(i, Align.lead) = (Align.QRScorr(i, Align.lead) >= Param.corrQRS) && (Align.Tcorr(i, Align.lead) >= Param.corrT);
    end;
    Align.validleads(Align.lead) = true;
end;

return;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function orientation = MaxFrontOrientation(ecg, q, s)

NPos = 0;

for i = 1:min(20, length(s))
    [ma maI] = max(ecg(q(i):s(i)));
    [mi miI] = min(ecg(q(i):s(i)));

    NPos = NPos + (maI > miI);
end;

orientation = (NPos > 10);

return;