How do I fit an exponential curve to my data?

Say, I have the following data: x=[1,2,4,6,8],y=[100,140,160,170,175]. How do I fit an exponential curve of the form y=a-b*exp(-c*x) to my data? Is there any Matlab function to do that? Thanks in advance.

2 commentaires

Arturo Gonzalez
Arturo Gonzalez le 1 Sep 2020
Modifié(e) : Arturo Gonzalez le 1 Sep 2020
Per this answer, you can do it as follows:
clear all;
clc;
% get data
dx = 0.02;
x = (dx:dx:1.5)';
y = -1 + 5*exp(0.5*x) + 4*exp(-3*x) + 2*exp(-2*x);
% calculate integrals
iy1 = cumtrapz(x, y);
iy2 = cumtrapz(x, iy1);
iy3 = cumtrapz(x, iy2);
% get exponentials lambdas
Y = [iy1, iy2, iy3, x.^3, x.^2, x, ones(size(x))];
A = pinv(Y)*y;
lambdas = eig([A(1), A(2), A(3); 1, 0, 0; 0, 1, 0]);
lambdas
%lambdas =
% -2.9991
% -1.9997
% 0.5000
% get exponentials multipliers
X = [ones(size(x)), exp(lambdas(1)*x), exp(lambdas(2)*x), exp(lambdas(3)*x)];
P = pinv(X)*y;
P
%P =
% -0.9996
% 4.0043
% 1.9955
% 4.9999
H. Sh. G.
H. Sh. G. le 28 Juil 2022
Modifié(e) : H. Sh. G. le 28 Juil 2022
Nice solution!
I implemented a generalized function to handle n exponential functions.
function [lambdas, c, yhat] = ExpFunFit(Data, n, intcpt)
%Fits an exponential summation function to Data = [t, y].
% y = c0 + Sum{c_i * exp(lambda_i * t)}; i = 1, ..., n.
% H.Sh.G. - 2022
% See Prony's method for exponential function fitting.
if nargin<3, intcpt = 0; end
x = Data(:,1);
nx = size(x, 1);
y = Data(:,2);
% Calculate integrals
yi = [y, zeros(nx, n)];
xi = [zeros(nx, n-1), x];
for i = 2:n+1
yi(:,i) = cumtrapz(x, yi(:,i-1));
if i<=n
xi(:,i-1) = x.^(n+2-i);
end
end
% Get exponentials' lambdas
Y = [yi(:,2:n+1), xi];
if intcpt, Y = [Y, ones(size(x))]; end
A = pinv(Y)*y;
lambdas = eig([A(1:n)'; ...
eye(n-1), zeros(n-1,1)]);
% Get exponentials' multipliers
X = ones(nx, n+1);
for i = 1:n
X (:, i+1) = exp(lambdas(i)*x);
end
if ~intcpt, X = X(:, 2:end); end
c = pinv(X)*y;
yhat = X * c;
Thanks Arturo.
Hamed.

Connectez-vous pour commenter.

 Réponse acceptée

Andrei Bobrov
Andrei Bobrov le 23 Oct 2013
Modifié(e) : Chad Greene le 14 Jan 2021
[EDIT] Please read about fit and try:
x=[1,2,4,6,8]';
y=[100,140,160,170,175].';
g = fittype('a-b*exp(-c*x)');
f0 = fit(x,y,g,'StartPoint',[[ones(size(x)), -exp(-x)]\y; 1]);
xx = linspace(1,8,50);
plot(x,y,'o',xx,f0(xx),'r-');

13 commentaires

