1

I have the following plot and a file of the data which creates that plot. I would like to have Matlab find the following points for me:

  1. [y,x] for peak noted by the 100% line
  2. [x] for where the plot crosses the y=0 line
  3. [x] for where y is 50% and 20% of the peak found in part 1.

Are there any add-on tools or packages which people are aware of which can help me accomplish this? I need to do this for a collection of plots so something reasonably automated would be ideal.

I can certainly do the programming and calculation parts in Matlab, it's just a matter of being able to load in the data file, matching it to a curve or function, and find the various [x,y] co-ordinates.

Data plot

Update Here's a sample dataset I am testing with:

x-values        y-values
-9.90056E+01    4.08949E-03
-8.58224E+01   -2.52083E-02
-7.26381E+01    3.39976E-02
-5.94526E+01   -6.90023E-02
-4.62659E+01    8.37428E-02
-3.30781E+01   -1.74139E-01
-1.98891E+01    2.09784E-01
-6.69894E+00    7.43248E-01
6.49238E+00    6.08539E-02
1.96849E+01   -1.64983E-01
3.28785E+01    8.34376E-02
4.60733E+01   -6.71712E-02
5.92692E+01    7.21458E-02
7.24664E+01   -2.20038E-02
8.56646E+01    3.44554E-02
9.88641E+01   -9.46063E-04
Carl
  • 405

2 Answers2

2

Maybe this code can help you:

function mse


x = linspace(0,10,100);
y = sin(x)+x-(x/5).^2;
hold off

plot(x,y)

yMax = max(y);
xMax = x(find(y==yMax));

hold on
plot(xMax,yMax,'*g')



y90 = yMax*0.9;
plot(x,y90,'-k')


for i=2:length(x)
    if y(i-1)<=y90 && y(i)>=y90 || y(i-1)>=y90 && y(i)<=y90
        plot(x(i),y(i),'og')
        plot(x(i-1),y(i-1),'og')

    end
end


y50 = yMax*0.5;
plot(x,y50,'-k')
for i=2:length(x)
    if y(i-1)<=y50 && y(i)>=y50 || y(i-1)>=y50 && y(i)<=y50
        plot(x(i),y(i),'og')
        plot(x(i-1),y(i-1),'og')

    end
end
end

Here $x,y$ are my data. Finding the maximum is easy, but for the 90% or 50% values I iterated through the data. As we do not have continous data we check, whether the 90% or 50% values lies between to points. The result is shown below. If you only want to highlight a single point instead of the two you could perform some (linear) interpolation. enter image description here

EDIT: This would highlight all points that match the X% criteria. If you only want to highlight the closest points to the maximum, you could change the loop to something like

 for i=find(y==ymax):length(x)

Which finds the point on the right and for the left side

 for i=find(y==ymax):-1:length(x)

To mark only one point you could use a break command.

EDIT2: The following code performs the same thing as the for loops, but it is shorter.

y90 = yMax*0.9;
xId= find(diff(sign(y-y90))~=0);
plot(x(xId),y(xId),'*k')
plot(x(xId+1),y(xId+1),'*k')

EDIT3: For your date you need to interpolate between the two values. Replace the loop with something like

for i=2:length(x)
    if y(i-1)<=y90 && y(i)>=y90 || y(i-1)>=y90 && y(i)<=y90
        plot(x(i),y(i),'og')
        plot(x(i-1),y(i-1),'og')

        xl = x(i-1);
        yl = y(i-1);
        xr = x(i);
        yr = y(i);

        xMid  = (y90-yl)*(xr-xl)/(yr-yl)+xl;
        plot(xMid,y90,'or');

    end
end
Thomas
  • 4,363
  • 1
    You can get the index by calling with two output parameters: $[value,index]=\max(array)$. – Daryl Apr 08 '13 at 11:50
  • @Daryl: Thanks! I did not know that. – Thomas Apr 08 '13 at 11:51
  • @macydanim: This is a great help. When I replace your signal with the data I have though, it doesn't hit the points on the 50%/90% line. I'll update the question with my dataset. – Carl Apr 08 '13 at 12:31
  • @Carl, yeah that is due to the problem that the jumps between your data are large. In my example this is not the case. Therefore, the point above and below the 90% line is exactly the maximum and a value far below. I think you need to interpolate in this case, give me some time. – Thomas Apr 08 '13 at 12:38
  • @Carl see the last edit, this works for me, using your date – Thomas Apr 08 '13 at 12:45
  • @macydanim Thanks once again. I've adapted it for my specific needs and it seems to work quite well. Thanks. – Carl Apr 08 '13 at 13:31
  • @macydanim: One more small question. What would I need in order to match a polynomial to it instead of finding a straight-line match? – Carl Apr 08 '13 at 14:43
  • Take a look at the polyfit and polyval command in matlab. Or maybe interp1. http://www.mathworks.de/de/help/matlab/ref/polyfit.html http://www.mathworks.de/de/help/matlab/ref/polyval.html http://www.mathworks.de/de/help/matlab/ref/interp1.html – Thomas Apr 09 '13 at 05:31
  • @k1next You have such high frequency of those potential lines for the car that Nyquist gets angry. But good answer by the way. – mathreadler May 21 '16 at 11:32
1

You can find the maximum point using the $\tt max$ and $\tt find$ commands in Matlab:

$\tt ymax = max(y);$

$\tt xmax = x(find(y == ymax));$

The other points do not exist in your data, i.e. there is probably no point that hits exactly the 20% line or the 50% line. For these you would need to interpolate.

Matt L.
  • 10,636
  • That Matt. That's a useful start for me. Much appreciated. How would I go about getting Matlab to approximate a gaussian curve to fit the signal? From that I should be able to interpolate the 20% and 50% points. – Carl Apr 08 '13 at 11:28
  • 1
    $xmax$ would not be the x-position of the maximum, but the ID of the element of vector $x$ where the maximum occurs. So it should rather be xmax = x(find(y==ymax)) – Thomas Apr 08 '13 at 11:30
  • @Carl You can also get the index of the maximum value of an array by $[value,index] =\max(array)$. – Daryl Apr 08 '13 at 11:49
  • Thanks macydanim for pointing out my mistake, you are perfectly right of course. – Matt L. Apr 08 '13 at 12:19