in

Simulation 105: Double Pendulum Modeling with Numerical Integration | by Le Nguyen | Aug, 2023


Modeling a chaotic system

The pendulum is a classical physics system that we’re all conversant in. Be it a grandfather clock or a baby on a swing, now we have seen the common, periodic movement of the pendulum. A single pendulum is effectively outlined in classical physics, however the double pendulum (a pendulum hooked up to the top of one other pendulum) is literal chaos. On this article, we’re going to construct on our intuitive understanding of pendulums and mannequin the chaos of the double pendulum. The physics is fascinating and the numerical strategies wanted are an important software in anybody’s arsenal.

Determine 1: Example of a chaotic double pendulum

On this article we are going to:

  • Find out about harmonic movement and mannequin the habits of a single pendulum
  • Study the basics of chaos principle
  • Mannequin the chaotic habits of a double pendulum numerically

Easy Harmonic Movement

We describe the periodic oscillating motion of a pendulum as harmonic motion. Harmonic movement happens when there’s motion in a system that’s balanced out by a proportional restoring pressure in the wrong way of stated motion. We see an instance of this in determine 2 the place a mass on a spring is being pulled down on account of gravity, however this places power into the spring which then recoils and pulls the mass again up. Subsequent to the spring system, we see the peak of the mass going round in a circle referred to as a phasor diagram which additional illustrates the common movement of the system.

Determine 2: Instance of simple harmonic motion of a mass on a spring

Harmonic movement could be damped (lowering in amplitude on account of drag forces) or pushed (growing in amplitude on account of exterior pressure being added), however we are going to begin with the only case of indefinite harmonic movement with no exterior forces appearing on it (undamped movement). That is type of movement is an effective approximation for modeling a single pendulum that swings at a small angle/low amplitude. On this case we are able to mannequin the movement with equation 1 under.

Equation 1: Easy harmonic movement for a small angle pendulum

We will simply put this operate into code and simulate a easy pendulum over time.

def simple_pendulum(theta_0, omega, t, phi):
theta = theta_0*np.cos(omega*t + phi)
return theta

#parameters of our system
theta_0 = np.radians(15) #levels to radians

g = 9.8 #m/s^2
l = 1.0 #m
omega = np.sqrt(g/l)

phi = 0 #for small angle

time_span = np.linspace(0,20,300) #simulate for 20s break up into 300 time intervals
theta = []
for t in time_span:
theta.append(simple_pendulum(theta_0, omega, t, phi))

#Convert again to cartesian coordinates
x = l*np.sin(theta)
y = -l*np.cos(theta) #destructive to ensure the pendulum is dealing with down

Determine 3: Easy pendulum simulation

Full Pendulum Movement with Lagrangian Mechanics

A easy small angle pendulum is an effective begin, however we need to transcend this and mannequin the movement of a full pendulum. Since we are able to not use small angle approximations it’s best to mannequin the pendulum utilizing Lagrangian mechanics. That is an important software in physics that switches us from wanting on the forces in a system to wanting on the power in a system. We’re switching our body of reference from driving pressure vs restoring pressure to kinetic vs potential power.

The Lagrangain is the distinction between kinetic and potential power given in equation 2.

Equation 2: The Lagrangian

Substituting within the Kinetic and Potential of a pendulum given in equation 3 yields the Lagrangain for a pendulum seen is equation 4

Equation 3: Kinetic and potential power for a pendulum
Equation 4: Lagrangian for a pendulum

With the Lagrangian for a pendulum we now describe the power of our system. There’s one final math step to undergo to rework this into one thing that we are able to construct a simulation on. We have to bridge again to the dynamic/pressure oriented reference from the power reference utilizing the Euler-Lagrange equation. Utilizing this equation we are able to use the Lagrangian to get the angular acceleration of our pendulum.

Equation 5: Angular acceleration from the Euler-Lagrange equation

After going by way of the mathematics, now we have angular acceleration which we are able to use to get angular velocity and angle itself. This may require some numerical integration that might be specified by our full pendulum simulation. Even for a single pendulum, the non-linear dynamics means there isn’t any analytical resolution for fixing for theta, thus the necessity for a numerical resolution. The combination is sort of easy (however highly effective), we use angular acceleration to replace angular velocity and angular velocity to replace theta by including the previous amount to the latter and multiplying this by a while step. This will get us an approximation for the world underneath the acceleration/velocity curve. The smaller the time step, the extra correct the approximation.

def full_pendulum(g,l,theta,theta_velocity, time_step):
#Numerical Integration
theta_acceleration = -(g/l)*np.sin(theta) #Get acceleration
theta_velocity += time_step*theta_acceleration #Replace velocity with acceleration
theta += time_step*theta_velocity #Replace angle with angular velocity
return theta, theta_velocity

