How to find the corner points at a plateau

35 visualizzazioni (ultimi 30 giorni)
Armindo
Armindo il 26 Gen 2017
Modificato: Ajinkya Gorad il 14 Giu 2017
I need to find the two corner points at a plateau. For that I am using this function and I am able to get the first but not the second (at the right corner of the red mark and before the curve goes down). Note that the top not always is as flat as in the image.
y = -Data; % invert the signal and get the index of all the first maxs [peakValues, indexes] = findpeaks(y,'MinPeakProminence',500, 'MinPeakWidth', 0.4);
Please any help apreciated.
There is another nd better way to achieve this?

Risposte (3)

John D'Errico
John D'Errico il 27 Feb 2017
Modificato: John D'Errico il 28 Feb 2017
I think this is easier than it has been made out to be. Findpeaks won't really work, since it is looking for peaks, and these plateaus are not really constant in value.
The plateaus are regions of the curve here where it has a value of 0, within some tolerance. I lack your data, nor do I know what a reasonable tolerance would be.
Since the plateau appears to be at zero, just do a simple test.
pbool = (y >= -tol);
this gives you a logical vector where the curve is in the plateau region. Then, find the locations in that logical vector where a transition is made into the plateau, and then out of it.
Start by adding with zeros (false) at each end, in case a plateau is already in existence at either end.
pbool = [false, pbool, false];
Now just search for the string [0 1]. That will indicate where a plateau starts. And we will find EVERY plateau in the one operation. Searching for the transition out of the plateau is also easy, because we search for [1 0].
pstart = strfind(pbool,[0 1]);
pend = strfind(pbool,[1 0]) - 1;
the elements of pstart are the beginnings of each plateau. And the corresponding elements of pend are the end points for that plateau. I had to subtract 1 from the end points, because of the zero pad.
y = min(0,sin(0:.1:14) - 0.9);
y = y + randn(size(y)) * 0.001;
plot(y)
grid on
Lets try it out. I know a good tolerance, because I know the noise standard deviation was 0.001. 5 sigma should suffice, so 0.005 should be quite adequate. But if you have no a-priori clue as to the noise variance, you could try my estimatenoise code (on the FEX)
sqrt(estimatenoise(y))
ans =
0.0012083
So 5 sigma would then be 0.006. Either will be close enough for government work.
tol = 0.005;
pbool = (y >= -tol);
pbool = [false, pbool, false];
pstart = strfind(pbool,[0 1]);
pend = strfind(pbool,[1 0]);
pstart
pstart =
13 75 138
pend
pend =
21 84 141
plot(1:numel(y),y,'-b',pstart,y(pstart),'ro',pend,y(pend),'rx')
grid on
The change in case your nominal plateau level is not actually at zero is trivial to code, as long as you know where to set it. That too would be easily done automatically.
  1 Commento
Greg Dionne
Greg Dionne il 28 Feb 2017
Hi John,
If you look at Armindo's original post, you'll see the findpeaks(-x) trick, so it looks like this is an attempt to find the base points of each peak.
So my hunch is that the data is clipped for anything less than zero (no fuzzy noise on it). BTW, I've always liked your FEX submissions.

Accedi per commentare.


Ajinkya Gorad
Ajinkya Gorad il 14 Giu 2017
Modificato: Ajinkya Gorad il 14 Giu 2017
You can use the findpeaks to find both the points of the plateau. You could multiply your function with the plateau with the increasing function (e^x) to find the ending maxima & also by a decreasing function to find the starting maxima. Then merge both the locations and check the slope between the points if is less than some threshold values it is a plateau. Otherwise it could be a rising or falling signal. This will find the top plateaus. For finding the bottom plateaus, invert the signal and follow the same procedure.
This image shows the detected plateaus
This image shows the detection procedure
%%Plateau detection
%
% Detect plateau in the simulated signal using findpeak
x = 1:0.01:10;
freq = 4;
y = sawtooth(freq*x,0.5);
y(find(y>0.5)) =0.5;
y(find(y<-0.5)) =-0.5;
y = awgn(y,40); %add some gaussian noise
H = (x-x(1))./(x(end)-x(1)); % make a linear transformation
Hc = 1-H;
% convert them into different transformation for the signal
H = exp(4*H); % the extent upto which the signal is changing
Hc = exp(4*Hc);
Hy = H.*y; % apply the transform to find the peaks
Hcy = Hc.*y;
min_peak_dist = 80; % a value little less than the time period of the signal
[~,lcs_end] = findpeaks(Hy,'MinPeakDistance',min_peak_dist);
[~,lcs_start] = findpeaks(Hcy,'MinPeakDistance',min_peak_dist);
plot(x,y,'-',x(lcs_start),y(lcs_start),'*',x(lcs_end),y(lcs_end),'o');
clf;
plot(x,H,'--',x,Hc,'--',x,Hy,'-',x,Hcy,'-',x(lcs_start),Hcy(lcs_start),'*',x(lcs_end),Hy(lcs_end),'o')

Greg Dionne
Greg Dionne il 30 Gen 2017
If you like FINDPEAKS' behavior, you can reverse your signal to get the other index.
iytemp = findpeaks(y(end:-1:1), ...)
iy = length(y) + 1 - iytemp(end:-1:1)
  2 Commenti
Armindo
Armindo il 8 Feb 2017
Modificato: Armindo il 8 Feb 2017
thak you but this dont seems to work. I get the same index for all the data. This seems to work but not all the corners are well detected. Any other aproch that I can use? yy = flipud(y); indexes = findpeaks(yy,...);
Greg Dionne
Greg Dionne il 27 Feb 2017
Modificato: Greg Dionne il 27 Feb 2017
Try something like this:
n = 2000;
x = sin(2*pi*10*(1:n)/n) + 0.5*sin(2*pi*5*(1:2000)/n) - linspace(0,3,2000);
x( x > 0) = 0;
plot(x);
[~,ifwd] = findpeaks(x);
[~,irev] = findpeaks(x(n:-1:1));
irev = n + 1 - irev(end:-1:1);
plot(1:n,x,'-', ...
ifwd,x(ifwd),'>', ...
irev,x(irev),'<');
legend('signal','leftside','rightside');
One caveat: FINDPEAKS does not consider endpoints to be peaks unless they are infinite.

Accedi per commentare.

Community Treasure Hunt

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

Start Hunting!

Translated by