I am coding a equation for curve fitting, but I am facing inaccuracy. I am not getting Elastic plateau in the curve. Can anyone guide me how I can address the issue.

104 次查看(过去 30 天)
clc; close all;
%% ---- Load data --
file = 'data.xlsx';
T = readtable(file); % expects columns: Strain, Stress (in GPa)
Warning: Column headers from the file were modified to make them valid MATLAB identifiers before creating variable names for the table. The original column headers are saved in the VariableDescriptions property.
Set 'VariableNamingRule' to 'preserve' to use the original column headers as table variable names.
disp(T.Properties.VariableNames)
{'Strain_mm_mm_'} {'Stress_GPa_'}
epsl = T.Strain_mm_mm_(:); % ensure column vector
sig = T.Stress_GPa_(:) * 1000; % convert GPa -> MPa
% keep only finite rows
good = isfinite(epsl) & isfinite(sig);
epsl = epsl(good);
sig = sig(good);
% (optional) trim extreme epsilon to avoid 1/(1-eps) blow-up in model
epsl = min(epsl, 0.981);
%% ---- Known strain rates -------------------------------------------------
edot = 0.000617; % test strain rate [s^-1]
edot0 = edot; % reference strain rate [s^-1]
%% ---- Initial guesses & bounds ------------------------------------------
% [A, E, B, m, n, a, b]
p0 = [0.4, 2000, 0.3, 0.95, 2.0, -0.05, 0.150]; % initial params (MPa-based)
lb = [-0.1, 1.2, -.01, -1, 1, 1, 0.01 ];
ub = [2, 20, 1, 5, 5, 4.0, 0.5 ];
%% ---- Fit with lsqcurvefit (Optimization Toolbox) -----------------------
model = @(p,eps) constitutive_model(eps, edot, p(1), p(2), p(3), p(4), p(5), p(6), p(7), edot0);
try
opts = optimoptions('lsqcurvefit','Display','iter','MaxIterations',1000);
[pfit, ~] = lsqcurvefit(model, p0, epsl, sig, lb, ub, opts);
catch ME
warning('lsqcurvefit unavailable (%s). Falling back to fminsearch (unconstrained).', ME.identifier);
obj = @(p) sum((model(p,epsl) - sig).^2);
pfit = fminsearch(obj, p0);
end
Norm of First-order Iteration Func-count Resnorm step optimality 0 8 1.35286e+07 5.23e+07 1 16 2.49293e+06 0.746691 7.98e+06 2 24 474328 0.819711 1.22e+06 3 32 93370.3 0.652941 1.88e+05 Objective function returned complex; trying a new point... 4 40 93370.3 0.223895 1.88e+05 5 48 85651.1 0.0111948 1.71e+05 6 56 71978.8 0.0223895 1.4e+05 7 64 50519.9 0.044779 9.4e+04 8 72 24094.8 0.089558 4.08e+04 Objective function returned complex; trying a new point... 9 80 24094.8 0.179116 4.08e+04 10 88 22378.6 0.0089558 3.76e+04 11 96 19264.9 0.0179116 3.18e+04 12 104 14147.2 0.0358232 2.26e+04 13 112 7295.89 0.0716464 1.09e+04 Objective function returned Inf; trying a new point... 14 120 7295.89 0.143293 1.09e+04 15 128 6820.58 0.00716464 1.01e+04 16 136 5944.95 0.0143293 8.7e+03 17 144 4463.38 0.0286586 6.38e+03 18 152 2375.57 0.0573171 3.24e+03 Objective function returned Inf; trying a new point... 19 160 2375.57 0.114634 3.24e+03 20 168 2225.43 0.00573171 3.03e+03 21 176 1946.42 0.0114634 2.63e+03 22 184 1466.67 0.0229269 1.95e+03 23 192 772.508 0.0458537 1.06e+03 Objective function returned Inf; trying a new point... 24 200 772.508 0.0917074 1.06e+03 25 208 721.962 0.00458537 1e+03 26 216 627.748 0.00917074 887 27 224 465.008 0.0183415 686 Objective function returned Inf; trying a new point... 28 232 465.008 0.036683 686 29 240 450.879 0.00183415 668 Objective function returned Inf; trying a new point... 30 248 450.879 0.0036683 668 31 256 449.485 0.000183415 667 32 264 446.708 0.00036683 663 33 272 441.187 0.000733659 656 34 280 430.281 0.00146732 642 Objective function returned Inf; trying a new point... 35 288 430.281 0.00293464 642 36 296 429.202 0.000146732 641 37 304 427.051 0.000293464 638 Objective function returned Inf; trying a new point... 38 312 427.051 0.000586927 638 39 320 426.837 2.93464e-05 638 40 328 426.408 5.86927e-05 637 41 336 425.551 0.000117385 636 Objective function returned Inf; trying a new point... 42 344 425.551 0.000234771 636 43 352 425.465 1.17385e-05 636 Objective function returned Inf; trying a new point... 44 360 425.465 2.34771e-05 636 Objective function returned Inf; trying a new point... 45 368 425.465 1.17385e-06 636 46 376 425.465 5.86927e-08 636 Local minimum possible. lsqcurvefit stopped because the size of the current step is less than the value of the step size tolerance.
sigma_fit = model(pfit, epsl);
%% ---- Goodness of fit (R^2, adj. R^2, RMSE) -----------------------------
SSE = sum((sig - sigma_fit).^2);
SST = sum((sig - mean(sig)).^2);
R2 = 1 - SSE/SST;
n = numel(sig);
k = numel(pfit); % number of fitted parameters
adjR2 = 1 - (1 - R2) * (n - 1) / max(n - k - 1, 1);
RMSE = sqrt(SSE / n);
% Print to console
fprintf('\nGoodness of fit:\n');
Goodness of fit:
fprintf('R^2 = %.6f\n', R2)
R^2 = -967.068970
fprintf('Adj R^2 = %.6f\n', adjR2);
Adj R^2 = -976.467698
fprintf('RMSE = %.6f MPa\n', RMSE)
RMSE = 0.763955 MPa
%% ---- Plot and Save ------------------------------------------------------
fig = figure; hold on;
plot(epsl, sig, 'k-', 'MarkerFaceColor','k','MarkerSize',2, 'DisplayName','Experimental');
plot(epsl, sigma_fit,'r-', 'LineWidth',1, 'DisplayName','Fitted model');
xlabel('Strain \epsilon');
ylabel('Stress \sigma_d (MPa)');
title(['Fitted Constitutive Model at \epsilon-dot = ', num2str(edot), ' s^{-1}']);
legend show; grid on;
% Add a readable stats box
ax = gca;
xL = xlim(ax); yL = ylim(ax);
txt = {sprintf('R^2 = %.4f', R2), ...
sprintf('Adj R^2 = %.4f', adjR2), ...
sprintf('RMSE = %.3g MPa', RMSE)};
text(xL(1) + 0.02*range(xL), yL(2) - 0.04*range(yL), txt, ...
'VerticalAlignment','top', 'BackgroundColor','w', ...
'Margin',6, 'EdgeColor',[0.1 0.1 0.1], 'FontWeight','bold');
% Save the figure
saveas(fig, 'fitted_model_plot.png'); % PNG
% For crisper output you can also use:
% exportgraphics(fig,'fitted_model_plot.png','Resolution',300);
%% ---- Print parameters ---------------------------------------------------
fprintf('\nFitted Parameters:\n');
Fitted Parameters:
fprintf('A = %.4f MPa\n', pfit(1));
A = 0.0000 MPa
fprintf('E = %.4f MPa\n', pfit(2));
E = 5.8811 MPa
fprintf('B = %.4f MPa\n', pfit(3));
B = 0.0227 MPa
fprintf('m = %.4f\n', pfit(4));
m = 2.9336
fprintf('n = %.4f\n', pfit(5));
n = 1.3294
fprintf('a = %.4f\n', pfit(6));
a = 2.5000
fprintf('b = %.4f\n', pfit(7));
b = 0.1500
%% ===================== Local functions (MUST be at file end) =====================
function sigma_d = constitutive_model(epsilon, edot, A, E, B, m, n, a, b, edot0)
% Vector-safe guards
epsilon = min(max(epsilon, 0.001), 0.99); % keep in [0,1)
one_me = max(1 - epsilon, eps);
% Static part
term1 = A .* (1 - exp(-(E./A) .* epsilon .* (1 - epsilon))).^m;
term2 = B .* (epsilon ./ one_me).^n;
sigma_static = term1 + term2;
% Strain-rate factor
rate_factor = 1 + (a + b .* epsilon) .* log(edot ./ edot0);
sigma_d = sigma_static .* rate_factor;
end

