DEMO: Visualizing waves#
import numpy as np
import matplotlib.pyplot as plt
import plotly.graph_objects as go
from plotly.subplots import make_subplots
from ipywidgets import interact, interactive
import scipy
from scipy.constants import physical_constants, hbar, h, c, k, m_e, Rydberg, e, N_A
%matplotlib inline
%config InlineBackend.figure_format='retina'
try:
from google.colab import output
output.enable_custom_widget_manager()
print('All good to go')
except:
print('Okay we are not in Colab just proceed as if nothing happened')
Okay we are not in Colab just proceed as if nothing happened
Standing and traveling waves in 1D#
We begin by plotting a simple periodic function using numpy (np) and matplotlib.pyplot (plt)
L=0.3 # Try different wavelengths
x = np.linspace(0.0, 1.0, 1000)
y = np.sin(2 * np.pi * x/L)
plt.plot(x, y)
[<matplotlib.lines.Line2D at 0x1666eec40>]
By putting above example inside a python function will make wavelength exploration convenient
def wave1d(L=2):
x = np.linspace(0.0, 1.0, 1000)
y = np.sin(2*np.pi * x / L )
plt.plot(x, y, label=f'L={L}')
plt.xlabel('x')
plt.xlabel('y')
plt.legend()
plt.title('Sine waves')
plt.ylim(-1,1)
plt.show()
# Change wavelength
wave1d(L=0.5)
Interact with waves#
By adding
@widgets.interact(parameters=(init,final))
to our functions we can interactively parameters in the function using slider widgets.
interactive(wave1d, L=(0.1, 2))
Traveling, standing waves and wave interference#
def wavef2(k=10, t=0, phi=0, v=1):
x = np.linspace(0, 1., 1000)
wave1 = np.sin(k*(x-v*t))
wave2 = np.sin(k*(x-v*t)+phi) #try flipping the direction of velocity to get standing wave
plt.plot(x, wave1, lw=2, color='blue')
plt.plot(x, wave2, lw=2, color='green')
plt.plot(x, wave1+wave2, lw=3, color='red')
plt.ylim([-2.5, 2.5])
plt.legend(['Wave1','Wave2','Wave1+Wave2'])
plt.grid('on')
plt.show()
interactive(wavef2, k=(2, 20), t=(0,50.0,0.1), phi=(0, 2*np.pi, np.pi/8),v=1)
Traveling wave as a function of time and position#
import plotly.express as px
def wave_x_t(A = 1, k = 1.0, omega = 1, phi = 0):
# Create a grid of x and t values
x = np.linspace(0, 2 * np.pi, 50)
t = np.linspace(0, 2 * np.pi, 50)
X, T = np.meshgrid(x, t)
# Calculate the wave amplitude for each combination of x and t
Y = A * np.sin(k * X - omega * T + phi)
return px.scatter_3d(x=X.ravel(),
y=T.ravel(),
z=Y.ravel(),
color = Y.ravel(),
labels={'x': 'Position', 'y': 'Time', 'z': 'Amplitude'},
width=1000,
height=1000)
wave_x_t(A=1, k = 1.0, omega=2, phi=0)
Normal modes of 1D guitar string#
def guitar1d(n=1, t=0):
v=1
L=1
omega= np.pi*v/L
x = np.linspace(0, +1., 1000)
y = np.sin(n*np.pi * x/L) * np.cos(omega*t)
plt.plot(x, y, lw=3)
plt.title(label=f'Normal mode # {n}')
plt.grid('--')
plt.ylim(-1,1)
plt.show()
interactive(guitar1d, n=(1,10), t=(0, 10, 0.1))
1D guitar vibrations as linear combination of normal modes#
For simplicity we will combine two modes with two different mode numbers and shifted with resepct to each ophter by a phase \(\phi\).
def wavef(n1=1, n2=1, phi=0,t=0):
L=1
omega=1
x = np.linspace(0, +1., 50)
mode1 = np.cos(omega*t) * np.sin(n1*np.pi * x/L)
mode2 = np.cos(omega*t + phi) * np.sin(n2*np.pi * x/L)
plt.plot(x, mode1+mode2, lw=5, color='orange')
plt.ylim([-2.5, 2.5])
plt.grid('on')
plt.show()
interactive(wavef, n1=(1,5), n2=(1,5), phi=(0,2*np.pi), t=(0,100,0.1) )
Normal modes of a 2D membrane#
Below we show two visualizations of 2D membrane normal modes, which allow you to visualize spatial profiles and temporal evolution using interactive sliders.
First visualization is using matplotlib which is a static plotting library.
Second visualization is using a Plotly a dynamic plotting loibrary allowing you to rotate and interact with plots
def membrane2d_mode(n=1, m=1, t=0):
'''The function returns 2D grid of points (X, Y) and the value of membrane normal mode at a time t: Z(X, Y, t)
'''
# Constants
Lx, Ly = 1.0, 1.0 # Dimensions of the rectangular region
v = 0.1 # wave speed
omega = v * np.pi/Lx * (n**2+m**2) # Angular rate
# Create a spatial grid
Nx, Ny = 100, 100
x, y = np.linspace(0, Lx, Nx), np.linspace(0, Ly, Ny)
X, Y = np.meshgrid(x, y)
# Compute spatial part of the normal mode
Z = np.sin(m * np.pi * X / Lx) * np.sin(n * np.pi * Y / Ly) * np.cos(omega*t)
return X, Y, Z
X, Y, Z = membrane2d_mode(n=3, m=2, t=0)
plt.contourf(X, Y, Z)
plt.colorbar()
<matplotlib.colorbar.Colorbar at 0x16a3ac970>
Visualization of 2D membrane vibrations using matplotlib#
def viz_membrane2d(n=1, m=1, t=0):
'''Normal modes of 2D membrane on a square geometry'''
X, Y, Z = membrane2d_mode(n, m, t)
### Plot in 3D
fig = plt.figure(figsize=(9, 4))
ax1 = fig.add_subplot(1, 2, 1)
ax1.contourf(X, Y, Z, 40, cmap='RdBu')
ax2 = fig.add_subplot(1, 2, 2, projection='3d')
ax2.plot_surface(X, Y, Z, cmap='RdBu')
ax2.set_zlim(-1, 1)
plt.show()
interactive(viz_membrane2d, n=(1,10), m=(1,10), t=(0,100))
Visualization of 2D membrane vibrations using plotly interactive plots#
def viz_membrane2d_plotly(n=1, m=1, t=0):
'''Normal modes of 2D membrane on a square geometry using Plotly plot'''
X, Y, Z = membrane2d_mode(n, m, t)
# Create a Plotly subplot with 1 row and 2 columns
fig = make_subplots(
rows=1,
cols=2,
subplot_titles=('2D Contour Plot', '3D Surface Plot'),
specs=[[{"type": "contour"}, {"type": "surface"}]]
)
# Add 2D contour plot to the left side
fig.add_trace(
go.Contour(x=X.flatten(), y=Y.flatten(), z=Z.flatten(), colorscale='RdBu'),
row=1, col=1
)
# Add 3D surface plot to the right side
fig.add_trace(
go.Surface(x=X, y=Y, z=Z, colorscale='RdBu'),
row=1, col=2
)
# Update layout for better visualization and adjust figure size
fig.update_layout(
title_text="2D Contour and 3D Surface plots of 2D Membrane vibrational normal modes",
width=1000,
height=500
)
fig.show()
interact(viz_membrane2d_plotly, n=(1,10), m=(1,10), t=(0,100))
<function __main__.viz_membrane2d_plotly(n=1, m=1, t=0)>