Determine the indice of real maximum using accumarray function
18 views (last 30 days)
Show older comments
I'm doing signal analysis on the peaks and valleys of a sinusoidal signal. Using accumarray has been quite effective at determining the extrema, but I'm seriously struggling with what should be a simple part of my implementation. Currently the returned peakLoc values are not integer timesteps, but a decimal average of all the timesteps that are considered part of the peak. The only new functionality I need is to get the real integer timestep for the highest (or lowest) extrema. Whether there is an option for the single accumarray line with @mean or another way, I don't care. Over the past three days I have been slopping together different nested loops to try to pin down the behavior I want and I'm sure there's got to be a simple way to accomplish this.
I'm sure there's a lot of other ways I could improve this code, but I just need it working. I'm not experienced and constantly bang my head against indexing problems (whether mixing up dimension, logical indexing oddities, etc.) and other beginner problems.
function [peakLoc, peakVal] = getExtrema(durThreshold, PEThreshold, gettingMax, PEAverage, timestep)
% Gets passed duration (# of consecutive timesteps above zero) and PE threshold (0).
% Returns the timestep and PE value for all of Maximum or of Minimum extrema.
if gettingMax == true
isPeak = PEAverage > PEThreshold;
else
isPeak = PEAverage < PEThreshold;
end
CC = bwconncomp(isPeak);
peakID = labelmatrix(CC);
peakLabel = unique(peakID);
peakSize = accumarray(peakID(:)+1,1);
peakSize(1) = 0; % set the # of <0 elements to 0
realPeakLabels = peakLabel(peakSize >= durThreshold);
isRealPeak = ismember(peakID,realPeakLabels);
% Now find the max in the real peaks (realPeakLabels?), accumarray will help
peakID(~isRealPeak) = 0;
if gettingMax == true
peakVal = accumarray(peakID(:)+1,PEAverage(:),[numel(peakSize) 1],@max,NaN);
else
peakVal = accumarray(peakID(:)+1,PEAverage(:),[numel(peakSize) 1],@min,NaN);
end
%% Get the right peakLoc, not the @mean
% @mean is approximation of the timestep where the real peak value occurs
peakLoc = accumarray(peakID(:)+1,timestep(:),[numel(peakSize) 1],@mean,NaN);
peakLoc = zeros(length(peakLabel),1);
j = 1;
for i = timestep
% Get the right index
if peakID(i) > j
j = peakID(i);
end
if ismember(j, realPeakLabels)
if gettingMax == true
if PEAverage(i) > peakVal(j)
peakLoc(j) = timestep(i);
end
else
if PEAverage(i) < peakVal(j)
peakLoc(j) = timestep(i);
end
end
end
end
peakVal(1) = NaN;
peakLoc(peakLoc == 0) = NaN;
end
0 Comments
Answers (1)
Star Strider
on 6 Aug 2024 at 23:39
I’m not certain what you want or how the .mat file figures into this (since you don’t have a load call or relevant code to determine what to do with it).
Since you have R2024a, you can use the islocalmax and islocalmin functions to get the peak maxima and peak minima, respectively. They are part of core MATLAB (and have been for the past few years) so don’t require any additional toolboxes. They return logical vectors, so if you want the numerical indices, use the find function to get them.
They also have other interesting features, such as being able to return the locations of the flat sections of a signal.
0 Comments
See Also
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!