Find all global minima und maxima of an Graph

22 vues (au cours des 30 derniers jours)
Benedikt Friedrich Nowak
Benedikt Friedrich Nowak le 10 Nov 2022
Commenté : Star Strider le 13 Nov 2022
Hi there,
i would like to find all global minima and maxima (red circles) of an graph. The graph itself was created with two vectors: Vektor 1 = Force in Newton [11902x2] and Vektor two = Time in seconds [11902x1]. So every Force-value has its own timestamp.
The Problem is that when i use the command 'findpeaks' it doesnt find the four global maxima and the three global minima (red circles), but it result in many small local peaks. The graph itself isnt so smooth after all and 'trembles` if you zoom in on it.
Does anyone know how to programm a code in which i can filter for those global peaks only ?
Thank you for your time and effort, Ben !

Réponse acceptée

Star Strider
Star Strider le 10 Nov 2022
The findpeaks function has a number of name-value pair arguments that you can use to restrict what it returns. (My favourite is 'MinPeakProminence' and doing some experimenting will return the correct result.)
t = linspace(0, 10);
s = sin(2*pi*t*0.5) + randn(size(t))*0.25;
[pks,plocs] = findpeaks(s, 'MinPeakProminence',0.75)
pks = 1×5
1.1302 1.0873 1.2338 1.1793 1.6063
plocs = 1×5
7 26 47 65 86
[vys,vlocs] = findpeaks(-s, 'MinPeakProminence',0.75)
vys = 1×5
1.4171 1.4373 1.3486 0.9590 1.5022
vlocs = 1×5
15 36 57 76 95
figure
plot(t,s, 'DisplayName','Signal')
hold on
plot(t(plocs), pks, '^r', 'DisplayName','Peaks')
plot(t(vlocs), -vys, 'vr', 'DisplayName','Valleys')
hold off
legend('Location','best')
.
  2 commentaires
Benedikt Friedrich Nowak
Benedikt Friedrich Nowak le 13 Nov 2022
Thank you !
Star Strider
Star Strider le 13 Nov 2022
As always, my pleasure!

Connectez-vous pour commenter.

Plus de réponses (2)

Mathieu NOE
Mathieu NOE le 10 Nov 2022
hello Benedikt
someone will probably tell you how findpeaks is powerfull but sometimes I simply prefer to rely on old but good / simple code like peakseek - even not bothered by the small amount of noise I added to the waveform.
a big thanks to Peter O'Connor, the author of peakseek
results :
%% dummy data
n = 1000;
x = 25*(0:n-1)/n;
y = sign(sin(x+0.05*x.^2)).*(1-0.01*x);
% low pass 1st order
% y = (1-alpha) * y_old + alpha * x
alpha = 0.02;
numd = [alpha 0];
dend = [1 -(1-alpha)];
yf = filter(numd,dend,y);
%% add some noise
yf = yf + 0.02*randn(size(yf));
%% try#1 with findpeaks
figure(1)
plot(x,yf);
findpeaks(yf)
%% try#2 with peakseek
minpeakdist = 50; % in samples
% positive peaks
minpeakh = max(yf)/10;
[locs1, pks1]=peakseek(yf,minpeakdist,minpeakh);
% negative peaks
[locs2, pks2]=peakseek(-yf,minpeakdist,minpeakh);
figure(2)
plot(x,yf,'b',x(locs1),yf(locs1),'dr',x(locs2),yf(locs2),'dg');
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [locs, pks]=peakseek(x,minpeakdist,minpeakh)
% x is a vector input (generally a timecourse)
% minpeakdist is the minimum desired distance between peaks (optional, defaults to 1)
% minpeakh is the minimum height of a peak (optional)
%
% (c) 2010
% Peter O'Connor
% peter<dot>ed<dot>oconnor .AT. gmail<dot>com
if size(x,2)==1, x=x'; end
% Find all maxima and ties
locs=find(x(2:end-1)>=x(1:end-2) & x(2:end-1)>=x(3:end))+1;
if nargin<2, minpeakdist=1; end % If no minpeakdist specified, default to 1.
if nargin>2 % If there's a minpeakheight
locs(x(locs)<=minpeakh)=[];
end
if minpeakdist>1
while 1
del=diff(locs)<minpeakdist;
if ~any(del), break; end
pks=x(locs);
[garb, mins]=min([pks(del) ; pks([false del])]); %#ok<ASGLU>
deln=find(del);
deln=[deln(mins==1) deln(mins==2)+1];
locs(deln)=[];
end
end
if nargout>1
pks=x(locs);
end
end

