How can I calculate the area under each peak / display the AUC on the graph?

35 views (last 30 days)
Hello, I have a graph that has been normalized to have a baseline of approximately 0. I have a to script to calculate the amplitude and width of peaks, but now i would like to find the area under the curve (AUC) for each peak. I have tried the script suggested here but the AUC seems inaccurate for part of my data. Once I calculate the AUC , how can I plot it on my graph to make bounderlines of each peak are as I expect. Hope someone can help. thanks!
  4 Comments

Sign in to comment.

Accepted Answer

Star Strider
Star Strider on 7 Aug 2021
I decided to give this another try, this time avoiding numerical integration (since it is very difficult to define the pulses), and instead fit a sum-of-exponentials to each pulse, and then analytically integrate the resulting fitted function.
See if it does what you want —
T1 = readtable('https://www.mathworks.com/matlabcentral/answers/uploaded_files/701067/peaks.txt', 'VariableNamingRule','preserve')
T1 = 4800×2 table
Time [s] Amplitude [AU] ________ ______________ 0.092 1.0037 0.141 -0.00069789 0.19 9.18e-05 0.239 0.00075242 0.289 -5.51e-05 0.397 0.014405 0.446 0.079252 0.485 0.15901 0.525 0.15714 0.574 0.11509 0.613 0.089312 0.652 0.071729 0.701 0.056006 0.751 0.042981 0.79 0.036651 0.839 0.030399
t = T1.('Time [s]');
s = T1.('Amplitude [AU]');
t = t(2:end);
s = s(2:end);
[sr,tr] = resample(s,t,151);
sfcn = @(b,x) b(4) + b(1).*x.*(exp(b(2).*x) + exp(b(3).*x));
AUC = @(b,x) - b(4).*(x(1) - x(end)) - b(1).*((exp(b(2).*x(1)).*(b(2)*x(1) - 1))./b(2).^2 - (exp(b(2).*x(end)).*(b(2)*x(end) - 1))./b(2).^2) - b(1)*((exp(b(3)*x(1)).*(b(3).*x(1) - 1))./b(3)^2 - (exp(b(3)*x(end))*(b(3)*x(end) - 1))./b(3)^2);
[pks,locs,fwhm,prom] = findpeaks(sr, 'MinPeakProminence',0.01);
% figure
% plot(tr,sr)
% hold on
% plot(tr(locs),sr(locs),'^r')
% hold off
% grid
% xlim([0 50])
% ylim([-0.01 0.2])
for k = 1:numel(locs)
ixrng = (locs(k)-20:locs(k)+200);
trv = tr(ixrng) - tr(ixrng(1));
B(k,:) = fminsearch(@(b)norm(sr(ixrng) - sfcn(b,trv)), [pks(k)*10 -rand(1,2)*10 0.01]);
sfit{k} = [trv+tr(ixrng(1)), sfcn(B(k,:),trv), ixrng(:)];
Area(k) = AUC(B(k,:),trv);
end
B
B = 13×4
1.3029 -7.7807 -7.7807 0.0006 0.2669 -7.8124 -7.8126 -0.0024 1.2522 -8.7176 -8.7177 0.0016 0.3972 -7.5704 -7.5704 -0.0024 0.9614 -8.1114 -14.2029 0.0014 0.5551 -8.2782 -8.2783 -0.0009 1.0323 -9.2185 -9.2185 0.0017 0.6511 -7.5927 -7.5927 -0.0009 0.3373 -7.9615 -7.9615 -0.0007 0.6078 -8.0836 -8.0837 0.0007
Area(1:7)*1E+3
ans = 1×7
43.9803 5.2608 35.3279 10.3314 21.3830 14.8322 26.7076
Area(8:13)*1E+3
ans = 1×6
21.2254 9.6888 19.6559 14.9595 9.0663 4.2181
figure
plot(tr,sr)
hold on
for k = 1:numel(locs)
plot(sfit{k}(:,1), sfit{k}(:,2),'-r')
end
% plot(tr(locs),sr(locs),'^r')
hold off
grid
text(tr(locs), pks, compose('\\leftarrow Area = %.2fx10^{-3}', Area*1E+3), 'Horiz','left', 'Vert','middle', 'Rotation',90, 'FontSize',7)
xlim([-10 max(tr)])
ylim([-0.01 0.3])
figure
plot(tr,sr)
hold on
for k = 1:numel(locs)
plot(sfit{k}(:,1), sfit{k}(:,2),'-r')
end
% plot(tr(locs),sr(locs),'^r')
hold off
grid
text(tr(locs), pks, compose('\\leftarrow Area = %.2fx10^{-3}', Area*1E+3), 'Horiz','left', 'Vert','middle', 'Rotation',90, 'FontSize',7)
xlim([-2 25])
ylim([-0.01 0.3])
title('Subset Showing Detail')
Because it uses nonlilnear parameter estimation techniques, it does not always give the same results.
figure
for k = 1:numel(locs)
subplot(5,3,k)
plot(tr(sfit{k}(:,3)), sr(sfit{k}(:,3)),'-b')
hold on
plot(sfit{k}(:,1), sfit{k}(:,2),'-r')
hold off
grid
title(sprintf('Peak #%2d',k))
end
The fits are not perfect, however they are acceptably close.
Make appropriate changes to get the result you want.
.
  2 Comments
