How to address initial conditions for coupled system in Matlab - matlab

We have a coupled system of 10 ode each. The coupling presents in the last equation.
I thought about using a matrix 10 by 2 as initial conditions.I also followed a similar question with the same title here, but I still get the same errors ('Too many input arguments.')
time = [0 5];
x1_0 = [0 0 0 0 0 0 0 0 0 0];
x2_0 = [0 0 0 0 0 0 0 0 0 0];
initial = [x1_0;x2_0];
x = NaN(length(initial),2*length(time));
[t,x] = ode45(#ode,time,initial);
function [dxdt] = ode(x)
N = 2;
dxdt = NaN(10,2);
for i = 1:N
dxdt(1,i) = x(6,i);
dxdt(6,i) = (x(3,i)-x(4,i)+x(5,i)) - x(6,i) - x(1,i);
dxdt(2,i) = x(7,i);
dxdt(7,i) = (x(3,i)-x(4,i)+x(5,i)) - x(7,i) - x(2,i);
dxdt(3,i) = x(8,i);
dxdt(8,i) = (x(1,i)) - x(8,i) - x(3,i);
dxdt(4,i) = x(9,i);
dxdt(9,i) = (x(2,i)) - x(9,i) - x(4,i);
dxdt(5,i) = x(10,i);
if i == 1
j = 2;
elseif i == 2
j = 1 ;
end
dxdt(10,i) = (x(3,j)-x(4,j)+x(5,j)) - x(10,i) - x(5,i);
end
end
If my mistake is the use of a matrix initial conditions instead of a vector, using a 1 by 20 vector, and adjust the ode form accordingly would be not practical, I think
- What would be another more efficient way to address the initial conditions
-What is unnecessary from the inputs I have given and why?
-Is there any other computational way to represent the coupling?
EDIT: If I use the option: "function dxdt = ode(t,x)" the errors are the following:
Error in Test11>ode (line 33)
dxdt(10,i) = (x(3,j)-x(4,j)+x(5,j)) - x(10,i) - x(5,i);
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 Test11 (line 9)
[t,x] = ode45(#ode,time,initial);
If I change the way I call the function, so that:
"[t,x] = ode45(#(t,x)ode(x), time, initial);"
the results are the following:
Not enough input arguments.
Error in Test11>ode (line 19)
dxdt(1,i) = x(6,i);
Error in Test11>#(t,x)ode(x)
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 Test11 (line 9)
[t,x] = ode45(#(t,x)ode(x), time, initial);

The error 'Too many input arguments.' is caused by the fact that your ode function only accepts one variable, x, while ode45 is passing it two variables, time instance t and state x. Even if your ode equations are independent off the current time, you do need to handle this input argument.
Either let your ode function accept two input arguments:
function dxdt = ode(t,x)
% etc
or, change the way you call your ode function:
[t,x] = ode45(#(t,x)ode(x), time, initial);
Furthermore, I don't think ode45 can handle a 'state matrix', so I would indeed concatenate your two state vectors vertical to one large state vector. If your don't want to rewrite your code, add some reshapes before and after the loop:
function [dxdt] = ode(xv)
N = 2;
dxdt = NaN(10,2);
% reshape to two column vectors
x = reshape(xv,[],2); % xv is one large column vector
for ki = 1:N
dxdt(1,ki) = x(6,ki);
dxdt(6,ki) = (x(3,ki)-x(4,ki)+x(5,ki)) - x(6,ki) - x(1,ki);
dxdt(2,ki) = x(7,ki);
dxdt(7,ki) = (x(3,ki)-x(4,ki)+x(5,ki)) - x(7,ki) - x(2,ki);
dxdt(3,ki) = x(8,ki);
dxdt(8,ki) = (x(1,ki)) - x(8,ki) - x(3,ki);
dxdt(4,ki) = x(9,ki);
dxdt(9,ki) = (x(2,ki)) - x(9,ki) - x(4,ki);
dxdt(5,ki) = x(10,ki);
if ki == 1
kj = 2;
elseif ki == 2
kj = 1;
end
dxdt(10,ki) = (x(3,kj)-x(4,kj)+x(5,kj)) - x(10,ki) - x(5,ki);
end
% reshape dxdt to one column vector
dxdt = reshape(dxdt,[],1);
end

Related

fsolve issue with initial condition for ODE

I am trying to solve the following ODE:
function [eta, sol] = compressible_similarity_wo
global Gamm Ma Pr omega;
Gamm = 1.4;
Ma = 2;
Pr = 0.7;
omega=0.76;
global eta_max_ode;
eta_max_ode = 20;
opt = optimset('Display','off','TolFun',1E-20);
F = fsolve(#(F) eval_boundary(F),[0,0,0.4,1,0],opt);
[eta_ode, fg_ode] = solve_ode(F);
sol = [fg_ode];
eta = eta_ode;
end
function [eta_ode, fg_ode] = solve_ode(F)
global eta_max_ode
options = odeset('RelTol',1e-9,'AbsTol',1e-9);
[eta_ode, fg_ode] = ode45(#BLFunc,[0,eta_max_ode],F,options);
end
function [g] = eval_boundary(F)
% Get the solution to the ODE with inital condition F
[eta_ode, fg_ode] = solve_ode(F);
% Get the function values (for BCs) at the starting/end points
f_start = fg_ode(1,1); %f(0) = 0
df_start = fg_ode(1,2); %f'(0) = 0
df_end = fg_ode(end,2); %f'(inf) - 1 = 0
t_end = fg_ode(end,4); %T(inf) - 1 = 0
dt_start = fg_ode(1,5); %T'(0) = 0
% Evaluate the boundary function
g = [f_start
df_start
df_end - 1
t_end - 1
dt_start];
end
function [df] = BLFunc(f)
global Gamm Ma Pr omega;
df = zeros(5,1);
df(1) = f(2);
df(2) = f(3);
df(3) = -f(1)*f(3)/(f(4)^(omega-1))-(omega-1)*f(3)/f(4);
df(4) = f(5);
df(5) = -Pr*f(1)*f(5)/(f(4)^(omega-1)) - Pr*(Gamm - 1.0)*Ma*Ma*f(3)*f(3) - (omega-1)*f(5)/f(4);
end
but fsolve returns the following problem
Error using BLFunc
Too many input arguments.
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 solve_ode (line 5)
[eta_ode, fg_ode] = ode45(#BLFunc,[0,eta_max_ode],F,options);
Error in eval_boundary (line 3)
[eta_ode, fg_ode] = solve_ode(F);
Error in compressible_similarity_wo>#(F)eval_boundary(F) (line 15)
F = fsolve(#(F) eval_boundary(F),[0,0,0.4,1,0],opt);
Error in fsolve (line 230)
fuser = feval(funfcn{3},x,varargin{:});
Error in compressible_similarity_wo (line 15)
F = fsolve(#(F) eval_boundary(F),[0,0,0.4,1,0],opt);
Error in launch (line 3)
[eta, sol] = compressible_similarity_wo;
Caused by:
Failure in initial objective function evaluation. FSOLVE cannot continue.
Do you have an idea of what's going on?
I'll cite you the friendly manual page
The function dydt = odefun(t,y), for a scalar t and a column vector y, must return a column vector dydt of data type single or double that corresponds to f(t,y). odefun must accept both input arguments, t and y, even if one of the arguments is not used in the function.
That is, you simply need to change to
function [df] = BLFunc(t,f)
to get a result (no guarantee that it is THE result).
Try to replace BLFunc signature to
function [df] = BLFunc(t, f)
You need to provide odefun to ode45, which takes 2 arguments, as stated in documentation:
The function dydt = odefun(t,y), for a scalar t and a column vector y, must return a column vector dydt of data type single or double that corresponds to f(t,y). odefun must accept both input arguments, t and y, even if one of the arguments is not used in the function.

How to solve for x for a built-in function in MATLAB?

I'am traying to solve for p for a binomial distribution function where p is the probability of success.
I have tried many methods but none of them worked, shown bellow one of the methods that I have used:
syms p
y = 1 - binocdf(5,15,p) == 0.999;
X = vpasolve(y, p,[-1 1]);
This is the error that I got after running the code:
Error using symengine Unable to prove 'p < 0 | 1 < p' literally. Use
'isAlways' to test the statement mathematically. Error in
sym/subsindex (line 792)
X = find(mupadmex('symobj::logical',A.s,9)) - 1;
Error in sym/privsubsasgn (line 1067)
L_tilde2 = builtin('subsasgn',L_tilde,struct('type','()','subs',{varargin}),R_tilde);
Error in sym/subsasgn (line 904)
C = privsubsasgn(L,R,inds{:});
Error in binocdf (line 63) y(k1) = NaN;
Error in myfun (line 6) y=binocdf(5,15,p)==0.999;
Use function handle instead of syms function as binocdf() doesn't allow p to be syms variable
y = 1 - binocdf(5,15,p) == 0.999;
could be rewritten as
y = 1 - binocdf(5,15,p) - 0.999 == 0;
Using function handle, omitting the right hand side of
the equation
y = #(p)1 - binocdf(5,15,p) - 0.999
fzero() finds the root of a function, in another words solves the equation y == 0
Also the third parameter in binocdf(5,15,p), namely p is a probability ranging from 0 to 1
change the range from [-1, 1] to [0, 1]
fzero(y, [0 1])
The entire code is as follows
y = #(p)1 - binocdf(5,15,p) - 0.999;
X = fzero(y, [0 1])
Result
X = 0.7432

Calculate the derivative of the sum of a mathematical function-MATLAB

In Matlab I want to create the partial derivative of a cost function called J(theta_0, theta_1) (in order to do the calculations necessary to do gradient descent).
The function J(theta_0, theta_1) is defined as:
Lets say h_theta(x) = theta_1 + theta_2*x. Also: alpha is fixed, the starting values of theta_1 and theta_2 are given. Let's say in this example: alpha = 0.1 theta_1 = 0, theta_2 = 1. Also I have all the values for x and y in two different vectors.
VectorOfX =
5
5
6
VectorOfX =
6
6
10
Steps I took to try to solve this in Matlab: I have no clue how to solve this problem in matlab. So I started off with trying to define a function in Matlab and tried this:
theta_1 = 0
theta_2 = 1
syms x;
h_theta(x) = theta_1 + t2*x;
This worked, but is not what I really wanted. I wanted to get x^(i), which is in a vector. The next thing I tried was:
theta_1 = 0
theta_2 = 1
syms x;
h_theta(x) = theta_1 + t2*vectorOfX(1);
This gives the following error:
Error using sym/subsindex (line 672)
Invalid indexing or function definition. When defining a
function, ensure that the body of the function is a SYM
object. When indexing, the input must be numeric, logical or
':'.
Error in prog1>gradientDescent (line 46)
h_theta(x) = theta_1 + theta_2*vectorOfX(x);
I looked up this error and don't know how to solve it for this particular example. I have the feeling that I make matlab work against me instead of using it in my favor.
When I have to perform symbolic computations I prefer to use Mathematica. In that environment this is the code to get the partial derivatives you are looking for.
J[th1_, th2_, m_] := Sum[(th1 + th2*Subscript[x, i] - Subscript[y, i])^2, {i, 1, m}]/(2*m)
D[J[th1, th2, m], th1]
D[J[th1, th2, m], th2]
and gives
Coming back to MATLAB we can solve this problem with the following code
%// Constants.
alpha = 0.1;
theta_1 = 0;
theta_2 = 1;
X = [5 ; 5 ; 6];
Y = [6 ; 6 ; 10];
%// Number of points.
m = length(X);
%// Partial derivatives.
Dtheta1 = #(theta_1, theta_2) sum(2*(theta_1+theta_2*X-Y))/2/m;
Dtheta2 = #(theta_1, theta_2) sum(2*X.*(theta_1+theta_2*X-Y))/2/m;
%// Loop initialization.
toll = 1e-5;
maxIter = 100;
it = 0;
err = 1;
theta_1_Last = theta_1;
theta_2_Last = theta_2;
%// Iterations.
while err>toll && it<maxIter
theta_1 = theta_1 - alpha*Dtheta1(theta_1, theta_2);
theta_2 = theta_2 - alpha*Dtheta2(theta_1, theta_2);
it = it + 1;
err = norm([theta_1-theta_1_Last ; theta_2-theta_2_Last]);
theta_1_Last = theta_1;
theta_2_Last = theta_2;
end
Unfortunately for this case the iterations does not converge.
MATLAB is not very flexible for symbolic computations, however a way to get those partial derivatives is the following
m = 10;
syms th1 th2
x = sym('x', [m 1]);
y = sym('y', [m 1]);
J = #(th1, th2) sum((th1+th2.*x-y).^2)/2/m;
diff(J, th1)
diff(J, th2)

Create flexible function handle

I am using numerical integration in MATLAB, with one varibale to integrate over but the function also contains a variable number of terms depending on the dimension of my data. Right now this looks like the following for the 2-dimensional case:
for t = 1:T
fxt = #(u) exp(-0.5*(x(t,1)-theta*norminv(u,0,1)).^2) .* ...
exp(-0.5*(x(t,2) -theta*norminv(u,0,1)).^2);
f(t) = integral(fxt,1e-4,1-1e-4,'AbsTol',1e-3);
end
I would like to have this function flexible in the sense that there could be any number of data points in, each in the following term:
exp(-0.5*(x(t,i) -theta*norminv(u,0,1)).^2);
I hope this is understandable.
If x and u have a valid dimension match (vector-vector or array-scalar) for the subtraction, you can put the whole matrix x into the handle and pass it to the integral function using the name-parameter pair ('ArrayValued',true):
fxt = #(u) exp(-0.5*(x - theta*norminv(u,0,1)).^2) .* ...
exp(-0.5*(x - theta*norminv(u,0,1)).^2);
f = integral(fxt,1e-4,1-1e-4,'AbsTol',1e-3,'ArrayValued',true);
[Documentation]
You may need a loop if integral ever passes a vector u into the handle.
But in looking at how the integral function is written, the integration nodes are entered as scalars for array-valued functions, so the loop shouldn't be necessary unless some weird dimension-mismatch error is thrown.
Array-Valued Output
In response to the comments below, you could try this function handle:
fx = #(u,t,k) prod(exp(-0.5*(x(t,1:k)-theta*norminv(u,0,1)).^2),2);
Then your current loop would look like
fx = #(u,t,k) prod(exp(-0.5*(x(t,1:k)-theta*norminv(u,0,1)).^2),2);
k = 2;
for t = 1:T
f(t) = integral(#(u)fx(u,t,k),1e-4,1-1e-4,'AbsTol',1e-3,'ArrayValued',true);
end
The ArrayValued flag is needed since x and u will have a dimension mismatch.
In this form, another loop would be needed to sweep through the k indexes.
However, we can improve this function by skipping the loop altogether since each iterate of the loop is independent by using the ArrayValued mode:
fx = #(u,k) prod(exp(-0.5*(x(:,1:k)-theta*norminv(u,0,1)).^2),2);
k = 2;
f = integral(#(u)fx(u,k),1e-4,1-1e-4,'AbsTol',1e-3,'ArrayValued',true);
Vector-Valued Output
If ArrayValued is not desired, which may be the case if the integration requires a lot of subdivisions and a vector-valued u is preferable, you can also try a recursive version of the handle using cell arrays:
% x has size [T,K]
fx = cell(K,1);
fx{1} = #(u,t) exp(-0.5*(x(t,1) - theta*norminv(u,0,1)).^2);
for k = 2:K
fx{k} = #(u,t) fx{k-1}(u,t).*exp(-0.5*(x(t,k) - theta*norminv(u,0,1)).^2);
end
f(T) = 0;
k = 2;
for t = 1:T
f(t) = integral(#(u)fx{k}(u,t),1e-4,1-1e-4,'AbsTol',1e-3);
end
ThanksTroy but now I run into the follwing:
x = [0.3,0.8;1.5,-0.7];
T = size(x,1);
k = size(x,2);
theta= 1;
fx = #(u,t,k) prod(exp(-0.5*(x(t,1:k) - theta*norminv(u,0,1))^2));
for t = 1,T
f(t) = integral(#(u)fx(u,t,k),1e-4,1-1e-4,'AbsTol',1e-3);
end
Error using -
Matrix dimensions must agree.
Error in #(u,t,k)prod(exp(-0.5*(x(t,1:k)-theta*norminv(u,0,1))^2))
Error in #(u)fx(u,t,k)
Error in integralCalc/iterateScalarValued (line 314)
fx = FUN(t);
Error in integralCalc/vadapt (line 133)
[q,errbnd] = iterateScalarValued(u,tinterval,pathlen);
Error in integralCalc (line 76)
[q,errbnd] = vadapt(#AtoBInvTransform,interval);
Error in integral (line 89)
Q = integralCalc(fun,a,b,opstruct);

Matlab ode45 basic setup

I'm trying to simulate the Morris-Lecar model for neurons with ode45.
I am having trouble initializing the ode45 call, and documentation hasn't been able to help me. I understand that I have to call the ode45 through a function, and call that function from my main script.
I have a limited grasp of ODEs in general, and seem to have trouble understanding the syntax required to initialize the ODE45-call.
Also, I am indicated to use a time range for a variable 'pulse', but there is no input for a time range (which seems to be a variable, not fixed) in the function that takes in input from the main script and sends that with the other function to the ode45 function. The function that feeds into the ode45 has a time input as well, but again I cannot figure out how I can input a time range. The instructions are very clear that the function used in the main script does not take in any time variables.
It would be very appreciated if you could point out any glaring errors I have made in the initialization.
the current (below) version's error code is as following:
Error using ODEequation (line 89)
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 ODEquestion (line 32)
[t Vm]=ode45(#ODEequation,[-20 20],[-30, 0.1]',[],constants, stim_on, stim_off, amp);
Error in YoonS_Lab3_EBME308_Fall2012 (line 355)
[t Vm] = ODEquestion(20,100,30)
I think this goes back to my non-existing and yet needed time input.
The problem involves
Cm * dVm / dt = -Gm(Vm-Vrest) - Gca Minf (Vm - Eca) - Gk w(Vm - Ek) + pulse(t)
dw/dt = (wInf - w) / Tau-w;
wInf = (1+tanh(Vm/30)) / 2;
mInf = (1+tanh(Vm+1)) / 2;
Tau-w = 5/ (cosh(Vm/60));
Cm = membrane leakage capacticance;
Gm = membrane leakage conductance;
Vm = membrane voltage;
Vrest = membrane voltage # neuron resting
Gca = max Ca conductance through membrane
Gk = max K conductance through membrane;
mInf refers = P ( Ca ion channel open )
wInf refers = P ( K ion channel open )
Tau-w = rate which K channels respond to change in membrane voltage
Eca = reversal potential of Ca
Ek = reversal potential of K
pulse(t) = stimulus applied to neuron
pulse(t) = A (stim-on <= t <= stim-off) or 0 (else);
as the variables.
I have created a function that gets sent to the ode45, as below.
function dy = ODEequation(t, Vm, w, constants, stim_on, stim_off, amp)
wInf = (1 + tan(Vm / 30)) / 2
mInf = (1 + tan((Vm + 1)/ 15)) / 2
tauW = 5/ (cosh(Vm/60))
pulse = amp * ((stim_on < t ) - ( t >= stim_off));
dy(1) = y(1) * ((-constants(2) - constants(4) * constants(9) - constants(5) * y(2)) + (constants(2) * constants(3) + constants(6) * constants(4) * constants(9) + constants(5) * y(2) * constants(7) + constants(11))) / constants(1) ;
dy(2) = = ( constants(8) - y(2) )/constants(10)
dy = dy'
and the function that passes that is as below
function [t Vm] = ODEquestion(stim_on, stim_off, amp)
%i)
Cm = 1;
Gm = 0.5;
Vrest = -50;
Gca = 1.1;
Gk = 2;
Eca = 100;
Ek = -70;
%ii)
Vm(1) = -30;
w(1) = 0.1;
%iii)
wInf = (1 + tan(Vm / 30)) / 2
mInf = (1 + tan((Vm + 1)/ 15)) / 2
tauW = 5/ (cosh(Vm/60))
IC1 = Vm(1) % = -30
IC2 = w(1) % = 0.1
pulse = amp %* ((stim_on < t ) - ( t >= stim_off));
constants = [Cm , Gm, Vrest, Gca, Gk, Eca, Ek, wInf, mInf, tauW, pulse];
[t Vm]=ode45(#ODEequation,[-20 20],[-30, 0.1]',[],constants, stim_on, stim_off, amp);
From help ode45:
ODE45 Solve non-stiff differential equations, medium order method.
[TOUT,YOUT] = ODE45(ODEFUN,TSPAN,Y0) with TSPAN = [T0 TFINAL] integrates
the system of differential equations y' = f(t,y) from time T0 to TFINAL
with initial conditions Y0. ODEFUN is a function handle. For a scalar T
and a vector Y, ODEFUN(T,Y) must return a column vector corresponding
to f(t,y).
So the function ODEFUN expects only two inputs (t and y), whereas your function expects 7 inputs.
You can solve this by following instructions found on this site, or this question:
wrapper = #(t,Vm) ODEequation(t, Vm, w, constants, stim_on, stim_off, amp);
[t Vm]=ode45(wrapper, [-20 20],[-30, 0.1]',[],constants, stim_on, stim_off, amp);
e.g., by creating a small wrapper function that passes all the constants while forwarding the variables inserted by ode45.