Week 5 - Curve fitting
Questions:
- What does popt and pcov mean? (Watch the video to get some context)
Curve fit option works by taking a polynomial function with constants/arguments, and the input data points as ‘x-data’ and ‘y-data’, then it calculates the optimum values for the constants/arguments using ‘popt’ such that, the squared residuals of (f(xdata, popt) – ydata) are kept minimal. ‘pcov’ on the other hand estimates the co-variance of ‘popt’. These parameters calculate the optimum values for the constants to get a closer plot.
- What does np.array(temperature) do?
np.array command converts the array in() after the command into a nested sequence instead of an array. Which is equivalent to making a for loop in our example as the ‘curve’ function requires an argument as a constant in the polynomial equation rather than an array/list.
- What does the * in *popt mean?
The star basically calls the optimized value of the constants (which is calculated and defined in the line prior) in the input function for the given ‘x-data’ and ‘y-data’. If the ‘*’ is omitted, the program throws in the error that values/arguments for the constant are not listed/are missing. Simply put, it works as a function which can be called later on when needed.
- Write code to fit a linear and cubic polynomial for the Cp data. Explain if your results are good or bad.
It is very clear that the input data has a non-linear nature as the two variables- temperature and specific pressure do not wary linearly as seen from the plot of input data, hence using a linear polynomial would certainly give inaccurate results.
Cubic polynomial has a highest degree of three, hence has 4 ‘constants’/arguments which can be optimized to get a relation closest to the actual input data plot. This concludes the fact that a higher degree polynomial, will give the closest fit to actual plot. The plots are are shown at the end:
- What needs to be done in order to make the curve fit perfect?
As we have done in this example, we can use a polynomial equation with optimized constants, to get a relation between ‘x’ and ‘y’ co-ordinates closer to the actual plot. A polynomial with a number of constants can be used to define such a non-linear plot if the values for the constants are calculated / tweaked correctly. The ‘curve fit’ operation with ‘popt’ and ‘pcov’ commands can be used effectively to optimize the arguments.
We can split the actual plot in 2 or more plots and use 1 polynomial per split to fit a curve even more effectively. This can be particularly useful if the plot changes abruptly.
2.
Objective: To write a program which outputs a curve to fit the given data, with minimal error and calculate the error.
Solution:
Given data file contains a distribution of temperature and specific pressure values in points form. The code is used to first open the data file and read it line by line using a ‘for’ loop and ‘open’ and ‘r’ commands. It is important to have the data file in the same folder as the code directory. As the values for temperature and ‘cp’ are separated by a ‘,’ comma sign, using ‘line.split’ command the values are first separated into 2 quantities, and then using predefined arrays, stored into two variables. A function is defined for this operation of storing the input file data in arrays for further operation and plotting – which can be simply done using ‘matplotlib’ module.
To fit a curve to this input data, we use ‘curve fit’ option in ‘scipy.optimize’ module. Curve fit option works by taking a polynomial function with constants, and the input data points as ‘x-data’ and ‘y-data’, then is calculates the optimum values for the constants using ‘popt’ such that, the squared residuals of (f(xdata, popt) – ydata) are kept minimal. ‘pcov’ on the other hand estimates the co-variance of ‘popt’.
Now, using the ‘curve’ function defined previously, which contains a polynomial function with a given degree utilized by ‘popt’ to calculates the optimum values we calculate the ‘y data’. Using ‘np.array’ command to convert the array of ‘x-data’ into a sequence which can be used in the ‘curve’ function as an argument, we get ‘y’ co-ordinates for each ‘x’. It is then stored in a different variable and finally the fir curve is plotted using ‘matplotlib’ module.
To test the accuracy of fit, we calculate the RMS or root mean square value. It is the square root of the mean of the square of error: The sum of errors was calculated by subtracting the y-coefficient from the input data from the y-coefficient obtained the fitted curve.
error = `(y_(Input curve[i]) – y_(fit curve[i]))`
(sum error)2 = `∑_(i=1)^n(y_(Input data[i] )– y_(fit curve[i] ) )^2`
RMS =`√[(Sum errOr)^2/n]`
The error comes out to be less than 2% at 1.6 of Cp
Matlab code:
#curve fitting challenge
import math
import matplotlib.pyplot as plt
import numpy as np
from scipy.optimize import curve_fit
#defining a function to plot the data file
def read_data():
temperature = []
cp = []
for line in open('data','r'):
value = line.split (',')
temperature.append(float(value[0]))
cp.append(float(value[1]))
return [temperature,cp]
#Defining function to use the curve fitting option using quadratic equation
def curve(t,a,b,c,d,e):
return a*pow(t,4)+b*pow(t,3)+c*pow(t,2)+d*pow(t,1)+e
x,y = read_data()
#print(x)
#print(y)
#optimizing the curve using equation
popt,pcov = curve_fit(curve,x,y)
fit_cp =[]
fit_cp = curve(np.array(x),*popt)
"""
for z in x:
fit_cp1 = curve(z,*popt)
fit_cp.append(fit_cp1)
b = np.array(x)
print(b)
print(x)
"""
#Finding the RMS error
sum_error = 0
error = 0
for n in range(30,3171):
error = (y[n] - fit_cp[n])
sum_error = sum_error + pow((error),2)
#print(error)
print(sum_error)
print(fit_cp[1])
rms = pow((sum_error/3171),0.5)
print(rms)
plt.plot(x,fit_cp,'b',linewidth = 2)
plt.plot(x,y,'r',linewidth = 2)
plt.xlabel('Temperature')
plt.ylabel('Cp')
plt.title('Curve fitting using quartic equation')
plt.legend(['b = Curve fit','r = Actual data plot'])
plt.grid()
plt.show()
Procedure:
- First all the necessary modules were imported including the ‘curve fit’ tool from ‘scipy.optimize’ module. In no particular order the functions were defined to be called later on. One of these functions is for storing the input data in separate variables as arrays. As mentioned earlier, the data file is first opened, read line by line using a ‘for’ loop, split by the ‘,’ using ‘line.split’ command and stored in variables previously defined as empty arrays.
- These variables are then plotted using ‘matplotlib’ module to visualize the input data curve.
- Now, to produce a fit curve, first a polynomial equation is defined using the ‘def’ command, the constants of this equations or arguments are optimized for a accurate curve using ‘popt’ and ‘pcov’ commands with the help of ‘curve fit’ operation.
- For the optimization of the arguments, as mentioned before, we call the function with polynomial equation, we call the variables consisting the input data as the ‘xdata’ and ‘ydata’ parameters, all in the ‘curve fit’ operation as per its syntax.
- Now using the function with these arguments optimized for minimal error, the y-co-ordinates for the fit curve were calculated. As the function for the polynomial equation requires an argument or a constant and not an array for the variable ‘t’, ‘np.array’ command is used, which converts the array into a sequence of inputs. For the remaining arguments, the optimized constants were input using ‘*popt’ which calls the constants calculated in the previous line. This ‘y-curve fit data’ is stored in a different variable and plotted using ‘matplotlib’ module.
- To calculate the error between the input data and the fitted curve, Root mean square method was used. Using a ‘for’ loop, the error between ‘y of fitted curve’ and ‘y of input data’ was calculated for each of the ‘x’, then all these ‘error’s were squared and added to get ‘(sum error)2’. We square the error value before adding then to make sure any negative errors are not neutralized. Finally this squared error sum value was divided by the sample space, and the square root of the dividend was calculated to counter the square operation, and we get the ‘RMS’ value of the plots.
Plots:
1. Curve fitting using quadratic equation:
RMS error: 11.032 of Cp
- Curve fitting using cubic equation:
RMS error: 5.42 of Cp
- Curve fitting using quartic equation:
RMS error: 1.62 of Cp
Conclusion:
- It is very clear that the input data has a non-linear nature as the two variables - temperature and specific pressure do not wary linearly as seen from the plot of input data. A polynomial with a number of constants can be used to define such a non-linear plot if the values for the constants are calculated / tweaked correctly. Cubic polynomial has a highest degree of three, hence has 4 ‘constants’/arguments which can be optimized to get a relation closest to the actual input data plot. This concludes the fact that a higher degree polynomial, will give the closest fit to actual plot.
- Root mean square method for calculation of errors is suitable for such a plot where no negative parameters are plotted. The square operation of each error value calculated makes sure any negative errors are preserved in case the fitted curve overshoots the input data. If the RMS error calculated is less than 5% the curve can be assumed as accurate, in our case (polynomial with highest degree 4) it is less than 1% (0.45%).