Custom exponential fit doesn't seem to work

10 views (last 30 days)
Hey everyone,
I was stumbling in a bit of a problem and I hope one of you might be able to help me out. I have some data points (it's about 250ish) and am trying to fit an exponentially decreasing function with non-zero constant term to it, i.e. . However, no matter what I tried so far (different fitting functions, methods, starting points), I always end up with something that looks a lot like a constant function and basically resembles the data points not at all. This is the code I've been using so far:
% Here comes a previous part of the code, which extracts the data in
% question from a larger array and ends up giving you some x- and y-values.
% Those will be attached to the question.
x0 = [1 -2 12500];
fitfun = fittype( @(a,b,c,x) a*exp(b*x)+c );
[fitted_curve,gof] = fit(Data(:,1),Data(:,2),fitfun,'StartPoint',x0)
Unfortunately, when I plot the results, I end up with the following:
That obviously can't be the best fit possible.I've already looked at the fit-Function itself, but didn't get any useful information regarding my problem from the doc. Even though I'm almost certain it's just some trivial error, I fail to spot it. So thanks in advance for anyone trying to help me out here.
Cheers!
  2 Comments
Alex Sha
Alex Sha on 14 Nov 2022
Edited: Alex Sha on 14 Nov 2022
The start values your given/guessed are not appropriate。Refer to the result below:
Sum Squared Error (SSE): 31299597.4141903
Root of Mean Square Error (RMSE): 353.128292963896
Correlation Coef. (R): 0.992075938598263
R-Square: 0.984214667945624
Parameter Best Estimate Std. Deviation Confidence Bounds[95%]
--------- ------------- -------------- --------------------------------
a 4.76448778913171E18 1.06042570762486E-5 [4.76448778913171E18, 4.76448778913171E18]
b -0.0445919965391538 24.8230867373737 [-48.935539282319, 48.8463552892407]
c 12317.7442468735 4.75238610300809E-14 [12317.7442468735, 12317.7442468735]
Jannis Korn
Jannis Korn on 14 Nov 2022
@Alex Sha Thanks for the info! Is there a way to automatically find more appropriate initial guesses? This is part of a code processing a bunch of different sets of data, so trying varying initial guesses for each of them is not exactly what I planned to do

Sign in to comment.

Accepted Answer

Matt J
Matt J on 14 Nov 2022
Edited: Matt J on 14 Nov 2022
Is there a way to automatically find more appropriate initial guesses?
Use fminspleas from the File Exchange. Then you only need an initial guess for 'b'.
load Data
x=Data(:,1); y=Data(:,2);
funlist={@(b,x)exp(b.*x),1};
warning off
[b,ac]=fminspleas(funlist,0,x,y,-2,0)
b = -0.0386
ac = 2×1
1.0e+16 * 4.9888 0.0000
warning on
f=@(x) ac(1)*exp(b*x)+ac(2);
plot(x,y,'x',x,f(x))

More Answers (2)

Steven Lord
Steven Lord on 14 Nov 2022
Consider specifying the Normalize name-value pair argument in your fit call to normalize the X data. In my example below I'll use the normalize function instead of that argument, but it's the same general idea.
format longg
x = (750:10:800)';
Your x data is so large in magnitude that the exponential overflows to Inf.
plainExp = exp(x)
plainExp = 6×1
Inf Inf Inf Inf Inf Inf
Even if we cut the magnitude by a factor of 10, the values of the exponential are still really large in magnitude.
expOfOneTenthX = exp(x/10)
expOfOneTenthX = 6×1
1.0e+00 * 3.733241996799e+32 1.01480038811389e+33 2.75851345452317e+33 7.49841699699012e+33 2.03828106651267e+34 5.54062238439351e+34
But if we normalize the x data, the values are much smaller:
centeredAndScaledX = normalize(x)
centeredAndScaledX = 6×1
-1.33630620956212 -0.801783725737273 -0.267261241912424 0.267261241912424 0.801783725737273 1.33630620956212
and so are the values of the exponential. These can be "nicer" to work with.
centedAndScaledExp = exp(centeredAndScaledX)
centedAndScaledExp = 6×1
0.26281466013124 0.448528198864534 0.765473071693191 1.30638168340533 2.22951422570875 3.80496278061747

Matt J
Matt J on 14 Nov 2022
Edited: Matt J on 14 Nov 2022
It would be better to parametrize the function as
xmin=min(x)
f=@(x)a*exp(-b.*(x-xmin))+c;
The fit is better conditioned that way, and you don't get such insanely large values for a and c. Your original approach works much better with this change, as you can see below.
load Data; x=Data(:,1); y=Data(:,2);
xmin=min(x);
fitfun = fittype( @(a,b,c,x) a*exp(b*(x-xmin))+c );
[fitted_curve,gof] = fit(Data(:,1),Data(:,2),fitfun,'StartPoint',[max(y) -2 min(y)])
fitted_curve =
General model: fitted_curve(x) = a*exp(b*(x-xmin))+c Coefficients (with 95% confidence bounds): a = 1.424e+04 (1.396e+04, 1.452e+04) b = -0.04459 (-0.04604, -0.04314) c = 1.232e+04 (1.226e+04, 1.237e+04)
gof = struct with fields:
sse: 3.1300e+07 rsquare: 0.9842 dfe: 248 adjrsquare: 0.9841 rmse: 355.2577
plot(fitted_curve,x,y)
  1 Comment
Matt J
Matt J on 14 Nov 2022
You don't really even need a StartPoint guess (although you do need positivity bounds):
[fitted_curve,gof] = fit(Data(:,1),Data(:,2),fitfun,'Lower',[0,0,0])
Warning: Start point not provided, choosing random start point.
fitted_curve =
General model: fitted_curve(x) = a*exp(-b*(x-xmin))+c Coefficients (with 95% confidence bounds): a = 1.424e+04 (1.396e+04, 1.452e+04) b = 0.04459 (0.04314, 0.04604) c = 1.232e+04 (1.226e+04, 1.237e+04)
gof = struct with fields:
sse: 3.1300e+07 rsquare: 0.9842 dfe: 248 adjrsquare: 0.9841 rmse: 355.2577
plot(fitted_curve,x,y)

Sign in to comment.

Categories

Find more on Get Started with Curve Fitting Toolbox in Help Center and File Exchange

Products


Release

R2022a

Community Treasure Hunt

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

Start Hunting!