I am having trouble using lsqcurvefit with an function
Show older comments
Here is the code I have:
clear all, clc
data=load('OneLorentzian.txt');
t = data(:,1);
y = data(:,2);
plot(t,y,'r.')
F = @(y, ydata) (1/pi*ydata).*( ydata.^2./((t-0).^2 + ydata.^2));
x0 = [1 1 1 0];
[x,resnorm,~,exitflag,output] = lsqcurvefit(F,x0,t,y)
hold on
plot(t,F(x,t))
hold off
When I run the code my function does not fit the spectra. I get this message at the bottom:
Initial point is a local minimum.
Optimization completed because the size of the gradient at the initial point
is less than the value of the optimality tolerance.
<stopping criteria details>
x =
1 1 1 0
resnorm =
1.9478e+07
exitflag =
1
output =
struct with fields:
firstorderopt: 0
iterations: 0
funcCount: 5
cgiterations: 0
algorithm: 'trust-region-reflective'
stepsize: 1
message: '↵Initial
Answers (2)
Star Strider
on 15 Mar 2022
0 votes
Experiment with different values for ‘x0’ since nonlinear parameter estimation routines are very sensitive to the initial parameter estimates. Initial estimates that are far from the global minimum will generally not be changed, as they are not here.
1 Comment
Russ Rohloff
on 15 Mar 2022
Walter Roberson
on 15 Mar 2022
Initial point is a local minimum.
That is the normal output when the fitting function does the best that can possibly be done.
The function you are using does not use calculus to analyze the function to determine what the global minima of the function is -- and even if it did, there are a lot of functions where the calculus approach is too difficult to navigate, realistically.
Because of this, the fitting function does not assume that it has definitely found the global minima: it says that it found a local minima because it does not have the ability to prove that there is absolutely no possible set of parameters that could do better. It would be overpromising to say otherwise.
Consider the simple function
f = @(x) (x-5).^2 - 1000*(x == 8.2511135319564 )
This has a global minima at 8.2511135319564 but the function cannot analyze the code to determine that it has a special case to analyze, and instead just analyzes the hessians and so on. The hessians converge at the point x = 5 so the function would report x = 5 but would not claim that it is a global minima, just that it is a local minima, since it knows that you might have had something weird in the function that was beyond the ability of the numeric estimation routines to notice.
9 Comments
Walter Roberson
on 15 Mar 2022
Edited: Walter Roberson
on 15 Mar 2022
F = @(y, ydata) (1/pi*ydata).*( ydata.^2./((t-0).^2 + ydata.^2));
Bad function for fitting purposes. You ignore y and you use the external value t
When the fitting functions run, they pass in a vector of proposed parameters for the function, and a vector of values of the indepenent variable. The function is responsible for calculating the values the set of parameters would predict at the given locations of the independent variable. lsqcurvefit() then subtracts the values of the dependent variable, calculates the residue, figures out how to adjust the parameter.
When the fitting starts out, it may probe at a subset of the full data in order to determine whether the fitting function is behaving properly.
Under the assumption that y is your set of parameters, then your function should probably be
F = @(y, t) (1/pi*t).*( t.^2./((y-0).^2 + t.^2));
but I would not recommend using y as the names of the parameters, as that conflicts with using y as the independent variable.. You are calling the results x and using x0 so you should probably
F = @(x, t) (1/pi*t).*( t.^2./((x-0).^2 + t.^2));
I get the impression that you might have reversed the parameters and the independent variable in your fitting function.
Walter Roberson
on 15 Mar 2022
You are passing in a 1 x 4 vector for your parameters (x0). You are receiving a column vector of values. You are doing vectorized calculations. The result is going to be an N x 4 array that the N x 1 dependent values (y) are subtracted from. This is unlikely to be what you want. Please be explicit about how you want the vector of parameters to affect the output. If that means sum() along the second dimension, then sum() along the second dimension.
I would point out that at the moment, you do not distinguish the meaning of the four different parameters, so there is nothing driving a particular ordering of them.
Russ Rohloff
on 15 Mar 2022
Russ Rohloff
on 15 Mar 2022
Walter Roberson
on 15 Mar 2022
If you are fitting a lorenzian then you would typically need to fit the location, magnitude, width (or half-width), and phase. If you look at your original function,
F = @(y, ydata) (1/pi*ydata).*( ydata.^2./((t-0).^2 + ydata.^2));
then the t-0 would appear to be an attempt to deal with the location, but it is assuming that the location is 0. If we let
be the location of the peak then y would expect a
term
term Your function is not suitable for fitting a single lorentzian, at least not without making assumptions about some of the parameters... and if you make assumptions about those parameters then you would reduce the number of parameters to be fitted.
Russ Rohloff
on 15 Mar 2022
Walter Roberson
on 15 Mar 2022
Perhaps your x0 should not be a vector of length 4.
It is not immediately obvious to me what parameter is being fit.
Torsten
on 15 Mar 2022
So for the bell-shaped curve, I suggest using
t = data(:,1);
y = data(:,2);
plot(t,y,'r.')
F = @(x,t) x(1)*exp(-((t-x(2))/x(3)).^2);
x0 = [0.035;1920;5];
[x,resnorm,~,exitflag,output] = lsqcurvefit(F,x0,t,y)
hold on
plot(t,F(x,t))
hold off
Categories
Find more on Get Started with Curve Fitting Toolbox in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!