Challenge

Week 3 - Solving second order ODEs

MAIN SCRIPT

% Program to solve the second order ODE using build in function ode45 and to create an animation using the solution of the equation

% 2nd-order equation: d^2(theta)/dt^2 + (b/m)*d(theta)/dt + (g/L)*sin(theta) = 0
% substituting    theta = theta1
% substituting    d(theta)/dt = d(theta1)/dt = theta2
% by making these substitutions we can rewrite the 2nd-order ODE as two first-order ODEs
% d(theta1)/dt = theta2 ------------ 1st eqn
% d(theta2)/dt = -(b/m)*(theta2)-(g/L)*sin(theta1) ---------- 2nd eqn

clear
close all
clc

% Initializing the variables for input values

L = 1;          % Length of pendulum (m)
m = 1;          % mass of the pendulum (kg)
b = 0.05;       % damping coefficient (dimensionless)
g = 9.81;       % acceleration due to gravity (m/s^2)

ct = 1;         % initializing the counter

% Specifying the time interval and initializing the variable t_span for it.

t_span = linspace(0,20,500);   % time interval - 0 to 20 sec, with 500 data points 

% Specifying the initial conditions at time  t = 0 sec.
% initial angular displacement = 0
% initial angular velocity = 3 rad/s

theta_0 = [0;3];                      % column vector representing initial conditions at t = 0.

% calling ode45 function to solve the ODE. Two outputs are returned by the function

[t,solutions] = ode45(@(t,theta) func_ode(t,theta,L,m,b,g),t_span,theta_0);

% 't' is the time column vector
% 'Solutions' is an array with two columns.
% The first column of array solutions represents angular displacement with respect to time
% The second column of array solutions represents angular velocity with respect to time


% plotting 

figure(1)                % 1st figure will have plots for time,angular displacement and angular velocity
plot(t,solutions(:,1))   % time and angular displacement plot.
hold on                  % command hold on holds the plot to the same figure
plot(t,solutions(:,2))   % time and angular velocity plot.
xlabel('Time')           % labelling horizontal axis as time
ylabel('Solutions')      % labelling vertical axis as Solutions
title('Solution of Simple Pendulum Equation with damper')  % giving title to the plot
legend('Angular Displacement (rad)','Angular Velocity (rad/s)')   % creating legend to show the lines used for displacement and velocity


% Creating the animation movie for pendulum

ang_disp = solutions(:,1);     % assigning values of angular dispacement from the array solution to a variable ang_disp. This will create a column vector ang_disp.

% using for loop to get the series of plots to create an animation

for i = 1:length(ang_disp)
    % Specifying the coordinates of the fixed end of the pendulum
    xf = 0;
    yf = 0;
    
    % calculating the coordinates of the end with bob.
    xb = L*sin(ang_disp(i));
    yb = -L*cos(ang_disp(i));
    
    
    figure(2)    % new figure for the animation plot
    
    plot([-1 1],[0 0],'color','k','linewidth',6)   % plotting the line representing fixed surface
    hold on
    plot([0 0],[-1.5 1.5],'-.','color','k','linewidth',1)  % plotting the line representing mean position
    hold on
    plot([xf xb],[yf yb],'color','k','linewidth',4)   % plotting the line representing pendulum rod
    hold on
    plot(xf,yf,'o','markersize',5,'markerfacecolor','w')  % plotting the cirle marker representing the fixed end joint between pendulum and fixed surface
    hold on
    plot(xb,yb,'o','markersize',20,'markerfacecolor','c','markeredgecolor','k')   % plotting the circle marker representing the bob
    hold off                                            % hold off so that the next frame does not carry this plot.
    axis([-1.5 1.5 -2 0.5])   % scaling the x and y axes
    xlabel('X-axis')          % labelling x axis
    ylabel('Y-axis')          % labelling y axis

    M(ct) = getframe(gcf);    % funciton getframe returns a movie frame. It takes snapshots and store them in the variable M 
    ct = ct+1;                % counter variable ct will help changing the indices of the M array with each loop
    
end
movie(M)    % Playing the movie

% creating and saving the video file

videofile = VideoWriter('Challenge_Simple_Pendulum.avi','Uncompressed AVI');  % creating a file in which the movie can be written.
open(videofile)    % openning the file
writeVideo(videofile,M)   % writing data to the file
close(videofile)   % closing the file

   

User-defined function - func_ode

