In [1]:
%pylab inline
In [2]:
# mathematical routines are expecting 'array'
x = array([-10, -9, -8, -7, -6, -5, -4, -3, 0]);
y = array([2.65, 2.10, 1.90, 1.40, 1.00, 0.80, 0.60, 0.30, 0.00]);
ey = array([0.1, 0.1, 0.1, 0.1, 0.05, 0.05, 0.05, 0.05, 0.2]);
# Plot the data with error bars
errorbar(x,y,ey,linestyle = '',marker = 'o') # no connecting line, circle
# Don’t forget axes labels
xlabel('x (mm)')
ylabel('y (mm)')
axis([-12,0.5,-0.5,3])
grid(True)
For physical reasons we expect our data is described by a circle.
The equation of a circle with radius $a$ centered at $(x,y)=(b,c)$ is given by
$$(x-b)^2+(y-c)^2 = a^2$$
Let's rewrite this in terms of $y$,
$$y=-\sqrt{a^2-(x-b)^2}+c$$
We define the function and then want to find the best estimates for $a, b, c$ consistent with our data.
In [3]:
def myfun(x,a,b,c):
ans = -sqrt(a**2-(x-b)**2)+c # this is y, "the function to be fit"
return ans
Here are the initial guesses for the parameters $a$, $b$, and $c$ to pass to the fitting function.
In [4]:
p0 = [15, 0, 15]
The 'curve_fit' function gets the best y by adjusting the parameters 'p'.
In [5]:
from scipy.optimize import curve_fit # import the curve fitting function
plsq, pcov = curve_fit(myfun, x, y, p0, ey) # curve fit returns p and covariance matrix
# these give the parameters and the uncertainties
print('a = %.3f +/- %.3f' % (plsq[0], sqrt(pcov[0,0])))
print('b = %.3f +/- %.3f' % (plsq[1], sqrt(pcov[1,1])))
print('c = %.3f +/- %.3f' % (plsq[2], sqrt(pcov[2,2])))
Now we use the fitted parameters in our function to compare with the data.
In [6]:
xlots = linspace(-11,0.5) # need lots of data points for smooth curve
yfit = myfun(xlots,plsq[0],plsq[1],plsq[2]) # use fit results for a, b, c
In [7]:
errorbar(x,y,ey,linestyle = '',marker = 'o')
xlabel('x (mm)')
ylabel('y (mm)')
plot(xlots,yfit)
title('Least-squares fit to data')
legend(['data','Fit'])
axis([-12,0.5,-0.5,3])
grid(True)