Rinu
Rinu le 23 Oct 2013
Modifié(e) : Rinu le 23 Oct 2013
I tried to plot the fitted curve by manually defining a function curvft using the values of a, b and c I got from c. But the fitted curve seems to be just a straight line which doesn't fit the data satisfactorily.
>> c c = General model: c(x) = a-b*exp(-c*x) Coefficients (with 95% confidence bounds): a = 149 (66.01, 232) b = -9.783 c = 180.8 >> curvft=149+9.783*exp(-180.8*r); >> plot(r,s,'ro',r,curvft)
Is there any way to fit the data better?
Andrei Bobrov
Andrei Bobrov le 23 Oct 2013
I corrected my answer.
Rinu
Rinu le 24 Oct 2013
Thanks.
Torsten
Torsten le 27 Mar 2017
Please show your MATLAB-code.
Are you sure about the order of your y-values ?
Best wishes
Torsten.
Torsten
Torsten le 27 Mar 2017
Modifié(e) : Torsten le 27 Mar 2017
Of course, you must change the interval for plotting from
xx = linspace(1,8,50);
to
xx = linspace(0,50,100)
or something.
Best wishes
Torsten.
Torsten
Torsten le 27 Mar 2017
What fit parameters do you get for a, b and c ?
Best wishes
Torsten.
Torsten
Torsten le 27 Mar 2017
I get an exponential curve when plotting the function
f(x) = 2060-1504*exp(-0.01156*x)
Best wishes
Torsten.
Torsten
Torsten le 27 Mar 2017
Yes, I get the same.
If you plot the function for a larger x-interval, you'll see that the curve is exponential.
Best wishes
Torsten.
Manoj
Manoj le 27 Mar 2017
Thanks.
Best Regards,
Manoj
Bert Liu
Bert Liu le 16 Oct 2020
Can someone kindly explain the math for obtaining the StartPoint?
[[ones(size(x)), -exp(-x))]\y; 1] worked well for the data I'm fitting, but I don't understand the math. Thanks.
@Bert Yeah, the way Andrei suggests obtaining the initial guess isn't very intuitive, but it's pretty clever. It's a least-squares solution to the general form
y = a-b*exp(c*x);
and the initial guess, the 1 in the last term of
[[ones(size(x)), -exp(-x)]\y; 1]
ans =
169.1061
191.7259
1.0000
means we don't know anything about c, so we'll just start by guessing it's 1.
Try plotting the curve with the coefficients of the initial guess:
y_lsq = 169.1061-191.7259*exp(-1*xx);
hold on
plot(xx,y_lsq)
This requires MATLAB Curve Fit package. Is there a way to do a simple one exponential fit without it?
Image Analyst
Image Analyst le 14 Mai 2021
@Michael Solonenko, of course. My code below doesn't use the Curve Fitting Toolbox. Mine uses the Statistics and Machine Learning Toolbox, which is much more common. You probably have that toolbox. type "ver" on the command line to find out what toolboxes you have.

Connectez-vous pour commenter.

Plus de réponses (2)

I tried it with the form
'a*exp(-((x/b)^c))'
I got this warning messsage:
Warning: Rank deficient, rank = 1, tol = 4.019437e-14.
and it only plots the data, but not the fit... What am I doing wrong?

9 commentaires

