import matplotlib.pyplot as plt
import numpy as np
from sympy import *
xx, yy, aa, bb, cc = symbols('xx yy aa bb cc')
xdata = np.array([1, 2, 3, 4, 5])
ydata = np.array([1., 2.3, 3., 3.7, 3.])
yerr = np.array([0.5, 0.5, 0.5, 0.5, 0.5])
We want to find the parameters $a$, $b$ and $c$ of the parabola $y = c x^2 + b x + a$ which minimize: $ \chi^2 = \sum_i \frac{(y_i - c x_i^2 - b x_i - a)^2}{\sigma_i^2}$
The minimum condition can be derived expanding $(yy - cc \cdot xx^2 - bb \cdot xx - aa)^2$, and equating the derivatives with respect to $aa$, $bb$, $cc$ to zero.
s = expand((yy - cc*xx**2 - bb*xx - aa)**2)
s
Compute the three derivatives:
s_aa = diff(s,aa)
s_aa
s_bb = diff(s,bb)
s_bb
s_cc = diff(s,cc)
s_cc
$a$, $b$ and $c$ are the solutions of the linear system: $\begin{bmatrix} \sum_i \frac{1}{\sigma_i^2} & \sum_i \frac{x_i}{\sigma_i^2} & \sum_i \frac{x_i^2}{\sigma_i^2}\\ \sum_i \frac{x_i}{\sigma_i^2} & \sum_i \frac{x_i^2}{\sigma_i^2} & \sum_i \frac{x_i^3}{\sigma_i^2}\\ \sum_i \frac{x_i^2}{\sigma_i^2} & \sum_i \frac{x_i^3}{\sigma_i^2} & \sum_i \frac{x_i^4}{\sigma_i^2}\\ \end{bmatrix}$ $\begin{bmatrix} a\\b\\c \end{bmatrix}$ = $\begin{bmatrix} \sum_i \frac{y_i}{\sigma_i^2} \\ \sum_i \frac{x_i y_i}{\sigma_i^2}\\\sum_i \frac{x_i^2 y_i}{\sigma_i^2} \end{bmatrix}$
Compute numerically the entries of the left-hand-side matrix:
yerrSq = yerr*yerr
sum_one_over_yerrSq = (1./yerrSq).sum()
sum_x_over_yerrSq = (xdata/yerrSq).sum()
sum_x2_over_yerrSq = (xdata*xdata/yerrSq).sum()
sum_x3_over_yerrSq = (xdata*xdata*xdata/yerrSq).sum()
sum_x4_over_yerrSq = (xdata*xdata*xdata*xdata/yerrSq).sum()
sum_y_over_yerrSq = (ydata/yerrSq).sum()
sum_xy_over_yerrSq = (xdata*ydata/yerrSq).sum()
sum_x2y_over_yerrSq = (xdata*xdata*ydata/yerrSq).sum()
mat = np.array([[sum_one_over_yerrSq,sum_x_over_yerrSq,sum_x2_over_yerrSq],
[sum_x_over_yerrSq,sum_x2_over_yerrSq,sum_x3_over_yerrSq],
[sum_x2_over_yerrSq,sum_x3_over_yerrSq,sum_x4_over_yerrSq]])
mat
Invert the matrix:
mat_inv = np.linalg.inv(mat)
mat_inv
Check
np.dot(mat,mat_inv)
Compute the entries of the right-hand-side vector:
noti = np.array([sum_y_over_yerrSq,sum_xy_over_yerrSq,sum_x2y_over_yerrSq])
noti
Compute $a$, $b$ and $c$:
np.dot(mat_inv,noti)
a, b, c = np.dot(mat_inv,noti)[0],np.dot(mat_inv,noti)[1],np.dot(mat_inv,noti)[2]
print(a)
print(b)
print(c)
Plot, adding extra points for the parabola:
fig, ax = plt.subplots()
thickxdata = np.arange(0.8,5.4,0.1)
plt.plot(thickxdata,c*thickxdata*thickxdata+b*thickxdata+a,xdata,ydata,'o')