How to find the maximum point of a fitted curve

17 views (last 30 days)
I am trying to find the maximum point of a fitted curve, the fitting method is being done using smoothing splines. I have looked around on how this can be done and found the following technique in the link below, which seems to be exactly what I am trying to do, except that I am getting a wrong output.
with reference to similar problem that I found in matlab answer in the link below
Now the output that I am getting is the attched plot where the maximum point appear to have a wrong location on the x-axis, is there any way to fix it or at least to figure out what is causing the issue?
attached below is the used code to generate the plot, I attach also a sample of the data used
function [fitresult, gof] = createFit3(x, y)
%% Fit: 'untitled fit 1'.
[xData, yData] = prepareCurveData( x, y );
% Set up fittype and options.
ft = fittype( 'smoothingspline' );
opts = fitoptions( 'Method', 'SmoothingSpline' );
opts.Normalize = 'on';
opts.SmoothingParam = 0.99602;
% Fit model to data.
[fitresult, gof] = fit( xData, yData, ft, opts );
% Plot fit with data.
% figure( 'Name', 'untitled fit 1' );
plot( fitresult, xData, yData );
[ymax,xloc] = slmpar(coeffvalues(fitresult),'maxfun');
hold on
plot(xloc,ymax,'b*');
many thanks,
  1 Comment
John D'Errico
John D'Errico on 24 Oct 2022
What was wrong with the result? (Since I wrote the SLM tools.)
Can I test your code? Of course not. We are not given the routine prepareCurveData. So how can I even test anything out?
MAYBE, that function just does
xdata = x;
ydata = y;
but how can I know?

Sign in to comment.

Accepted Answer

John D'Errico
John D'Errico on 24 Oct 2022
Edited: John D'Errico on 24 Oct 2022
What was wrong with the result? (Since I wrote the SLM tools.)
Can I test your code? Of course not. We are not given the routine prepareCurveData. So how can I even test anything out?
MAYBE, that function just does
xdata = x;
ydata = y;
but how can I know? Perhaps I'll guess that is all it does, since the plot you show seems to be the same in fig1.fig.
Anyway, suppose I try that, trying to guess what you actually have..
ft = fittype( 'smoothingspline' );
opts = fitoptions( 'Method', 'SmoothingSpline' );
opts.Normalize = 'on';
opts.SmoothingParam = 0.99602;
% Fit model to data.
[fitresult, gof] = fit( x, y, ft, opts )
fitresult =
Smoothing spline:
fitresult(x) = piecewise polynomial computed from p
where x is normalized by mean 347.5 and std 88.74
Coefficients:
p = coefficient structure
Do you understand that fit returns a SPECIFIC form, from the curve fitting toolbox? Most importantly, READ THE MESSAGE YOU GOT. AND THINK ABOUT WHAT IT DID. Then you did this, without doing what I just said to do:
[ymax,xloc] = slmpar(coeffvalues(fitresult),'maxfun');
OF COURSE SLMPAR GIVES YOU SOMETHIGN STRANGE! You fed it something it was not designed to accept as input!!!!!!!
Why is there a problem? REREAD THE MESSAGE that fit returns.
where x is normalized by mean 347.5 and std 88.74
Coefficients:
So the curve fitting toolbox AUTOMATICALLY chose to shift and scale your data. The spline returned to you was:
coeffvalues(fitresult)
ans =
struct with fields:
form: 'pp'
breaks: [-1.6058 -1.4368 -1.2677 -1.0987 -0.92967 -0.76064 -0.59161 -0.42258 -0.25355 ]
coefs: [19×4 double]
pieces: 19
order: 4
dim: 1
Do you see that the breaks are NOT the vector of x values?
x'
ans =
Columns 1 through 16
205 220 235 250 265 280 295 310 325 340 355 370 385 400 415 430
Columns 17 through 20
445 460 475 490
Now look at what SLMPAR told you.
[ymax,xloc] = slmpar(coeffvalues(fitresult),'maxfun')
ymax =
1.5267e+12
xloc =
0.23313
So the maximum was correct. But the x location is not, and that is because you fed it a SHIFTED AND SCALED SPLINE! Can SLMPAR somehow magically know that fact? In fact, fit did not repair what it did, by unshifing and unscaling the spline. You needed to do that yourself. (Sorry, but that is just an unforgivable error on the part of the authors of fit. The code SHOULD make it possible to use the spline it returns! Worse, in order to extract the shift and scale parameters, I had to force them to be returned, using a call to struct.)
F = struct(fitresult);
Warning: Calling STRUCT on an object prevents the object from hiding its implementation details
and should thus be avoided. Use DISP or DISPLAY to see the visible public details of an object.
See 'help struct' for more information.
xloc*F.stdx + F.meanx
ans =
368.19
So that is the actual location of the maximum.
Plotting that point on the curve, we see;
plot( fitresult, x, y );
hold on
plot(xloc*F.stdx + F.meanx,ymax,'b*')
Don't say my code did not work. It does work, IF you use it as it should be used.
  1 Comment
Salma fathi
Salma fathi on 25 Oct 2022
I never said your code didn't work, your code is a king. I only asked for help because I did not understand why I am getting such result. Now thank to you I understand. Appreciate all the help.

Sign in to comment.

More Answers (1)

Mathieu NOE
Mathieu NOE on 24 Oct 2022
hello
a simple and compact code that only uses this Fex submission
code
load('x&y.mat')
z = smoothn(y); % Regular smoothing
[ymax,idx] = max(z);
xloc = x(idx);
plot(xloc,ymax,'b*',x,y,'r.',x,z,'k','Markersize',20,'LineWidth',2)
result :
  2 Comments
Mathieu NOE
Mathieu NOE on 24 Oct 2022
hello again
yes there is a possibility to change the smoothing factor
load('x&y.mat')
z = smoothn(y); % Regular smoothing, S auto
zs = smoothn(y,4); % Regular smoothing, S used % Z = SMOOTHN(Y,S) smoothes the array Y using the smoothing parameter S.
[ymax,idx] = max(zs);
xloc = x(idx);
plot(xloc,ymax,'b*',x,y,'r.',x,z,'k',x,zs,'g','Markersize',20,'LineWidth',2)
legend('peak','data','smoothn auto','smoothn S = 4');

Sign in to comment.

Community Treasure Hunt

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

Start Hunting!