Cardiac Output Estimation from Arterial Blood Pressure Waveforms 1.0.0

File: <base>/code/3estimate/estimateCO.m (4,546 bytes)
function [co, to, told, fea] = estimateCO(fname,estID,filt_order)
% ESTIMATECO  Cardiac output estimator.
%   [CO, TO, TOLD, FEA] = ESTIMATECO(FNAME, ESTID, FILT_ORDER) is the 
%   main function for estimating cardiac output.  
%
%   In:   FNAME      <1xn>  --- file where ABP and features are located
%         ESTID      <1x1>  --- the CO estimator to use
%         FILT_ORDER <1x1>  --- order of running avg LPF to use on output 
%                                      (enter 0 or 1 for no LPF)
%
%   Out:  CO         <kx1>  --- estimated CO (uncalibrated)
%         TO         <kx1>  --- time [minutes] (not evenly sampled!)
%         TOLD       <mx1>  --- time [minutes], not sqi filtered
%         FEA        <kx11> --- feature matrix
% 
%   Usage:
%   This function is only a wrapper.  Actual CO estimation computation is 
%   done in the following required functions:
%   ESTID 1: est01_MAP      - Mean pressure
%         2: est02_WK       - Windkessel 1st order LTI RC circuit model
%         3: est03_SA       - Systolic area distributed model
%         4: est04_SAwarner - Warner systolic area with time correction
%         5: est05_Lilj     - Liljestrand PP/(Psys+Pdias) estimator
%         6: est06_Herd     - Herd estimator
%         7: est07_SAwessCI - Wesseling systolic area with impedance correction
%         8: est08_Pulsion  - Pulsion non-linear compliance model
%         9: est09_LidCO    - LidCO root-mean-square model
%        10: est10_RCdecay  - RC exponential decay fit
%        11: est11_mf       - Wesseling non-linear, time-varying 3-element model
%
%   Written by James Sun (xinsun@mit.edu) on Nov 19, 2005.
%   - v2.0 - 1/18/06 - added output for detecting percentage of good beats
%   - v3.0 - 1/20/06 - added "feature" output, CO no longer normalized

% load features from fname
load(fname,'F','onset','sqi','t0','m2t');
load agegender

co = [];
to = [];
told=[];
fea = [];
for seg=1:size(t0,1)  % loop through each ABP waveform segment
%seg
    onset1 = onset{seg};

    % skip segment if too little data
    if length(onset1)<50 || length(onset1)<(3*filt_order)
        continue
    end

    % read features
    F1      = F{seg};
    Psys    = F1(:,2);
    Pdias   = F1(:,4);
    PP      = F1(:,5);
    MAP     = F1(:,6);
    Period  = F1(:,7);
    HR      = 60*125./Period; 
    tSArr   = F1(:,9);
    SArr    = F1(:,10);
    tSAcosm = F1(:,11);
    SAcosm  = F1(:,12);

    % select systolic area estimate
    SA      = SArr;
    tSA     = tSArr;

    % special items for estID 8,9,11
    if estID==11
        caseid = m2t.caseid;
        ind = find(agegender(:,1)==caseid);
        % quit if no age, gender info found
        if isempty(ind)
            continue
        end
        age = agegender(ind,3);
        gender = agegender(ind,4);
    end
    
    if estID==8 || estID==9 || estID==11
        str = sprintf('load %s abp%d',fname,seg); eval(str);
        str = sprintf('abp=abp%d; clear abp%d',seg,seg); eval(str);
    end

    
    % estimate CO!
    switch estID
        case  1,   x = est01_MAP(MAP);
        case  2,   x = est02_WK(PP,HR);
        case  3,   x = est03_SA(SA,HR);
        case  4,   x = est04_SAwarner(SA,HR,onset1,tSA);
        case  5,   x = est05_Lilj(PP,HR,Psys,Pdias);
        case  6,   x = est06_Herd(MAP,Pdias,HR);
        case  7,   x = est07_SAwessCI(MAP,SA,HR);
        case  8,   x = est08_Pulsion(abp, onset1, MAP, HR, tSA);
        case  9,   x = est09_LidCO(abp,onset1,HR);
        case 10,   x = est10_RCdecay(Period,Psys,Pdias,MAP);
        case 11,   x = est11_mf(abp,onset1,MAP,HR,age,gender);
        case 12,   x = est12_coalees(PP,HR,onset1,tSA,Psys,Pdias);
        case 13,   x = est13_trivial(PP,HR,MAP);
        otherwise, x = nan;
    end
    
    % synchronize time of of all segments
    offset = (t0(seg,1)-t0(1,1))*24*60;
    t      = onset1(1:end-1)/(125*60)+offset; %[min]

    % remove all datapoints with bad SQI
    sqi1   = sqi{seg}(:,1);
    ind    = find(sqi1);
    t_old  = t;
    x(ind) = [];
    t(ind) = [];

    % apply zero-phase moving avg LPF
    if filt_order<2, x_filt = x;
    else             x_filt = filtfilt(ones(filt_order,1)/filt_order,1,x);
    end

    % features
    ff = F{seg};
    ff(ind,:) = [];
    
    % append segment data to pool
    co = [co; x_filt];
    to = [to; t];
    told = [told; t_old];
    fea = [fea; ff];
end

% normalize estimated CO to 1st point
%co = co/co(1);