How do I fit an exponential curve to my data?

859 visualizzazioni (ultimi 30 giorni)
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 Commenti
Arturo Gonzalez
Arturo Gonzalez il 1 Set 2020
Modificato: Arturo Gonzalez il 1 Set 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. il 28 Lug 2022
Modificato: H. Sh. G. il 28 Lug 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.

Accedi per commentare.

Risposta accettata

Andrei Bobrov
Andrei Bobrov il 23 Ott 2013
Modificato: Chad Greene il 14 Gen 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 Commenti
Michael Solonenko
Michael Solonenko il 14 Mag 2021
This requires MATLAB Curve Fit package. Is there a way to do a simple one exponential fit without it?
Image Analyst
Image Analyst il 14 Mag 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.

Accedi per commentare.

Più risposte (2)

Image Analyst
Image Analyst il 21 Nov 2018
You could also use fitnlm (Fit Non Linear Model):
0000 Screenshot.png

Tamara Schapitz
Tamara Schapitz il 20 Nov 2018
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 Commenti
Image Analyst
Image Analyst il 9 Apr 2020
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);
Tamara Schapitz
Tamara Schapitz il 9 Apr 2020
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!

Accedi per commentare.

Categorie

Scopri di più su Get Started with Curve Fitting Toolbox in Help Center e File Exchange

Community Treasure Hunt

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

Start Hunting!

Translated by