how to obtain a fit with nonlinear regression data?

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);
Local minimum possible. lsqcurvefit stopped because the final change in the sum of squares relative to its initial value is less than the value of the function tolerance.
% 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');
Parametri adattati:
fprintf('ΔH = %.2f\n', DeltaH);
ΔH = 7737.42
fprintf('ΔV = %.2f\n', DeltaV);
ΔV = 26.79
fprintf('ΔS = %.2f\n', DeltaS);
ΔS = 2.60
%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);
mean_detaT = 0.26
%% 1 sigma statistics
%calculate standard deviation
sigma_value=std(deltaT);
fprintf ('1σ of deltaT=%.2f\n', sigma_value);
1σ of deltaT=47.81
%% R^2
R_sq= 1-var(temperature-predicted_temperature)/var(temperature);
fprintf('R^2=%.2f\n',R_sq);
R^2=0.91
%% 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);
Error using fittype>iCreateFittype
First input argument must be a string scalar or character vector, cell array or anonymous function.

Error in fittype (line 330)
obj = iCreateFittype( obj, varargin{:} );
[fit_canil,gof]= fit(pressure,T_canil,ft,'Keq',2);
plot(fit_canil, pressure,'m')
xlabel('Pressure (GPa)')
ylabel('Temperature (°C)');

2 Kommentare

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.
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.

Melden Sie sich an, um zu kommentieren.

Antworten (1)

Cris LaPierre
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

thanks for the raplay, but the code doesn't works.
i try to explain, i want to obtain a scatter graph of pressure-temperature where is present a fit curve of a series of data. Its obtain from this eq of temperature T_canil = 8772 ./(2.53-log(Keq))-273, the pressure is alredy calculate. there is only one variable that is keq, i tinks is my indipendet vaiable and the dipendent one is temperature.
i wolud obtain something like that.
something like that
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?
Torsten
Torsten am 8 Nov. 2023
Bearbeitet: Torsten am 8 Nov. 2023
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
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
fitresult =
General model: fitresult(x) = a./(b-log(x))-c Coefficients (with 95% confidence bounds): a = 8772 (8772, 8772) b = 2.53 (2.53, 2.53) c = 273 (273, 273)
%% 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
andrea rigotto am 8 Nov. 2023
Bearbeitet: andrea rigotto am 8 Nov. 2023
I'm so confused what i need to do and probably i have also make some mistake in my mind about what is fitiing process.
probably what i want to do is not a fit, but draw a curve that rappresent the trends of my data in a scatter plot. something like a pictures above.
if i want a draw the curve of the function how i will to do?which is the function i need to use?
i need to draw a curve for a nonlinear relation
Can you first share with us the code you would use to plot the data? Not the curve, just the raw data.
@Cris LaPierre, you are so colse what in need to do. :)
i have a graphs in x axis the temperature and y axis the pressure, the eq above is used to retrive the temperature, i need to create a curve that fit the pressure and temperature of my data samples. probavly the problem that idk the eq that describe the relation between pressure and temperature.
Sorry if I'm not clear and waste your time.
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)');
yes, this is my data, and i want to draw a curve of the trend of the data.
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)
Local minimum possible. lsqcurvefit stopped because the final change in the sum of squares relative to its initial value is less than the value of the function tolerance.
x_fit = 1×3
1.0e+03 * 4.8576 0.0216 0.0014
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
fitresult =
General model: fitresult(x) = a*exp(-b*x)+c Coefficients (with 95% confidence bounds): a = 10.73 (-11.89, 33.34) b = -0.05179 (-0.08102, -0.02256) c = 967.7 (893.2, 1042)
figure
plot( fitresult, pressure, temperature )
legend('temperature vs. pressure', 'Fit 1');
xlabel('Pressure (GPa)')
ylabel('Temperature (°C)');
@Cris LaPierre i thinks that is the answer i try to have, thanks you so much!!:)
but i have question for you, in this code the aim is to do a nonlinear regression to obtain some parameters. starting from eq T= (a+ Pressure*b)/(c-log(keq)) i want to find a,b and c, pressure and Keq we know. it's correct use lsqcurvefit function ? or i need another function?sorry, i'm a beginner in matlab.
You are asking questions that only you can answer. Based on your knowlege in this space, what relationship is the data expected to have?
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.
thanks you, i have undertood that i need more knowledge about statistics, and i need to do more test to choising the correct functions.
now that i have more knowledge abot my study case, i have understood that what i want to do is plot graph with trendlines about differents temperature equation. Now i need to understand how to do in my case and which is the function to do this.

Melden Sie sich an, um zu kommentieren.

Kategorien

Mehr zu Get Started with Curve Fitting Toolbox finden Sie in Hilfe-Center und File Exchange

Gefragt:

am 8 Nov. 2023

Kommentiert:

am 10 Nov. 2023

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by