Fitting data with multiple inputs, ODE equation, and lsqnonlin

17 views (last 30 days)
Hi everyone,
I am currently trying out MATLAB fitting to model a series chemical kinetics, which is based on an existing question in this forum seen here.
In my case, I add parameter of temperature to determine the reaction constant ki. The problem is intended to be solved using lsqnonlin.
Thus, the objective is to fit the data and parameters to find the values of Arrhenius coefficients A1-4 and Ea1-4.
Currently, I am having a code (seen at the end of this post) that generates some errors and can't be executed, so there I must've done some mistakes in either coding or my way of thinking. I looked up and refer to similar problems in the forum as well, but it seems it hasn't been working for my case so far.
I'm still pretty new in Matlab, especially in fitting nonlinear models. I hope someone can help me find the mistakes and give a solution to the problem.
Thanks in advance.
Warning: Length of lower bounds is < length(x); filling in missing lower bounds with -Inf.
> In checkbounds (line 33)
In lsqnsetup (line 77)
In lsqnonlin (line 207)
In Untitled2_trial3 (line 53)
Warning: Length of upper bounds is > length(x); ignoring extra bounds.
> In checkbounds (line 41)
In lsqnsetup (line 77)
In lsqnonlin (line 207)
In Untitled2_trial3 (line 53)
Exiting due to infeasibility: at least one lower bound exceeds the corresponding upper bound.
>>
%Reaction system
%c1 --> c2
%c1 --> p1
%c2 --> p2
%Reaction rates are described as r = k*c^n
%As c2 --> c3 is found negligable, data is available only for c1 and c2
%The data for p1 and p2 is unknown.
%Data
time = [10 20 40 60 100 140 180];
c1 = [0.508 0.442 0.385 0.354 0.299 0.267 0.258];
c2 = [0.246 0.301 0.359 0.398 0.422 0.467 0.489];
T_o = [400 423 433 456 467 468 463];
c1_0 = 0.711;
c2_0 = 0;
T_o_0 = 400;
R = 8.314;
%Plot
time_plot = [0,time];
c1_plot = [c1_0,c1];
c2_plot = [c2_0,c2];
T_o_plot = [0,T_o];
%figure 1, C1 and C2 vs time
figure(1)
plot(time_plot,c1_plot,'bo')
grid on
hold on
plot(time_plot,c2_plot,'ro')
hold off
xlabel('Time [min]')
ylabel('Concentration [mol/L]')
legend('c1','c2')
%figure 2, C1 and C2 vs T
figure(2)
plot(T_o_plot,c1_plot,'bo')
grid on
hold on
plot(T_o_plot,c2_plot,'ro')
hold off
xlabel('Temperature [K]')
ylabel('Concentration [mol/L]')
legend('c1','c2')
%Data processing
x_in = [time',T_o'];
y_in = [c1',c2'];
%Lsqnonlin
%[p,Rsdnrm,Rsd,ExFlg,OptmInfo,Lmda,Jmat] = lsqnonlin(@diff1,p0,x_in,y_in,lb,ub);
%FitData = diff1(p,time,1);
%c1_out = FitData(:,1);
%c2_out = FitData(:,2);
% Options for fitting
options = optimoptions('lsqnonlin', ...
'Display', 'iter', ...
'Algorithm', 'levenberg-marquardt', ...
'UseParallel', false, ...
'StepTolerance', 1e-6);
%initial value for iteration
B0 = [0.1,1,0.1,1,0.1,1,0.1,1,0.1,1,0.1,1,c1(1),c2(1),T_o(1)];
% lsqnonlin
optimizedParams = lsqnonlin(@diff1, B0, x_in, y_in, [], [], options);
function C = diff1(p,time,~)
%dc1/dt = -(k1*c1^n1+k3*c1^k3)
%dc2/dt = k1*c1^n1-(k2*c2^k2+k4*c2^n4)
%where
%k1 = A1*exp(-E1/RT_o)
%k2 = A2*exp(-E2/RT_o)
%k3 = A3*exp(-E3/RT_o)
%k4 = A4*exp(-E4/RT_o)
%
%variables: c1 = x(1), c2 = x(2), T_o = x(3)
%parameters:
%A1 = B(1), E1 = B(2), n1 = B(3)
%A2 = B(4), E2 = B(5), n2 = B(6)
%A3 = B(7), E3 = B(8), n3 = B(9)
%A4 = B(10), E4 = B(11), n4 = B(12)
x0 = B(11:12);
[t,Cout] = ode45(@DifEq, time, x0);
function dC = DifEq(t, x)
xdot = zeros(3,1);
xdot(1) = -(B(1)*exp(-B(2)/R/x(3)).*x(1).^B(3)-B(7)*exp(-B(8)/R/x(3)).*x(1)^B(9));
xdot(2) = B(4)*exp(-B(5)/R/x(3)).*x(1).^B(6)-B(10)*exp(-B(11)/R/x(3)).*x(2).^B(12);
dC = xdot;
end
C = Cout;
end

Accepted Answer

