# Multiple curve fitting via optimization

7 views (last 30 days)
klmdr on 27 Jan 2023
Commented: Alex Sha on 29 Jan 2023
Hello,
I have strain-stress data at different temperatures and strain rates(4x4 matrix) and need to find the parameters of the equation below. I usually use Excel solver to find constitutive equation parameters. But there are nine different parameters in this equation and I think I need to use Matlab for it. You can see the results that I have found in Excel in the attachment. It cannot capture the bumps at the beginning of the curve and its not a good fit at all. Can you please give me some hints how to construct the code?
stress = A*(exp(m1*T))*(strain^m2)*(sr^m3)*(exp(m4/strain))*((1+strain)^m5*T)*(exp(m7*strain))*(sr^m8)*(T^m9)
A,m1,m2,m3,m4,m5,m7,m8,m9 are the parameters I have to find. T=Temperature, sr=Strain rate
Alex Sha on 29 Jan 2023
Your original fitting formula can be simplified to the following, with the same fitting effect but less parameters and stable parameter values:
Original one:
stress = A*(exp(m1*T))*(strain^m2)*(sr^m3)*(exp(m4/strain))*((1+strain)^m5*T)*(exp(m7*strain))*(sr^m8)*(T^m9);
Simplified one:
stress = A*(strain^m2)*(exp(m4/strain))*((1+strain)^m5*T)*(exp(m7*strain));
The results of first four dataset are as below (for simplified fitting function, and ignoring the first data points with strain = 0):
1: 1000C-0.15SR
Sum Squared Error (SSE): 23.6730174432142
Root of Mean Square Error (RMSE): 0.769301914777518
Correlation Coef. (R): 0.982032567779678
R-Square: 0.964387964179949
Parameter Best Estimate
--------- -------------
a 0.16791350361708
m2 0.267072305431708
m4 0.0011468937880592
m5 -6.60477948264248
m7 3.61825264240761 2: 1100C-0.15SR
Sum Squared Error (SSE): 20.0468246994224
Root of Mean Square Error (RMSE): 0.70793404882486
Correlation Coef. (R): 0.979615018206333
R-Square: 0.959645583895393
Parameter Best Estimate
--------- -------------
a 0.132995979333497
m2 0.32434785420116
m4 0.00111417690433741
m5 -7.90718730551637
m7 4.31198101497506 3: 1200C-0.15SR
Sum Squared Error (SSE): 7.83639177584002
Root of Mean Square Error (RMSE): 0.442616983853987
Correlation Coef. (R): 0.987336715319379
R-Square: 0.974833789417659
Parameter Best Estimate
--------- -------------
a 0.0474196228353134
m2 0.109565052679149
m4 -0.00306254669951433
m5 -4.37704958424755
m7 2.31591332215742 4: 900C-1.5SR
Sum Squared Error (SSE): 52.3830536945957
Root of Mean Square Error (RMSE): 1.14436722356283
Correlation Coef. (R): 0.996039729733376
R-Square: 0.992095143207337
Parameter Best Estimate
--------- -------------
a 0.389573406540817
m2 0.47858711583706
m4 0.00828239426004025
m5 -3.24842781707287
m7 0.594709755492173 Bjorn Gustavsson on 27 Jan 2023
Edited: Bjorn Gustavsson on 27 Jan 2023
For this type of problem I would use lsqnonlin, so read the help and documentation of that function and what additinoally you need to. Most of the time I'd do something like this (untested and written on the hoof):
function residuals = res_strains_fcn(pars,T_obs,strain_obs,stress_obs)
% stress = A*(exp(m1*T))*(strain^m2)*(sr^m3)*(exp(m4/strain))*((1+strain)^m5*T)*(exp(m7*strain))*(sr^m8)*(T^m9)
% A,m1,m2,m3,m4,m5,m7,m8,m9
A = pars(1);
m = pars(2);
sr = 12; % that one is not obvious what it should be...
for iT = numel(T):-1:1
for iS = numel(strain_obs):-1:1
stress_mod(iT,iS) = A*(exp(m(1)*T(iT)))*(strain_obs(iS)^m(2))*(sr^m(3)) * ...
(exp(m(4)/strain_obs(iS)))*((1+strain_obs(iS))^m(5)*T(iT)) * ...
(exp(m(6)*strain_obs(iS)))*(sr^m(7))*(T(iT)^m(8));
end
end
residuals = stress_obs - stress_mod;
end
This works for the case where you have one array of temperatures, T_obs, with size [nT x 1] or [1 x nT], one array for the strains, strain_obs, with size [nS x 1] or [1 x nS], and the observed stresses in an array, stress_obs with size [nT x nS]. The modifications should be reasonably obvious if your obsevations are similar, the function should just calculate the modeled stresses for all observations.
Then the optimization-call for this would be something like:
% load the temperature and stress and strain-data
% put them into the variables T_obs, strain_obs, stress_obs or change the
% names below to the names you use.
% initial guess of parameters (I have no idea, you should hopefully have a good/OK idea)
par0 = [A_best_guess,m1_b_g,m2_b_g,m3_b_g,m4_b_g,m5_b_g,m7_b_g,m8_b_g,m9_b_g];
[best_pars,[X,res_n,stress_residuals,exFlag] = lsqnonlin(@(pars) res_strains_fcn(pars,T_obs,strain_obs,stress_obs),...
par0);
% If you get a value in exFlag that is different from 1 (possibly 2 or 3
% are OK), especially if it is 0, then you can continue the search from :
[best_pars,[X,res_n,stress_residuals,exFlag] = lsqnonlin(@(pars) res_strains_fcn(pars,T_obs,strain_obs,stress_obs),...
best_pars);
% If you can define lower and upper bounds on some of the parameters then
% that might help the fitting (much, very much, ?)
LB = par0-27; % not a serious suggestion, you have to set these based off of
LB(3) = -inf; % your field expertise, -inf means unbounded towards small values
UB = par0*3; % not a serious suggestion, you have to set these based off of
UB(5) = inf; % your field expertise, -inf means unbounded towards small values
[best_pars,[X,res_n,stress_residuals,exFlag] = lsqnonlin(@(pars) res_strains_fcn(pars,T_obs,strain_obs,stress_obs),...
par0,LB,UB);
If you also have standard deviations you that can be trusted you should use those to get properly weighted residuals.
HTH
Matt J on 27 Jan 2023
But first, I would do a linear fit to log(stress) as an easy of coming up with an initial guess.