Create function to use in ode45 - matlab

So this is part of a larger project but I am stuck on number two of this section. I rewrote the system to get it in the required form:
dx(1)/dt = x(2)
dx(2)/dt = (-(M+m)/mL))x(4) + 1/(mL)u
dx(3)/dt = x(4)
dx(4)/dt = -(mg/M)x(1) + (1/M)u
After substituting the variables given in the problem I wrote the funcion:
function dx = fun(t,x)
dx = zeros(4,1);
dx(1) = x(2);
dx(2) = -((2+.1)/(.1*.5)).*x(4);
dx(3) = x(4);
dx(4) = -((.1*9.81)/2).*x(1);
end
I am confused on how to implement u(t) = 0 and how to create the theta function.
Any help even if its just pointing me in the right direction would be amazing. Thank you in advance :)

It's easy. You implement theta as another state. This is possible since you know the derivative, which does not even depend on the other states. To be more precise, you should add two more states here. One for theta and one for theta_dot.
dx(5) = x(6) % Theta'
dx(6) = -0.1 % Theta''
And by the way, you can also pass additional variables to your differential equation. You just add more arguments to it
function dx = diffeq(t,x,parameters)
...
end
and create a new function handle where you execute the ODE solver
[T,X] = ode45(#(t,x)diffeq(t,x,parameters),t_span,X0, ode_options);
This is just a hint since you're using magic numbers in your differential equation function.

Related

Applying runge kutta for coupled equations

so I have 2 second order nonlinear ODE and after applying the state-space theorm I have 4 first order ODE.
I'm trying to apply RK4 but I think I'm doing it wrong because the graphs diverge.
I'm getting a hard time applying it because the equations are coupled.
Those are the main equations. L and Fa also have state-space variables in them but it doesn't make a diffrence for my qustion.
Equations image
After applying the state-space theorm, Those are my equations:
f1 = #(x2) x2; % = x1'
f2 = #(x1, x2, x3) K/m*(l_0/sqrt((X_d(t, t1, t2, a_x0, X_d0, X_d0_tag)-x1).^2+(Z_d(t, t0, a_z0, Z_d0, Z_d0_tag)-x3).^2)-1)*(x1-X_d(t, t1, t2, a_x0, X_d0, X_d0_tag)) ...
- 0.5*Rho*A*C_d*(x2-Interpolation(Z_d(t, t0, a_z0, Z_d0, Z_d0_tag), data)).^2*sgn(x2, Z_d(t, t0, a_z0, Z_d0, Z_d0_tag), data)/m;
% = x2'
f3 = #(x1) x1; % = x3'
f4 = #(x1, x3) K/m*(l_0/sqrt((X_d(t, t1, t2, a_x0, X_d0, X_d0_tag)-x1).^2+(Z_d(t, t0, a_z0, Z_d0, Z_d0_tag)-x3).^2)-1)*(x3-Z_d(t, t0, a_z0, Z_d0, Z_d0_tag))-g;
% x4'
Than I tried to apply RK4. Heads up, it might be a complete nonsense. I also applied initial conditions but I don't want to make it messy.
h=0.2; % step size
t_array = 0:h:10;
w = zeros(1,length(t_array));
x = zeros(1,length(t_array));
y = zeros(1,length(t_array));
z = zeros(1,length(t_array));
for i=1:(length(t_array)-1) % calculation loop
t = 0 +h*i; % A parameter needed for the interpolation in f2
k_1 = f1(x(i));
k_2 = f1(x(i)+0.5*h*k_1);
k_3 = f1(x(i)+0.5*h*k_2);
k_4 = f1(x(i)+k_3*h);
x(i+1) = x(i) + (1/6)*(k_1+2*k_2+2*k_3+k_4)*h;
disp(x(i+1));
m_1 = f3(z(i));
m_2 = f3(z(i)+0.5*h*k_1);
m_3 = f3(z(i)+0.5*h*k_2);
m_4 = f3(z(i)+k_3*h);
z(i+1) = z(i) + (1/6)*(m_1+2*m_2+2*m_3+m_4)*h;
n_1 = f2(x(i), z(i), w(i));
n_2 = f2(x(i), z(i) ,w(i)+0.5*h*k_1);
n_3 = f2(x(i), z(i) ,w(i)+0.5*h*k_2);
n_4 = f2(x(i), z(i) ,w(i)+k_3*h);
w(i+1) = w(i) + (1/6)*(k_1+2*k_2+2*k_3+k_4)*h;
l_1 = f4(x(i), z(i));
l_2 = f4(x(i), z(i));
l_3 = f4(x(i), z(i));
l_4 = f4(x(i), z(i));
y(i+1) = y(i) + (1/6)*(k_1+2*k_2+2*k_3+k_4)*h;
end
As I said my graphs are divering (they souldn't be) so I suspect my code is wrong.
Please help me fix the algorithm.
Thank you very much!
What are XD and ZD? Why don't they have differential equations associated with them? Can you give more details about this?
Also, it would help if you used vectors for the state variable, and had one single function handle that produced a vector output. That cuts down on the code you write, and allows you to compare your results with ode45( ) since it can take the same function handle as input.
It appears that the fundamental flaw in your code is that although you state the equations are coupled, you are attempting to integrate them piecemeal. E.g., you do the RK4 scheme for one variable using k_1, k_2, k_3, k_4 to propagate x(i) to x(i+1). But during this process all the other coupled variables z(i) and w(i) and y(i) remain static in your code. This is a flaw. All of the coupled variables need to propagate at the same time through those intermediate calculations. I.e., you need to generate all of the k_1, m_1, n_1, and l_1 first, then using those results calculate all of the k_2, m_2, n_2, and l_2. Then using those results calculate all of the k_3, m_3, n_3, and l_3. Then using all of those results calculate k_4, m_4, n_4, and l_4. And finally use all of this to propagate all your variables forward one step. This is where a vector function handle can greatly help you. By making one function handle that takes a vector input (each element of the vector representing one of your variables) and returns a vector output, you can boil your code down to writing only one set of RK4 equations that automatically propagates all the variables forward at the same time because they are all part of the same vector. This will also make your code easier to debug.
Finally, you are mixing variables and derivatives. x's should go with k's, z's should go with m's, w's should go with n's, and y's should go with l's. In particular, the l's don't even have RK4 scheme implemented.

How to solve a second order non linear ode system with bvp4c?

I'm trying to solve a system of two second order non linear Odes and since it is a boundary valued problem I suppose I need to use the bvp4c function.
The system I'm talking about is the following:
f''(x) = F(f,f',x);
s''(x) = G(f, f',s,s',x)
with the conditions f(0) = pi, f(inf = 35) = s(inf = 35) = 0. The F and G functions are known and I assumed that 35 would be a decent replacement for infinity.
It is separable and I have already solved for f but I don't know how to solve it for s either.
The code that allegedly solves for f is the following:
options = bvpset('RelTol', 1e-5);
Xstart = 0.01;
Xend = 35;
solinit = bvpinit(linspace(Xstart, Xend, 1000), [0, 1]);
sol = bvp4c(#twoode, #twobc, solinit, options);
x = linspace(Xstart,Xend);
y = deval(sol,x);
figure(1)
plot(x,y(1,:))
figure(2)
plot(x,y(2,:))
function dydx = twoode(x,y)
dydx = [y(2); ((-1/(x^2 + 2+sin(y(1))^2))*(2*x*y(2) + sin(2*y(1))*y(2)^2 -
2*sin(2*y(1)) - (sin(y(1)^2)*sin(2*y(1)))/x^2) )];
end
function res = twobc(ya,yb)
res = [ya(1) - pi
yb(2)];
end
So my question is how can I use the results I obtained for f in order to solve the equation for s? I have tried doing the same things I did for f but if I define a function for s that uses y(1,:) and y(2,:) it gives me an error message that says y is not defined.
Since I am quite new to solving dfferential equations with Matlab and to using Matlab in general I am probably making some trivial mistake but I have been looking for answers and couldn't find any. I hope someone with enough patience can help me.
Thanks in advance for any useful advice.

How to add a very simple controller to a set of differential equations

I have a very complicated set of differential equations with several time dependent variables. I have found a simplification of my code online, it's here;
It's in two sections. First
`t_values=linspace(0,10,101);
initial_cond=[1 ; 0 ; 0];
[tv,Yv]=ode45('simplemodel',t_values,initial_cond);
plot(tv,Yv(:,1),'+',tv,Yv(:,2),'x',tv,Yv(:,3),'o');
legend('y1','y2','y3');`
Then another
function Dy = simplemodel(t,y)
Dy=[ a(t)*y(1)+b(t)*y(2); ...
-a(t)*y(3)+b(t)*y(1); ...
a(t)*y(2)] ;
end
function fa=a(t);
fa=cos(t); % or place whatever you want to place for a(t)..
end
function fb=b(t);
fb=sin(t) % or place whatever you want to place for b(t)..
end
I have a problem however, that I want to try to add a PID controller to my a(t) term.. I have tried to do first add a "proportional term" by changing the fb=sin(t) line to fb=-K*y(2)+d+K*int(y(2))+K*diff(y(2)), where K and d are constants. When I substitute this fb line for the one in the code, I get errors. Any ideas guys? Thank you very much
You want to go from a system that is described by
function Dy = simplemodel(t,y)
a = cos(t)
b = sin(t)
Dy=[ a*y(1)+b*y(2); ...
-a*y(3)+b*y(1); ...
a*y(2)] ;
end
to something that has
b = -K*y(2)+d+K*Iy2+K*Dy2
where Dy2 is the derivative and Iy2 the anti-derivative of the second component. The first problem is that
Dy(2) = -a*y(3)+b*y(1)
depends itself on b, which depends on Dy(2) so that you get some feed-back resp. a dependency circle that you have to solve. This can be done by solving
Dy(2) = -a*y(3)+(b1+K*Dy(2))*y(1);
for Dy(2). b1 contains all the other parts of b, so that in total the circle is solved as
b1 = -K*y(2)+d+K*Iy2
Dy(2) = (-a*y(3) + b1*y(1))/(1-K*y(1))
b = b1+K*Dy(2);
This still contains the as-of-yet unaddressed anti-derivative value. In other words, we need a function whose derivative is y(2). As such a function is not present in the system, we have to add an extra component to it,
function Dy = simplemodel(t,y)
a = cos(t)
Dy(4) = y(2) % y(4) = integral(y(2))
b1 = -K*y(2)+d+K*y(4) % missing +K*Dy(2)
Dy(2) = (-a*y(3) + b1*y(1))/(1-K*y(1))
b2 = K*Dy(2);
b = b1+b2;
Dy(1) = a*y(1)+b*y(2)
Dy(3) = a*y(2)
end
You will still need some initial value for the anti-derivative, most likely it will be 0 if the system is thought of being switched on after a state of rest.

Trying to minimise a function wrt 2 variables for robust portfolio optimisation. How to do this with fmincon?

I am currently involved in a group project where we have to conduct portfolio selection and optimisation. The paper being referenced is given here: (specifically page 5 and 6, equations 7-10)
http://faculty.london.edu/avmiguel/DeMiguel-Nogales-OR.pdf
We are having trouble creating the optimisation problem using M-Portfolios, given below
min (wrt w,m) (1/T) * sum_(rho)*(w'*r_t - m) (Sorry I couldn't get the formatting to work)
s.t. w'e = 1 (just a condition saying that all weights add to 1)
So far, this is what we have attempted:
function optPortfolio = portfoliofminconM(returns,theta)
% Compute the inputs of the mean-variance model
mu = mean(returns)';
sigma = cov(returns);
% Inputs for the fmincon function
T = 120;
n = length(mu);
w = theta(1:n);
m = theta((n+1):(2*n));
c = 0.01*ones(1,n);
Aeq = ones(1,(2*n));
beq = 1;
lb = zeros(2,n);
ub = ones(2,n);
x0 = ones(n,2) / n; % Start with the equally-weighted portfolio
options = optimset('Algorithm', 'interior-point', ...
'MaxIter', 1E10, 'MaxFunEvals', 1E10);
% Nested function which is used as the objective function
function objValue = objfunction(w,m)
cRp = (w'*(returns - (ones(T,1)*m'))';
objValue = 0;
for i = 1:T
if abs(cRp(i)) <= c;
objValue = objValue + (((cRp(i))^2)/2);
else
objValue = objValue + (c*(abs(cRp(i))-(c/2)));
end
end
The problem starts at our definitions for theta being used as a vector of w and m. We don't know how to use fmincon with 2 variables in the objective function properly. In addition, the value of the objective function is conditional on another value (as shown in the paper) and this needs to be done over a rolling time window of 120 months for a total period of 264 months.(hence the for-loop and if-else)
If any more information is required, I will gladly provide it!
If you can additionally provide an example that deals with a similar problem, can you please link us to it.
Thank you in advance.
The way you minimize a function of two scalars with fmincon is to write your objective function as a function of a single, two-dimensional vector. For example, you would write f(x,y) = x.^2 + 2*x*y + y.^2 as f(x) = x(1)^2 + 2*x(1)*x(2) + x(2)^2.
More generally, you would write a function of two vectors as a function of a single, large vector. In your case, you could rewrite your objfunction or do a quick hack like:
objfunction_for_fmincon = #(x) objfunction(x(1:n), x(n+1:2*n));

Matlab - Unexpected Results from Differential Equation Solver Ode45

I am trying to solve a differential equation with the ode solver ode45 with MATLAB. I have tried using it with other simpler functions and let it plot the function. They all look correct, but when I plug in the function that I need to solve, it fails. The plot starts off at y(0) = 1 but starts decreasing at some point when it should have been an increasing function all the way up to its critical point.
function [xpts,soln] = diffsolver(p1x,p2x,p3x,p1rr,y0)
syms x y
yp = matlabFunction((p3x/p1x) - (p2x/p1x) * y);
[xpts,soln] = ode45(yp,[0 p1rr],y0);
p1x, p2x, and p3x are polynomials and they are passed into this diffsolver function as parameters.
p1rr here is the critical point. The function should diverge after the critical point, so i want to integrate it up to that point.
EDIT: Here is the code that I have before using diffsolver, the above function. I do pade approximation to find the polynomials p1, p2, and p3. Then i find the critical point, which is the root of p1 that is closest to the target (target is specified by user).
I check if the critical point is empty (sometimes there might not be a critical point in some functions). If its not empty, then it uses the above function to solve the differential equation. Then it plots the x- and y- points returned from the above function basically.
function error = padeapprox(m,n,j)
global f df p1 p2 p3 N target
error = 0;
size = m + n + j + 2;
A = zeros(size,size);
for i = 1:m
A((i + 1):size,i) = df(1:(size - i));
end
for i = (m + 1):(m + n + 1)
A((i - m):size,i) = f(1:(size + 1 - i + m));
end
for i = (m + n + 2):size
A(i - (m + n + 1),i) = -1;
end
if det(A) == 0
error = 1;
fprintf('Warning: Matrix is singular.\n');
end
V = -A\df(1:size);
p1 = [1];
for i = 1:m
p1 = [p1; V(i)];
end
p2 = [];
for i = (m + 1):(m + n + 1)
p2 = [p2; V(i)];
end
p3 = [];
for i = (m + n + 2):size
p3 = [p3; V(i)];
end
fx = poly2sym(f(end:-1:1));
dfx = poly2sym(df(end:-1:1));
p1x = poly2sym(p1(end:-1:1));
p2x = poly2sym(p2(end:-1:1));
p3x = poly2sym(p3(end:-1:1));
p3fullx = p1x * dfx + p2x * fx;
p3full = sym2poly(p3fullx); p3full = p3full(end:-1:1);
p1r = roots(p1(end:-1:1));
p1rr = findroots(p1r,target); % findroots eliminates unreal roots and chooses the one closest to the target
if ~isempty(p1rr)
[xpts,soln] = diffsolver(p1x,p2x,p3fullx,p1rr,f(1));
if rcond(A) >= 1e-10
plot(xpts,soln); axis([0 p1rr 0 5]); hold all
end
end
I saw some examples using another function to generate the differential equation but i've tried using the matlabFunction() method with other simpler functions and it seems like it works. Its just that when I try to solve this function, it fails. The solved values start becoming negative when they should all be positive.
I also tried using another solver, dsolve(). But it gives me an implicit solution all the time...
Does anyone have an idea why this is happening? Any advice is appreciated. Thank you!
Since your code seems to work for simpler functions, you could try to increase the accuracy options of the ode45 solver.
This can be achieved by using odeset:
options = odeset('RelTol',1e-10,'AbsTol',1e-10);
[T,Y] = ode45(#function,[tspan],[y0],options);