Star Strider
Star Strider on 24 Nov 2020
The fundamental problem is that lsqnonlin ~= lsqcurvefit! They are definitely not interchangable, and have different argument lists and calling conventions, the ones used here being for lsqcurvefit, so that change was straightforward (after checking to be sure everything matched correctly).
Beyond that, there is no ‘x(3)’ since there is no third differential equation. Since ‘x(3)’ should be temperature (that I here assume is a funciton of time), I created:
Temp = interp1(x_in(:,1), x_in(:,2),t); % <— ADDED & Changed ‘x(3)’ To ‘Temp’
to interpolate temperature with time, and then made the substitutions in the differential equations. If temperature is not a function of time, it will be necessary to create a function that expresses temperature in a way that is meaningful for the differential equations.
I also set the lower bounds on the parameters to zero, since concentrations and kinetic constants, at least in this system, appear to always be greater than zero.
This version runs without errors:
%Reaction system
%c1 --> c2
%c1 --> p1
%c2 --> p2
%Reaction rates are described as r = k*c^n
%As c2 --> c3 is found negligable, data is available only for c1 and c2
%The data for p1 and p2 is unknown.
%Data
time = [10 20 40 60 100 140 180];
c1 = [0.508 0.442 0.385 0.354 0.299 0.267 0.258];
c2 = [0.246 0.301 0.359 0.398 0.422 0.467 0.489];
T_o = [400 423 433 456 467 468 463];
c1_0 = 0.711;
c2_0 = 0;
T_o_0 = 400;
R = 8.314;
%Data processing
x_in = [time(:),T_o(:)];
y_in = [c1(:),c2(:)];
%Lsqnonlin
%[p,Rsdnrm,Rsd,ExFlg,OptmInfo,Lmda,Jmat] = lsqnonlin(@diff1,p0,x_in,y_in,lb,ub);
%FitData = diff1(p,time,1);
%c1_out = FitData(:,1);
%c2_out = FitData(:,2);
% Options for fitting
options = optimoptions('lsqcurvefit', ...
'Display', 'iter', ...
'Algorithm', 'levenberg-marquardt', ...
'UseParallel', false, ...
'StepTolerance', 1e-6);
%initial value for iteration
B0 = [0.1,1,0.1,1,0.1,1,0.1,1,0.1,1,0.1,1,c1(1),c2(1),T_o(1)];
% lsqnonlin
optimizedParams = lsqcurvefit(@diff1, B0, x_in, y_in, zeros(size(B0)), [], options)
function C = diff1(B,x_in)
%dc1/dt = -(k1*c1^n1+k3*c1^k3)
%dc2/dt = k1*c1^n1-(k2*c2^k2+k4*c2^n4)
%where
%k1 = A1*exp(-E1/RT_o)
%k2 = A2*exp(-E2/RT_o)
%k3 = A3*exp(-E3/RT_o)
%k4 = A4*exp(-E4/RT_o)
%
%variables: c1 = x(1), c2 = x(2), T_o = x(3)
%parameters:
%A1 = B(1), E1 = B(2), n1 = B(3)
%A2 = B(4), E2 = B(5), n2 = B(6)
%A3 = B(7), E3 = B(8), n3 = B(9)
%A4 = B(10), E4 = B(11), n4 = B(12)
time = x_in(:,1);
x0 = B(11:12);
[t,Cout] = ode45(@DifEq, time, x0);
function dC = DifEq(t, x)
xdot = zeros(2,1);
Temp = interp1(x_in(:,1), x_in(:,2),t); % <— ADDED & Changed 'x(3)' To 'Temp'
xdot(1) = -(B(1)*exp(-B(2)/R/Temp).*x(1).^B(3)-B(7)*exp(-B(8)/R/Temp).*x(1)^B(9));
xdot(2) = B(4)*exp(-B(5)/R/Temp).*x(1).^B(6)-B(10)*exp(-B(11)/R/Temp).*x(2).^B(12);
dC = xdot;
end
C = Cout;
end
%Plot
time_plot = [time];
c1_plot = [c1];
c2_plot = [c2];
T_o_plot = [T_o];
Cest = diff1(optimizedParams,x_in)
%figure 1, C1 and C2 vs time
figure(1)
plot(time_plot,c1_plot,'bo')
grid on
hold on
plot(time_plot,c2_plot,'ro')
plot(x_in(:,1), Cest, '--')
hold off
xlabel('Time [min]')
ylabel('Concentration [mol/L]')
legend('c1','c2')
%figure 2, C1 and C2 vs T
figure(2)
plot(T_o_plot,c1_plot,'bo')
grid on
hold on
plot(T_o_plot,c2_plot,'ro')
plot(x_in(:,2), Cest, '--')
hold off
xlabel('Temperature [K]')
ylabel('Concentration [mol/L]')
legend('c1','c2')
I shifted the plots to the end in order to incorporate the fitted equations, and added those.
It will be necessary to experiment with different initial parameter estimates to get a decent fit, since the current estimates do not create that. If you have the Golbal Optimization Toolbox, use the ga (genetic algorithm) function for this. It will generally find a reasonable fit, although the 'InitialPopulationMatrix' may need to be designed specifically for these parameters. I can hel with that if necessary.
  12 Comments
Anthony Hamzah
Anthony Hamzah on 27 Nov 2020
Sorry for the late reply. I've been busy handling other stuff at work all day yesterday.
Thanks for the help, I find it extremely helpful.

Sign in to comment.

More Answers (1)

Alan Weiss
Alan Weiss on 24 Nov 2020
I do not have the time right now to help debug your code, sorry. But I believe that you might be able to use some documentation examples that run correctly as models to help figure out your own error:
Good luck,
Alan Weiss
MATLAB mathematical toolbox documentation

Products


Release

R2020b

Community Treasure Hunt

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

Start Hunting!