Peak Width at Half Height

I started using MATLAB only a few days ago. And I have trouble finding the width of peak. I have two subplots, both of which represent one peak from the data only. I want to know the width of peak at half distance. I also want the line representing width to be displayed on the plot. Please tell me how this can be done.
I searched the internet for help but could not get the desired result.
Here is my code for both graphs:
subplot(2,1,1)
plot(Hwave,Hintense,'.'),title('Original data'),xlabel('Wavelength'),ylabel('Intensity')
axis tight, grid
subplot(2,1,2)
plot(Hwaveinter,Hreal,'.'),title('Eight Times Interpolated Data'),xlabel('Wavelength'),ylabel('Intensity')
axis tight, grid
Thanks

3 Comments

Adam Danz
Adam Danz on 10 Mar 2020
Edited: Adam Danz on 10 Mar 2020
Could we see an example curve or two? A simple approach would be shift the curve so its baseline is a y=0 find the peak using max(), find the corresponding y value at half the height of the peak, and then get the corresponding x values on each side of the curve where y equals half-height. But that simple approach may not work with some curves.
I have attached the image
Image Analyst's demo will work well with your data.

Sign in to comment.

 Accepted Answer

Image Analyst
Image Analyst on 10 Mar 2020
Edited: Image Analyst on 10 Mar 2020
See this demo:
% Initialization steps.
clc; % Clear the command window.
close all; % Close all figures (except those of imtool.)
clear; % Erase all existing variables. Or clearvars if you want.
workspace; % Make sure the workspace panel is showing.
format long g;
format compact;
fontSize = 24;
% Make Gaussian https://en.wikipedia.org/wiki/Gaussian_function
x = linspace(0, 100, 1024);
amp = 50;
mu = 35;
sigma = 20;
y = amp * exp(-(x - mu).^2 / (2 * sigma^2));
hFig = figure;
plot(x, y, 'b-', 'LineWidth', 2);
grid on;
xlabel('x', 'FontSize', fontSize);
ylabel('y', 'FontSize', fontSize);
hFig.WindowState = 'maximized';
% Find the half height - midway between min and max y values.
halfHeight = (min(y) + max(y)) / 2;
hold on;
yline(halfHeight, 'Color', 'g', 'LineWidth', 2);
% Find left edge
index1 = find(y >= halfHeight, 1, 'first');
x1 = x(index1)
line([x1, x1], [0, y(index1)], 'Color', 'r', 'LineWidth', 2);
text(x1+1, 5, sprintf('x1 = %.2f', x1), 'FontSize', fontSize, 'Color', 'r');
% Find right edge
index2 = find(y >= halfHeight, 1, 'last');
x2 = x(index2)
line([x2, x2], [0, y(index2)], 'Color', 'r', 'LineWidth', 2);
text(x2+1, 5, sprintf('x2 = %.2f', x2), 'FontSize', fontSize, 'Color', 'r');
% Compute the full width, half max.
fwhm = x2 - x1
text(mu, halfHeight+2, sprintf('width = %.2f', fwhm), 'FontSize', fontSize, 'Color', 'r', 'HorizontalAlignment', 'center');
caption = sprintf('Full Width, Half Max = %.2f', x2 - x1);
title(caption, 'FontSize', fontSize);
Adapt code as needed for your variable names.

12 Comments