g = 9.8 #m/s^2
l = 1.0 #m

theta = [np.radians(90)] #theta_0
theta_velocity = 0 #Begin with 0 velocity
time_step = 20/300 #Outline a time step

time_span = np.linspace(0,20,300) #simulate for 20s break up into 300 time intervals
for t in time_span:
theta_new, theta_velocity = full_pendulum(g,l,theta[-1], theta_velocity, time_step)
theta.append(theta_new)

#Convert again to cartesian coordinates
x = l*np.sin(theta)
y = -l*np.cos(theta)

Determine 4: Simulation of a full pendulum

We have now simulated a full pendulum, however that is nonetheless a effectively outlined system. It’s now time to step into the chaos of the double pendulum.

Chaos, within the mathematical sense, refers to techniques which are extremely delicate to their preliminary circumstances. Even slight modifications within the system’s begin will result in vastly completely different behaviors because the system evolves. This completely describes the movement of the double pendulum. Not like the one pendulum, it isn’t a effectively behaved system and can evolve in a vastly completely different approach with even slight modifications in beginning angle.

To mannequin the movement of the double pendulum, we are going to use the identical Lagrangian strategy as earlier than (see full derivation).

We can even be utilizing the identical numerical integration scheme as earlier than when implementing this equation into code and discovering theta.

#Get theta1 acceleration 
def theta1_acceleration(m1,m2,l1,l2,theta1,theta2,theta1_velocity,theta2_velocity,g):
mass1 = -g*(2*m1 + m2)*np.sin(theta1)
mass2 = -m2*g*np.sin(theta1 - 2*theta2)
interplay = -2*np.sin(theta1 - theta2)*m2*np.cos(theta2_velocity**2*l2 + theta1_velocity**2*l1*np.cos(theta1 - theta2))
normalization = l1*(2*m1 + m2 - m2*np.cos(2*theta1 - 2*theta2))

theta1_ddot = (mass1 + mass2 + interplay)/normalization

return theta1_ddot

#Get theta2 acceleration
def theta2_acceleration(m1,m2,l1,l2,theta1,theta2,theta1_velocity,theta2_velocity,g):
system = 2*np.sin(theta1 - theta2)*(theta1_velocity**2*l1*(m1 + m2) + g*(m1 + m2)*np.cos(theta1) + theta2_velocity**2*l2*m2*np.cos(theta1 - theta2))
normalization = l1*(2*m1 + m2 - m2*np.cos(2*theta1 - 2*theta2))

theta2_ddot = system/normalization
return theta2_ddot

#Replace theta1
def theta1_update(m1,m2,l1,l2,theta1,theta2,theta1_velocity,theta2_velocity,g,time_step):
#Numerical Integration
theta1_velocity += time_step*theta1_acceleration(m1,m2,l1,l2,theta1,theta2,theta1_velocity,theta2_velocity,g)
theta1 += time_step*theta1_velocity
return theta1, theta1_velocity

#Replace theta2
def theta2_update(m1,m2,l1,l2,theta1,theta2,theta1_velocity,theta2_velocity,g,time_step):
#Numerical Integration
theta2_velocity += time_step*theta2_acceleration(m1,m2,l1,l2,theta1,theta2,theta1_velocity,theta2_velocity,g)
theta2 += time_step*theta2_velocity
return theta2, theta2_velocity

#Run full double pendulum
def double_pendulum(m1,m2,l1,l2,theta1,theta2,theta1_velocity,theta2_velocity,g,time_step,time_span):
theta1_list = [theta1]
theta2_list = [theta2]

for t in time_span:
theta1, theta1_velocity = theta1_update(m1,m2,l1,l2,theta1,theta2,theta1_velocity,theta2_velocity,g,time_step)
theta2, theta2_velocity = theta2_update(m1,m2,l1,l2,theta1,theta2,theta1_velocity,theta2_velocity,g,time_step)

theta1_list.append(theta1)
theta2_list.append(theta2)

x1 = l1*np.sin(theta1_list) #Pendulum 1 x
y1 = -l1*np.cos(theta1_list) #Pendulum 1 y

x2 = l1*np.sin(theta1_list) + l2*np.sin(theta2_list) #Pendulum 2 x
y2 = -l1*np.cos(theta1_list) - l2*np.cos(theta2_list) #Pendulum 2 y

return x1,y1,x2,y2

#Outline system parameters
g = 9.8 #m/s^2

m1 = 1 #kg
m2 = 1 #kg

l1 = 1 #m
l2 = 1 #m