John D'Errico
John D'Errico le 10 Nov 2022
A peak is a peak. If your data has many peaks in it, can findpeaks really know that? At the same time, findpeaks is the correct tool to use. You just need to smooth out the noise, FIRST. So that means you need to use a tool that can smooth your curve in advance. smooth is a good choice, because it has multiple methods to perform the smoothing, and you can make the choice yourself.
help smooth
SMOOTH Smooth data. Z = SMOOTH(Y) smooths data Y using a 5-point moving average. Z = SMOOTH(Y,SPAN) smooths data Y using SPAN as the number of points used to compute each element of Z. Z = SMOOTH(Y,SPAN,METHOD) smooths data Y with specified METHOD. The available methods are: 'moving' - Moving average (default) 'lowess' - Lowess (linear fit) 'loess' - Loess (quadratic fit) 'sgolay' - Savitzky-Golay 'rlowess' - Robust Lowess (linear fit) 'rloess' - Robust Loess (quadratic fit) Z = SMOOTH(Y,METHOD) uses the default SPAN 5. Z = SMOOTH(Y,SPAN,'sgolay',DEGREE) and Z = SMOOTH(Y,'sgolay',DEGREE) additionally specify the degree of the polynomial to be used in the Savitzky-Golay method. The default DEGREE is 2. DEGREE must be smaller than SPAN. Z = SMOOTH(X,Y,...) additionally specifies the X coordinates. If X is not provided, methods that require X coordinates assume X = 1:N, where N is the length of Y. Notes: 1. When X is given and X is not uniformly distributed, the default method is 'lowess'. The 'moving' method is not recommended. 2. For the 'moving' and 'sgolay' methods, SPAN must be odd. If an even SPAN is specified, it is reduced by 1. 3. If SPAN is greater than the length of Y, it is reduced to the length of Y. 4. In the case of (robust) lowess and (robust) loess, it is also possible to specify the SPAN as a percentage of the total number of data points. When SPAN is less than or equal to 1, it is treated as a percentage. For example: Z = SMOOTH(Y) uses the moving average method with span 5 and X=1:length(Y). Z = SMOOTH(Y,7) uses the moving average method with span 7 and X=1:length(Y). Z = SMOOTH(Y,'sgolay') uses the Savitzky-Golay method with DEGREE=2, SPAN = 5, X = 1:length(Y). Z = SMOOTH(X,Y,'lowess') uses the lowess method with SPAN=5. Z = SMOOTH(X,Y,SPAN,'rloess') uses the robust loess method. Z = SMOOTH(X,Y) where X is unevenly distributed uses the 'lowess' method with span 5. Z = SMOOTH(X,Y,8,'sgolay') uses the Savitzky-Golay method with span 7 (8 is reduced by 1 to make it odd). Z = SMOOTH(X,Y,0.3,'loess') uses the loess method where span is 30% of the data, i.e. span = ceil(0.3*length(Y)). See also SPLINE. Documentation for smooth doc smooth Other uses of smooth curvefit/smooth ssm/smooth trackingABF/smooth dssm/smooth statespace/smooth trackingIMM/smooth msVAR/smooth
Which method is correct for you? The best thing is to try out a few, and see which one makes you happy. Really, it will not be the specific methoid you choose, but how wide you make the window or span of that method. And that is dependent on how much noise is in your data. So noiser data will require a longer span to help to smooth out the noise and thus to elmininate the spurious bumps and crap. Of course, if you make the span too large, then your peaks will become brodened out more than you want. So this will be a tradeoff, and we don't actually have your data to give an example specific to your problem. In turn, all that allows me to do is suggest you smooth your data using perhaps smooth.
Other methods like a spline fit are less likely to be good choices, because your curve seems to have sharp transitions in slope at the peaks. And spline hate singularities, even singularities in the derivative. That means you want to use a simpler low order method, like the ones you will find in smooth.
So just smooth your data, THEN call findpeaks. If you are finding too many spurious peaks, then you needed to smooth your data a little more strongly.

Produits


Version

R2022b

Community Treasure Hunt

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

Start Hunting!

Translated by