You are now following this question
- You will see updates in your followed content feed.
- You may receive emails, depending on your communication preferences.
Parameter Estimation for a System of Differential Equations
125 views (last 30 days)
Show older comments
Hello. Ok, so I'm new to matlab and I've got a question regarding parameter estimation for a kinetic model. I have 4 different reactants and their concentrations are c1, c2, c3 and c4. I also have 4 differential equations, each one related to a concentration (c1, c2, c3 and c4, respectively -see below-) and experimental data for all these concentrations on 12 different times plus the initial condition. The k's are the rate coefficients. I want to solve this system of ODE's using ode45 and then use the output to compute the experimental data minus the observed data and use these results to estimate the values of k's using lsqnonlin, but apparently I can't solve these ODE's without numerical values for k -which is what I want to know-. Any help on how to set up the command to solve this?
function dcdt=batch(t,c,k)
dcdt=zeros(4,1);
dcdt(1)=-k(1)*c(1)-k(2)*c(1);
dcdt(2)= k(1)*c(1)+k(4)*c(3)-k(3)*c(2)-k(5)*c(2);
dcdt(3)= k(2)*c(1)+k(3)*c(2)-k(4)*c(3)+k(6)*c(4);
dcdt(4)= k(5)*c(2)-k(6)*c(4);
end
Data:
t c1 c2 c3 c4
0 1 0 0 0
0.1 0.902 0.06997 0.02463 0.00218
0.2 0.8072 0.1353 0.0482 0.008192
0.4 0.6757 0.2123 0.0864 0.0289
0.6 0.5569 0.2789 0.1063 0.06233
0.8 0.4297 0.3292 0.1476 0.09756
1 0.3774 0.3457 0.1485 0.1255
1.5 0.2149 0.3486 0.1821 0.2526
2 0.141 0.3254 0.194 0.3401
3 0.04921 0.2445 0.1742 0.5277
4 0.0178 0.1728 0.1732 0.6323
5 0.006431 0.1091 0.1137 0.7702
6 0.002595 0.08301 0.08224 0.835
Thanks in advance!
7 Comments
Alex Sha
on 5 Sep 2019
the results below are much better:
k1 0.756713424357579
k2 0.246983152463589
k3 0.100637714178661
k4 0.24638788199029
k5 0.582535403727263
k6 -0.0269993611093679
Star Strider
on 5 Sep 2019
@Alex Sha — Show the code you used to get those results. The results themselves are otherwise meaningless.
Torsten
on 5 Sep 2019
A negative reaction rate constant (k6) does not make sense.
You will have to constrain the ki to be non-negative.
Alex Sha
on 6 Sep 2019
if want to all parameters are positive, the results will be:
k1 0.757805051886583
k2 0.248942776988651
k3 0.182367452149268
k4 0.462511556999762
k5 0.620286121513934
k6 0
Star Strider has done this kind of job perfectly, I just used another package to obtain the result above, This result can be used to compare with Matlab results。
Star Strider
on 8 May 2020
Please do not post new problems to this thread unless they relate directly to it. Post them instead as new Questions.
Votes are always appreciated!
.
Budda
on 2 Jan 2021
Hi Star Srider, How would I change the code if only say the data for first variable ( equation) available in the Igor_Moura.m?
Thank you in advance
Star Strider
on 2 Jan 2021
Budda —
Make appropriate changes to the ‘kinetics’ function (specifically to the ‘C’ variable) to output only the variable you need. In that code, there are 4 columns, so address only the column you want returned in ‘C’.
Accepted Answer
Star Strider
on 1 Dec 2016
52 Comments
Igor Moura
on 1 Dec 2016
Hi, Star Rider, thanks for your help! Both problems are very alike, those techniques might be what I'm looking for, but I just can't get the code to work :( I created a kinetics.m file with the following code:
function C=kinetics(t,theta)
c0=[1;0;0;0];
[T,Cv]=ode45(@DifEq,t,c0);
%
function dC=DifEq(t,c)
dcdt=zeros(4,1);
dcdt(1)=-theta(1).*c(1)-theta(2).*c(1);
dcdt(2)= theta(1).*c(1)+theta(4).*c(3)-theta(3).*c(2)-theta(5).*c(2);
dcdt(3)= theta(2).*c(1)+theta(3).*c(2)-theta(4).*c(3)+theta(6).*c(4);
dcdt(4)= theta(5).*c(2)-theta(6).*c(4);
dC=dcdt;
end
C=Cv(:,1);
end
and then I called it using:
t=[0.1
0.2
0.4
0.6
0.8
1
1.5
2
3
4
5
6];
c=[0.902 0.06997 0.02463 0.00218
0.8072 0.1353 0.0482 0.008192
0.6757 0.2123 0.0864 0.0289
0.5569 0.2789 0.1063 0.06233
0.4297 0.3292 0.1476 0.09756
0.3774 0.3457 0.1485 0.1255
0.2149 0.3486 0.1821 0.2526
0.141 0.3254 0.194 0.3401
0.04921 0.2445 0.1742 0.5277
0.0178 0.1728 0.1732 0.6323
0.006431 0.1091 0.1137 0.7702
0.002595 0.08301 0.08224 0.835];
theta0=[1;1;1;1;1;1];
[theta,Rsdnrm,Rsd,ExFlg,OptmInfo,Lmda,Jmat]=lsqcurvefit(@kinetics,theta0,t,c);
but I keep getting the following errors:
Error using odearguments (line 83)
The last entry in tspan must be different from the first entry.
%
Error in ode45 (line 115)
odearguments(FcnHandlesUsed, solver_name, ode, tspan, y0, options, varargin);
%
Error in kinetics (line 3)
[T,Cv]=ode45(@DifEq,t,c0);
%
Error in lsqcurvefit (line 202)
initVals.F = feval(funfcn_x_xdata{3},xCurrent,XDATA,varargin{:});
%
Error in cu (line 26)
[theta,Rsdnrm,Rsd,ExFlg,OptmInfo,Lmda,Jmat]=lsqcurvefit(@kinetics,theta0,t,c);
%
Caused by:
Failure in initial objective function evaluation. LSQCURVEFIT cannot continue.
Star Strider
on 4 Dec 2016
I apologise for the delay. It’s been four years since I dealt with the Monod kinetics problem and I had to go back to remember what I’d done.
There were two problems:
- Your ‘kinetics’ function has to have the parameter variable (here ‘theta’) as the first argument, and ‘t’ as the second;
- You need to return all the values of your ‘Cv’ vector as ‘C’ since you are fitting all of them.
I made those changes and put all the corrected code, data, and plot calls in the attached ‘Igor_Moura.m’ file, so you can run it by typing Igor_Moura in your Command Window. I won’t post it here. Open it in your Editor to see the changes and my added code.
If you want to return ‘theta’, the concentrations, and other variables to your workspace, the easiest way is to add them as outputs to the ‘Igor_Moura’ function.
The Estimated Rate Constants:
Rate Constants:
Theta(1) = 0.89197
Theta(2) = 0.26069
Theta(3) = 0.24870
Theta(4) = 0.48183
Theta(5) = 0.60977
Theta(6) = -0.01301
The Plot:
![](https://www.mathworks.com/matlabcentral/answers/uploaded_files/186347/image.png)
Make appropriate changes in the legend code to describe the concentrations.
Khan Jan
on 3 Apr 2017
Hello. My problem is much similar to this example. I want to plot different markers for each experimental data columns c1 to c4 (square, cross, circle and diamond). How to plot them? My second question:Is it possible to constrain the rate constant value between 0 and 0.80 using LSQCURVEFIT function, if yes how to do it?please guide.
Star Strider
on 3 Apr 2017
‘How to plot them’
See the code in the ‘Igor_Moura.m’ file I attached to my previous Comment.
‘Is it possible to constrain the rate constant value between 0 and 0.80 using LSQCURVEFIT function, if yes how to do it?’
Yes. See the documentation for lsqcurvefit.
Taimur Akhtar
on 4 Apr 2017
Edited: Taimur Akhtar
on 4 Apr 2017
Thank you Star strider for quick feedback. I got plots and answer to my 2nd question is solved. However, my point relevant to markers is still unclear. I will try to clarify my ambiguous question. Based on code from Igor_Moura.m, i got single marker 'pentagram' with different colors for different concentrations (attachment 2), however my target is to get more than one marker assigned to C1, C2, C3 and C4, respectively (attachment 1). Is it possible to get 4 different markers with 4 different colors assigned to each 4 concentrations? In simple words, is it possible to replace attachment 2 by attachment 1?
Khan Jan
on 4 Apr 2017
I tried to solve them for different markers, but its seems i can get only pentagram with different colors. Star strider, i will appreciate your guidline for solving it.
Taimur Akhtar
on 6 May 2017
I got plots after solving ODE'S. Now, I need to fit a power law line in the plot. Any idea.
Wouter Van Hecke
on 25 Aug 2017
Hi all,
Great post.
Do you have an idea on how to deal with incomplete data sets? Assume matrix c in the "Igor_Moura.m" file is incomplete and contains some unknown "NaN" values. In that case, lsqcurvefit gives the following error:
"Objective function is returning undefined values at initial point. lsqcurvefit cannot continue. " One option is to remove the entire row(s) with the unknown values, but aren't there more elegant approaches for this problem?
Many thanks for your suggestions!
Best regards, Wouter
Star Strider
on 25 Aug 2017
‘One option is to remove the entire row(s) with the unknown values, but aren't there more elegant approaches for this problem?’
Not that I’m aware of. The only other approach would be to use interpolation, and that has the extreme hazard of creating data that don’t actually exist, especially if the data are noisy or changing rapidly, making the parameter estimates essentially worthless. The Statistics and Machine Learning Toolbox functions ignore the rows with NaN values. I would follow that convention.
SHUBHAM PATEL
on 1 Oct 2019
Hello everyone, I had a very similar problem and used the above code by Star Strider for the fit. One of the problem i am facing is that, i am getting negative values for the parameters which for my specfic problem is not physical.
How do i constrain my parameters to give only postive values.
Thank you.
Star Strider
on 1 Oct 2019
Set the ‘lb’ (lower bound) argument in lsqcurvefit (or other optimization routines that allow bounded parameters) to a zeros vector the size of your parameter vector.
In the context of this code, that would be:
[theta,Rsdnrm,Rsd,ExFlg,OptmInfo,Lmda,Jmat]=lsqcurvefit(@kinetics,theta0,t,c,zeros(size(theta0)));
↑
Gustavo Lunardon
on 24 Mar 2020
Edited: Gustavo Lunardon
on 24 Mar 2020
Could someone show me how to do the same minimization, (same data) but with fminsearch? I was trying to adapt the example for a while and tried to pass the variables and parameters in different ways but I keep getting :
Assignment has more non-singleton rhs dimensions than non-singleton subscripts
My attempt is in attachment.
Star Strider
on 24 Mar 2020
Use this:
[theta,fval,exitflag] = fminsearch(@(theta)norm(c - kinetics(theta,t,c0)),theta0);
and:
Cfit = kinetics(theta, tv, c0);
I suggest optimising the initial conidtions as well, rather than using fixed initial conditions.
Gustavo Lunardon
on 24 Mar 2020
Thank you very much Star Strider!
I accompany many of your answers and they are always helpful, but answering this question in so little time exceeded my expectations!
Star Strider
on 24 Mar 2020
My pleasure!
Thank you!
I cannot always respond quickly, however I do my best!
Daphne Deidre Wong
on 27 Aug 2020
Hi Star Strider.
My the set of equations that i need to solve are very much similar to the file attached above 'Igor_Moura.m'. However I was wondering how should i implement the code if i want the reaction to occur over a range of temperature?
or would i need to put in the experimental results data at the certain temperature to get my theta value @ that temperature?
Kind regards, Daphne
Star Strider
on 27 Aug 2020
It depends.
If they are functions of temperature only and not of time, then use temperature as the independent variable and adjust the code accordingly.
If they are functions of time and temperature simultaneously, and both vary, that requires a completely different approach since the system is one of partial differential equations, not ordinary differential equations. The parameters would then not be scalars, but functions of temperature. That would be very difficult. One option would be to solve them with respect to time at each temperature (in a loop) as ordinary differential equations, and then later use appropriate parameter estimation techniques to characterise each parameter as a function of temperature. (That would likely be the approach I would use, at least at the outset, to determine if it was appropriate.)
Daniel Zhou
on 19 Nov 2020
Hi, Star.
I'm using the same code to fit data now. But I want to print this Rsdnrm value. How can I print that value?
Star Strider
on 19 Nov 2020
Daniel Zhou — The ‘Rsdnrm’ output is a scalar double value, and exists in the workspace after lsqcurvefit completes its estimation. Just use fprintf or sprintf to print it.
Star Strider
on 7 Dec 2020
ana ramirez de las heras’s Answer moved here —
Hi Star Strider,
Do I have to know c() values to use this method? I have a similar problem and I have data from the exercise statement but without knowing the values of theta() I don't know how to obtain c() values...
Thank you in advance!
Star Strider
on 7 Dec 2020
ana ramirez de las hera —
In order to estimate the parameters, the ‘c’ data (including the time vector associated with it) have to exist in your workspace. The code in my Answer estimates the kinetic parameters ‘theta’ vector from the data, so knowing them in advance is not necessary, however approximate estimates of their amplitudes are necessary, since the parameter estimation routines require an initial estimate of the parameters.
If you already have the parameters and are simply simulating the system, the ‘c’ values are not necessary.
If this Comment does not address your problems, please post a new Question with more detail as to what you are starting with and the result you want.
ana ramirez de las heras
on 7 Dec 2020
Thank you for answering, Star. I have posted a new Question: https://es.mathworks.com/matlabcentral/answers/685053-ode-system-solution-with-unknown-constant
Yasin Islam
on 18 Jan 2021
Hi Star Strider,
thank you very much for the usefull solution to the problem! I adapted the code to fit for my 6 diff. eq. and 12 k-values. it works.
unfortunately i not only have unknown k-values but also unknown concentrations.
The problem in my case extends up to 18 concentrations with 18 differential equations (i do know time dependend concentration values for 6 of them)
How can I update the code to not only look for my k-values but also for the unknown concentrations in order to represent the experimental concentrations best? Although alot of the unknown concentrations will be equal to 0 and/or neglectable.
Star Strider
on 18 Jan 2021
Yasin Islam — You can obviously fit only the concentrations you have data for. If the other 12 concentrations (actually, differential equations describing them) can be expressed in terms of the parameters (‘k values’) you can estimate, simply simulate them outside the ‘kinetics’ function using the parameters and plot all of them.
If the other 12 differential equations involve parameters that you cannot estimate (or cannot derive from the parameters you can estimate), then you cannot simulate them. There is no way around that unfortunate situation.
si heon Seong
on 2 Feb 2021
Hi Star Strider,
first, thank you for introducing this page! It was great help to me
One thing I have a additional question about this example
What should I do to give each parameter the constraint I want? For instance, thetas must be bigger than 0 etc..
Thank you
Star Strider
on 2 Feb 2021
si heon Seong — The lsqcurvefit and many other optimisation functions allow parameter constraints, at least setting the upper and lower parameter bounds. Use those arguments.
Here, that would be:
[theta,Rsdnrm,Rsd,ExFlg,OptmInfo,Lmda,Jmat]=lsqcurvefit(@kinetics,theta0,t,c,zeros(size(theta0)));
with the zeros call setting the lower limit. (The upper limit is not set here, since it is not necessary.)
si heon Seong
on 4 Feb 2021
Dear @Star Strider
I really appreciate your help! Can I ask the last one?
I have a model of 6 coupled differential equations for c1, c2, c3, c4, c5 and c6
but there are only two data set for c1 and c2
Can I still do the fitting job?
Always thank you
Star Strider
on 4 Feb 2021
si heon Seong — You can only fit ‘c1’ and ‘c2’ to your data, so in ‘kinetics’:
C = Cv(:,1:2);
(assuming that ‘c1’ and ‘c2’ are the first 2 differential equations in your system).
There have to be more data (more rows in the data matrix and time vector) than there are parameters to estimate.
My pleasure!
Khoi Ly
on 21 Feb 2021
Edited: Khoi Ly
on 21 Feb 2021
I was directed by your answer in another post regarding a similar problem.
In that post, I was trying to estimate the parameters of the differential equations using more than one time series data sets.
In the example above, given.
t=[0.1; 0.2; 0.4; 0.6; 0.8; 1; 1.5; 2; 3; 4; 5; 6];
c=[0.902 0.06997 0.02463 0.00218
0.8072 0.1353 0.0482 0.008192
0.6757 0.2123 0.0864 0.0289
0.5569 0.2789 0.1063 0.06233
0.4297 0.3292 0.1476 0.09756
0.3774 0.3457 0.1485 0.1255
0.2149 0.3486 0.1821 0.2526
0.141 0.3254 0.194 0.3401
0.04921 0.2445 0.1742 0.5277
0.0178 0.1728 0.1732 0.6323
0.006431 0.1091 0.1137 0.7702
0.002595 0.08301 0.08224 0.835];
we can estimate the parameters theta. Since the example above uses only one data set, what should I do if I have multiple data sets? Can I just concatenate the time-series data sets together and run the lsqcurvefit as usual?
Also, in my problem, each different time-series data set contains a different initial value. How do I modify the example to allow for different initial values depending on the chosen time-series data set?
Thank you
sumit kumar
on 28 Jun 2022
Edited: sumit kumar
on 28 Jun 2022
@Star Strider Thankyou so much. Your replies on various problems have helped me a lot. I was stuck in a parameter estimation problem and your answer is the exact thing i was looking for. You are a saviour man..
Star Strider
on 22 Sep 2022
UPDATE
Slightly revised code with some aethetic tweaks so that the lines and markers colours now match —
t=[0.1
0.2
0.4
0.6
0.8
1
1.5
2
3
4
5
6];
c=[0.902 0.06997 0.02463 0.00218
0.8072 0.1353 0.0482 0.008192
0.6757 0.2123 0.0864 0.0289
0.5569 0.2789 0.1063 0.06233
0.4297 0.3292 0.1476 0.09756
0.3774 0.3457 0.1485 0.1255
0.2149 0.3486 0.1821 0.2526
0.141 0.3254 0.194 0.3401
0.04921 0.2445 0.1742 0.5277
0.0178 0.1728 0.1732 0.6323
0.006431 0.1091 0.1137 0.7702
0.002595 0.08301 0.08224 0.835];
theta0 = rand(10,1);
[theta,Rsdnrm,Rsd,ExFlg,OptmInfo,Lmda,Jmat]=lsqcurvefit(@kinetics,theta0,t,c,zeros(size(theta0)));
Local minimum found.
Optimization completed because the size of the gradient is less than
the value of the optimality tolerance.
fprintf(1,'\tRate Constants:\n')
Rate Constants:
for k1 = 1:length(theta)
fprintf(1, '\t\tTheta(%2d) = %8.5f\n', k1, theta(k1))
end
Theta( 1) = 0.76483
Theta( 2) = 0.23492
Theta( 3) = 0.20878
Theta( 4) = 0.49179
Theta( 5) = 0.62211
Theta( 6) = 0.00000
Theta( 7) = 0.90288
Theta( 8) = 0.07146
Theta( 9) = 0.02840
Theta(10) = 0.00000
tv = linspace(min(t), max(t));
Cfit = kinetics(theta, tv);
figure
hd = plot(t, c, 'p');
for k1 = 1:size(c,2)
CV(k1,:) = hd(k1).Color;
hd(k1).MarkerFaceColor = CV(k1,:);
end
hold on
hlp = plot(tv, Cfit);
for k1 = 1:size(c,2)
hlp(k1).Color = CV(k1,:);
end
hold off
grid
xlabel('Time')
ylabel('Concentration')
legend(hlp, compose('C_%d',1:size(c,2)), 'Location','best')
![](https://www.mathworks.com/matlabcentral/answers/uploaded_files/1133255/image.png)
function C=kinetics(theta,t)
c0=theta(end-3:end);
[T,Cv]=ode45(@DifEq,t,c0);
%
function dC=DifEq(t,c)
dcdt=zeros(4,1);
dcdt(1)=-theta(1).*c(1)-theta(2).*c(1);
dcdt(2)= theta(1).*c(1)+theta(4).*c(3)-theta(3).*c(2)-theta(5).*c(2);
dcdt(3)= theta(2).*c(1)+theta(3).*c(2)-theta(4).*c(3)+theta(6).*c(4);
dcdt(4)= theta(5).*c(2)-theta(6).*c(4);
dC=dcdt;
end
C=Cv;
end
.
uki71319
on 24 Oct 2022
Edited: uki71319
on 24 Oct 2022
Dear @Star Strider, thanks for your detailed explanations. I've followed your codes, but i still got some problmes. Thus, i posted a new question under this link and hope to find out the solution for my lsqcurvefit problem. Would you mind taking a look and see where the issues are?
Any advice and help would be greatly appreciated. Thanks in advance!
Star Strider
on 24 Oct 2022
I looked at it just now, however it has already been answered.
Note that initial parameter estimates of zeros is never a good approach. Choose something nonzero and preferably not the same values for both parameters.
Maria Teresa Aguirrezabala Campano
on 26 Jan 2023
@Star Strider may I also ask for your help with my problem? https://www.mathworks.com/matlabcentral/answers/1900830-double-monod-maximum-rate-estimation
Jan
on 26 Jan 2023
@Maria Teresa Aguirrezabala Campano: Imagine what happens if all users advertise their questions and ask specific members to answer them. These member will be cluttered by messages and they will find less time to answer questions. Please consider this.
Continuum
on 25 Jan 2024
I have a set of ODEs (attached), I have been able to solve them using ode45, however, my issue now is my experimental results don't match the integrated values of the equations. So, I am looking to fit only the solution for epsilon with it's experimental results to find the best parameters A, B, (A0/alpha), k0, Q, and QG. Is this achievable using the Igor_Moura.m script? If so, which modifications are necessary? Like I said, I have already solved for G, theta, and epsilon, but I only have experimental data for epsilon. Thank you.
Star Strider
on 25 Jan 2024
If you only have one variable (column) to fit, that being epsilon, choose that variable as ‘C’.
So if
is ‘dcdt(3)’ then:
![](https://www.mathworks.com/matlabcentral/answers/uploaded_files/1600111/image.png)
C = Cv(:,3);
That should work, providing that you have more (preferably at least twice as many) data than the number of parameters (6) you want to estimate.
Star Strider
on 25 Jan 2024
You have to write the ‘kinetics’ function.
First, write all the differential equations, and then verify that the differential equation system works with parameters of the appropriate magnitudes (they do not have to be exact, since that is the point of the parameter estimation problem). It would likely be best to use ode15s or ode23s to integrate the differential equation system, since it is likely a ‘stiff’ system (most kinetics systems are ‘stiff’).
Writing the rest of the ‘kinetics’ code after that should be straightforward. Include the temperature in your differential equation system as independent variable data. It would likely have to be passed in the same independent variable argument as the time vector:
function C = kinetics(theta, tT)
where:
tT = [t T];
(they are both column vectors), then separate them inside the ‘kinetics’ function. This is your project, so you get to make all the design decisions. Use the ‘kinetics’ function here as a guide.
The parameters you want to estimate have to be presented to lsqcurvefit as a single vector, although you can assign them meaningful names inside the ‘kinetics’ function. That might be something like this:
ko = theta(1);
QG = theta(2);
and so for the rest of them.
I plotted the data, including the extra ‘exp_epsilon’ vector. I do not see any problems with it.
Star Strider
on 26 Jan 2024
You need to put your code in the same forma as the ‘kinetics’ example (although you can call it whatever you like, providing the naming is consistent throughout your code). As I mentioned previously, put ‘t’ and ‘T’ together in the same independent variable matrix, use that as the independent variable in your call to lsqcurvefit, then separate them in the ‘kinetics’ function into the time vector and the matching temperature vector.
It may be necesary to interpolate the temperature vector to match the time value that the ODE solver generates. See the documentation section on ODE with Time-Dependent Terms (this is in the ode45 documentation, however it works for all the solvers) for an esample on how to do that.
Choose the appropriate vector for ‘epsilon’ that you want to use as the dependent variable, and then return as ‘C’ the appropriate column of the integrated differential equations to fit to it.
Continuum
on 26 Jan 2024
Thanks @Star Strider. In the case of the Igor_Moura.m, what is the essence of t and c values from lines 20 to 44? Are they the solution/output from ode45? If so, why do you need to explicitly copy them over within the function? Is it possible to use the outputs t and c directly from the ode45 in the 'lsqcurvefit'?
Continuum
on 26 Jan 2024
I have tried to write it in your format, but the code just runs continuously which makes me think something is not right. Could it be that the there are too many parameters to fit? Attached is what I tried to run.
P.S. To my earlier question, I figured the t and c were from experiments or what the model is calibrating against?
Star Strider
on 26 Jan 2024
This should actually be a new question. If you post it as such, and post the link here, I will post my edited version of you code.
I finally got it to work (run without error), however the fit is not good, and that will likely require using the genetic algorithm or other Global Optiomization Toolbox functions that can change the parameters (or initial parameter estimates) until it can get a good fit.
Pedro
on 2 Aug 2024
Edited: Pedro
on 2 Aug 2024
@Star Strider I followed the code here discussed and i successfully applied to a similar case, incorporating also multistart to try to find the global optimum (I think I could use GlobalSearch, but i haven't tried it yet). The "PE_LScurvefit_Multistart" code is working fine
Now I want the lsqcurvefit to estimate the kinetic parameters using data from several experiments, each one with different initial conditions and under different operating condition, namely temperature, so i can adjust directly temperature dependent parameters (Arrhenius equation). I tried it but I keep getting errors in the lsqcurvefit.
In this case the data sets are same sized, but some experiments I want to further include have less data points, and from what i read that can also be a problem...
If you or anyone could help me, I would really appreciate it.
The "PE_LScurvefit_Multistart_Severaldata" code is the one not working.
Star Strider
on 2 Aug 2024
I do nott have extensive experience with MultiStart, however I have coded this with the genetic algorithm () function —
t=[0.1
0.2
0.4
0.6
0.8
1
1.5
2
3
4
5
6];
c=[0.902 0.06997 0.02463 0.00218
0.8072 0.1353 0.0482 0.008192
0.6757 0.2123 0.0864 0.0289
0.5569 0.2789 0.1063 0.06233
0.4297 0.3292 0.1476 0.09756
0.3774 0.3457 0.1485 0.1255
0.2149 0.3486 0.1821 0.2526
0.141 0.3254 0.194 0.3401
0.04921 0.2445 0.1742 0.5277
0.0178 0.1728 0.1732 0.6323
0.006431 0.1091 0.1137 0.7702
0.002595 0.08301 0.08224 0.835];
% theta0=[1;1;1;1;1;1];
% % [theta,Rsdnrm,Rsd,ExFlg,OptmInfo,Lmda,Jmat]=lsqcurvefit(@kinetics,theta0,t,c);
ftns = @(theta) norm(c-kinetics(theta,t));
PopSz = 100;
Parms = 10;
optsAns = optimoptions('ga', 'PopulationSize',PopSz, 'InitialPopulationMatrix',randi(1E+4,PopSz,Parms)*1E-3, 'MaxGenerations',5E3, 'FunctionTolerance',1E-10); % Options Structure For 'Answers' Problems
opts = optimoptions('ga', 'PopulationSize',PopSz, 'InitialPopulationMatrix',randi(1E+4,PopSz,Parms)*1E-3, 'MaxGenerations',5E3, 'FunctionTolerance',1E-10, 'PlotFcn',@gaplotbestf, 'PlotInterval',1);
optshf = optimoptions('ga', 'PopulationSize',PopSz, 'InitialPopulationMatrix',randi(1E+4,PopSz,Parms)*1E-3, 'MaxGenerations',5E3, 'FunctionTolerance',1E-10, 'HybridFcn',@fmincon, 'PlotFcn',@gaplotbestf, 'PlotInterval',1); % With 'HybridFcn'
t0 = clock;
fprintf('\nStart Time: %4d-%02d-%02d %02d:%02d:%07.4f\n', t0)
Start Time: 2024-08-02 19:45:33.7134
[theta,fval,exitflag,output,population,scores] = ga(ftns, Parms, [],[],[],[],zeros(Parms,1),Inf(Parms,1),[],[],optsAns);
ga stopped because the average change in the fitness value is less than options.FunctionTolerance.
t1 = clock;
fprintf('\nStop Time: %4d-%02d-%02d %02d:%02d:%07.4f\n', t1)
Stop Time: 2024-08-02 19:47:28.1651
GA_Time = etime(t1,t0)
GA_Time = 114.4517
DT_GA_Time = datetime([0 0 0 0 0 GA_Time], 'Format','HH:mm:ss.SSS');
fprintf('\nElapsed Time: %23.15E\t\t%s\n\n', GA_Time, DT_GA_Time)
Elapsed Time: 1.144517280000000E+02 00:01:54.451
fprintf('Fitness value at convergence = %.4f\nGenerations \t\t\t\t = %d\n\n',fval,output.generations)
Fitness value at convergence = 0.2829
Generations = 4807
fprintf(1,'\tRate Constants:\n')
Rate Constants:
for k1 = 1:length(theta)
fprintf(1, '\t\tTheta(%2d) = %8.5f\n', k1, theta(k1))
end
Theta( 1) = 0.04758
Theta( 2) = 1.08874
Theta( 3) = 2.36663
Theta( 4) = 6.81355
Theta( 5) = 1.19491
Theta( 6) = 0.40068
Theta( 7) = 1.04379
Theta( 8) = 0.03577
Theta( 9) = 0.05275
Theta(10) = 0.00001
tv = linspace(min(t), max(t));
Cfit = kinetics(theta, tv);
figure
hd = plot(t, c, 'p');
for k1 = 1:size(c,2)
CV(k1,:) = hd(k1).Color;
hd(k1).MarkerFaceColor = CV(k1,:);
end
hold on
hlp = plot(tv, Cfit);
for k1 = 1:size(c,2)
hlp(k1).Color = CV(k1,:);
end
hold off
grid
xlabel('Time')
ylabel('Concentration')
legend(hlp, compose('C_%d',1:size(c,2)), 'Location','N')
![](https://www.mathworks.com/matlabcentral/answers/uploaded_files/1745851/image.png)
function C=kinetics(theta,t)
c0 = theta(7:10);
% c0=[1;0;0;0];
[T,Cv]=ode45(@DifEq,t,c0);
%
function dC=DifEq(t,c)
dcdt=zeros(4,1);
dcdt(1)=-theta(1).*c(1)-theta(2).*c(1);
dcdt(2)= theta(1).*c(1)+theta(4).*c(3)-theta(3).*c(2)-theta(5).*c(2);
dcdt(3)= theta(2).*c(1)+theta(3).*c(2)-theta(4).*c(3)+theta(6).*c(4);
dcdt(4)= theta(5).*c(2)-theta(6).*c(4);
dC=dcdt;
end
C=Cv;
end
I probably posted this in another Answer, however I can’t find it at present. Starting with a larger population size may make it more accurate, although the code will take longer to run. You can use the parameters estimated here (‘theta’) as the initial estimates to lsqcurvefit, and then run this using my updated code in an earlier Comment.
.
Pedro
on 3 Aug 2024
Perfect! Thank you so much, @Star Strider. Yes, with a larger population size (1000), it gets more accurate, although it is slower and it obtains a worst results compared to using directly the "Multistart". But both ways work. Maybe I will also try GlobalSearch.
Star Strider
on 3 Aug 2024
This runs, though it tales too long to run here.
I created:
SetCell{1} = {t1, c1, temp1, c0_1};
SetCell{2} = {t2, c2, temp2, c0_2};
SetCell{3} = {t3, c3, temp3, c0_3};
and then a loop to loop through them. Note that I included the various ‘temp’ variables in my cell array.
I also corrected several errors, all of which were introduced here and are not part of my original code.
If the first seet of parameters produces a decent fit to the datta, preserve them and use them as the initial estimates for the subsequent sets. It may make this more efficient.
A Vote for my Answer here would be appreciated!
PE_LScurvefit_Multiple_data_sets_non_isothermal
Warning: Length of lower bounds is < length(x); filling in missing lower bounds with -Inf.
Warning: Length of upper bounds is < length(x); filling in missing upper bounds with +Inf.
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.
Rate Constants:
Theta( 1) = 0.05025
Theta( 2) = 0.08310
Theta( 3) = 0.66899
Theta( 4) = 0.66844
Theta( 5) = 0.00006
Theta( 6) = 0.19195
Theta( 7) = 1367.83624
Theta( 8) = 2619.94112
Theta( 9) = 2964.46774
Theta(10) = 13236.98878
Theta(11) = -3738.19745
Theta(12) = 529.43631
![](https://www.mathworks.com/matlabcentral/answers/uploaded_files/1746111/image.png)
Warning: Length of lower bounds is < length(x); filling in missing lower bounds with -Inf.
Warning: Length of upper bounds is < length(x); filling in missing upper bounds with +Inf.
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.
Rate Constants:
Theta( 1) = 0.00908
Theta( 2) = 0.71083
Theta( 3) = 0.43675
Theta( 4) = 0.75300
Theta( 5) = 0.00062
Theta( 6) = 0.61537
Theta( 7) = -58.95522
Theta( 8) = 3751.88913
Theta( 9) = 2646.80729
Theta(10) = 17763.40859
Theta(11) = -2821.47869
Theta(12) = 462.55345
![](https://www.mathworks.com/matlabcentral/answers/uploaded_files/1746116/image.png)
Warning: Length of lower bounds is < length(x); filling in missing lower bounds with -Inf.
Warning: Length of upper bounds is < length(x); filling in missing upper bounds with +Inf.
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.
Rate Constants:
Theta( 1) = 0.00000
Theta( 2) = 0.00232
Theta( 3) = 0.11307
Theta( 4) = 0.78547
Theta( 5) = 0.86578
Theta( 6) = 0.90149
Theta( 7) = 8.45868
Theta( 8) = 9.95011
Theta( 9) = -440.41576
Theta(10) = 103.26330
Theta(11) = 59.29220
Theta(12) = 0.24303
![](https://www.mathworks.com/matlabcentral/answers/uploaded_files/1746121/image.png)
Elapsed time is 3.514244 seconds.
function PE_LScurvefit_Multiple_data_sets_non_isothermal
tic
%Attempt to update from 1 dataset (t,c) and isothermal operation to
% three data sets (t1,c1), (t2,c2), (t3,c3), each set at different
% temperatures, meaning now theta is theta_temp, so theta_temp(1),
% theta_temp(2) and theta_temp(3) have different values.
%So, the parameter to be estimated are k(1 to 6) and E(1 to 6).
%The plotting part is not updated because the code is not running
%T14 oxidation 80ºC 6bar
t1=[0
16
30
45
61
96
121
180
240
362
492
640];
%T14 oxidation 80ºC 6bar
c1=[105.84 0.00 0.00 0.00
83.03 17.36 2.29 2.47
74.82 19.85 1.63 3.61
69.28 21.98 1.33 4.81
62.72 25.19 1.26 6.18
51.98 28.93 0.82 9.16
43.11 29.59 0.60 9.97
28.58 28.07 0.51 12.28
17.87 24.32 0.53 12.98
7.84 16.22 0.53 11.40
2.68 8.22 0.83 6.92
0.66 2.77 0.28 0.85];
%T24 oxidation 90ºC 6bar
t2=[0
15.25
30
45
60
90
120
180
240
300
360
412
];
%T24 oxidation 90ºC 6bar
c2=[110.16 0.00 0.00 0.00
79.13 17.04 1.22 2.82
68.77 21.16 0.88 4.74
56.83 25.07 0.74 6.46
45.17 27.84 0.71 8.03
35.49 28.68 0.87 11.40
20.73 25.15 0.49 10.94
9.77 18.07 0.54 11.40
2.78 10.48 0.00 6.45
0.98 5.35 0.00 3.71
0.42 2.13 0.00 1.69
0.35 0.76 0.00 0.89
];
% T3 oxidation 70ºC 6bar DIFFERENT SIZED
t3 = [0; 50; 100; 150; 200; 250; 300; 350; 400];
c3 = [120.5 0.0 0.0 0.0
110.2 5.6 0.1 4.3
100.8 3.2 0.2 2.1
90.5 2.1 0.3 1.5
80.2 1.5 0.4 1.0
70.9 1.1 0.5 0.7
60.6 0.8 0.6 0.5
50.3 0.6 0.7 0.4
40.0 0.4 0.8 0.3];
temp1 = 80; % Temperature for data set 1
temp2 = 90; % Temperature for data set 2
temp3 = 70; % Temperature for data set 3
% Initial conditions
c0_1 = [105.84; 0; 0; 0];
c0_2 = [110.16; 0; 0; 0];
c0_3 = [120.5; 0; 0; 0];
SetCell{1} = {t1, c1, temp1, c0_1};
SetCell{2} = {t2, c2, temp2, c0_2};
SetCell{3} = {t3, c3, temp3, c0_3};
% Combine the additional data sets and initial conditions
% t = {t1, t2, t3};
% c = {c1, c2, c3};
% c0 = {c0_1, c0_2, c0_3};
% Kinetics function to include the temperature variable
function C = kinetics(theta, t, c0,temp)
[~, Cv] = ode15s(@(t,c) DifEq (t,c,temp), t, c0);
function dC = DifEq(t, c, temp)
dcdt = zeros(4, 1);
% Introduce temperature dependence on theta parameter - theta = k *
% Exp (-E/(R*temp))
k = theta(1:6);
E = theta(7:12);
R = 8.314; % Gas constant
% whos
theta_temp = k .* exp(-E ./ (R * temp));
dcdt(1) = -theta_temp(1) * c(1) - theta_temp(2) * c(1);
dcdt(2) = theta_temp(1) * c(1) - theta_temp(3) * c(2) - theta_temp(4) * c(2);
dcdt(3) = theta_temp(2) * c(1) + theta_temp(4) * c(2) - theta_temp(6) * c(3);
dcdt(4) = theta_temp(3) * c(2) - theta_temp(5) * c(4);
dC = dcdt;
end
C = Cv;
end
% Initialize theta values
theta0 = rand(12, 1);
% Boundaries for theta
lb = [0; 0; 0; 0; 0; 0];
ub = [1; 1; 1; 1; 1; 1];
% Combine the data sets
% t = {t1, t2};
% c = {c1, c2};
% c0 = {c0_1, c0_2};
% Non-linear solver
for k = 1:numel(SetCell)
t = SetCell{k}{1};
c = SetCell{k}{2};
temp = SetCell{k}{3};
c0 = SetCell{k}{4};
[theta, Rsdnrm, Rsd, ExFlg, OptmInfo, Lmda, Jmat] = lsqcurvefit(@(theta, t) kinetics(theta, t, c0, temp), theta0, t, c, lb, ub);
fprintf(1, '\tRate Constants:\n')
for k1 = 1:length(theta)
fprintf(1, '\t\tTheta(%2d) = %8.5f\n', k1, theta(k1))
end
tv = linspace(min(t), max(t));
Cfit1 = kinetics(theta, tv, c0_1, temp);
% Cfit2 = kinetics(theta, tv, c0_2);
figure
hd = plot(t, c, 'p');
for k1 = 1:size(c, 2)
CV(k1, :) = hd(k1).Color;
hd(k1).MarkerFaceColor = CV(k1, :);
end
hold on
hlp = plot(tv, Cfit1);
for k1 = 1:size(c, 2)
hlp(k1).Color = CV(k1, :);
end
% hd = plot(t, c2, 'p');
% for k1 = 1:size(c2, 2)
% CV(k1, :) = hd(k1).Color;
% hd(k1).MarkerFaceColor = CV(k1, :);
% end
% hlp = plot(tv, Cfit2);
% for k1 = 1:size(c2, 2)
% hlp(k1).Color = CV(k1, :);
% end
hold off
grid
xlabel('Time')
ylabel('Concentration')
legend(hlp, compose('C_%d', 1:size(c1, 2)), 'Location', 'North')
end
toc
end
The fitted values are reasonably good, and the code did not take more than a few seconds (actually about 3.514 seconds) to run.
.
Kishen Mahadevan
on 21 Nov 2024
I would like to add that in situations when the data is uniformly sampled, you can also use grey box estimation techniques from System Identification Toolbox to estimate these parameters.
Here is an example that highlights the steps of estimating coefficients of ODEs that describe the model dynamics to fit a given response trajectory.
More Answers (0)
See Also
Categories
Find more on Grey-Box Model Estimation in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!An Error Occurred
Unable to complete the action because of changes made to the page. Reload the page to see its updated state.
Select a Web Site
Choose a web site to get translated content where available and see local events and offers. Based on your location, we recommend that you select: .
You can also select a web site from the following list
How to Get Best Site Performance
Select the China site (in Chinese or English) for best site performance. Other MathWorks country sites are not optimized for visits from your location.
Americas
- América Latina (Español)
- Canada (English)
- United States (English)
Europe
- Belgium (English)
- Denmark (English)
- Deutschland (Deutsch)
- España (Español)
- Finland (English)
- France (Français)
- Ireland (English)
- Italia (Italiano)
- Luxembourg (English)
- Netherlands (English)
- Norway (English)
- Österreich (Deutsch)
- Portugal (English)
- Sweden (English)
- Switzerland
- United Kingdom(English)
Asia Pacific
- Australia (English)
- India (English)
- New Zealand (English)
- 中国
- 日本Japanese (日本語)
- 한국Korean (한국어)