# This code block installs ffmpeg to your Deepnote Machine
# Allows Deepnote to write MP4
!apt update -y
!apt install ffmpeg -y
# Bead on a wire code:
import numpy as np
from numpy.linalg import solve
import matplotlib.pyplot as plt
from matplotlib.animation import FFMpegWriter
from matplotlib.patches import Circle
# Defining parameters
g = 9.8 # gravity (m/s^2)
m = 1 # mass of the bead (kg)
# Define Time Vector for Simulation
dt = 0.001 # Time Step (s)
sim_time = 10 # Length of Simulation (s)
t_vec = np.arange(0, sim_time, dt)
# Initialize State Vectors:
vec_size = len(t_vec)
x_vec = np.zeros(vec_size)
dx_vec = np.zeros(vec_size)
y_vec = np.zeros(vec_size)
dy_vec = np.zeros(vec_size)
# Assign Intial Values:
x_vec[0] = -1
dx_vec[0] = 0
y_vec[0] = x_vec[0]**2 # ** is to the power of
dy_vec[0] = 0
# Euler Simulation: Using Matrix Form (A*x = B)
# Initialize A and B:
A = np.array([[m, 0, 2*x_vec[0]], [0, m, -1], [2*x_vec[0], -1, 0]])
B = np.array([0, -m*g, 0])
# Initialize constraint Force
lagrangeMultiplier = np.zeros(vec_size)
for i in range(1, vec_size):
# Updating the arrays
A[0, 2] = 2*x_vec[i-1]
A[2, 0] = 2*x_vec[i-1]
B[2] = -2*(dx_vec[i-1]**2)
# Find the accelerations and the Lagrange Multiplier
[ddx, ddy, lMultiplier] = np.linalg.solve(A, B)
lagrangeMultiplier[i] = lMultiplier
# Use accelerations to find next position and velocities
x_vec[i] = x_vec[i-1] + dx_vec[i-1]*dt
y_vec[i] = y_vec[i-1] + dy_vec[i-1]*dt
dx_vec[i] = dx_vec[i-1] + ddx*dt
dy_vec[i] = dy_vec[i-1] + ddy*dt
# Plotting x(t), y(t), and lambda
plt.plot(t_vec, x_vec)
plt.title("X Position versus Time")
plt.xlabel("Time [s]")
plt.ylabel("X Position [m]")
plt.show()
plt.plot(t_vec, y_vec)
plt.title("Y Position versus Time")
plt.xlabel("Time [s]")
plt.ylabel("Y Position [m]")
plt.show()
plt.plot(t_vec, x_vec)
plt.title("Normal Force versus Time")
plt.xlabel("Time [s]")
plt.ylabel("Normal Force [N]")
plt.show()
# Create animation
# Setup figure:
fig, ax = plt.subplots()
p, = ax.plot([],[],color='dimgray')
ax.axis('equal')
ax.set_xlim([-3, 3])
ax.set_ylim([-3, 3])
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_title('Bead on a Wire Simulation')
title = "simulation"
# Setup animation writer
FPS = 20
sample_rate = int(1/(dt*FPS)) # Real time playback
dpi = 300
writerObj = FFMpegWriter(fps=FPS)
# Initialize Patch (bead)
c = Circle((x_vec[0], y_vec[0]), radius=0.1, color='cornflowerblue')
ax.add_patch(c)
# Draw the wire
x_wire = np.arange(-1.3, 1.3, dt)
y_wire = x_wire**2
# Plot and Create Animation
with writerObj.saving(fig, title+".mp4", dpi):
p.set_data(x_wire, y_wire)
# Sample only a few frames
# Update position of bead on the wire
for i in range(0, vec_size, sample_rate):
patch_center = x_vec[i], y_vec[i]
c.center = patch_center
# Update drawing, grab and save frame
fig.canvas.draw()
writerObj.grab_frame()