theta1 = np.radians(90)
theta2 = np.radians(45)

theta1_velocity = 0 #m/s
theta2_velocity = 0 #m/s

theta1_list = [theta1]
theta2_list = [theta2]

time_step = 20/300

time_span = np.linspace(0,20,300)
x1,y1,x2,y2 = double_pendulum(m1,m2,l1,l2,theta1,theta2,theta1_velocity,theta2_velocity,g,time_step,time_span)

Determine 5: Double pendulum simulation

We’ve lastly achieved it! We have now efficiently modeled a double pendulum, however now it’s time to watch some chaos. Our last simulation might be of two double pendulums with barely completely different beginning situation. We are going to set one pendulum to have a theta 1 of 90 levels and the opposite to have a theta 1 of 91 levels. Let’s see what occurs.

Determine 6: 2 Double pendulums with barely completely different beginning circumstances

We will see that each pendulums begin off with comparable trajectories however rapidly diverge. That is what we imply after we say chaos, even a 1 diploma distinction in angle cascades into vastly completely different finish habits.

On this article we discovered about pendulum movement and how you can mannequin it. We began from the only harmonic movement mannequin and constructed as much as the advanced and chaotic double pendulum. Alongside the way in which we discovered in regards to the Lagrangian, chaos, and numerical integration.

The double pendulum is the only instance of a chaotic system. These techniques exist in every single place in our world from population dynamics, climate, and even billiards. We will take the teachings now we have discovered from the double pendulum and apply them at any time when we encounter a chaotic techniques.

Key Take Aways

  • Chaotic techniques are very delicate to preliminary circumstances and can evolve in vastly alternative ways with even slight modifications to their begin.
  • When coping with a system, particularly a chaotic system, is there one other body of reference to have a look at it that makes it simpler to work with? (Just like the pressure reference body to the power reference body)
  • When techniques get too sophisticated we have to implement numerical options to unravel them. These options are easy however highly effective and supply good approximations to the precise habits.

All figures used on this article had been both created by the creator or are from Math Images and full underneath the GNU Free Documentation License 1.2

Classical Mechanics, John Taylor https://neuroself.files.wordpress.com/2020/09/taylor-2005-classical-mechanics.pdf

Easy Pendulum

def makeGif(x,y,identify):
!mkdir frames

counter=0
photographs = []
for i in vary(0,len(x)):
plt.determine(figsize = (6,6))

plt.plot([0,x[i]],[0,y[i]], "o-", shade = "b", markersize = 7, linewidth=.7 )
plt.title("Pendulum")
plt.xlim(-1.1,1.1)
plt.ylim(-1.1,1.1)
plt.savefig("frames/" + str(counter)+ ".png")
photographs.append(imageio.imread("frames/" + str(counter)+ ".png"))
counter += 1
plt.shut()

imageio.mimsave(identify, photographs)

!rm -r frames

def simple_pendulum(theta_0, omega, t, phi):
theta = theta_0*np.cos(omega*t + phi)
return theta

#parameters of our system
theta_0 = np.radians(15) #levels to radians

g = 9.8 #m/s^2
l = 1.0 #m
omega = np.sqrt(g/l)

phi = 0 #for small angle

time_span = np.linspace(0,20,300) #simulate for 20s break up into 300 time intervals
theta = []
for t in time_span:
theta.append(simple_pendulum(theta_0, omega, t, phi))

x = l*np.sin(theta)
y = -l*np.cos(theta) #destructive to ensure the pendulum is dealing with down

Pendulum

def full_pendulum(g,l,theta,theta_velocity, time_step):
theta_acceleration = -(g/l)*np.sin(theta)
theta_velocity += time_step*theta_acceleration
theta += time_step*theta_velocity
return theta, theta_velocity

g = 9.8 #m/s^2
l = 1.0 #m

theta = [np.radians(90)] #theta_0
theta_velocity = 0
time_step = 20/300

time_span = np.linspace(0,20,300) #simulate for 20s break up into 300 time intervals
for t in time_span:
theta_new, theta_velocity = full_pendulum(g,l,theta[-1], theta_velocity, time_step)
theta.append(theta_new)

#Convert again to cartesian coordinates
x = l*np.sin(theta)
y = -l*np.cos(theta)

#Use identical operate from easy pendulum
makeGif(x,y,"pendulum.gif")

Double Pendulum

def theta1_acceleration(m1,m2,l1,l2,theta1,theta2,theta1_velocity,theta2_velocity,g):
mass1 = -g*(2*m1 + m2)*np.sin(theta1)
mass2 = -m2*g*np.sin(theta1 - 2*theta2)
interplay = -2*np.sin(theta1 - theta2)*m2*np.cos(theta2_velocity**2*l2 + theta1_velocity**2*l1*np.cos(theta1 - theta2))
normalization = l1*(2*m1 + m2 - m2*np.cos(2*theta1 - 2*theta2))

