how to obtain a fit with nonlinear regression data?
Ältere Kommentare anzeigen
EDIT: modified your code so that it can run here
Hello everyone, I'm trying to get a graph with a curve that fits a series of data obtained from a non-linear regression, but I can't find the error. The error occur when i try to polt figure(1) between lines 90-100.
%% author: Andrea Rigotto
clc
clear all
close all
%%
%read all .xlsx file inside the fwolder
%cicle for obtain the sample data content directly from the .xlsx file
table = readtable('P_T_Ni.xlsx');
temperature(:,1) = table.temperature;
pressure(:,1) = table.pressure;
Ni_grt(:,1) = table.Ni_Grt;
Ni_ol(:,1) = table.Ni_Ol;
Cr_grt(:,1) = table.Wt_Cr;
Ca_grt(:,1) = table.Wt_Ca;
%% calculation
%Keq
Ni_grt = Ni_grt(~isnan(Ni_grt), :);
Keq= Ni_grt ./2900;
%temperature from °C to K
temperature = temperature +273.15 ;
%Ni olivine mean
%Ni_ol = Ni_ol(~isnan(Ni_ol), :);
%mean_Ni_ol = mean(Ni_ol);
%% ignore the NaN value
temperature = temperature(~isnan(temperature), :);
pressure = pressure(~isnan(pressure), :);
Ca_grt = Ca_grt(~isnan(Ca_grt), :);
Cr_grt = Cr_grt(~isnan(Cr_grt), :);
%% Calculate the parameters (ΔH, ΔV, ΔS)
pressure_keq=[pressure Keq];
% function of T
T = @(x,pressure_Keq) (x(1) + pressure_Keq(:,1) * x(2)) ./ (x(3) - log( pressure_Keq(:,2)));
% fixed start parameters (ΔH, ΔV, ΔS)
% The chosen values must be of the same order of magnitude as the expected values
x0 = [1000, 10, 1];
% nonlinear regression with lsqcurvefit
x_fit = lsqcurvefit(T, x0, pressure_keq, temperature);
% Extract the fitted parameters
DeltaH = x_fit(1);
DeltaV = x_fit(2);
DeltaS = x_fit(3);
% the new value od temperature from Ni_grt of database
predicted_temperature = T(x_fit, pressure_keq);
% print the result
fprintf('Parametri adattati:\n');
fprintf('ΔH = %.2f\n', DeltaH);
fprintf('ΔV = %.2f\n', DeltaV);
fprintf('ΔS = %.2f\n', DeltaS);
%fprintf('Ni_ol = %.2f\n', mean_Ni_ol);
%% diff T(Ni-in-grt)-T(TA98)
deltaT = predicted_temperature-temperature;
mean_deltaT = mean(deltaT);
fprintf('mean_detaT = %.2f\n', mean_deltaT);
%% 1 sigma statistics
%calculate standard deviation
sigma_value=std(deltaT);
fprintf ('1σ of deltaT=%.2f\n', sigma_value);
%% R^2
R_sq= 1-var(temperature-predicted_temperature)/var(temperature);
fprintf('R^2=%.2f\n',R_sq);
%% T°C Ryan 1996
T_Ryan = (1000 ./(1.506-0.184*log(Ni_grt)))-273;
%% T°C Canil 1999
T_canil = 8772 ./(2.53-log(Keq))-273;
%% T°C sudholz 2021
T_sudholz = -8254.568 ./((Ca_grt*3.023)+(Cr_grt*2.307)+(log(Keq)-2.639))-273;
%% graphs
%transform the pressure from Kbar to Gpa
pressure= pressure/10;
%trasform the Temperature from k to °C
temperature = temperature-273.15;
% comparison between T_canil, T_Ryan, T_Sudholz and us
figure(1);
fo = fitoptions('Method','NonlinearLeastSquares');
ft = fittype(8772 ./(2.53-log(Keq))-273,'Keq','options',fo);
[fit_canil,gof]= fit(pressure,T_canil,ft,'Keq',2);
plot(fit_canil, pressure,'m')
xlabel('Pressure (GPa)')
ylabel('Temperature (°C)');
2 Kommentare
Peter Perkins
am 10 Nov. 2023
Don't do this:
table = readtable('P_T_Ni.xlsx');
table is the name of a class. Eventually, this variable name will come back to bite you. Name it t.
Peter Perkins
am 10 Nov. 2023
You are using fit from Curve Fitting tbx. You might also look into using fitnlm from Statistics & Machine Learning, which supports fitting using data stored in a table. No need to extract things.
Antworten (1)
Cris LaPierre
am 8 Nov. 2023
The equation needs to be entered as a char array or string. You also need to have Name-Value pairs for the optional inputs. See this example: https://www.mathworks.com/help/curvefit/fittype.html#btpaend-8
I think this is what you want
ft = fittype("8772./(2.53-log(Keq))-273",'independent','Keq','options',fo);
However, note that this will still give you an error. The reason is that, if Keq is your independent variable, there are no other variables for MATLAB to adjust. What is the atual equation you are trying to fit to your data? What are your dependent and independent variables?
13 Kommentare
andrea rigotto
am 8 Nov. 2023
Cris LaPierre
am 8 Nov. 2023
I believe I said that it wouldn't work, and provided the reason why.
If everything is calculated, then you aren't fitting. It sounds like you just want to create a function that calculates T based on Keq?
You usually have an equation
y = f(x,p)
where x is the independent variable, y is the dependent variable and p are the parameters to be fitted.
E.g. in the linear case
y = p(1)*x + p(2)
In your case, we cannot decipher what x, y and p are.
My guess is that T_canil is the dependent variable y and Keq is the independent variable x. But then I don't see a parameter p that could be fitted in your model equation
T_canil = 8772 ./(2.53-log(Keq))-273
Cris LaPierre
am 8 Nov. 2023
Bearbeitet: Cris LaPierre
am 8 Nov. 2023
For example, we could use Keq and T_canil as (x,y) and back out what the parameters of the equation you have shared are.
table = readtable('P_T_Ni.xlsx');
%% ignore the NaN value
idx = isnan(table.temperature);
table(idx,:) = [];
Ni_grt = table.Ni_Grt;
%% calculation
%Keq
Keq= Ni_grt ./2900;
%% T°C Canil 1999
T_canil = 8772 ./(2.53-log(Keq))-273;
%% Set up fittype and options.
The fit equation is 
We can use a nonlinear least-squares approach to find a,b, and c
ft = fittype( 'a./(b-log(x))-c', 'independent', 'x', 'dependent', 'y' );
opts = fitoptions( 'Method', 'NonlinearLeastSquares' );
opts.StartPoint = [10000 1 0];
%% Fit model to data.
[fitresult, gof] = fit( Keq, T_canil, ft, opts );
Now inspect what the fit parameter values for a, b, and c are
fitresult
%% Plot fit with data.
figure( 'Name', 'untitled fit 1' );
h = plot( fitresult, Keq, T_canil );
legend( h, 'T_canil vs. Keq', 'untitled fit 1', 'Location', 'NorthEast', 'Interpreter', 'none' );
% Label axes
xlabel( 'Keq');
ylabel( 'T_canil');
andrea rigotto
am 8 Nov. 2023
Bearbeitet: andrea rigotto
am 8 Nov. 2023
Cris LaPierre
am 8 Nov. 2023
Can you first share with us the code you would use to plot the data? Not the curve, just the raw data.
andrea rigotto
am 8 Nov. 2023
So is this your raw data?
table = readtable('P_T_Ni.xlsx');
%% ignore the NaN value
idx = isnan(table.temperature);
table(idx,:) = [];
scatter(table.pressure,table.temperature,'filled')
xlabel('Pressure (GPa)')
ylabel('Temperature (°C)');
andrea rigotto
am 8 Nov. 2023
Cris LaPierre
am 8 Nov. 2023
Bearbeitet: Cris LaPierre
am 8 Nov. 2023
It looks like your code already fits a line to your data using lsqcurvefit, but this is a 3D fit (pressure and Keq are inputs, T is the output). It has 3 parameters that get determined by the fit (x, y, and z come from the data).
table = readtable('P_T_Ni.xlsx');
%% ignore the NaN value
idx = isnan(table.temperature);
table(idx,:) = [];
temperature = table.temperature;
pressure = table.pressure;
Ni_grt = table.Ni_Grt;
Ni_ol = table.Ni_Ol;
Cr_grt = table.Wt_Cr;
Ca_grt = table.Wt_Ca;
%% calculation
%Keq
Keq= Ni_grt ./2900;
%temperature from °C to K
temperatureK = temperature +273.15 ;
%% Calculate the parameters (ΔH, ΔV, ΔS)
pressure_keq=[pressure Keq];
Here is your fit equation. It can be simplified to 
% function of T
T = @(x,pressure_Keq) (x(1) + pressure_Keq(:,1) * x(2)) ./ (x(3) - log( pressure_Keq(:,2)));
Here are the starting estimates
% fixed start parameters (ΔH, ΔV, ΔS)
% The chosen values must be of the same order of magnitude as the expected values
x0 = [1000, 10, 1];
Here is the fit function
% nonlinear regression with lsqcurvefit
x_fit = lsqcurvefit(T, x0, pressure_keq, temperature)
This calculates the fit y values. So not a fit line, but a prediction of each point based on the equation.
% the new value od temperature from Ni_grt of database
predicted_temperature = T(x_fit, pressure_keq);
scatter3(pressure,temperature,Keq)
hold on
P_K_sorted = sortrows(pressure_keq);
scatter3(P_K_sorted(:,1),predicted_temperature,P_K_sorted(:,2),'r*')
hold off
xlabel('pressure')
ylabel('Keq')
zlabel('Temperature')
legend('Data','Fit')
If you want to fit to just pressure and temperature, you need a 2D equation. You need to have some idea what type of relationship the fit should be. This data doesn't really make the choice easy, as the data actually looks like two separate linear trends to me. That's another problem.
So although I don't think this is the proper relationship, I'll use a custom exponential equation to demonstrate a custom fit.
The equation is 
We already know x - it is the pressure data. We also already know y - it is the temperature data. We don't know a, b and c. That is what the fit will determine for us.
% Set up fittype and options.
ft = fittype( 'a*exp(-b*x)+c', 'independent', 'x', 'dependent', 'y' );
opts = fitoptions( 'Method', 'NonlinearLeastSquares' );
opts.StartPoint = [1 0 0.5];
% Fit model to data.
[fitresult, gof] = fit( pressure, temperature, ft, opts );
fitresult
figure
plot( fitresult, pressure, temperature )
legend('temperature vs. pressure', 'Fit 1');
xlabel('Pressure (GPa)')
ylabel('Temperature (°C)');
andrea rigotto
am 9 Nov. 2023
Cris LaPierre
am 9 Nov. 2023
You are asking questions that only you can answer. Based on your knowlege in this space, what relationship is the data expected to have?
- lsqcurvefit solves nonlinear curve-fitting (data-fitting) problems in least-squares sense.
- When using fit, you specified the method to be NonlinearLeastSquares.
In both cases, the fit comes down to defining the function you want to fit. Coming up with that function is where your expertise comes in.
If the code is getting in the way, try taking a more interactive approach using the Curve Fitter App.
Again, if you are trying to derive the parameters of an equation to calculate temperature from pressure and Keq, you must first have existing data for temperature at known pressure and Keq values.
andrea rigotto
am 9 Nov. 2023
Kategorien
Mehr zu Get Started with Curve Fitting Toolbox finden Sie in Hilfe-Center und File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!




