I'm trying to solve a system of ode's using Runge-kutta, i made a function for RK2(f,h,x0,y0,xfinal) and tried to solve the system shown below with specified IC's. Could someone help fix the code as I get errors and code doesn't work.
ode set
beta = 1/3;
gamma = 1/7;
syms R S I % Symbolic Math Toolbox
N = S+I+R;
ode1 = -(beta*I*S)/N;
ode2 = -(beta*I*S)/N-gamma*I;
ode3 = gamma*I;
odes = [ode1,ode2,ode3];
for j = odes
RK2(j,0.2,0,8e6,7);
end
function [xs,ys] = RK2(f,h,x0,y0,xfinal)
ffnc = matlabFunction(f);
fprintf('\n x y ');
o = 1;
while x0 <= xfinal
fprintf('\n%4.3f %4.3f ',x0,y0); %values of x and y
xs(o) = x0;
ys(o) = y0;
k1 = h*ffnc (x0,y0);
x1 = x0+h;
k2 = h*ffnc (x1,y0+k1);
y1 = y0+(k1+k2)/2;
x0 = x1;
y0 = y1;
o = o+1;
end
end
Related
I would like some help with my program. I still don’t understand where my problem is, since it’s kind of a big mess. So it consists of the main program:
function x = NewtonM(funcF,JacF)
x= zeros(2,1);
x(1) = 1
x(2) = 5
k = 1;
kmax = 100;
TOL = 10^(-7);
while k < kmax
s = J(x)\(-F(x));
x= x + s
if (norm(s,2)< TOL)
break;
endif
end
and these are the fellow functions:
function y = F(x)
x1 = x(1);
x2 = x(2);
y = zeros(2,1);
y(1) = x1+x2-3;
y(2) = x1^2 + x2^2 -9;
end
function z = Z(x)
x1 = x(1);
x2 = x(2);
z = zeros(3,1);
z(1) = x1+x2-3+10^(-7);
z(2) = (x1+10^(-7))^2 + x2^2 -9;
z(3) = x1^2 + (x2+10^(-7))^2 -9;
end
function J = J(x)
x1 = x(1);
x2 = x(2);
J = zeros(2,2);
J(1,1) = (Z(1)-F(1))/(10^(-7))
J(1,2) = (Z(1)-F(1))/(10^(-7))
J(2,1) = (Z(2)-F(2))/(10^(-7))
J(2,2) = (Z(3)-F(2))/(10^(-7))
end
These are the error messages:
The problem is that you are calling both Z and F with only one input, in the function J.
Then, the first thing you do is try to interpret the input as a 2 valued array (x1,x2) but they don't exist, as you defined x as e.g. 1, by doing Z(1).
I wonder if instead of using Z(1) etc, you meant to do z=Z(x) and then use z(1), inside J.
Consider the following problem:
I am now in the third part of this question. I wrote the vectorial loop equations (q=teta2, x=teta3 and y=teta4):
fval(1,1) = r2*cos(q)+r3*cos(x)-r4*cos(y)-r1;
fval(2,1) = r2*sin(q)+r3*sin(x)-r4*sin(y);
I have these 2 functions, and all variables except x and y are given. I found the roots with help of this video.
Now I need to plot graphs of q versus x and q versus y when q is at [0,2pi] with delta q of 2.5 degree. What should I do to plot the graphs?
Below is my attempt so far:
function [fval,jac] = lorenzSystem(X)
%Define variables
x = X(1);
y = X(2);
q = pi/2;
r2 = 15
r3 = 50
r4 = 45
r1 = 40
%Define f(x)
fval(1,1)=r2*cos(q)+r3*cos(x)-r4*cos(y)-r1;
fval(2,1)=r2*sin(q)+r3*sin(x)-r4*sin(y);
%Define Jacobian
jac = [-r3*sin(X(1)), r4*sin(X(2));
r3*cos(X(1)), -r4*cos(X(2))];
%% Multivariate NR
%Initial conditions:
X0 = [0.5;1];
maxIter = 50;
tolX = 1e-6;
X = X0;
Xold = X0;
for i = 1:maxIter
[f,j] = lorenzSystem(X);
X = X - inv(j)*f;
err(:,i) = abs(X-Xold);
Xold = X;
if (err(:,i)<tolX)
break;
end
end
Please take a look at my solution below, and study how it differs from your own.
function [th2,th3,th4] = q65270276()
[th2,th3,th4] = lorenzSystem();
hF = figure(); hAx = axes(hF);
plot(hAx, deg2rad(th2), deg2rad(th3), deg2rad(th2), deg2rad(th4));
xlabel(hAx, '\theta_2')
xticks(hAx, 0:pi/3:2*pi);
xticklabels(hAx, {'$0$','$\frac{\pi}{3}$','$\frac{2\pi}{3}$','$\pi$','$\frac{4\pi}{3}$','$\frac{5\pi}{3}$','$2\pi$'});
hAx.TickLabelInterpreter = 'latex';
yticks(hAx, 0:pi/6:pi);
yticklabels(hAx, {'$0$','$\frac{\pi}{6}$','$\frac{\pi}{3}$','$\frac{\pi}{2}$','$\frac{2\pi}{3}$','$\frac{5\pi}{6}$','$\pi$'});
set(hAx, 'XLim', [0 2*pi], 'YLim', [0 pi], 'FontSize', 16);
grid(hAx, 'on');
legend(hAx, '\theta_3', '\theta_4')
end
function [th2,th3,th4] = lorenzSystem()
th2 = (0:2.5:360).';
[th3,th4] = deal(zeros(size(th2)));
% Define geometry:
r1 = 40;
r2 = 15;
r3 = 50;
r4 = 45;
% Define the residual:
res = #(q,X)[r2*cosd(q)+r3*cosd(X(1))-r4*cosd(X(2))-r1; ... Δx=0
r2*sind(q)+r3*sind(X(1))-r4*sind(X(2))]; % Δy=0
% Define the Jacobian:
J = #(X)[-r3*sind(X(1)), r4*sind(X(2));
r3*cosd(X(1)), -r4*cosd(X(2))];
X0 = [acosd((45^2-25^2-50^2)/(-2*25*50)); 180-acosd((50^2-25^2-45^2)/(-2*25*45))]; % Accurate guess
maxIter = 500;
tolX = 1e-6;
for idx = 1:numel(th2)
X = X0;
Xold = X0;
err = zeros(maxIter, 1); % Preallocation
for it = 1:maxIter
% Update the guess
f = res( th2(idx), Xold );
X = Xold - J(Xold) \ f;
% X = X - pinv(J(X)) * res( q(idx), X ); % May help when J(X) is close to singular
% Determine convergence
err(it) = (X-Xold).' * (X-Xold);
if err(it) < tolX
break
end
% Update history
Xold = X;
end
% Unpack and store θ₃, θ₄
th3(idx) = X(1);
th4(idx) = X(2);
% Update X0 for faster convergence of the next case:
X0 = X;
end
end
Several notes:
All computations are performed in degrees.
The specific plotting code I used is less interesting, what matters is that I defined all θ₂ in advance, then looped over them to find θ₃ and θ₄ (without recursion, as was done in your own implementation).
The initial guess (actually, analytical solution) for the very first case (θ₂=0) can be found by solving the problem manually (i.e. "on paper") using the law of cosines. The solver also works for other guesses, but you might need to increase maxIter. Also, for certain guesses (e.g. X(1)==X(2)), the Jacobian is ill-conditioned, in which case you can use pinv.
If my computation is correct, this is the result:
I'm currently learning Matlab's ODE-functions to solve simple vibration-problems.
For instance mx''+cx'+kx=F*sin(wt) can be solved using
function dx = fun(t,x)
m=0.02; % Mass - kg
k=25.0; % Stiffness - N/m
c=0.0125; % System damping - Ns/m
f=10; % Frequency
F=5;
dx= [x(2); (F*sin(2*pi*f*t)-c*x(2)-k*x(1))/m]
And then calling the ode45 function to get displacement and velocity
[t,x]=ode45(#fun,[0 10],[0.0;0.0])
My question, which I have not fully understood searching the web, is if it is possible to use ODE-function for a multiple degree of freedom system? For instance, if we have two masses, springs and dampers, which we excite att mass 1, we get the following equations:
m1*x1''+c1*x1'-c2*x2'+(k1+k2)*x1-k2*x2 = f1(t)
m2*x2''-c2*x1'+(c1+c2)*x2'-k2*x1+k2*x2 = 0
Here, the displacements x1 & x2 depend on each other, my question is how one should go about to solve these ODE's in Matlab?
There is no restriction that the inputs to the function solved by ODE45 be scalar. Just pass in an input matrix and expect out an output matrix. For example here is a function that solves the position of a 6 bar mechanism.
function zdot = cp_solve(t,z)
%% Constants
g = -9.81;
L1 = .2;
m0 = 0;
I0 = 0;
m1 = 1;
I1 = (1/3) * m1 * L1^2;
%% Inputs
q = z(1:6);
qdot = z(7:12);
%% Mass Matrix
M = zeros(6,6);
M(1,1) = m0;
M(2,2) = m0;
M(3,3) = I0;
M(4,4) = m1;
M(5,5) = m1;
M(6,6) = I1;
%% Constraint Matrix
Phiq = zeros(5,6);
Phiq(1,1) = 1;
Phiq(2,2) = 1;
Phiq(3,3) = 1;
Phiq(4,1) = 1;
Phiq(4,4) = -1;
Phiq(4,6) = (-L1/2)*sin(q(6));
Phiq(5,2) = 1;
Phiq(5,5) = -1;
Phiq(5,6) = (L1/2)*cos(q(6));
%% Generalized Forces
Q = zeros(6,1);
Q(5) = m1 * g;
%% Right Side Vector
rs = zeros(5,1);
rs(4) = (L1/2) * cos(q(6)) * qdot(6)^2;
rs(5) = (L1/2) * sin(q(6)) * qdot(6)^2;
%% Coefficient Matrix
C = [M Phiq'; Phiq zeros(5,5)];
R = [Q; rs];
%% Solution
Sol = C \ R;
zdot = [qdot; Sol(1:6)];
end
The inputs are the positions and velocities of the members. The outputs are the new positions and velocities.
You use it the same way you would any ODE45 problem. Setup the initial conditions, define a time and solve the problem.
%% Constants
L1 = .2;
C1 = L1/2;
theta1 = 30*pi/180;
theta_dot1 = 0;
tspan = 0:.001:2;
%% Initial Conditions
q = zeros(6,1);
q(6) = theta1;
q(4) = C1 * cos(q(6));
q(5) = C1 * sin(q(6));
qdot = zeros(6,1);
qdot(6) = theta_dot1;
z0 = [q; qdot];
%% Solve the problem
options = odeset('RelTol', 1.0e-9, 'AbsTol', 1.0e-6);
[Tout, Zout] = ode45(#cp_solve, tspan, z0, options);
In your case you have 2 equations and 2 unknowns. Set the problem up as a matrix problem and solve it simultaneously in your function. I would recommend the modal approach for your case.
Introduction
I am using Matlab to simulate some dynamic systems through numerically solving systems of Second Order Ordinary Differential Equations using ODE45. I found a great tutorial from Mathworks (link for tutorial at end) on how to do this.
In the tutorial the system of equations is explicit in x and y as shown below:
x''=-D(y) * x' * sqrt(x'^2 + y'^2)
y''=-D(y) * y' * sqrt(x'^2 + y'^2) + g(y)
Both equations above have form y'' = f(x, x', y, y')
Question
However, I am coming across systems of equations where the variables can not be solved for explicitly as shown in the example. For example one of the systems has the following set of 3 second order ordinary differential equations:
y double prime equation
y'' - .5*L*(x''*sin(x) + x'^2*cos(x) + (k/m)*y - g = 0
x double prime equation
.33*L^2*x'' - .5*L*y''sin(x) - .33*L^2*C*cos(x) + .5*g*L*sin(x) = 0
A single prime is first derivative
A double prime is second derivative
L, g, m, k, and C are given parameters.
How can Matlab be used to numerically solve a set of second order ordinary differential equations where second order can not be explicitly solved for?
Thanks!
Your second system has the form
a11*x'' + a12*y'' = f1(x,y,x',y')
a21*x'' + a22*y'' = f2(x,y,x',y')
which you can solve as a linear system
[x'', y''] = A\f
or in this case explicitly using Cramer's rule
x'' = ( a22*f1 - a12*f2 ) / (a11*a22 - a12*a21)
y'' accordingly.
I would strongly recommend leaving the intermediate variables in the code to reduce chances for typing errors and avoid multiple computation of the same expressions.
Code could look like this (untested)
function dz = odefunc(t,z)
x=z(1); dx=z(2); y=z(3); dy=z(4);
A = [ [-.5*L*sin(x), 1] ; [.33*L^2, -0.5*L*sin(x)] ]
b = [ [dx^2*cos(x) + (k/m)*y-g]; [-.33*L^2*C*cos(x) + .5*g*L*sin(x)] ]
d2 = A\b
dz = [ dx, d2(1), dy, d2(2) ]
end
Yes your method is correct!
I post the following code below:
%Rotating Pendulum Sym Main
clc
clear all;
%Define parameters
global M K L g C;
M = 1;
K = 25.6;
L = 1;
C = 1;
g = 9.8;
% define initial values for theta, thetad, del, deld
e_0 = 1;
ed_0 = 0;
theta_0 = 0;
thetad_0 = .5;
initialValues = [e_0, ed_0, theta_0, thetad_0];
% Set a timespan
t_initial = 0;
t_final = 36;
dt = .01;
N = (t_final - t_initial)/dt;
timeSpan = linspace(t_final, t_initial, N);
% Run ode45 to get z (theta, thetad, del, deld)
[t, z] = ode45(#RotSpngHndl, timeSpan, initialValues);
%initialize variables
e = zeros(N,1);
ed = zeros(N,1);
theta = zeros(N,1);
thetad = zeros(N,1);
T = zeros(N,1);
V = zeros(N,1);
x = zeros(N,1);
y = zeros(N,1);
for i = 1:N
e(i) = z(i, 1);
ed(i) = z(i, 2);
theta(i) = z(i, 3);
thetad(i) = z(i, 4);
T(i) = .5*M*(ed(i)^2 + (1/3)*L^2*C*sin(theta(i)) + (1/3)*L^2*thetad(i)^2 - L*ed(i)*thetad(i)*sin(theta(i)));
V(i) = -M*g*(e(i) + .5*L*cos(theta(i)));
E(i) = T(i) + V(i);
end
figure(1)
plot(t, T,'r');
hold on;
plot(t, V,'b');
plot(t,E,'y');
title('Energy');
xlabel('time(sec)');
legend('Kinetic Energy', 'Potential Energy', 'Total Energy');
Here is function handle file for ode45:
function dz = RotSpngHndl(~, z)
% Define Global Parameters
global M K L g C
A = [1, -.5*L*sin(z(3));
-.5*L*sin(z(3)), (1/3)*L^2];
b = [.5*L*z(4)^2*cos(z(3)) - (K/M)*z(1) + g;
(1/3)*L^2*C*cos(z(3)) + .5*g*L*sin(z(3))];
X = A\b;
% return column vector [ed; edd; ed; edd]
dz = [z(2);
X(1);
z(4);
X(2)];
I have a linear system Ay = b, which is created by matrix looks like this:
Here attempt to find the curves based on the matrix in the image description:
n = 10;
x0 = 0;
xn = 1;
h = 1/n;
y0 = 0;
y1 = 0;
x = zeros(1:n-1);
for i = 1:n-1;
x(i) = i*h
end
A =zeros(n-1);
for j = 1:n-2;
A(j,j+1) = (1+h/2);
A(j,j) = (h*exp(x(j))-2);
A(j+1,j) = (1-h/2);
end
A(n-1,n-1) = (h*exp(x(n-1))-2);
b = zeros(1,n-1); %Right-hand side vector
for i = 1:n-1
b(i)=h^2*((exp(x(i))-pi^2)*sin(pi*x(i))+pi*cos(pi*x(i)));
end
b=b';
y = zeros(1,n-1);
y = inv(A)*b % Solving for y
figure
plot(x,y,x,sin(x))
This is code that I create but the curves disappear, anyone can help me to check my code?