Discover Ezyfit: A free curve fitting toolbox for Matlab
F. Moisy, 19 nov 2008.
Laboratory FAST, University Paris Sud.
Contents
About the Ezyfit Toolbox
The EzyFit toolbox for Matlab enables you to perform simple curve fitting of one-dimensional data using arbitrary fitting functions. It provides command-line functions and a basic graphical user interface for interactive selection of the data.
Simple fit: exponential decay
First plot some data, say, an exponential decay
plotsample exp nodisp
A predefined fit called 'exp' allows you to fit your data:
showfit exp
Equation: y(x) = a*exp(b*x)
a = 4.3408
b = -0.22743
R = 0.99697 (lin)
Suppose now you want to use your own variable and function names. Let's fit this data with the function f(t)=a*exp(-t/tau), and show the fit with a bold red line:
undofit % deletes the previous fit showfit('f(t)=a*exp(-t/tau)','fitlinewidth',2,'fitcolor','red');
Equation: f(t) = a*exp(-t/tau)
a = 4.3409
tau = 4.397
R = 0.99697 (lin)
Note that showfit recognizes that t is the variable, and the coefficients of the fit are named a and tau.
If you want to use the values of the coefficients a and tau into Matlab, you need to create these variables into the base workspace:
makevarfit a tau
a =
4.3409
tau =
4.3970
Initial guesses
Now suppose you want to fit more complex data, like a distribution showing two peaks. Let's try to fit these peaks with two gaussians, each of height a, mean m and width s.
plotsample hist2 nodisp showfit('a_1*exp(-(x-x_1)^2/(2*s_1^2)) + a_2*exp(-(x-x_2)^2/(2*s_2^2))');
Exiting: Maximum number of function evaluations has been exceeded
- increase MaxFunEvals option.
Current function value: 369920.454653
Equation: y(x) = a_1*exp(-(x-x_1)^2/(2*s_1^2))+a_2*exp(-(x-x_2)^2/(2*s_2^2))
a_1 = 41.052
a_2 = -2492.7
s_1 = 1269.4
s_2 = 13.262
x_1 = 1062.3
x_2 = -38.289
R = 0.32602 (lin)
The solver obviously get lost in our 6-dimensional space. Let's help it, by providing initial guesses
undofit showfit('a_1*exp(-(x-m_1)^2/(2*s_1^2)) + a_2*exp(-(x-m_2)^2/(2*s_2^2)); a_1=120; m_1=7; a_2 = 100; m_2=15', 'fitcolor','blue','fitlinewidth',2);
Equation: y(x) = a_1*exp(-(x-m_1)^2/(2*s_1^2))+a_2*exp(-(x-m_2)^2/(2*s_2^2))
a_1 = 128.41
a_2 = 77.126
m_1 = 6.9929
m_2 = 14.783
s_1 = 0.42396
s_2 = 1.4307
R = 0.98977 (lin)
The result seems to be correct now. Note that only 4 initial guesses are given here; the two other ones, s_1 and s_2, are taken as 1 -- which is close to the expected solution.
Fitting in linear or in log scale
Suppose you want to fit a power law in logarithmic scale:
plotsample power nodisp showfit power
Equation: y(x) = a*x^n
a = 0.4784
n = 2.494
R = 0.99934 (log)
would you have obtained the same result in linear scale? No:
swy % this shortcut turns the Y-axis to linear scale showfit('power','fitcolor','red');
Equation: y(x) = a*x^n
a = 2.9016
n = 2.2564
R = 0.99608 (lin)
The value of the coefficients have changed. In the first case, LOG(Y) was fitted, whereas in the second case Y was fitted, because the Y-axis has been changed.
You may however force showfit to fit LOG(Y) or Y whatever the Y axis, by specifying 'lin' or 'log' in the first input argument:
rmfit % this removes all the fits showfit('power; lin','fitcolor','red'); showfit('power; log','fitcolor','blue');
Equation: y(x) = a*x^n
a = 2.9016
n = 2.2564
R = 0.99608 (lin)
Equation: y(x) = a*x^n
a = 0.4784
n = 2.494
R = 0.99934 (log)
In the equation information, it is specified (lin) or (log) after the R coefficient.
Using the fit structure f
You can fit your the data without displaying it:
x=1:10;
y=[15 14.2 13.6 13.2 12.9 12.7 12.5 12.4 12.4 12.2];
f = ezfit(x,y,'beta(rho) = beta_0 + Delta * exp(-rho * mu); beta_0 = 12');
f is a structure that contains all the informations about the fit:
f
f =
name: 'beta(rho)=beta_0+Delta*exp(-rho*mu)'
yvar: 'beta'
xvar: 'rho'
fitmode: 'lin'
eq: 'beta_0+Delta*exp(-rho*mu)'
r: 0.9992
param: {'Delta' 'beta_0' 'mu'}
m: [3.9949 12.1058 0.3237]
m0: [1 12 1]
x: [1 2 3 4 5 6 7 8 9 10]
y: [1x10 double]
From this structure, you can plot the data and the fit:
clf
plot(x,y,'r*');
showfit(f)
Equation: beta(rho) = beta_0+Delta*exp(-rho*mu)
Delta = 3.9949
beta_0 = 12.106
mu = 0.32368
R = 0.99925 (lin)
you can also display the result of the fit
dispeqfit(f)
Equation: beta(rho) = beta_0+Delta*exp(-rho*mu)
Delta = 3.9949
beta_0 = 12.106
mu = 0.32368
R = 0.99925 (lin)
or create the variables in the base workspace
makevarfit(f) beta_0 mu Delta
beta_0 =
12.1058
mu =
0.3237
Delta =
3.9949
Weigthed fit
Suppose now we want to fit data with unequal weights, shown here as error bars of different lengths:
x = 1:10;
y = [1.56 1.20 1.10 0.74 0.57 0.55 0.31 0.27 0.28 0.11];
dy = [0.02 0.02 0.20 0.03 0.03 0.10 0.05 0.02 0.10 0.05];
clf, errorbar(x,y,dy,'o');
In order to perform a weighted fit on this data, the vectors y and dy have to be merged into a 2-by-N matrix and given as the second input argument to ezfit. Compare the results for the usual and weighted fits:
fw = ezfit(x, [y;dy], 'exp'); showfit(fw,'fitcolor','red'); f = ezfit(x, y, 'exp'); showfit(f,'fitcolor','blue');
Equation: y(x) = a*exp(b*x)
a = 2.0017
b = -0.2519
R = 0.98832 (lin)
Equation: y(x) = a*exp(b*x)
a = 2.0071
b = -0.24013
R = 0.99067 (lin)
The red curve (weighted fit) tends to go through the data with smaller error bars.