Week 5 - Curve fitting
AIM: TO PERFORM CURVE FITTING FOR THE GIVEN TEMPERATURE AND CP DATA IN PYTHON
THEORY: Curve fitting is the process of constructing a curve, or mathematical function, that has the best fit to a series of data points, possibly subject to constraints. Curve fitting can involve either interpolation, where an exact fit to the data is required, or smoothing, in which a "smooth" function is constructed that approximately fits the data. It examines the relationship between one or more predictors (independent variables) and a response variable (dependent variable), with the goal of defining a "best fit" model of the relationship.
How to choose the best fit?
Upon finding a curve that satisfies the data points there are 4 quantities that help us measure the goodness of fit criteria or how well the equation is representing the data points. They are listed as: -
- The sum of squares due to error (SSE)
- R-Square
- Adjusted R-Square
- Root Mean Square Error (RMSE)
How to make a curve fit perfectly?
In order to have a curve to fit perfectly over the data points provided, the error should be negligible, i.e. the values of R-Square should be exactly ‘1’. Generally, the minimal error is taken into account for best fit but to obtain a perfect fit, all the errors including centering and scaling errors should be nulled.
How to get the best fit?
A line of best fit can be roughly determined using an eyeball method by drawing a straight line on a scatter plot so that the number of points above the line and below the line is about equal (and the line passes through as many points as possible).
Also, the Split Polynomial technique can be opted to obtain a curve fit closest to the data set. This is one of the most viable techniques to be performed for the best fit.
What could be done to improve the cubic fit?
- Increase the number of iterations or function evaluations allowed.
- Reduce the convergence tolerance.
- Try also sub-setting the data and fitting different subsets of data separately.
GOVERNING EQUATIONS:
- SSE:
SSE=∑ni=1(Y(i)−f(x(i)))2���=∑�=1�(�(�)-�(�(�)))2
- R-SQUARE:
R2=SSRSST�2=������
where,
SSR=∑ni=1(f(x(i))−Mean)2���=∑�=1�(�(�(�))-����)2
SST=SSR+SSE���=���+���
- ADJUSTED R-SQUARE:
R2adj=1−[(1−R2)n−1n−k−1]����2=1-[(1-�2)�-1�-�-1]
where,
n = no. of datapoints
k = no. of independent variables
- RMSE:
RMSE=√(SSEn)����=√(����)
OBJECTIVES:
- Curve Fitting of the Temperature and CP
- Determining Goodness of fit.
INPUTS:
Data file (Temperature v/s CP): https://drive.google.com/file/d/1vWi9Vj3AdQf0gqUK1u9jwS8zg92BHGR0/view
QUESTIONS & ANSWERS:
Q. What do 'popt' and 'pcov' mean?
A. 'popt': - It is an array of the coefficients of a polynomial specified at the beginning of the program.
'pcov': - It is a square matrix that contains the true variance and covariance of the parameters.
Q. What does np.array(temperature) do?
A. Creates an array of temperatures from the values stored in a data file using numpy module.
Q. What does the * in *popt mean?
A. It helps to refer to the coefficients of the polynomial into consideration.
Q. What needs to be done in order to make the curve fit perfect?
A. To make the curve fit perfect, the value of RMSE should be minimum and the value of R2 should be close to 1. It can be done by increasing the order of polynomial that we are trying to curve fit.
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
# Curve fit function
def func_1(t, a, b):
return a*t + b
def func_2(t, a, b, c):
return a*pow(t,2) + b*t + c
def func_3(t, a, b, c, d):
return a*pow(t,3) + b*pow(t,2) + c*t + d
def func_4(t, a, b, c, d, e):
return a*pow(t,4) + b*pow(t,3) + c*pow(t,2) + d*t + e
# Reading thermodynamic data file
def read_file():
temperature = []
cp = []
for line in open('data','r'):
values = line.split(',')
temperature.append(float(values[0]))
cp.append(float(values[1]))
return [temperature, cp]
# Main Program
temperature, cp = read_file()
# Linear Curve Fitting
popt, pcov = curve_fit(func_1, temperature, cp)
fit_cp_1 = func_1(np.array(temperature), *popt)
plt.figure(1)
plt.plot(temperature, cp, 'k-.', linewidth=2)
plt.plot(temperature, fit_cp_1, color='red', linewidth=3)
plt.legend(['Actual data', 'Curve fit'])
plt.title('LINEAR CURVE FITTING')
plt.xlabel('Temperature [K]')
plt.ylabel('Cp')
plt.show()
# Quadratic Curve Fitting
popt, pcov = curve_fit(func_2, temperature, cp)
fit_cp_2 = func_2(np.array(temperature), *popt)
plt.figure(2)
plt.plot(temperature, cp, 'k-.', linewidth=2)
plt.plot(temperature, fit_cp_2, color='red', linewidth=3)
plt.legend(['Actual data', 'Curve fit'])
plt.title('QUADRATIC CURVE FITTING')
plt.xlabel('Temperature [K]')
plt.ylabel('Cp')
plt.show()
# Cubic Curve Fitting
popt, pcov = curve_fit(func_3, temperature, cp)
fit_cp_3 = func_3(np.array(temperature), *popt)
plt.figure(3)
plt.plot(temperature, cp, 'k-.', linewidth=2)
plt.plot(temperature, fit_cp_3, color='red', linewidth=3)
plt.legend(['Actual data', 'Curve fit'])
plt.title('CUBIC CURVE FITTING')
plt.xlabel('Temperature [K]')
plt.ylabel('Cp')
plt.show()
# Biquadratic Curve Fitting
popt, pcov = curve_fit(func_4, temperature, cp)
fit_cp_4 = func_4(np.array(temperature), *popt)
plt.figure(1)
plt.plot(temperature, cp, 'k-.', linewidth=2)
plt.plot(temperature, fit_cp_4, color='red', linewidth=3)
plt.legend(['Actual data', 'Curve fit'])
plt.title('BIQUADRATIC CURVE FITTING')
plt.xlabel('Temperature [K]')
plt.ylabel('Cp')
plt.show()
# Fitness Characteristics Calculation
s = np.sum(cp)
n = np.size(cp)
# Mean
m = s/n
# For Linear Curve Fit
SSR_lin = 0
SSE_lin = 0
for i in range(n):
error = abs((np.sum((cp[i] - fit_cp_1[i]))))
SSE_lin = SSE_lin + pow(error,2)
SSR_lin = SSR_lin + (np.sum(pow((fit_cp_1[i] - m),2)))
SST_lin = SSE_lin + SSR_lin
Rsq_lin = SSR_lin/SST_lin
RMSE_lin = pow((SSE_lin/n),0.5)
print('SST_lin:', SST_lin)
print('Rsq_lin:', Rsq_lin)
print('RMSE_lin:', RMSE_lin)
# For Quadratic Curve Fit
SSR_quad = 0
SSE_quad = 0
for i in range(n):
error = abs((np.sum((cp[i] - fit_cp_2[i]))))
SSE_quad = SSE_quad + pow(error,2)
SSR_quad = SSR_quad + (np.sum(pow((fit_cp_2[i] - m),2)))
SST_quad = SSE_quad + SSR_quad
Rsq_quad = SSR_quad/SST_quad
RMSE_quad = pow((SSE_quad/n),0.5)
print('SST_quad:', SST_quad)
print('Rsq_quad:', Rsq_quad)
print('RMSE_quad:', RMSE_quad)
# For Cubic Curve Fit
SSR_cub = 0
SSE_cub = 0
for i in range(n):
error = abs((np.sum((cp[i] - fit_cp_3[i]))))
SSE_cub = SSE_cub + pow(error,2)
SSR_cub = SSR_cub + (np.sum(pow((fit_cp_3[i] - m),2)))
SST_cub = SSE_cub + SSR_cub
Rsq_cub = SSR_cub/SST_cub
RMSE_cub = pow((SSE_cub/n),0.5)
print('SST_cub:', SST_cub)
print('Rsq_cub:', Rsq_cub)
print('RMSE_cub:', RMSE_cub)
# For Biquadratic Curve Fit
SSR_bquad = 0
SSE_bquad = 0
for i in range(n):
error = abs((np.sum((cp[i] - fit_cp_4[i]))))
SSE_bquad = SSE_bquad + pow(error,2)
SSR_bquad = SSR_bquad + (np.sum(pow((fit_cp_4[i] - m),2)))
SST_bquad = SSE_bquad + SSR_bquad
Rsq_bquad = SSR_bquad/SST_bquad
RMSE_bquad = pow((SSE_bquad/n),0.5)
print('SST_bquad:', SST_bquad)
print('Rsq_bquad:', Rsq_bquad)
print('RMSE_bquad:', RMSE_bquad)
EXPLANATION OF PROGRAM:
- Initially, the necessary modules are imported and the required functions are specified.
- A function for reading the data file provided is also written and arrays are formed for temperature and cp values.
- The Linear Curve fit is initiated using popt and pcov commands.
- The curve fitted graphs are lotted with legends and comparison is done.
- Similarly, Curve fit is initiated for Quadratic, Cubic, and Biquadratic polynomials.
- The best fit is chosen and the limitations are mentioned using the 'Goodness of Fit' criterion.
- The SST, RMSE, and R2 values are calculated and the results are mentioned for comparison purposes.