function [dtheta_dt] = func_ode(t,theta,L,m,b,g)
% this function defines the system of equations which is created after rewriting the second-order ODE as a first-order equation system

% d(theta1)/dt = theta2 ------------ 1st eqn
% d(theta2)/dt = -(b/m)*(theta2) - (g/L)*sin(theta1) ---------- 2nd eqn

% initializing variables to assign initial condition values

theta1 = theta(1);     % angular displacement at (t = 0) = 0
theta2 = theta(2);     % angular velocity at (t = 0) = 3 rad/s

% initializing the variables and assign  the first order equations to them

dtheta1_dt = theta(2);                                 % 1st eqn
dtheta2_dt = -(b/m)*theta2 - (g/L)*sin(theta1);        % 2nd eqn

% initializing the output array (dtheta_dt) and should return 2x1 column vector.

[dtheta_dt] = [dtheta1_dt; dtheta2_dt];     

end

The objective of this program is:

1) To solve the second order ODE using built in function ode45.

2) To create an animation using the solution of the equation.

This 2nd-order ODE represents the motion of a simple pendulum with damper:

d^2(theta)/dt^2 + (b/m)*d(theta)/dt + (g/L)*sin(theta) = 0

substituting theta = theta1
substituting d(theta)/dt = d(theta1)/dt = theta2

by making these substitutions we can rewrite the 2nd-order ODE as two first-order ODEs

d(theta1)/dt = theta2 ------------ 1st eqn
d(theta2)/dt = -(b/m)*(theta2)-(g/L)*sin(theta1) ---------- 2nd eqn

Explanation of the main script

First I've initialized the variable for input values.

L is the length of pendulum in meter, m is the mass in kg, b is the damping coefficient (dimensionless) and g is acceleration due to gravity (m/s^2)

L = 1;
m = 1;
b = 0.05;
g = 9.81;

Then I've initialized a counter variable which will be required later.

ct = 1;

Then I've used linspace command to specify the time interval from 0 to 20 seconds with 500 data points.

t_span = linspace(0,20,500);

The given initial conditions at time (t=0) are:

Initial angular displacement = 0

Initial angular velocity = 3 rad/s

For initial conditions I've used a column vector and assigned it to varable called theta_0.

theta_0 = [0;3];

Now to solve the equation I've used the build-in function (ode45)

To call the function I've used the syntax:

[t,solutions] = ode45(@(t,theta) func_ode(t,theta,L,m,b,g),t_span,theta_0);

Explaining the syntax

On the left side are the two output variables t and solutions. These variables will store the values returned by the ode45 function after solving the equation. On the right side the functions is called ode45 and inside the parenthesis @(t,theta) specifies the two main input variables. Then the user defined function that defines the given system of equation is specified and inside the parenthesis along with t and theta the rest of the input variables can be passed func_ode(t,theta,L,m,b,g). After this the time interval is specified t_span and lastly the initial conditions are specified theta_0

The function ode45 will solve the equations by integrating the system of equations for time interval t_span and initial conditions theta_0.

For each time value in vector 't' the function will return a corresponding value of angular displacement and angular velocity in the array 'solutions'

The output variable 't' is the time column vector

The output variable 'solutions' is an array with two columns. The first column represents angular displacement with respect to time and the second column represents angular velocity with respect to time.

After this I've plotted the time vs angular displacement and time vs angular velocity in figure 1. command hold on is used to plot both plots in same figure. I've labelled the x-axis as 'Time' and y-axis as volume. I've used title command to give the plot a title. To indicate the displacement and velocity plot I've used legend command.

figure(1)
plot(t,solutions(:,1))
hold on
plot(t,solutions(:,2))
xlabel('Time')
ylabel('Solutions')
title('Solution of Simple Pendulum Equation with damper')
legend('Angular Displacement (rad)','Angular Velocity (rad/s)')

To create the animation the coordinates of both the ends of pendulum are required. One end of the pendulum is fixed. The other end with the bob will move. The coordinates of the moving end with bob are calculated using the length of pendulum (L) and the values of angular displacements in the array solutions. I've assigned the values of angular displacement from the 'solutions' array to a variable called ang_disp.

ang_disp = solutions(:,1);

Now a for loop is used to calculate all the coordinates and plot them repeatedly to get frames for the animation. The loop variable i is initialized. It will go from 1 to the length of vector ang_disp which is 500 in this case. Meaning loop will run 500 times.

for i = 1:length(ang_disp)

