How can I iterate using ode45? - matlab

I'm trying to write some matlab code. Why won't my new variable w get accepted so that my function can take another parameter? I want to iterate over the variable that is now 7.8 and use iteration instead.
function dZ=sys(x,Z,w)
c=#(z)4800 - 20.2090 + (17.3368)*z/1000+ (272.9057)*exp(-z*0.7528/1000); % c(z)
c=c(2000);
deg=w;
% Z(1):=z
% Z(2):=u
dZ=zeros(2,1); % a column vector
dZ(1)=Z(2);
dZ(2)=-(c/cosd(7.8))^2*(((-272.9057*0.7528/1000)*exp(-Z(1)*0.7528/1000)) + 17.3368/1000)/...
(4800 - 20.2090 + (17.3368)*Z(1)/1000+ (272.9057)*exp(-Z(1)*0.7528/1000))^3;
end
I get an error message when trying to use the new variable in my function that worked before.
Error using sys (line 4)
Not enough input arguments.
Error in odearguments (line 88)
f0 = feval(ode,t0,y0,args{:}); % ODE15I sets args{1} to yp0.
Error in ode45 (line 114)
[neq, tspan, ntspan, next, t0, tfinal, tdir, y0, f0, odeArgs, odeFcn, ...
Error in underwater (line 2)
[X,Z]=ode45(#sys,x,[2000 tand(7.8)], 7.8);

I would write the function as follows (although w doesn't appear to be used):
function dZ=sys(t,Z,w)
z = 2000;
c = 4800 - 20.2090 + (17.3368)*z/1000+ (272.9057)*exp(-z*0.7528/1000);
deg=w; % not used?
dZ=zeros(2,1); % a column vector
dZ(1)=Z(2);
dZ(2)=-(c/cosd(7.8))^2*(((-272.9057*0.7528/1000)*exp(-Z(1)*0.7528/1000)) + 17.3368/1000)/...
(4800 - 20.2090 + (17.3368)*Z(1)/1000+ (272.9057)*exp(-Z(1)*0.7528/1000))^3;
end
and then call the ode solver as follows:
[T,Z_sol] = ode45(#(t,Z) sys(t,Z,w),x,[2000 tand(7.8)]);
where w and x are defined in your base or caller workspace.

The ODE solver is expecting a function of two variables. It is looking for a function in the form of:
y' = f(t, y)
So, if you are passing #sys to ode45, it must be a function of only two variables.
In the comments below you reference another question. They use the following call:
[t,N] = ode45(#(t,y) rateEquations(t,y,F), timeSpan, initialConditions)
Using #(t,y) makes a generic function which is a function of two variables. In this example the function rateEquations is called with a fixed F value. So ODE is in fact expecting a function of two variables. If you have a function of more than two variables you can recast it as a function of two variables by copying the technique used in the example you reference. Hope this helps!

Related

ode45, error in odeargument, growth kinetics

I am trying to solve this system of ODEs related to micro algae growth kinetics, I attach my function and script. I am getting some error related to the arguments. Please let me know where my error is thank you :) the system is composed of 7 ODEs and 7 corresponding state variables with 25 parameters
Function
function dx=odesys(t,var)
%dxdt=var(1);
%dldt=var(2);
%dsdt=var(3);
%dndt=var(4);
%gadt=var(5);
%Fadt=var(6);
%dhdt=var(7);
mumax=var(1);
Kxs=var(2);
Kixs=var(3);
Kxn=var(4);
Kixn=var(5);
qlmax=var(6);
Kls=var(7);
Kils=var(8);
Kinl=var(9);
Yxs=var(10);
Yxn=var(11);
Kh=var(12);
Yls=var(13);
Kxl=var(14);
Kixl=var(15);
Kli=var(16);
Kili=var(17);
sigma=var(18);
k1=var(19);
Kgas=var(20);
Kgan=var(21);
Kigan=var(22);
k2=var(23);
Kfas=var(24);
Kfan=var(25);
%Variable
%oilfree biomass--x(1)
%lipid production rate--x(2)
%Substrate consumption rate--x(3)
%N consumption rate--x(4)
%Byproduct GA--x(5)
%Byproduct FA--x(6)
%pH change--x(7)
%Rate equations
S=2.01; %g/L
N=0.098; %g/L
X=0.001; %g/L
Io=125*10-6; %E/m^2*s
l=1;
Il=Io*exp(-sigma*X*l);
mux=mumax*(S/(S+Kxs+(S^2/Kixs)))*(N/(N+Kxn+(N^2/Kixn)))*(Il/(Il+Kxl+(Il^2/Kixl)));
mul=(qlmax)*(S/(S+Kls+(S^2/Kils)))*(Kinl/(N+Kinl)*(Il/(Il+Kli+(Il^2/Kili))));
%ODE
dx(1)=(mux*X);
dx(2)=(mul*X);
dx(3)=(-(1/Yxs)*dx(1))-((1/Yls)*dx(2));
dx(4)=(-(1/Yxn)*dx(1));
dx(5)=(k1*(S/(S+Kgas))*(N/(N+Kgan+(N^2/Kigan))));
dx(6)=(k2*(S/S+Kfas)*(N/N+Kfan));
dx(7)=-Kh*dx(3);
% The function return value is always a vector length equal to number of
% equations in model, and has to be a column vector
dx=dx';
% dx=[dx(1);dx(2);dx(3);dx(4);dx(5);dx(6);dx(7)];
end
Script
clear all
clc
%Time span to solve ODE
tspan=[0 120];
int=[0,0,0,0,0,0,0];
%Conditions
var=[0.227;0.050;9.923;0.065;0.5;0.121;6.554;0.110;380.023;1.47;6.883;0.879;0.064;19.519;2053.924;15.023;2152.918;34.104;0.329;1.456;12.976;2.533;1.4055;12.976;2.533];
V = odesys(tspan(1), var);
iscolumn(V) % false
isrow(V) % true?
%Using ODE 45 to solve system
[t,X]=ode45(#odesys,tspan,int,var);
Error functions
Error in odearguments (line 90)
f0 = feval(ode,t0,y0,args{:}); % ODE15I sets args{1} to yp0.
Error in ode45 (line 115)
odearguments(FcnHandlesUsed, solver_name, ode, tspan, y0, options, varargin);
Error in run (line 17)
[t,X]=ode45(#odesys,tspan,int,var);
An easy way to do this is to define the 'var' variable inside your odesys function not in the script:
function dx=odesys(t, x)
%dxdt=var(1);
%dldt=var(2);
%dsdt=var(3);
%dndt=var(4);
%gadt=var(5);
%Fadt=var(6);
%dhdt=var(7);
var=[0.227;0.050;9.923;0.065;0.5;0.121;6.554;0.110;380.023;1.47;6.883;0.879;0.064;19.519;2053.924;15.023;2152.918;34.104;0.329;1.456;12.976;2.533;1.4055;12.976;2.533];
mumax=var(1);
Kxs=var(2);
...
Note the changes in the function declaration.
You have to add the x parameter here in function declaration. This is the variable which you are differentiating with respect to. You are not using it in your equations so you can name it anything but it should be included.
And finally, no need for the 'var' variable in the script as in here:
V = odesys(tspan(1));
and here:
[t,X]=ode45(#odesys,tspan,int);

Error when passing arguments to function handles

Suppose we have the following function:
function f=lorenz(t,x,a,b,c)
% solve differential equation like this
%dx/dt=a*(y-x)
%dy/dt=-x*z+b*x-y
%dz/dt=xy-c*z/3
f=zeros(3,1);% preallocate result
f(1)=a*(x(2)-x(1));
f(2)=-x(1)*x(3)+b*x(1)-x(2);
f(3)=x(1)*x(2)-c*x(3)/3;
end
For running this program, let us use the following test file:
% test program
x0=[-2 -3.5 21];% initial point
a=input(' enter first coefficient : ');
b=input(' enter second coefficient: ');
c=input(' enter third coefficient : ');
[t,x]=ode45(#(x) lorenz(x,a,b,c),[0 10],x0);
plot(t,x(:,1),'r');
title(' solution of x part');
grid on
I have tried passing arguments to the function handle,
test_program
enter first coefficient : 10
enter second coefficient: 28
enter third coefficient : -8
but it gives me the following error:
Error using #(x)lorenz(x,a,b,c)
Too many input arguments.
Error in odearguments (line 87)
f0 = feval(ode,t0,y0,args{:}); % ODE15I sets args{1} to yp0.
Error in ode45 (line 113)
[neq, tspan, ntspan, next, t0, tfinal, tdir, y0, f0, odeArgs, odeFcn, ...
Error in test_program (line 6)
[t,x]=ode45(#(x) lorenz(x,a,b,c),[0 10],x0);
one solution involves using global variables, like this:
function f=lorenz(t,x)
% solve differential equation like this
%dx/dt=a*(y-x)
%dy/dt=-x*z+b*x-y
%dz/dt=xy-c*z/3
global a
global b
global c
f=zeros(3,1);% preallocate result
f(1)=a*(x(2)-x(1));
f(2)=-x(1)*x(3)+b*x(1)-x(2);
f(3)=x(1)*x(2)-c*x(3)/3;
end
but then it takes too long to run.
How else can I fix this issue? What I want is to pass different arguments, if I write inside code something like this
a=input('enter the coefficient : ')
then this will be repeated several times.
Don't use global variables.
The fix is very simple, add the t as input too:
[t,x] = ode45(#(t,x) lorenz(t,x,a,b,c),[0 10],x0);

MATLAB function fminunc generates errors

I am facing an error when using the function fminunc in the context of a maximum-likelihood estimation. I am afraid that it is very straight forward however my experience with MATLAB is very limited.
The function "normal" contains the log-likelihood function. I seek to estimate the expectation and std. deviation of a normal distribution given the observations stored in the variable x.
function f = normal(X, theta)
mean = theta(1);
sigma = theta(2);
z = (X-mean)./sigma;
f = -(sum(-log(sigma) -(1/2).*z.^2 ));
I basically execute the following code:
theta = [1,1]
f = #(theta)normal(x, theta)
[est, fval, exitflag, output, grad, hessian] = fminunc('normal', x, theta)
The error is the following:
Warning: Struct field assignment overwrites a value with class "double". See MATLAB R14SP2 Release
Notes, Assigning Nonstructure Variables As Structures Displays Warning, for details.
In createOptionFeedback at 34
In prepareOptionsForSolver at 31
In fminunc at 157
Warning: Struct field assignment overwrites a value with class "double". See MATLAB R14SP2 Release
Notes, Assigning Nonstructure Variables As Structures Displays Warning, for details.
In fminunc at 203
Error using feval
Undefined function 'normal' for input arguments of type 'double'.
Error in fminunc (line 254)
f = feval(funfcn{3},x,varargin{:});
Caused by:
Failure in initial user-supplied objective function evaluation. FMINUNC cannot continue.
Unfortunately the manual did not help me to fix the code. Calling
[est, fval, exitflag, output, grad, hessian] = fminunc(f, x, theta)
did not help either. What am I doing wrong?
Thank you in advance!
You have called fminunc with the wrong sintax, please refer to the documentation.
A way to fix your code is by defining the function normal to accept only one parameter: theta.
function f = normal(theta)
global X
mean = theta(1);
sigma = theta(2);
z = (X-mean)./sigma;
f = -(sum(-log(sigma) -(1/2).*z.^2 ));
and call fminunc with
global X
X = randn(100, 1); % A possible time series.
theta0 = [1,1];
[est, fval, exitflag, output, grad, hessian] = fminunc(#normal, theta0);

ode45 not passing arguments (MATLAB)

I'm implementing a filtering algorithm in matlab and having some difficulty with parameter passing.
my dynamics are controlled by the function:
function zdot = VortexDynamics(t, z, vorticity)
for ii=1:length(vorticity),
zdot(ii,1) = 1i/(2*pi) * sum( vorticity([1:ii-1,ii+1:end]) .* ( z(ii) - z([1:ii-1,ii+1:end]) ) ./ (abs(z(ii) - z([1:ii-1,ii+1:end]) ).^2 ) ) ;
end
end
I initially compute the trajectories with ode45, with no issue
[t_true,z_true]=ode45(#VortexDynamics, tspan ,z0_true, OPTIONS, vorticity) ;
To implement the filter, I call a function for each time step:
[z_a , Gam, z_ens] = EnKF_nonlinear(num_tracers, Func_Observation, Observations(:,ii),vorticity, [prev_t t], z_ens, Gam, W,R, VortexDynamics, H, N) ;
EnKF_nonlinear is defined by:
function [z_a, Gam_a, z_ens] = EnKF_nonlinear(num_tracers, Func_Observation, Observations,vorticity, tspan, z0_est, Gam0_est, W,R, dynFunc, H,N )
Within EnKF_nonlinear, I need to integrate the dynamics again with ode45:
for ii = 1:N
[t_out, z_out] = ode45(dynFunc, tspan, z0_est(:,ii), vorticity);
z_ens(:,ii) = z_out(end,:) ;
end
but I get the error:
Error using VortexEnKF>VortexDynamics (line 85)
Not enough input arguments.
Error in VortexEnKF (line 63)
[z_a , Gam, z_ens] = EnKF_nonlinear(num_tracers, Func_Observation,
Observations(:,ii),vorticity, [prev_t t], z_ens, Gam, W,R, VortexDynamics, H,
N) ;
but VortexDynamics only requires t,z,vorticity as parameters. I call ode45 the same way in both functions, but I only get the error when I call it through EnKFnonlinear.
I don't see how its not calling with the right number of parameters. Any ideas?
silly me,
I forgot to include a [] in the ode45 call as a placeholder for the precision options.
ode45(dynFunc, tspan, z0_est(:,ii), [], vorticity);
passes the vorticity parameter to dynFunc, and it works fine.

ode23 in MatLab - using optional arguments as input

I am trying to learn MatLab on my own. I get most of the concepts regarding solving ODEs, but I am a little unsure about the use of optional arguments as input. I have created the following function:
function xdot = funn(t,x,mu);
if nargin < 3 | isempty(mu)
mu = 1;
end
xdot = t +mu*x;
In addition I have defined:
tspan = [0 2];
x0 = 0;
options = odeset('outputfcn','odeplot');
What I am unsure about is how to change the variable mu when I use the ode23 function. I understand that this should be possible through the input of optional arguments, but I can't get it to work. Say if I write:
[t y] = ode23('funn',tspan,x0,options)
Then everything computes correctly, and we automatically get mu = 1.
But if I want to change this, how do I proceed? I tried writing the following to set mu = 4:
[t y] = ode23('funn',tspan,x0,options,4)
But then I just get the following:
??? Error using ==> funn
Too many input arguments.
Error in ==> odearguments at 98
f0 = feval(ode,t0,y0,args{:}); % ODE15I sets args{1} to yp0.
Error in ==> ode23 at 171
[neq, tspan, ntspan, next, t0, tfinal, tdir, y0, f0, odeArgs, odeFcn, ...
I did this based on how I understood the procedure as it is written in my textbook, but obviously I'm doing something wrong here. If anyone can explain how I go about changing the parameter mu, and in general how optional arguments p1, p2, ... are used with ode23 I would really appreciate it!
what you need to do is pass data in the function call using anonymous functions:
[t y] = ode23(#(t,y)funn(t,y,4),tspan,x0,options)
I think the problem has nothing to do with ode23. The problem seems to be in that you have not listed varargin in the function definition of funn. It should be:
function xdot = funn(t,x,mu,varargin)
This way funn accepts 3 or more arguments, and you should not get error "Too many input arguments".