回答(1 个)

Matt J
Matt J 2025-9-2,0:58
编辑:Matt J 2025-9-2,1:12
You need a better initial guess. Also, you should exclude the data from the linear elastic region, since clearly that is not captured by your model equation.
file = 'data.xlsx';
[epsl,sig]=readvars(file) ;
sig=sig*1000;% convert GPa -> MPa
% keep only finite and mid-range data
good = isfinite(epsl) & isfinite(sig) & epsl>0.15 & epsl<0.981;
epsl = epsl(good);
sig = sig(good);
%% ---- Known strain rates -------------------------------------------------
edot = 0.000617; % test strain rate [s^-1]
edot0 = edot; % reference strain rate [s^-1]
%% ---- Initial guesses & bounds ------------------------------------------
% [A, E, B, m, n, a, b]
p0 = [0.04, 100, 0.03, 0.95, 2.0, -0.05, 0.150]; % initial params (MPa-based)
lb = [-0.1, 1.2, -.01, -1, 1, 1, 0.01 ];
ub = [2, 20, 1, 5, 5, 4.0, 0.5 ];
%% ---- Fit with lsqcurvefit (Optimization Toolbox) -----------------------
model = @(p,eps) constitutive_model(eps, edot, p(1), p(2), p(3), p(4), p(5), p(6), p(7), edot0);
try
opts = optimoptions('lsqcurvefit','Display','iter','MaxIterations',1000);
[pfit, ~] = lsqcurvefit(model, p0, epsl, sig, lb, ub, opts);
catch ME
warning('lsqcurvefit unavailable (%s). Falling back to fminsearch (unconstrained).', ME.identifier);
obj = @(p) sum((model(p,epsl) - sig).^2);
pfit = fminsearch(obj, p0);
end
Norm of First-order Iteration Func-count Resnorm step optimality 0 8 32818.8 1.19e+05 1 16 5880.21 0.190567 1.77e+04 Objective function returned complex; trying a new point... 2 24 5880.21 0.183082 1.77e+04 3 32 5003.93 0.00915412 1.5e+04 4 40 3537.19 0.0183082 1.06e+04 5 48 1554.94 0.0366165 4.58e+03 6 56 273.676 0.0732329 766 Objective function returned complex; trying a new point... 7 64 273.676 0.140406 766 8 72 202.263 0.00702032 568 9 80 95.1124 0.0140406 344 10 88 6.97485 0.0280813 70.4 11 96 0.332829 0.0561625 10.9 12 104 0.0509524 0.0466304 1.25 13 112 0.040492 0.112325 11.3 14 120 0.0340305 0.22465 48 15 128 0.0340305 0.200009 48 16 136 0.0254048 0.0500021 21.5 17 144 0.0212187 0.100004 24.5 18 152 0.014874 0.0570038 15.4 19 160 0.00842121 0.000418076 0.0642 20 168 0.00775609 0.00339075 0.000648 21 176 0.00775564 0.00319446 4.24e-05 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.
sigma_fit = model(pfit, epsl);
postAnalysis(epsl,sig,pfit,sigma_fit,edot)
Goodness of fit: R^2 = 0.962642 Adj R^2 = 0.962249 RMSE = 0.003395 MPa
%% ===================== Local functions (MUST be at file end) =====================
function sigma_d = constitutive_model(epsilon, edot, A, E, B, m, n, a, b, edot0)
% Vector-safe guards
epsilon = min(max(epsilon, 0.001), 0.99); % keep in [0,1)
one_me = max(1 - epsilon, eps);
% Static part
term1 = A .* (1 - exp(-(E./A) .* epsilon .* (1 - epsilon))).^m;
term2 = B .* (epsilon ./ one_me).^n;
sigma_static = term1 + term2;
% Strain-rate factor
rate_factor = 1 + (a + b .* epsilon) .* log(edot ./ edot0);
sigma_d = sigma_static .* rate_factor;
end
function postAnalysis(epsl,sig,pfit, sigma_fit,edot)
%% ---- Goodness of fit (R^2, adj. R^2, RMSE) -----------------------------
SSE = sum((sig - sigma_fit).^2);
SST = sum((sig - mean(sig)).^2);
R2 = 1 - SSE/SST;
n = numel(sig);
k = numel(pfit); % number of fitted parameters
adjR2 = 1 - (1 - R2) * (n - 1) / max(n - k - 1, 1);
RMSE = sqrt(SSE / n);
% Print to console
fprintf('\nGoodness of fit:\n');
fprintf('R^2 = %.6f\n', R2)
fprintf('Adj R^2 = %.6f\n', adjR2);
fprintf('RMSE = %.6f MPa\n', RMSE)
%% ---- Plot and Save ------------------------------------------------------
fig = figure; hold on;
plot(epsl, sig, 'k-', 'MarkerFaceColor','k','MarkerSize',2, 'DisplayName','Experimental');
plot(epsl, sigma_fit,'r-', 'LineWidth',1, 'DisplayName','Fitted model');
xlabel('Strain \epsilon');
ylabel('Stress \sigma_d (MPa)');
title(['Fitted Constitutive Model at \epsilon-dot = ', num2str(edot), ' s^{-1}']);
legend show; grid on;
% Add a readable stats box
ax = gca;
xL = xlim(ax); yL = ylim(ax);
txt = {sprintf('R^2 = %.4f', R2), ...
sprintf('Adj R^2 = %.4f', adjR2), ...
sprintf('RMSE = %.3g MPa', RMSE)};
text(xL(1) + 0.02*range(xL), yL(2) - 0.04*range(yL), txt, ...
'VerticalAlignment','top', 'BackgroundColor','w', ...
'Margin',6, 'EdgeColor',[0.1 0.1 0.1], 'FontWeight','bold');
axis padded
end
  14 个评论
