Custom exponential fit doesn't seem to work

5 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
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))
  1 Comment
Jannis Korn
Jannis Korn on 14 Nov 2022
Thanks a lot for your comprehensive answer!

Sign in to comment.

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.

Community Treasure Hunt

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

Start Hunting!