ode23 in MatLab - using optional arguments as input - matlab

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".

Related

Computing the Jacobian of an anonymous function - MATLAB

I'm trying to solve a system of non linear odes in Matlab as follows.
editparams %parameters
Tend = 50;
Nt = 100;
% Define RHS functions
RHS = #(t,x) ModelRHS(t,x,param); %anonymous function defining the set of equations
%Execution-----------------------------------------------------------------
x0 =[0.04;0.75;0.85]; %Initial condition
t = linspace(0,Tend,Nt); %TSPAN
[t x] = ode45(RHS, t, x0);
Now, I need to find the steady state of the system and I'm trying to create a function for this. I thought I'd calculate the steady state using the Jacobian. My equations are in an anonymous function which is defined as f in the code below. However, I realised that jacobian does not work for anonymous functions (or may be there is a way to do with anonymous functions) . so I thought I would convert the anonymous function to a symbolic function and try it. But
i still have a difficulty in getting that done. So any help is really appreciated!
function SS = SteadyState(param, E)
f = #(t,x)ModelRHS(t,x,param,E); %set of odes
SymbolicSystem = sym(f); %trying to make the anonymous function symbolic
SymbolicJacobian = jacobian(SymbolicSystem',x); %jacobian
Jacob = matlabFunction(SymbolicJacobian,x);
end
Also if there is any other way apart from finding the Jacobian, kindly let me know about that too.
I tried using 'fsolve' to calculate the steady-state as follows:
f = #(t,x)ModelRHS(t,x,param);
x0 =[0.04;0.75;0.85]';
options = optimoptions('fsolve','Display','iter'); % Option to display output
SS = fsolve(f,x0,options); % Call solver
but it returned an error
Not enough input arguments.
Error in #(t,x)ModelRHS(t,x,param)
Error in fsolve (line 242)
fuser = feval(funfcn{3},x,varargin{:});
Caused by:
Failure in initial objective function evaluation. FSOLVE cannot continue.

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);

How can I iterate using ode45?

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!

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.