Week 5 - Curve fitting
CURVE FITTING USING LINEAR APPROXIMATION:
INPUT:
import math as M
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
# FITTING LINEAR CURVE THROUGH DATA
# defining curve fit function for the first order(linear) polynomial
def poly_1(t,a,b):
f = a*t + b
return(f)
# getting source data from data file
def get_data():
temperature = []
cp_real = []
for line in open('data','r'):
columns = line.split(',')
temperature.append(float(columns[0]))
cp_real.append(float(columns[1]))
return [temperature,cp_real]
# curve fit code
temperature, cp_real = get_data()
coeff, coeff_covariance = curve_fit(poly_1,temperature, cp_real)
cp_assumed = poly_1(np.array(temperature),*coeff)
# plotting curve fit data with real values
plt.plot(temperature,cp_real,linewidth=3,color='blue')
plt.plot(temperature,cp_assumed,color='red')
plt.legend(['Real data','curve fit'])
plt.xlabel('Temperature (kelvin)')
plt.ylabel('specific heat (J/kg K)')
plt.show()
output:
from observing this plot, we can apparently conclude that the purpose is not carried out with required efficiency.
keeping our first order as a limitation, this approximation can be further optimized with the use of multiple straight lines i.e split wise technique.
USING SPLIT-WISE TECHNIQUE FOR LINEAR APPROXIMATION
here, we will divide our temperature range (actually its called 'domain' precisely) in several parts in order to accommodate different curvatures of real data curve and approximate a smaller and 'better fitting' portion of a line.
INPUT:
split_number = 4
temperature, cp_real = get_data()
for i in range(1,split_number+1):
start = (3200/split_number)*(i-1)
finish = (3200/split_number)*i - 1
temperature_split = temperature[int(start):int(finish)]
cp_real_split = cp_real[int(start):int(finish)]
# curve fit code
coeff, coeff_covariance = curve_fit(poly_1,temperature_split, cp_real_split)
cp_assumed = poly_1(np.array(temperature_split),*coeff)
# plotting curve fit data with real values
plt.plot(temperature,cp_real,linewidth=3,color='blue')
plt.plot(temperature_split,cp_assumed,color='black',linewidth=5)
plt.title('linear split approximation')
plt.legend(['Real data','curve fit'])
plt.xlabel('Temperature (kelvin)')
plt.ylabel('specific heat (J/kg K)')
plt.show()
OUTPUT:
hence, by splitting the linear approximation for different portions of the graph, we can clearly observe that the curve fitting is much better.
above example uses 4 split lines (which can be adjusted by setting the split variable ' i ' at the very beginning of for loop. the more split lines, the better would be fitting and lesser would error become.
by extracting the coefficients, we can get functions of spit line used for particular range of temperatures. each line will have different sets of coefficients for different range of temperature based on least square method.
CURVE FIT USING CUBIC APPROXIMATION (split-wise technique):
INPUT:
import math as M
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
# FITTING CUBICAL CURVE THROUGH DATA
# defining curve fit function for the third-order polynomial
def poly_3(t,a,b,c,d):
f = a*pow(t,3) + b*pow(t,2) + c*t + d
return(f)
# getting source data from data file
def get_data():
temperature = []
cp_real = []
for line in open('data','r'):
columns = line.split(',')
temperature.append(float(columns[0]))
cp_real.append(float(columns[1]))
return [temperature,cp_real]
# FITTING CURVE THROUGH DATA USING SPLIT-WISE METHOD
split_number = 4;
temperature, cp_real = get_data()
for i in range(1,split_number+1):
start = (3200/split_number)*(i-1)
finish = (3200/split_number)*i - 1
temperature_split = temperature[int(start):int(finish)]
cp_real_split = cp_real[int(start):int(finish)]
# curve fit code
coeff, coeff_covariance = curve_fit(poly_3,temperature_split, cp_real_split)
cp_assumed = poly_3(np.array(temperature_split),*coeff)
# plotting curve fit data with real values
plt.plot(temperature,cp_real,linewidth=3,color='blue')
plt.plot(temperature_split,cp_assumed,color='black',linewidth=5)
plt.title('linear split approximation')
plt.legend(['Real data','curve fit'])
plt.xlabel('Temperature (kelvin)')
plt.ylabel('specific heat (J/kg K)')
plt.show()
OUTPUT:
as we can see, the nature of a curve fit is more efficient compared to linear approximation as the graph of split polynomials is closely fitted to the real data set.
furthermore, the split-wise technique is more efficient compared to using a single polynomial curve in this case. as there are changes in real curve that cannot be justified by a single polynomial curve. hence, split parts can be used to justify individual portions of the real data set.
QUESTION REFERENCE :
1. What does popt and pcov mean?
A : popt is optimum value of parameters for a given function. where it decides the value of coefficients for a polynomial taken for the approximation of the real data so that the 'least square method' of error regression estimation is satisfied.
pcov decides the covariance for the given optimum values for the curve, which, in our case is coefficients of an approximation polynomial.
2. What does np.array(temperature) do?
A: np.array(temperature) is a function handle passed to the format of the approximation curve which then feeds the temperature values along with coefficient values to the approximation function and generates the assumed values for cp which follows the polynomial function used to approximate real data.
3. What does the * in *popt mean?
A: *popt inside a line, cp_assumed = poly_3(np.array(temperature_split),*popt) feeds the value of the optimum coefficient obtained by the least square method of error regression. curve_fit function generates optimum parameter value for a given data set then stores it inside output called popt. which is then used as a function handle for generating an approximated cp values.