Torsten
Torsten le 20 Nov 2018
How many data points do you have ? I hope at least three, not only one.
Hi,
I have about 20 data points. Is this maybe too much?
thanks for your help!
Torsten
Torsten le 21 Nov 2018
What do you get if you use the code
xdata = [...]; %row vector, should contain positive values
ydata = [...]; %row vector
lb = [-Inf,0,-Inf];
ub = [Inf,Inf,Inf];
fun=@(p,xdata) p(1)*exp(-((xdata/p(2)).^p(3)));
p0 = [1 1 1];
p = lsqcurvefit(fun,p0,xdata,ydata,lb,ub)
Best wishes
Torsten.
Thank you Thorsten,
the error disappeared, but for
p = lsqcurvefit(fun,p0,xdata,ydata,lb,ub)
I get the answer
p =
1 1 1
Torsten
Torsten le 21 Nov 2018
Start with p0 = [1 1000 1]
Now it worked! Thanks for your help! (y)
Again, I have to fit exponential data and get the coefficients. I thought it should work with my old code, but apparently, I am doing something wrong, but I don't see my mistake... Excel retuns an exponential function of 150e-0.115x, so I took this as starting values for the coefficients p.
The last row returns 31.3705881793848 for all values! why?
x=[7.48673807584469;7.48673807584469;9.52211367803178;9.52211367803178;9.52211367803178;11.2093975148163;11.2093975148163;11.2093975148163;15.8637542852664;15.8637542852664;15.8637542852664;17.5649842553087;17.5649842553087;17.5649842553087;26.3442681704923;26.3442681704923;26.3442681704923];
y=[61.8;78.6;63.1;53.8;52.5;31.4;20.8;27.2;28.4;17.2;25.2;16.8;9.5;12.7;13.6;9.2;11.5];
g = fittype('a-b*exp(-c*x)');
f0 = fit(x,y,g,'StartPoint',[[ones(size(x)), -exp(-x)]\y; 1]);
xx = linspace(8,30,50);
plot(x,y,'*',xx,f0(xx),'r-'); %fit looks good
hold on %because I want to plot the data with the determined coefficients to check
lb = [-Inf,0,-Inf];
ub = [Inf,Inf,Inf];
fun=@(p,x) p(1)-p(2)*exp(-(x*p(3)));
p0 = [0 100 0.155];
p = lsqcurvefit(fun,p0,x,y,lb,ub)
y1=p(1)-p(2)*exp(-(x*p(3))); %returns 31.3705881793848 for all values?
plot(x,y1,'g-'); %Yerks!
That code requires the Curve Fitting Toolbox, which I don't have, so I can't run it. But I did plot(x,y) and noticed that several of your x all have the same value. Perhaps it could be fixed by making the x all unique values by adding a very tiny amount of random noise to them (but not enough to affect the fit), like
x=[7.48673807584469;7.48673807584469;9.52211367803178;9.52211367803178;9.52211367803178;11.2093975148163;11.2093975148163;11.2093975148163;15.8637542852664;15.8637542852664;15.8637542852664;17.5649842553087;17.5649842553087;17.5649842553087;26.3442681704923;26.3442681704923;26.3442681704923];
x = x + 0.001 * rand(size(x))
If it complains that the x must be sorted in ascending order, you can sort x and y like this:
x=[7.48673807584469;7.48673807584469;9.52211367803178;9.52211367803178;9.52211367803178;11.2093975148163;11.2093975148163;11.2093975148163;15.8637542852664;15.8637542852664;15.8637542852664;17.5649842553087;17.5649842553087;17.5649842553087;26.3442681704923;26.3442681704923;26.3442681704923];
y=[61.8;78.6;63.1;53.8;52.5;31.4;20.8;27.2;28.4;17.2;25.2;16.8;9.5;12.7;13.6;9.2;11.5];
x = x + 0.001 * rand(size(x))
[x, sortOrder] = sort(x, 'ascend');
y = y(sortOrder);
Thanks for your answer! But the similar x-values are not the problem, there is no errror message or such. It DOES fit the data (as I can see in the plot), but the coefficients that are found, are not the correct ones...
I tried it with your fitNonLinearModel.m et voilà! With some small modifications, it works! And the coefficients are totally different from the other ones...
The above code returns:
p= 31.3705881793848 97.355156245024 6.39477241747793
and the adapted fitNonLinearModel.m returns:
coefficients =
10.6643318631924
398.728521237987
0.248005408824638
But I still don't see my mistake... Very strange... also because it worked for the old case two years ago... the only difference is the form of the exponential fit
'a-b*exp(-c*x)'
instead of
'a*exp(-((x/b)^c))'
Maybe I have to change some Syntax, too... Or change the starting value, like last time? Anyway... I have a solution for my plot, but if someone finds the error, I still would like to know...
Thanks!

Connectez-vous pour commenter.

Catégories

Community Treasure Hunt

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

Start Hunting!

Translated by