# Standing wave animation with labeled nodes and antinodes
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
# Parameters
A = 1.0
lam = 1.0
k = 2 * np.pi / lam
omega = 2 * np.pi * 2.0
x = np.linspace(0, 2 * lam, 500)
# Standing wave function
def y_standing(x, t):
return 2 * A * np.sin(k * x) * np.cos(omega * t)
# Node and antinode positions
n_nodes = np.arange(0, 5)
x_nodes = n_nodes * lam / 2
n_anti = np.arange(0, 4)
x_anti = (2 * n_anti + 1) * lam / 4
# Set up figure
fig, ax = plt.subplots(figsize=(10, 4))
line, = ax.plot([], [], lw=2, color="blue")
ax.set_xlim(0, 2 * lam)
ax.set_ylim(-2.2 * A, 2.2 * A)
ax.set_xlabel("x (m)")
ax.set_ylabel("y (m)")
ax.set_title("Standing Wave with Nodes and Antinodes")
ax.grid(True)
# Mark nodes and antinodes
ax.scatter(x_nodes, np.zeros_like(x_nodes), color="red", label="Nodes")
ax.scatter(x_anti, np.zeros_like(x_anti), color="green", label="Antinodes")
ax.legend(loc="upper right")
# Initialization
def init():
line.set_data([], [])
return (line,)
# Update function
def animate(i):
t = i / 40
y = y_standing(x, t)
line.set_data(x, y)
return (line,)
# Create animation
ani = animation.FuncAnimation(fig, animate, init_func=init, frames=80, interval=60, blit=True)
plt.close(fig)
ani
IyBTdGFuZGluZyB3YXZlIGFuaW1hdGlvbiB3aXRoIGxhYmVsZWQgbm9kZXMgYW5kIGFudGlub2RlcwppbXBvcnQgbnVtcHkgYXMgbnAKaW1wb3J0IG1hdHBsb3RsaWIucHlwbG90IGFzIHBsdAppbXBvcnQgbWF0cGxvdGxpYi5hbmltYXRpb24gYXMgYW5pbWF0aW9uCgojIFBhcmFtZXRlcnMKQSA9IDEuMApsYW0gPSAxLjAKayA9IDIgKiBucC5waSAvIGxhbQpvbWVnYSA9IDIgKiBucC5waSAqIDIuMAp4ID0gbnAubGluc3BhY2UoMCwgMiAqIGxhbSwgNTAwKQoKIyBTdGFuZGluZyB3YXZlIGZ1bmN0aW9uCmRlZiB5X3N0YW5kaW5nKHgsIHQpOgogICAgcmV0dXJuIDIgKiBBICogbnAuc2luKGsgKiB4KSAqIG5wLmNvcyhvbWVnYSAqIHQpCgojIE5vZGUgYW5kIGFudGlub2RlIHBvc2l0aW9ucwpuX25vZGVzID0gbnAuYXJhbmdlKDAsIDUpCnhfbm9kZXMgPSBuX25vZGVzICogbGFtIC8gMgpuX2FudGkgPSBucC5hcmFuZ2UoMCwgNCkKeF9hbnRpID0gKDIgKiBuX2FudGkgKyAxKSAqIGxhbSAvIDQKCiMgU2V0IHVwIGZpZ3VyZQpmaWcsIGF4ID0gcGx0LnN1YnBsb3RzKGZpZ3NpemU9KDEwLCA0KSkKbGluZSwgPSBheC5wbG90KFtdLCBbXSwgbHc9MiwgY29sb3I9ImJsdWUiKQpheC5zZXRfeGxpbSgwLCAyICogbGFtKQpheC5zZXRfeWxpbSgtMi4yICogQSwgMi4yICogQSkKYXguc2V0X3hsYWJlbCgieCAobSkiKQpheC5zZXRfeWxhYmVsKCJ5IChtKSIpCmF4LnNldF90aXRsZSgiU3RhbmRpbmcgV2F2ZSB3aXRoIE5vZGVzIGFuZCBBbnRpbm9kZXMiKQpheC5ncmlkKFRydWUpCgojIE1hcmsgbm9kZXMgYW5kIGFudGlub2RlcwpheC5zY2F0dGVyKHhfbm9kZXMsIG5wLnplcm9zX2xpa2UoeF9ub2RlcyksIGNvbG9yPSJyZWQiLCBsYWJlbD0iTm9kZXMiKQpheC5zY2F0dGVyKHhfYW50aSwgbnAuemVyb3NfbGlrZSh4X2FudGkpLCBjb2xvcj0iZ3JlZW4iLCBsYWJlbD0iQW50aW5vZGVzIikKYXgubGVnZW5kKGxvYz0idXBwZXIgcmlnaHQiKQoKIyBJbml0aWFsaXphdGlvbgpkZWYgaW5pdCgpOgogICAgbGluZS5zZXRfZGF0YShbXSwgW10pCiAgICByZXR1cm4gKGxpbmUsKQoKIyBVcGRhdGUgZnVuY3Rpb24KZGVmIGFuaW1hdGUoaSk6CiAgICB0ID0gaSAvIDQwCiAgICB5ID0geV9zdGFuZGluZyh4LCB0KQogICAgbGluZS5zZXRfZGF0YSh4LCB5KQogICAgcmV0dXJuIChsaW5lLCkKCiMgQ3JlYXRlIGFuaW1hdGlvbgphbmkgPSBhbmltYXRpb24uRnVuY0FuaW1hdGlvbihmaWcsIGFuaW1hdGUsIGluaXRfZnVuYz1pbml0LCBmcmFtZXM9ODAsIGludGVydmFsPTYwLCBibGl0PVRydWUpCnBsdC5jbG9zZShmaWcpCmFuaQo=