function r = abpfeature(abp,OnsetTimes)
% ABPFEATURE  ABP waveform feature extractor.
%   r = ABPFEATURE(ABP,ONSETTIMES) extracts features from ABP waveform such
%   as systolic pressure, mean pressure, etc.
%
%   In:   ABP (125Hz sampled), times of onset (in samples)
%   Out:  Beat-to-beat ABP features
%           Col 1:  Time of systole   [samples]
%               2:  Systolic BP       [mmHg]
%               3:  Time of diastole  [samples]
%               4:  Diastolic BP      [mmHg]
%               5:  Pulse pressure    [mmHg]
%               6:  Mean pressure     [mmHg]
%               7:  Beat Period       [samples]
%               8:  mean_dyneg
%               9:  End of systole time  0.3*sqrt(RR)  method
%              10:  Area under systole   0.3*sqrt(RR)  method
%              11:  End of systole time  1st min-slope method
%              12:  Area under systole   1st min-slope method
% 
%   Usage:
%   - OnsetTimes must be obtained using wabp.m
%
%   Written by James Sun (xinsun@mit.edu) on Nov 19, 2005.


% if length(OnsetTimes)<30 % don't process anything if too little onsets
%     r = [];
%     return
% end

%% P_sys, P_dias

Window    = 40;
OT        = OnsetTimes(1:end-1);
BeatQty   = length(OT);

[MinDomain,MaxDomain] = init(zeros(BeatQty,Window));
for i=1:Window
    MinDomain(:,i) = OT-i+1;
    MaxDomain(:,i) = OT+i-1;
end
MinDomain(MinDomain<1) = 1;  % Error protection
MaxDomain(MaxDomain<1) = 1;

[P_dias Dindex]  = min(abp(MinDomain),[],2);
[P_sys  Sindex]  = max(abp(MaxDomain),[],2);
% warning(['BeatQty: ', num2str(BeatQty)])
% warning(['Length of Dindex: ', num2str(length(Dindex))])
% warning(['Dindex: ', num2str(Dindex')])
DiasTime         = MinDomain(sub2ind(size(MinDomain),(1:BeatQty)',Dindex));
SysTime          = MaxDomain(sub2ind(size(MaxDomain),(1:BeatQty)',Sindex));

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Pulse Pressure [mmHg]
PP         = P_sys - P_dias;

% Beat Period [samples]
BeatPeriod = diff(OnsetTimes);

% Mean,StdDev, Median Deriv- (noise detector)
dyneg          = diff(abp);
dyneg(dyneg>0) = 0;

[MAP,stddev,mean_dyneg] = init(zeros(BeatQty,1));
for i=1:BeatQty
    interval       = abp(OnsetTimes(i):OnsetTimes(i+1));
    MAP(i)         = mean(interval);
    stddev(i)      = std(interval);

    dyneg_interval = dyneg(OnsetTimes(i):OnsetTimes(i+1));
    dyneg_interval(dyneg_interval==0) = [];
    if min(size(dyneg_interval))==0
        dyneg_interval = 0;
    end
    mean_dyneg(i)  = mean(dyneg_interval);
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Systolic Area calculation using 0.3*sqrt(RR)
RR                  = BeatPeriod/125;  % RR time in seconds
sys_duration        = 0.3*sqrt(RR);
EndOfSys1           = round(OT + sys_duration*125);
SysArea1            = localfun_area(abp,OT,EndOfSys1,P_dias);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Systolic Area calculation using 'first minimum slope' method
SlopeWindow         = 35;
ST                  = EndOfSys1; % start 12 samples after P_sys

if ST(end) > (length(abp)-35)   % error protection
    ST(end) = length(abp)-35;
end

SlopeDomain = zeros(BeatQty,SlopeWindow);
for i=1:SlopeWindow
    SlopeDomain(:,i) = ST+i-1;
end
% y[n] = x[n]-x[n-1]
Slope              = diff(abp(SlopeDomain),1,2);
Slope(Slope>0)     = 0; % Get rid of positive slopes

[MinSlope index]   = min(abs(Slope),[],2);
EndOfSys2          = SlopeDomain(sub2ind(size(SlopeDomain),(1:BeatQty)',index));
SysArea2           = localfun_area(abp,OT,EndOfSys2,P_dias);

% OUTPUT:
r = [SysTime'
     P_sys'
     DiasTime'
     P_dias'
     PP'
     MAP'
     BeatPeriod'
     mean_dyneg'
     EndOfSys1'
     SysArea1'
     EndOfSys2' 
     SysArea2']';
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Helper function:

function SysArea = localfun_area(abp,onset,EndSys,P_dias)
%% Input:  abp,
%%         onset, P_dias, end of systole, beat duration in unit of samples, same length
%% Output: systolic area, warner correction factor

BeatQty = length(onset);
SysArea = init(zeros(BeatQty,1));
for i=1:BeatQty
    SysArea(i) = sum(abp(onset(i):EndSys(i))); % faster than trapz below
    %b(i) = trapz(abp(onset(i):EndSys(i)));
end

SysPeriod  = EndSys     - onset;

% Time scale and subtract the diastolic area under each systolic interval
SysArea = (SysArea - P_dias.*SysPeriod)/125; % Area [mmHg*sec]
end

% for initializing a variable
function varargout = init(z)
for i=1:nargout
    varargout(i) = {z};
end
end