Curve fitting using MATLAB
Aim:
To write a program to fit a linear and cubic polynomial for the given Cp data and plot the linear and cubic fit curves using MATLAB.
Introduction:
Curve fitting is the process of constructing a curve or a mathematical function, that has the best fit to a series of data points which are subject to constraints. Curve fitting can involve interpolation and extrapolation and these fitted curves can be used as an aid for data visualization to infer values of a function where no data are available and also to study relationships among two or more variables.
MATLAB Program:
I would like to present this project with the help of three programs.
1. Program for Fitting of Linear and Cubic polynomial for Cp data :
%Curve fitting of Linear and Cubic Polynomial for Cp data
clear all
close all
clc
%Loading the data
cp_data = load('data.doc');
%Assigning values to variables
cp = cp_data(:,2);
temp = cp_data(:,1);
%Curve fit
%First order polynomial = a*t+c
coeff_1d = polyfit(temp,cp,1);
predicted_cp_1d = polyval(coeff_1d,temp);
%Third order polynomial = a*t^3 + b*t^2 + c*t + d
coeff_3d = polyfit(temp,cp,3);
predicted_cp_3d = polyval(coeff_3d,temp);
%Compare by plotting
%First order or Linear polynomial vs original data
figure(1)
plot(temp,cp,'linewidth',2);
hold on
plot(temp,predicted_cp_1d,'linewidth',2,'color','r');
hold off
xlabel('Temperature (K)');
ylabel('Specific Heat (kJ/kmol-K)')
legend('Original dataset','Curve fit','location','northwest')
title('Linear polynomial curve fit vs Original data')
%Third order or Cubic polynomial vs original data
figure(2)
plot(temp,cp,'linewidth',2);
hold on
plot(temp,predicted_cp_3d,'linewidth',2,'color','r');
hold off
xlabel('Temperature(K)');
ylabel('Specific Heat(kJ/kmol-K)')
legend('Original dataset','Curve fit','location','northwest')
title('Cubic polynomial curve fit vs Original data')
Explanation:
In this first program, I have coded the fitting of linear and cubic polynomial for Cp data.
Using 'load( )' command, I have loaded the data from the given document and assigned it to a variable 'cp_data'.
Using two other variables 'cp' and temp' , I have assigned the Cp values and Temperature values to the respective variables.
For polynomial fitting, I have used 'polyfit' function in which the number denotes the 'order of the polynomial' and the variables to be fitted, need to be defined inside the function.
Variables for first order or linear polynomial are 'coeff_1d' , for co efficients and 'predicted_cp_1d' for the predicted values of Cp using a linear polynomial.
For co efficients using Cubic polynomial, variable 'coeff_3d' was used and for predicted values of Cp using the cubic polynomial, variable 'predicted_cp_3d' was used.
To visualize the results, 'plot( )' command is used - one for Linear polynomial curve fit vs Original data and the other for Cubic polynomial curve fit vs Original data.
The 'title( )' command was used to indicate the respective plots.
Using 'legend( )' function, the curves in the plots are indicated and 'location' was used to move the legend box to one corner of the plot, for an unobstructed view of the curves.
Results and Explanation:
(a) First plot:
The above picture was the result of first plot command and it is between linear polynomial curve fit and original data curve.
The blue colored curve indicated the original data from the given file and red colored curve indicates Linear polynomial curve fit.
We can infer that, a linear polynomial did not give a good fit when compared to original data. There are a lot of errors in linear polynomial curve fit when compared to original data curve, except at the two intersecting points.
(b) Second plot:
The above image was the result of second plot command and it is between cubic polynomial curve fit and original data curve.
The blue colored curve indicated the original data from the given file and red colored curve indicates Cubic polynomial curve fit.
From this plot, we can infer that, 'Cubic or the third order polynomial curve fit is very close to the original data curve'. There are less number of errors compared to Linear polynomial curve fit.
Hence, cubic polynomial is better compared to Linear polynomial curve fit and higher the degree of the polynomial, greater the perfection of the curve fit.
Warnings:
Though the Cubic polynomial is closely fitting with original data curve, MATLAB throws a warning that the polynomial is badly conditioned.
This warning can be removed by following different ways of fitting the curves. I will be explaining it with the Third Program
2. Program for obtaining the best fit :
To get the best fit, we need to measure how successful the fit is in explaining the variation of the data. For that there are four methods and I have used R-square method.
R-Square : It is the square of the correlation between the response values and the predicted response values. It is also called the square of the multiple correlation coefficient and the coefficient of multiple determination. The values are classified as :
- 0 for the worst possible fit for the data set and
- 1 for the best possible fit for the data set
The value of R-square can be calculated using the following formula,
R^2 = SSR/SST where,
SSR = sum of squares of the regression, which is basically the square of the difference between the value of the fitting function at a given point and the arithmetic mean of the data set.
SST = summation of SSR and SSE.
%R-Square
clear all
close all
clc
%Loading the data
cp_data = load('data.doc');
%Assigning values to the variables
temp = cp_data(:,1);
cp = cp_data(:,2);
% Curve fit
%First order or Linear polynomial vs original data
coeff_1d= polyfit(temp,cp,1);
predicted_cp_1d = polyval(coeff_1d, temp);
% Compare using plotting
figure(1)
plot(temp,cp,'linewidth',2);
hold on
plot(temp,predicted_cp_1d,'linewidth',2,'color','r');
hold off
%Labels, Legends and Title
xlabel('Temperature (K)');
ylabel('Specific Heat (kJ/kmol-K)')
legend('Original dataset','Curve fit','location','northwest')
title('Linear polynomial curve fit vs Original data')
% Calculation of sum of squared error
error = predicted_cp_1d(:,1) - cp(:,1);
SSE = sum(error.^2);
% Calculation of sum of squares of regression
SSR = sum((cp(:,1) - mean(cp(:,1))).^2);
% Calculation of R_square
SST = SSR + SSE;
R1_square = SSR/SST
if R1_square>0.95
display('Good Fit')
else
display('Not a good fit')
end
%Third order or Cubic polynomial vs original data
coeff_3d = polyfit(temp,cp,3);
predicted_cp_3d = polyval(coeff_3d, temp);
figure(2)
plot(temp,cp,'linewidth',2);
hold on
plot(temp,predicted_cp_3d,'linewidth',2,'color','r');
hold off
%Labels, Legends and Title
xlabel('Temperature(K)');
ylabel('Specific Heat(kJ/kmol-K)')
legend('Original dataset','Curve fit','location','northwest')
title('Cubic polynomial curve fit vs Original data')
% Calculation of sum of squared error
error = predicted_cp_3d(:,1) - cp(:,1);
SSE = sum(error.^2);
% Calculation of sum of squares of regression
SSR = sum((cp(:,1) - mean(cp(:,1))).^2);
% Calculation of R_square
SST = SSR + SSE;
R2_square = SSR/SST
if R2_square>0.95
display('Good Fit')
else
display('Not a good fit')
end
Explanation:
Using 'load( )' command, I have loaded the data from the given document and assigned it to a variable 'cp_data'.
Using two other variables 'cp' and temp' , I have assigned the Cp values and Temperature values to the respective variables.
For polynomial fitting, I have used 'polyfit' function in which the number denotes the 'order of the polynomial' and the variables to be fitted, need to be defined inside the function.
The variable 'coeff_1d' is used for Linear polynomial and 'predicted_cp_1d ' for predicted values of Cp for Linear Polynomial.
Using 'plot()' function, the original data and Linear polynomial curve fit are plotted in a single figure.
The variable 'coeff_3d' is used for Linear polynomial and 'predicted_cp_3d ' for predicted values of Cp for Linear Polynomial.
Using 'plot()' function, the original data and Cubic polynomial curve fit are plotted in a single figure.
Errors are calculated for both Linear and Cubic Polynomial curve fit and finally the values of R-Square in each case is obtained using the same formula as discussed in the R-Square method theory part.
An 'If else' statement is used to return a string to indicate whether the obtained R-Square value indicates a Good fit or not. The output strings are either 'Good fit' or 'Not a good fit' depending on the value of R-Square.
The 'title( )' command was used to indicate the respective plots.
Using 'legend( )' function, the curves in the plots are indicated and 'location' was used to move the legend box to one corner of the plot, for an unobstructed view of the curves.
Results and Explanation:
For the first two plots , we obtain the same result as in the first program.
Upon solving the curves using R-Square method, the calculated values appear on the command window as follows:
The value of R-Square for Linear Polynomial curve fit is 0.9301 and for Cubic polynomial curve fit, it is 0.9967.
As per the theory, 'if the value is less than 0.95, then it is not a good fit and all values greater than 0.95 indicate a good fit'.
Hence, Cubic polynomial curve fit is the best fit when compared to Linear Polynomial curve fit which is also indicated by the R-Square values.
3. Program for Dividing the data into subsets:
One of the ways to make a better fit is to divide the given data into equal subsets.
This method reduces errors and removes warnings while doing curve fitting.
I have coded a program which analyses the output when the data is divided into 2 subsets as well as 4 subsets.
%Curve fitting by dividing data into subsets
clear all
close all
clc
%Loading the data
cp_data = load('data.doc');
%Assigning values to variables
cp = cp_data(:,2);
temp = cp_data(:,1);
%Curve fit
%Dividing into 2 subsets
%Cp values
cp_01 = cp_data([1:1600],2);
cp_02 = cp_data([1601:3200],2);
%Temperature values
temp_01 = cp_data([1:1600],1);
temp_02 = cp_data([1601:3200],1);
%Two subsets
coeff_01 = polyfit(temp_01,cp_01,2);
predicted_cp_01 = polyval(coeff_01,temp_01);
coeff_02 = polyfit(temp_02,cp_02,1);
predicted_cp_02 = polyval(coeff_02,temp_02);
%Compare by plotting
%Two subsets
figure(1)
plot(temp,cp,'linewidth',2);
hold on
plot(temp_01,predicted_cp_01,'linewidth',2,'color','r');
plot(temp_02,predicted_cp_02,'linewidth',2,'color','g');
hold off
%Labels, Legends and Title
xlabel('Temperature(K)');
ylabel('Specific Heat(kJ/kmol-K)')
legend('Original dataset','Curve fit 1', 'Curve fit 2','location','northwest')
title('Two subsets Curve fit vs Original data')
%Dividing into 4 subsets
%Cp values
cp_03 = cp_data([1:800],2);
cp_04 = cp_data([801:1600],2);
cp_05 = cp_data([1601:2400],2);
cp_06 = cp_data([2401:3200],2);
%Temperature values
temp_03 = cp_data([1:800],1);
temp_04 = cp_data([801:1600],1);
temp_05 = cp_data([1601:2400],1);
temp_06 = cp_data([2401:3200],1);
%Four subsets
coeff_03 = polyfit(temp_03,cp_03,2);
predicted_cp_03 = polyval(coeff_03,temp_03);
coeff_04 = polyfit(temp_04,cp_04,2);
predicted_cp_04 = polyval(coeff_04,temp_04);
coeff_05 = polyfit(temp_05,cp_05,1);
predicted_cp_05 = polyval(coeff_05,temp_05);
coeff_06 = polyfit(temp_06,cp_06,1);
predicted_cp_06 = polyval(coeff_06,temp_06);
%Compare by plotting
%Four subsets
figure(2)
plot(temp,cp,'linewidth',2);
hold on
plot(temp_03,predicted_cp_03,'linewidth',2,'color','r');
plot(temp_04,predicted_cp_04,'linewidth',2,'color','g');
plot(temp_05,predicted_cp_05,'linewidth',2,'color','m');
plot(temp_06,predicted_cp_06,'linewidth',2,'color','k');
hold off
%Labels, Legends and Title
xlabel('Temperature(K)');
ylabel('Specific Heat(kJ/kmol-K)')
legend('Original dataset','Curve fit 1','Curve fit 2','Curve fit 3','Curve fit 4','location','northwest')
title('Four subsets curve fit vs Original data')
Explanation:
In order to minimize errors and warnings, the above program is coded to curve fit by dividing the data into equal subsets.
Using 'load( )' command, I have loaded the data from the given document and assigned it to a variable 'cp_data'.
Using two other variables 'cp' and temp' , I have assigned the Cp values and Temperature values to the respective variables.
For polynomial fitting, I have used 'polyfit' function in which the number denotes the 'order of the polynomial' and the variables to be fitted, need to be defined inside the function.
(a) Two subsets:
First, I have divided the data into two equal subsets.
Hence I used 'cp_01' and 'cp_02' to indicate the two equal Cp values and 'temp_01' and 'temp_02' to indicate two equal temperature values.
The variables 'coeff_01' and 'coeff_2' indicate the polyfit function values for the respective subsets and 'predicted_cp_01' and 'predicted_cp_02' indicate the predicted Cp values under the two subsets.
For the first subset, the polynomial is Quadratic, which is defined by 'coeff_01 = polyfit(temp_01,cp_01,2);' and for the second subset, the polynomial is linear, which is defined by 'coeff_02 = polyfit(temp_02,cp_02,1);'
The reason I chose Quadratic for the first one is that the original data has more complex variation in the first part than the second part. A linear polynomial is sufficient to give a good fit for the second part.
While plotting, the above two subsets along with the original data are included in a single figure by using 'hold on' and 'hold off' functions.
Colours are specified in such a way to make each subset stand out for a clear view of the curve fit.
The 'title( )' command was used to indicate the respective plots.
Using 'legend( )' function, the curves in the plots are indicated and 'location' was used to move the legend box to one corner of the plot, for an unobstructed view of the curves.
(b) Four subsets:
In the next part of the program, I have divided the data into four equal subsets.
Hence I used 'cp_03' , 'cp_04', cp_05', and 'cp_06' to indicate the equal values of Cp and 'temp_03' , 'temp_04, 'temp_05', 'temp_06' to indicate equal values of temperature.
The variables 'coeff_03 ,'coeff_04', 'coeff_05', and 'coeff_06' indicate the polyfit function values for the respective subsets and 'predicted_cp_03' ,'predicted_cp_04' ,'predicted_cp_05' ,and 'predicted_cp_06' indicate the predicted Cp values under the four subsets.
For the first two subsets, the polynomials are Quadratic, which are defined by 'coeff_03 = polyfit(temp_03,cp_03,2);' and 'coeff_04 = polyfit(temp_04,cp_04,2);' .
For the second two subsets, the polynomials are linear, which are defined by 'coeff_05 = polyfit(temp_05,cp_05,1);' and 'coeff_06 = polyfit(temp_06,cp_06,1);' .
The reason I chose Quadratic for the first one is that the first part of the original data has more complex variation than the second part of the data. A linear polynomial is sufficient to give a good fit for the second part.
While plotting, the above four subsets along with the original data are included in a single figure by using 'hold on' and 'hold off' functions.
Colours for each subset are specified in such a way to make each subset stand out for a clear view of the curve fit.
The 'title( )' command was used to indicate the respective plots.
Using 'legend( )' function, the curves in the plots are indicated and 'location' was used to move the legend box to one corner of the plot, for an unobstructed view of the curves.
Results and Explanation:
(a) Two subsets plot:
The above image is the result of plot between two subsets and original data.
Since I used a Quadratic polynomial for the first part, as indicated by a red color curve , the error is far more reduced when compared to a linear polynomial as seen in the previous results.
The linear polynomial fit which is in Green color, is better for the second part as we can see minimum errors compared to the original data curve indicated by blue color.
Hence dividing a subset and fitting a curve is better than using a single polynomial for the entire curve fitting.
(b) Four subsets plot:
The above is a result of a plot between Four subsets and original data.
As we can see that, the curve fit obtained is much closer to the original data curve and there are very less number of errors as compared to the previous results.
The original data curve is indicated by blue color and the four subsets are indicated by different colors.
From these results, we can infer that, 'when the data is divided into many number of subsets, the errors reduce and the best fit can be obtained'.
Thus we can say that, Greater the number of divisions of the original data, greater is the improvement of a Cubic polynomial fit.
Inferences:
1. How to make a curve fit perfectly?
In order to make a perfect fit, we need to choose a Higher order Polynomial. This increases the accuracy by creating curves closer to the original curve and minimize the errors. (Program 1)
2. How to get the best fit?
To get the best fit, we need to measure how successful the fit is in explaining the variation of the data. For that, there are various methods, namely:
- The sum of squares due to error (SSE)
- R-square
- Adjusted R-square
- Root mean squared error (RMSE)
Using R-Square method, I have coded a program above and given a detailed explanation for the same. Hence using any of these techniques, we can obtain the best fit. (Program 2)
3. What could be done to improve the cubic fit?
In order to improve a cubic fit, we need to divide the data into many subsets until a better fit is obtained. This will not only reduce the errors but also provides a better result when compared to a single cubic polynomial fit.
I have explained this method using a program above and also given a detailed explanation for the same. (Program 3)
Conclusion:
Programs for Linear and Cubic Polynomial fit for the given Cp values were coded and detailed explanation for the code and results were given with the help of MATLAB Screenshots and Plots. After executing the programs and carrying out the research, inferences were also listed out.
References:
https://skill-lync.com/projects/Curve-Fitting-and-criterion-to-choose-best-fit-41860
https://en.wikipedia.org/wiki/Curve_fitting
https://in.mathworks.com/help/matlab/ref/legend.html
The data for Cp values and temperature is shared in the link below :
https://drive.google.com/file/d/1rmxNt28HLYKEA5fYR5z1ODpMyo5bRYUo/view?usp=sharing