Thanks
Since this does what you need, can you please "Accept this answer"? Or ask a follow up question if we're not done yet.
Thanks for your answer, Could you please help how this code can be improved to calculate the width of lots of following curves on the same graph.
Put it into a for loop:
for k = 1 : whatever
% Code to generate new curve and compute x1 and x2...
% Now compute fwhm and use an index so we get one fwhm for every curve:
fwhm(k) = x2 - x1;
end
% Initialization steps.
clc; % Clear the command window.
workspace; % Make sure the workspace panel is showing.
format long g;
format compact;
fontSize = 24;
% Make Gaussian https://en.wikipedia.org/wiki/Gaussian_function
x = linspace(0, 100, 1024);
amp = 100;
y = amp*sin(x);
hFig = figure;
plot(x, y, 'b-', 'LineWidth', 2);
grid on;
xlabel('x', 'FontSize', fontSize);
ylabel('y', 'FontSize', fontSize);
hFig.WindowState = 'maximized';
% Find the half height - midway between min and max y values.
halfHeight = 60;
hold on;
yline(halfHeight, 'Color', 'g', 'LineWidth', 2);
% Find left edge
index1 = find(y >= halfHeight, 1, 'first');
x1 = x(index1);
line([x1, x1], [0, y(index1)], 'Color', 'r', 'LineWidth', 2);
text(x1+1, 5, sprintf('x1 = %.2f', x1), 'FontSize', fontSize, 'Color', 'r');
% Find right edge
index2 = find(y >= halfHeight, 1, 'last');
x2 = x(index2);
line([x2, x2], [0, y(index2)], 'Color', 'r', 'LineWidth', 2);
text(x2+1, 5, sprintf('x2 = %.2f', x2), 'FontSize', fontSize, 'Color', 'r');
% Compute the full width, half max.
fwhm = x2 - x1;
for k=1:4:100
fwhm(k) = x2 - x1;
end
caption = sprintf('Full Width, Half Max = %.2f', x2 - x1);
title(caption, 'FontSize', fontSize);
Thanks for the initial suggestion
I did this but it seems to calcultae the first and last and ignores all the curves in the middle. Could all the x-points be stored into at the given halfHeight be stored in an array?
Thanks
What curves in the middle? You only computed one curve, and there was no curve at all created inside your loop like I showed, so x1 and x2 never change inside your loop. Why do you think you're creating multiple curves?
By the way, you can highlight your code and click the code button to format it as code, which gives us a little button we can click to copy it into the clipboard to make it easy to paste into MATLAB to run your code. Please do that next time.
Sorry I mean for each turning point of the curve.
Sorry I mean the width within each turning point as I have indicated with a,b,c,d e, ... in the image attached above.
% Initialization steps.
clc; % Clear the command window.
workspace; % Make sure the workspace panel is showing.
format long g;
format compact;
fontSize = 24;
% Make Gaussian https://en.wikipedia.org/wiki/Gaussian_function
x = linspace(0, 100, 1024);
amp = 100;
y = amp*sin(x);
hFig = figure;
plot(x, y, 'b-', 'LineWidth', 2);
grid on;
xlabel('x', 'FontSize', fontSize);
ylabel('y', 'FontSize', fontSize);
hFig.WindowState = 'maximized';
% Find the half height - midway between min and max y values.
halfHeight = 60;
hold on;
yline(halfHeight, 'Color', 'g', 'LineWidth', 2);
% Find left edge
index1 = find(y >= halfHeight, 1, 'first');
x1 = x(index1);
line([x1, x1], [0, y(index1)], 'Color', 'r', 'LineWidth', 2);
text(x1+1, 5, sprintf('x1 = %.2f', x1), 'FontSize', fontSize, 'Color', 'r');
% Find right edge
index2 = find(y >= halfHeight, 1, 'last');
x2 = x(index2);
line([x2, x2], [0, y(index2)], 'Color', 'r', 'LineWidth', 2);
text(x2+1, 5, sprintf('x2 = %.2f', x2), 'FontSize', fontSize, 'Color', 'r');
% Compute the full width, half max.
fwhm = x2 - x1;
for k=1:4:100
fwhm(k) = x2 - x1;
end
caption = sprintf('Full Width, Half Max = %.2f', x2 - x1);
title(caption, 'FontSize', fontSize);
Try this:
clc; % Clear the command window.
close all; % Close all figures (except those of imtool.)
clear; % Erase all existing variables. Or clearvars if you want.
workspace; % Make sure the workspace panel is showing.
format long g;
format compact;
fontSize = 18;
fprintf('Beginning to run %s.m ...\n', mfilename);
echo off;
% Make Gaussian https://en.wikipedia.org/wiki/Gaussian_function
x = linspace(0, 100, 1024);
amp = 100;
y = amp*sin(x);
hFig = figure;
subplot(2, 1, 1);
plot(x, y, 'b-', 'LineWidth', 2);
grid on;
xlabel('x', 'FontSize', fontSize);
ylabel('y', 'FontSize', fontSize);
caption = sprintf('Original Signal');
title(caption, 'FontSize', fontSize);
hFig.WindowState = 'maximized';
% Define a threshold level.
thresholdHeight = 60;
hold on;
yline(thresholdHeight, 'Color', 'g', 'LineWidth', 2);
% Find elements where y is above the thresholdHeight
aboveThreshold = y > thresholdHeight;
% Label each group.
[groups, numRegions] = bwlabel(aboveThreshold)
smallFontSize = 8;
for k = 1 : numRegions
% Get a mask for this particular group
mask = groups == k; % Logical "map" of where this group is.
indexes = find(mask); % Get actual element (index) numbers.
% Find left edge
index1 = min(indexes);
x1 = x(index1);
line([x1, x1], [0, y(index1)], 'Color', 'r', 'LineWidth', 2);
text(x1, 7, sprintf(' x1 = %.2f', x1), 'FontSize', smallFontSize, 'Color', 'r');
% Find right edge
index2 = max(indexes);
x2 = x(index2);
line([x2, x2], [0, y(index2)], 'Color', 'r', 'LineWidth', 2);
text(x2, 0, sprintf(' x2 = %.2f', x2), 'FontSize', smallFontSize, 'Color', 'r');
% Compute the full width, half max.
fwhm(k) = x2 - x1;
end
subplot(2, 1, 2);
bar(fwhm);
grid on;
caption = sprintf('Widths above a threshold of %d', thresholdHeight);
title(caption, 'FontSize', fontSize);
I appreciate your kindness. Thank you very much. This worked. Although it does not pick the x value at the exact y value for all the sub regions. It sometimes picks a point above the green line (thresholdHeight). I am not sure because of this section of the code.
% Find elements where y is above the thresholdHeight
aboveThreshold = y > thresholdHeight;
% Label each group.
[groups, numRegions] = bwlabel(aboveThreshold);
smallFontSize = 8;
You data is discrete - it's quantized. There are no elements that are exactly 0.6 for y. So it picks the closest element above that. If you want to interpolate with interp1() or polyval(), you're certainly welcome to do that.
Thank you very much

Sign in to comment.

More Answers (0)

Categories

Find more on Creating, Deleting, and Querying Graphics Objects in Help Center and File Exchange

Community Treasure Hunt

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

Start Hunting!