Then I've specified the coordinates of the fixed end of the pendulum at (0,0) and assigned them to xf and yf

xf = 0;
yf = 0;

After this I've calculated the coordinates of the end with bob and assigned them to xb and yb. The x and y coordinated will be calculated for all the values of the angular displacements in the array ang_disp. The values of angular displacements will be provided by ang_disp(i) as the value of (i) changes from 1 to 500. Since the pendulum is fixed at 0,0 the moving end will lie on the -ve y-axis therefore the -ve sign is used for calculating yb.

xb = L*sin(ang_disp(i));
yb = -L*cos(ang_disp(i));

Now for the animation I've created a new figure

figure(2)

Now in this figure I've plotted all the plots required for the animation. The first plot will represent the fixed surface in black color and linewidth 6. The second plot represents the mean position shown by a dash dotted black line and linewidth 1. The third plot is the pendulum rod plotted in black and linewidth 4. The fourth plot is showing the joint between the fixed surface and the fixed end of the pendulum with a white circle marker having marker size 5. The fifth plot represents the bob in cyan color with a cyan circle marker having black markeredge and size of the marker is 20.

I've used hold on command for every plot so that all the plots are plotted in the same figure to shape a pendulum. After the fifth plot I've used hold off so that the coordinates do not over lap in the figure.

I've also specified the scales for x and y axes and also have labelled them

plot([-1 1],[0 0],'color','k','linewidth',6)
hold on
plot([0 0],[-1.5 1.5],'-.','color','k','linewidth',1)
hold on
plot([xf xb],[yf yb],'color','k','linewidth',4)
hold on
plot(xf,yf,'o','markersize',5,'markerfacecolor','w')
hold on
plot(xb,yb,'o','markersize',20,'markerfacecolor','c','markeredgecolor','k')
hold off
axis([-1.5 1.5 -2 0.5])
xlabel('X-axis')
ylabel('Y-axis')

The function getframe returns a movie frame and it is stored in the array M. The variable ct is used to specify the indices to store the frames. In this case there will be 500 frames stored inside the array M

M(ct) = getframe(gcf);

The counter ct is set inside the loop. Every time the loop runs the value of ct is incremented by 1.

ct = ct+1;

the for loop is closed here with an end command

end

Now to test I've played the movie using movie command

movie(M)

To save the movie I used the command VideoWriter and created an .avi file 'Challenge_Simple_Pendulum.avi', specified the format 'Uncompressed AVI' and assigned it to variable videofile. Then I opened the file using open command and wrote the data inside it using command writeVideo. Then I closed the file using close command

videofile = VideoWriter('Challenge_Simple_Pendulum.avi','Uncompressed AVI');
open(videofile)
writeVideo(videofile,M)
close(videofile).

Explanation of the user defined function - func_ode

The function func_ode defines the system of differential equations which is obtained by rewriting the 2nd-order ODE as 1st-order equation sytem.

d(theta1)/dt = theta2 ------------ 1st eqn
d(theta2)/dt = -(b/m)*(theta2)-(g/L)*sin(theta1) ---------- 2nd eqn

first I've initialized two variables theta1 and theta2 and assigned values of initial conditons to them.

theta1 = theta(1);

theta2 = theta(2);

Then I've initialized the variables for the equations

dtheta1_dt = theta(2);

dtheta2_dt = -(b/m)*theta2 - (g/L)*sin(theta1);

Then I've initialized the output array dtheta_dt. This array should be in the form of a 2x1 column vector.

[dtheta_dt] = [dtheta1_dt; dtheta2_dt];

Then I've closed the function

end.

This concludes the program.

There was one problem that I faced in the execution of the program. The use of hold on command was leading to the overlapping of plots with each iteration of loop and my animation was getting messed up. I fixed this by using hold off command. I've attached a screenshot of this problem. Apart from this I've attached the screenshot of workspace after execution of program to show all the variables created. Also, one screenshot of figure 1 and three screenshots of figure 2 are attached.

The animation video is uploaded to the youtube and here's the link:

https://youtu.be/hRLWMOwLjA0

Your portfolio, next

Ship work like this
in your own course.

Talk to a career counsellor

Free 20-minute call. We'll map the right course to where you want to work.

By submitting you agree to our Terms and Privacy Policy.

Talk to a career counsellor

Free 20-minute call. We'll map the right course to where you want to work.

By submitting you agree to our Terms and Privacy Policy.