Findpeaks: find the interpolation points for the width with the x axis

5 views (last 30 days)
Hi,
I am using the function "findpeaks" to find the peaks and their widths for a given signal.
It works very nice, but I would like to get more information for the widths: in particular, the interpolation points in respect to the x-axis that, in my case, is time. I would like to know at what point in time does a width computation starts, and the point in time when it ends.
For example, in the screenshot below, I would like to get the two x values of the yellow width (which for some reasons that I ignore read as the same values now, 43.89).

Answers (1)

Tommy
Tommy on 26 May 2020
Edited: Tommy on 26 May 2020
After you call findpeaks, you could obtain a handle to the current axes, find the handle(s) to the yellow horizontal line(s) which indicate the widths, and pull out the XData.
findpeaks(data, 'Annotate', 'Extents')
ax = gca;
widthHandle = findobj(ax, 'Tag', 'HalfProminenceWidth');
widthLoc = [widthHandle.XData(1:3:end)', widthHandle.XData(2:3:end)'];
For the examples I tested, findobj returned just one handle, and the XData was formatted like [left1, right1, NaN, left2, right2, NaN, ...]. It's possible that this may not always be the case, so the above code may not always work, but you should be able to find the locations somehow using the same idea. Note that the tag will be 'HalfHeightWidth' if you tell findpeaks to use 'halfheight' as the 'WidthReference'.
You can also call findpeaks a second time, after your first call, this time requesting output arguments. When you request outputs, findpeaks doesn't plot anything. You could then locate where each width, situated at the half prominence, crosses your data just before and just after reaching the location of the peak. Something like this:
findpeaks(data, 'Annotate', 'Extents')
[peaks,locs,widths,prominence] = findpeaks(data);
widthLoc = nan(numel(peaks),2);
for ii = 1:numel(peaks)
y = peaks(ii) - (prominence(ii)/2); % height based on half prominence
crossLoc = find(diff(sign(data-y)))+1; % rough estimates of all crossings
[~, closestLeft] = find(crossLoc < locs(ii),1); % last crossing before locs(ii)
leftLoc = crossLoc(closestLeft);
x = [leftLoc-1 leftLoc+1]; % assuming actual crossing is between leftLoc-1 and leftLoc+1
widthLoc(ii,1) = interp1(data(x), x, y);
[~, closestRight] = find(crossLoc > locs(ii),1); % first crossing after locs(ii)
rightLoc = crossLoc(closestRight);
x = [rightLoc-1 rightLoc+1]; % similar assumption as above
widthLoc(ii,2) = interp1(data(x), x, y);
% alternatively:
% widthLoc(ii,2) = widthLoc(ii,1) + widths(ii);
end
I highly doubt this is anywhere near as rigorous as the actual code within findpeaks, but maybe it will help you get started.

Products


Release

R2020a

Community Treasure Hunt

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

Start Hunting!