How to find the corner points at a plateau

47 views (last 30 days)
Armindo
Armindo on 26 Jan 2017
Edited: Ajinkya Gorad on 14 Jun 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?

Answers (3)

John D'Errico
John D'Errico on 27 Feb 2017
Edited: John D'Errico on 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 Comment
Greg Dionne
Greg Dionne on 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.

Sign in to comment.


Ajinkya Gorad
Ajinkya Gorad on 14 Jun 2017
Edited: Ajinkya Gorad on 14 Jun 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 on 30 Jan 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 Comments
Armindo
Armindo on 8 Feb 2017
Edited: Armindo on 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 on 27 Feb 2017
Edited: Greg Dionne on 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.

Sign in to comment.

Community Treasure Hunt

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

Start Hunting!