Solving a system of ODEs in MATLAB? - matlab

this is my first time posting, so if you need anymore info or I havn't done something correct please let me know!
I want to plot a system of ODES, which would be no problem as I would do the following;
F=#(t,x) [
.the RHS of my first order ODES.
];
[t x]=ode45(F,[Range], [Initial conditions]);
Where a vector would be created containing x'(1), x'(2),... where x(1), x(2) would be the time dependant variable.
However my system is a little more complicated. I have 6 differential equations which are made up of equations that include differential equations and the time dependant variables. For example, the RHS of my ODES are something like
2*x(2)*x'(1)*f(a)
Where f(a) could be another function based on constants, a.
I have set up my code in the following order;
Constants, then equations of the form f(a), then my differential equations followed by the ode45 solver and the plot commands. However I am getting several errors "Undefined function or variable" as early equations depend on variables/equations that are not defined until later.
Thank you ever so much for you help :)
As suggested, here an example of the type of my code;
`%Constants
a=34
b=31
c=20
%Equations
A=b*cos(2*pi)
B=a*EQ1
C=c*x(2)
%DifferentialEquations
EQ1=x(1)*A
EQ2=(EQ3-EQ1)*(B-C)
EQ3=x(2)*x(3)
F=#(t,x) [EQ1;EQ2;EQ3;];[t x]=ode45(F,[0 10], [0 0 0 ]);
Provides the error.
Produces the undefined function or variable 'DEQ1A'.

Based on the comment you are trying to use a variable before it is defined. In MATLAB you need to define your variables and functions before you use them. Because the equations are functions of each other you can use anonymous functions to define F.
Example:
a=34;
b=31;
c=20;
A = b*cos(2*pi);
EQ1 = #(x) x(1)*A;
B = #(x) a*EQ1(x);
C = #(x) c*x(2);
EQ3 = #(x) x(2)*x(3);
EQ2 = #(x) (EQ3(x) - EQ1(x))*(B(x)-C(x));
F = #(t,x) [EQ1(x);EQ2(x);EQ3(x)];
[t,x] = ode45(F,[0 10], [0 0 0]);

Related

Time varying input ODE solving

I'm trying to solve a set of ODE equations using ode45. A number of my parameters are already a function of time but I keep getting errors.
function odo
dx(1,1) = (vl+vr)/2*cos(x(3));
dx(2,1) = (vl+vr)/2*sin(x(3));
dx(3,1) = obz
where obz, vr and vl are each vectors e.g:
obz = sin(t), t = 0:dt:tf;
I use the following syntax:
[t, x1] = ode45(#(t,x) odo(t,x,b,obz,vr,vl), 0:dt:tf, [0;0;0]);
with R15 but keep getting the error:
Assignment has more non-singleton rhs dimensions than non-singleton subscripts
How to solve this issue?
You have some syntax errors here. First You can't just type function odo and let the MATLAB guess what it should do here. The second, you call t and x twice in your solver expressions. Be consistent, call function in ode solver this way:
t_span=1:1:12;
b=0.2;
[t, x] = ode45(#odo, t_span, [0;0;0], b);
You don't need to pass t and x manually, solver do it itself. Only the additional parameter b (however it is not in use, in your example). Also in declaration of function do as follow:
function dx = odo(t,x,b)
vr=sin(t); %Non-OD equations here
vl=cos(t);
obz=0.05*sin(t);
n=numel(x); %this generate a holder for results
dx=zeros(n,1);
dx(1) = (vl+vr)/2*cos(x(3)); %All ODEs formatted like this
dx(2) = (vl+vr)/2*sin(x(3));
dx(3) = obz;
As you can see, vr, vl, and obz are time-depended values, so need to be re-calculated in every step of solver. You have to place it in your solver function.

Numeric solution to ODE with square-rooted coefficient

I'm trying to use MATLAB's ODE23 to solve the following equation:
u"(t) = -u'(t) - u(t)^0.5
I've created an auxiliary file for a function I simply called myfun2 as such:
function F2 = myfun2(t,x)
F2 = [-x(1) - power(x(2),0.5); x(1)];
Then I am calling ODE23 as:
[t,x] = ode23(#myfun2, [0:0.1:(7*pi())], [0, 1/0.6671])
The problem is that the solver is outputting a bunch of imaginary values for both t and u which doesn't make sense for u and absolutely none for t since t is supposed to be defined in a 0 to 7PI range at steps of 0.1, as far as I understand...

Solving a system with two equations and two variables in a for loop

I would like to solve a system with two equations and two variables.
Tau(i)and Roh(i) are input arrays.
Tau=[0.91411 0.91433 0.91389 0.91399 0.91511 0.915]
Roh=[0.07941 0.07942 0.07952 0.07946 0.07951 0.07947]
I would like to calculate R(i)and t(i)for each istep (for loop).
I will be glad to have help to solve the equations.
Tau(i)-((1-R(i))^2*t(i))/(1-R(i)^2*t(i)^2)==0
Roh(i)-R(i)-((1-R(i))^2*R(i)*t(i)^2)/(1-R(i)^2*t(i)^2)==0
I have tried the following script but I have difficulty to write the proper code to export the data. I get only "sym" which is not a value.
function [R,t] = glassair(Tau, Roh)
for i=1:6
syms R(i) t(i)
eq1(i)=sym('Tau(i)-((1-R(i))^2*t(i))/(1-R(i)^2*t(i)^2)');
eq2(i)=sym('Roh(i)-R(i)-((1-R(i))^2*R(i)*t(i)^2)/(1-R(i)^2*t(i)^2)');
sol(i)=solve(eq1(i),R(i), eq2(i),t(i));
end
end
There where multiple issues with your code.
Using the R(i) syntax with variables, you mixed in symbolic functions. I think here you only have variables. Same with eq(i), this created a symbolic function, not a list of your equations (as you probably intended)
You called solve with the wrong order of arguments
You called solve with the wrong order of arguments
Passing a string to sym your known constants Tau and Roh where not substituted, you ended up with 4 unknowns in your equations
.
Tau=[0.91411 0.91433 0.91389 0.91399 0.91511 0.915]
Roh=[0.07941 0.07942 0.07952 0.07946 0.07951 0.07947]
syms R t
for i=1:6
eq1=Tau(i)-((1-R)^2*t)/(1-R^2*t^2);
eq2=Roh(i)-R-((1-R)^2*R*t^2)/(1-R^2*t^2);
sol=solve([eq1,eq2]);
allsol(i).R=double(sol.R);
allsol(i).t=double(sol.t);
end
You just need to define the functions once, then use a for loop to get the values.
function [R_out,t_out] = glassair(Tau_in, Roh_in)
syms R t Tau Roh
eq1 = Tau-((1-R)^2*t)/(1-R^2*t^2);
eq2 = Roh-R-((1-R)^2*R*t^2)/(1-R^2*t^2);
R_out = zeros(1,6); % Given it will be always 6
t_out = zeros(1,6);
for i=1:6
Tau = Tau_in(i);
Roh = Roh_in(i);
sol = solve( subs( [eq1;eq2] ) );
R_out(i) = double(sol.R);
t_out(i) = double(sol.t);
end
end
Matlab is very smart in that defines the types for you. When you solve the equations it detects which variables are needed. The zero allocation is for speed up.

Solving an ODE when the function is given as discrete values -matlab-

I have the following ODE:
x_dot = 3*x.^0.5-2*x.^1.5 % (Equation 1)
I am using ode45 to solve it. My solution is given as a vector of dim(k x 1) (usually k = 41, which is given by the tspan).
On the other hand, I have made a model that approximates the model from (1), but in order to compare how accurate this second model is, I want to solve it (solve the second ODE) by means of ode45. My problem is that this second ode is given discrete:
x_dot = f(x) % (Equation 2)
f is discrete and not a continuous function like in (1). The values I have for f are:
0.5644
0.6473
0.7258
0.7999
0.8697
0.9353
0.9967
1.0540
1.1072
1.1564
1.2016
1.2429
1.2803
1.3138
1.3435
1.3695
1.3917
1.4102
1.4250
1.4362
1.4438
1.4477
1.4482
1.4450
1.4384
1.4283
1.4147
1.3977
1.3773
1.3535
1.3263
1.2957
1.2618
1.2246
1.1841
1.1403
1.0932
1.0429
0.9893
0.9325
0.8725
What I want now is to solve this second ode using ode45. Hopefully I will get a solution very similar that the one from (1). How can I solve a discrete ode applying ode45? Is it possible to use ode45? Otherwise I can use Runge-Kutta but I want to be fair comparing the two methods, which means that I have to solve them by the same way.
You can use interp1 to create an interpolated lookup table function:
fx = [0.5644 0.6473 0.7258 0.7999 0.8697 0.9353 0.9967 1.0540 1.1072 1.1564 ...
1.2016 1.2429 1.2803 1.3138 1.3435 1.3695 1.3917 1.4102 1.4250 1.4362 ...
1.4438 1.4477 1.4482 1.4450 1.4384 1.4283 1.4147 1.3977 1.3773 1.3535 ...
1.3263 1.2957 1.2618 1.2246 1.1841 1.1403 1.0932 1.0429 0.9893 0.9325 0.8725];
x = 0:0.25:10
f = #(xq)interp1(x,fx,xq);
Then you should be able to use ode45 as normal:
tspan = [0 1];
x0 = 2;
xout = ode45(#(t,x)f(x),tspan,x0);
Note that you did not specify what values of of x your function (fx here) is evaluated over so I chose zero to ten. You'll also not want to use the copy-and-pasted values from the command window of course because they only have four decimal places of accuracy. Also, note that because ode45 required the inputs t and then x, I created a separate anonymous function using f, but f can created with an unused t input if desired.

Implementing iterative solution of integral equation in Matlab

We have an equation similar to the Fredholm integral equation of second kind.
To solve this equation we have been given an iterative solution that is guaranteed to converge for our specific equation. Now our only problem consists in implementing this iterative prodedure in MATLAB.
For now, the problematic part of our code looks like this:
function delta = delta(x,a,P,H,E,c,c0,w)
delt = #(x)delta_a(x,a,P,H,E,c0,w);
for i=1:500
delt = #(x)delt(x) - 1/E.*integral(#(xi)((c(1)-c(2)*delt(xi))*ms(xi,x,a,P,H,w)),0,a-0.001);
end
delta=delt;
end
delta_a is a function of x, and represent the initial value of the iteration. ms is a function of x and xi.
As you might see we want delt to depend on both x (before the integral) and xi (inside of the integral) in the iteration. Unfortunately this way of writing the code (with the function handle) does not give us a numerical value, as we wish. We can't either write delt as two different functions, one of x and one of xi, since xi is not defined (until integral defines it). So, how can we make sure that delt depends on xi inside of the integral, and still get a numerical value out of the iteration?
Do any of you have any suggestions to how we might solve this?
Using numerical integration
Explanation of the input parameters: x is a vector of numerical values, all the rest are constants. A problem with my code is that the input parameter x is not being used (I guess this means that x is being treated as a symbol).
It looks like you can do a nesting of anonymous functions in MATLAB:
f =
#(x)2*x
>> ff = #(x) f(f(x))
ff =
#(x)f(f(x))
>> ff(2)
ans =
8
>> f = ff;
>> f(2)
ans =
8
Also it is possible to rebind the pointers to the functions.
Thus, you can set up your iteration like
delta_old = #(x) delta_a(x)
for i=1:500
delta_new = #(x) delta_old(x) - integral(#(xi),delta_old(xi))
delta_old = delta_new
end
plus the inclusion of your parameters...
You may want to consider to solve a discretized version of your problem.
Let K be the matrix which discretizes your Fredholm kernel k(t,s), e.g.
K(i,j) = int_a^b K(x_i, s) l_j(s) ds
where l_j(s) is, for instance, the j-th lagrange interpolant associated to the interpolation nodes (x_i) = x_1,x_2,...,x_n.
Then, solving your Picard iterations is as simple as doing
phi_n+1 = f + K*phi_n
i.e.
for i = 1:N
phi = f + K*phi
end
where phi_n and f are the nodal values of phi and f on the (x_i).