# -*- coding: utf-8 -*-
"""
Created on Thu Jun 5 10:48:06 2025
@author: eddyb
"""
import numpy as np
import matplotlib.pyplot as plt
from math import sin, cos
# Physical parameters
g = 9.81 # gravity (m/s²)
L = 1.0 # pendulum length (m)
theta0 = np.pi/4 # initial angle (radians)
omega0 = 0.0 # initial angular velocity (rad/s)
# Simulation parameters
t_max = 10.0 # simulation time (s)
dt = 0.01 # time step (s)
# Time array
t = np.arange(0, t_max, dt)
# Initialize arrays
theta = np.zeros_like(t)
omega = np.zeros_like(t)
theta[0] = theta0
omega[0] = omega0
# Energy arrays for verification
E_pot = np.zeros_like(t) # potential energy
E_kin = np.zeros_like(t) # kinetic energy
E_total = np.zeros_like(t) # total energy
# Verlet integration (better for oscillatory systems)
for i in range(1, len(t)):
# Calculate acceleration
alpha = -(g/L) * sin(theta[i-1])
# Verlet velocity update
omega[i] = omega[i-1] + alpha * dt
theta[i] = theta[i-1] + omega[i] * dt # Note we use omega[i] here
# Calculate energies for verification
E_pot[i] = g * L * (1 - cos(theta[i])) # Potential energy
E_kin[i] = 0.5 * (L*omega[i])**2 # Kinetic energy
E_total[i] = E_pot[i] + E_kin[i] # Total mechanical energy
# Convert to Cartesian coordinates
x = L * np.sin(theta)
y = -L * np.cos(theta)
# Create plots
plt.figure(figsize=(14, 10))
# Angle vs Time
plt.subplot(3, 2, 1)
plt.plot(t, theta)
plt.xlabel('Time (s)')
plt.ylabel('Angle (rad)')
plt.title('Angle vs Time')
plt.grid()
# Angular Velocity vs Time
plt.subplot(3, 2, 2)
plt.plot(t, omega)
plt.xlabel('Time (s)')
plt.ylabel('Angular Velocity (rad/s)')
plt.title('Angular Velocity vs Time')
plt.grid()
# Phase Space
plt.subplot(3, 2, 3)
plt.plot(theta, omega)
plt.xlabel('Angle (rad)')
plt.ylabel('Angular Velocity (rad/s)')
plt.title('Phase Space')
plt.grid()
# Trajectory
plt.subplot(3, 2, 4)
plt.plot(x, y)
plt.xlabel('x position (m)')
plt.ylabel('y position (m)')
plt.title('Pendulum Trajectory')
plt.grid()
plt.axis('equal')
# Energy plots
plt.subplot(3, 2, 5)
plt.plot(t, E_pot, label='Potential')
plt.plot(t, E_kin, label='Kinetic')
plt.xlabel('Time (s)')
plt.ylabel('Energy (J)')
plt.title('Potential and Kinetic Energy')
plt.legend()
plt.grid()
plt.subplot(3, 2, 6)
plt.plot(t, E_total)
plt.xlabel('Time (s)')
plt.ylabel('Energy (J)')
plt.title('Total Mechanical Energy (should be constant)')
plt.grid()
plt.tight_layout()
plt.show()
IyAtKi0gY29kaW5nOiB1dGYtOCAtKi0KIiIiCkNyZWF0ZWQgb24gVGh1IEp1biAgNSAxMDo0ODowNiAyMDI1CgpAYXV0aG9yOiBlZGR5YgoiIiIKaW1wb3J0IG51bXB5IGFzIG5wCmltcG9ydCBtYXRwbG90bGliLnB5cGxvdCBhcyBwbHQKZnJvbSBtYXRoIGltcG9ydCBzaW4sIGNvcwoKIyBQaHlzaWNhbCBwYXJhbWV0ZXJzCmcgPSA5LjgxICAgICAgICMgZ3Jhdml0eSAobS9zwrIpCkwgPSAxLjAgICAgICAgICMgcGVuZHVsdW0gbGVuZ3RoIChtKQp0aGV0YTAgPSBucC5waS80ICAjIGluaXRpYWwgYW5nbGUgKHJhZGlhbnMpCm9tZWdhMCA9IDAuMCAgICAgICMgaW5pdGlhbCBhbmd1bGFyIHZlbG9jaXR5IChyYWQvcykKCiMgU2ltdWxhdGlvbiBwYXJhbWV0ZXJzCnRfbWF4ID0gMTAuMCAgICAjIHNpbXVsYXRpb24gdGltZSAocykKZHQgPSAwLjAxICAgICAgICMgdGltZSBzdGVwIChzKQoKIyBUaW1lIGFycmF5CnQgPSBucC5hcmFuZ2UoMCwgdF9tYXgsIGR0KQoKIyBJbml0aWFsaXplIGFycmF5cwp0aGV0YSA9IG5wLnplcm9zX2xpa2UodCkKb21lZ2EgPSBucC56ZXJvc19saWtlKHQpCnRoZXRhWzBdID0gdGhldGEwCm9tZWdhWzBdID0gb21lZ2EwCgojIEVuZXJneSBhcnJheXMgZm9yIHZlcmlmaWNhdGlvbgpFX3BvdCA9IG5wLnplcm9zX2xpa2UodCkgICMgcG90ZW50aWFsIGVuZXJneQpFX2tpbiA9IG5wLnplcm9zX2xpa2UodCkgICMga2luZXRpYyBlbmVyZ3kKRV90b3RhbCA9IG5wLnplcm9zX2xpa2UodCkgICMgdG90YWwgZW5lcmd5CgojIFZlcmxldCBpbnRlZ3JhdGlvbiAoYmV0dGVyIGZvciBvc2NpbGxhdG9yeSBzeXN0ZW1zKQpmb3IgaSBpbiByYW5nZSgxLCBsZW4odCkpOgogICAgIyBDYWxjdWxhdGUgYWNjZWxlcmF0aW9uCiAgICBhbHBoYSA9IC0oZy9MKSAqIHNpbih0aGV0YVtpLTFdKQogICAgCiAgICAjIFZlcmxldCB2ZWxvY2l0eSB1cGRhdGUKICAgIG9tZWdhW2ldID0gb21lZ2FbaS0xXSArIGFscGhhICogZHQKICAgIHRoZXRhW2ldID0gdGhldGFbaS0xXSArIG9tZWdhW2ldICogZHQgICMgTm90ZSB3ZSB1c2Ugb21lZ2FbaV0gaGVyZQogICAgCiAgICAjIENhbGN1bGF0ZSBlbmVyZ2llcyBmb3IgdmVyaWZpY2F0aW9uCiAgICBFX3BvdFtpXSA9IGcgKiBMICogKDEgLSBjb3ModGhldGFbaV0pKSAgIyBQb3RlbnRpYWwgZW5lcmd5CiAgICBFX2tpbltpXSA9IDAuNSAqIChMKm9tZWdhW2ldKSoqMiAgICAgICAgIyBLaW5ldGljIGVuZXJneQogICAgRV90b3RhbFtpXSA9IEVfcG90W2ldICsgRV9raW5baV0gICAgICAgICMgVG90YWwgbWVjaGFuaWNhbCBlbmVyZ3kKCiMgQ29udmVydCB0byBDYXJ0ZXNpYW4gY29vcmRpbmF0ZXMKeCA9IEwgKiBucC5zaW4odGhldGEpCnkgPSAtTCAqIG5wLmNvcyh0aGV0YSkKCiMgQ3JlYXRlIHBsb3RzCnBsdC5maWd1cmUoZmlnc2l6ZT0oMTQsIDEwKSkKCiMgQW5nbGUgdnMgVGltZQpwbHQuc3VicGxvdCgzLCAyLCAxKQpwbHQucGxvdCh0LCB0aGV0YSkKcGx0LnhsYWJlbCgnVGltZSAocyknKQpwbHQueWxhYmVsKCdBbmdsZSAocmFkKScpCnBsdC50aXRsZSgnQW5nbGUgdnMgVGltZScpCnBsdC5ncmlkKCkKCiMgQW5ndWxhciBWZWxvY2l0eSB2cyBUaW1lCnBsdC5zdWJwbG90KDMsIDIsIDIpCnBsdC5wbG90KHQsIG9tZWdhKQpwbHQueGxhYmVsKCdUaW1lIChzKScpCnBsdC55bGFiZWwoJ0FuZ3VsYXIgVmVsb2NpdHkgKHJhZC9zKScpCnBsdC50aXRsZSgnQW5ndWxhciBWZWxvY2l0eSB2cyBUaW1lJykKcGx0LmdyaWQoKQoKIyBQaGFzZSBTcGFjZQpwbHQuc3VicGxvdCgzLCAyLCAzKQpwbHQucGxvdCh0aGV0YSwgb21lZ2EpCnBsdC54bGFiZWwoJ0FuZ2xlIChyYWQpJykKcGx0LnlsYWJlbCgnQW5ndWxhciBWZWxvY2l0eSAocmFkL3MpJykKcGx0LnRpdGxlKCdQaGFzZSBTcGFjZScpCnBsdC5ncmlkKCkKCiMgVHJhamVjdG9yeQpwbHQuc3VicGxvdCgzLCAyLCA0KQpwbHQucGxvdCh4LCB5KQpwbHQueGxhYmVsKCd4IHBvc2l0aW9uIChtKScpCnBsdC55bGFiZWwoJ3kgcG9zaXRpb24gKG0pJykKcGx0LnRpdGxlKCdQZW5kdWx1bSBUcmFqZWN0b3J5JykKcGx0LmdyaWQoKQpwbHQuYXhpcygnZXF1YWwnKQoKIyBFbmVyZ3kgcGxvdHMKcGx0LnN1YnBsb3QoMywgMiwgNSkKcGx0LnBsb3QodCwgRV9wb3QsIGxhYmVsPSdQb3RlbnRpYWwnKQpwbHQucGxvdCh0LCBFX2tpbiwgbGFiZWw9J0tpbmV0aWMnKQpwbHQueGxhYmVsKCdUaW1lIChzKScpCnBsdC55bGFiZWwoJ0VuZXJneSAoSiknKQpwbHQudGl0bGUoJ1BvdGVudGlhbCBhbmQgS2luZXRpYyBFbmVyZ3knKQpwbHQubGVnZW5kKCkKcGx0LmdyaWQoKQoKcGx0LnN1YnBsb3QoMywgMiwgNikKcGx0LnBsb3QodCwgRV90b3RhbCkKcGx0LnhsYWJlbCgnVGltZSAocyknKQpwbHQueWxhYmVsKCdFbmVyZ3kgKEopJykKcGx0LnRpdGxlKCdUb3RhbCBNZWNoYW5pY2FsIEVuZXJneSAoc2hvdWxkIGJlIGNvbnN0YW50KScpCnBsdC5ncmlkKCkKCnBsdC50aWdodF9sYXlvdXQoKQpwbHQuc2hvdygp