Matt J
Matt J 2025-9-4,23:21
编辑:Matt J 2025-9-4,23:27
To demonstrate problems, please get into the habit of running the code here in the online environment, as I have been doing. A screen shot of the results alone doesn't tell us anything, because we cannot see what has changed in the way you are running the code.
By "another strain rate", do you mean a different .xlsx data set?
Matt J
Matt J 2025-9-4,23:52
编辑:Matt J 2025-9-5,15:42
One thing that might be relevant to your last question. The known edot and edot0 parameters are not doing anything meaningful in your model, and should probably be removed. All they do is change the fitted values of a and b by a factor of log(edot/edot0). Attached is a version which removes edot,edot0 and also includes a routine to auto-guess the 'c' parameter (so, you no longer have to provide an initial guess or that parameter).
file = 'data_Copy.xlsx';
% [A, E, m, n, a, b]
p0 = [0.1, 500, 0.5, 2.0, 0, 0]; % initial params (MPa-based)
% [A, E, m, n, a, b]
lb = [-0.1, 1.2, -1, 1, -inf, -inf ];
ub = [2, 20, 5, 5, +inf, +inf ];
epsmax=0.85; %Maximum epsilon to fit
doFit(file, p0,lb,ub,epsmax)
Goodness of fit: R^2 = 0.998612 Adj R^2 = 0.998593 RMSE = 0.000270 MPa
%%
file = 'data.xlsx';
% ---- Initial guesses & bounds ------------------------------------------
% [A, E, m, n, a, b]
p0 = [0.9,500, 0.5, 2.0, 0, 0]; % initial params (MPa-based)
% [A, E, m, n, a, b]
lb = [-0.1, 1.2, -1, 1, -inf,-inf ];
ub = [2, 20, 5, 5, +inf, +inf ];
epsmax=0.85; %Maximum epsilon to fit
doFit(file, p0,lb,ub,epsmax)
Goodness of fit: R^2 = 0.994608 Adj R^2 = 0.994526 RMSE = 0.000322 MPa

请先登录,再进行评论。

类别

Help CenterFile Exchange 中查找有关 Simulink Report Generator 的更多信息

标签

产品

Community Treasure Hunt

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

Start Hunting!

Translated by