Marc Forrest
Marc Forrest on 9 Aug 2021
Hi, this is really great! the values correlate extremely well with Amplitude and AmpxWidth, as I would expect.
The 13 peaks are very well defined and the displays at the end are very helpful to understand how the AUC is extimated. thanks so much! this is what I needed.
Star Strider
Star Strider on 9 Aug 2021
As always, my pleasure!
It might be possible to get even better fits by wrapping the fminsearch call in a loop to run perhaps 10 times for each peak, getting the second output from fminsearch as well (the residual norm metric), then return as ‘B’ the parameter set with the lowest residual norm. This is sort of a simple genetic algorithgm approach, and would likely increasse the accuracy of the estimates. (I only thought about that later, after I submitted this.)
.

Sign in to comment.

More Answers (1)

Kumar Pallav
Kumar Pallav on 6 Aug 2021
I have executed the code you provided, and have plotted the same, and I see there are 13 peaks.
x = 0:numel(data(:,2))-1;
secondCol=data(:,2);
[pks,locs] = findpeaks(data(:,2),'MinPeakDistance',1,'MinPeakProminence',0.01)
%computing Cumulative trapezoidal numerical integration
IntTot = cumtrapz(x,data(:,2));
%calculating peak area
IntPks = diff(IntTot(locs));
%plot the peaks
findpeaks(data(:,2))
%numbered the peaks from variable "pks"
text(locs+.02,pks,num2str((1:numel(pks))'))
You can find the local extrema’s in the live editor.
You can hover the mouse over the points to get the coordinates and use it to calculate area. (Update “locs” vector to set ranges).Refer the following document for details on local extrema’s.
Please refer to the following document for more details on “findpeak” and on “cumtrapz” function.
  5 Comments
Kumar Pallav
Kumar Pallav on 6 Aug 2021
Hi Marc,
You can find local minimas by passing the negative of the input data to "findpeaks" function.
%Negate the input data to obtain minima locations
[pks,locs] = findpeaks(-data(:,2),'MinPeakDistance',1,'MinPeakProminence',0.01)
Now, the "locs" vector is having the coordinates of local minima's, just pass this vector and calculate AUC between local minima's bordering each peak in the same way as done in code shared previously.
Marc Forrest
Marc Forrest on 9 Aug 2021
Hi Kumar,
I will also try this analysis to see if it works. Thanks for your suggestions!

Sign in to comment.

Products


Release

R2020a

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!