theta1_ddot = (mass1 + mass2 + interplay)/normalization

return theta1_ddot

def theta2_acceleration(m1,m2,l1,l2,theta1,theta2,theta1_velocity,theta2_velocity,g):
system = 2*np.sin(theta1 - theta2)*(theta1_velocity**2*l1*(m1 + m2) + g*(m1 + m2)*np.cos(theta1) + theta2_velocity**2*l2*m2*np.cos(theta1 - theta2))
normalization = l1*(2*m1 + m2 - m2*np.cos(2*theta1 - 2*theta2))

theta2_ddot = system/normalization
return theta2_ddot

def theta1_update(m1,m2,l1,l2,theta1,theta2,theta1_velocity,theta2_velocity,g,time_step):

theta1_velocity += time_step*theta1_acceleration(m1,m2,l1,l2,theta1,theta2,theta1_velocity,theta2_velocity,g)
theta1 += time_step*theta1_velocity
return theta1, theta1_velocity

def theta2_update(m1,m2,l1,l2,theta1,theta2,theta1_velocity,theta2_velocity,g,time_step):

theta2_velocity += time_step*theta2_acceleration(m1,m2,l1,l2,theta1,theta2,theta1_velocity,theta2_velocity,g)
theta2 += time_step*theta2_velocity
return theta2, theta2_velocity

def double_pendulum(m1,m2,l1,l2,theta1,theta2,theta1_velocity,theta2_velocity,g,time_step,time_span):
theta1_list = [theta1]
theta2_list = [theta2]

for t in time_span:
theta1, theta1_velocity = theta1_update(m1,m2,l1,l2,theta1,theta2,theta1_velocity,theta2_velocity,g,time_step)
theta2, theta2_velocity = theta2_update(m1,m2,l1,l2,theta1,theta2,theta1_velocity,theta2_velocity,g,time_step)

theta1_list.append(theta1)
theta2_list.append(theta2)

x1 = l1*np.sin(theta1_list)
y1 = -l1*np.cos(theta1_list)

x2 = l1*np.sin(theta1_list) + l2*np.sin(theta2_list)
y2 = -l1*np.cos(theta1_list) - l2*np.cos(theta2_list)

return x1,y1,x2,y2

#Outline system parameters, run double pendulum
g = 9.8 #m/s^2

m1 = 1 #kg
m2 = 1 #kg

l1 = 1 #m
l2 = 1 #m

theta1 = np.radians(90)
theta2 = np.radians(45)

theta1_velocity = 0 #m/s
theta2_velocity = 0 #m/s

theta1_list = [theta1]
theta2_list = [theta2]

time_step = 20/300

time_span = np.linspace(0,20,300)
for t in time_span:
theta1, theta1_velocity = theta1_update(m1,m2,l1,l2,theta1,theta2,theta1_velocity,theta2_velocity,g,time_step)
theta2, theta2_velocity = theta2_update(m1,m2,l1,l2,theta1,theta2,theta1_velocity,theta2_velocity,g,time_step)

theta1_list.append(theta1)
theta2_list.append(theta2)

x1 = l1*np.sin(theta1_list)
y1 = -l1*np.cos(theta1_list)

x2 = l1*np.sin(theta1_list) + l2*np.sin(theta2_list)
y2 = -l1*np.cos(theta1_list) - l2*np.cos(theta2_list)

#Make Gif
!mkdir frames

counter=0
photographs = []
for i in vary(0,len(x1)):
plt.determine(figsize = (6,6))

plt.determine(figsize = (6,6))
plt.plot([0,x1[i]],[0,y1[i]], "o-", shade = "b", markersize = 7, linewidth=.7 )
plt.plot([x1[i],x2[i]],[y1[i],y2[i]], "o-", shade = "b", markersize = 7, linewidth=.7 )
plt.title("Double Pendulum")
plt.xlim(-2.1,2.1)
plt.ylim(-2.1,2.1)
plt.savefig("frames/" + str(counter)+ ".png")
photographs.append(imageio.imread("frames/" + str(counter)+ ".png"))
counter += 1
plt.shut()

imageio.mimsave("double_pendulum.gif", photographs)

!rm -r frames


StackOverflow’s Pivot: From Disruption to Alternative | by Viggy Balagopalakrishnan | Aug, 2023

Implementation of a Siamese Community in Keras and TensorFlow | by Rashida Nasrin Sucky | Aug, 2023