Source
%matplotlib widget
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
from ipywidgets import *
plt.style.use('dark_background')
fontsize = 14
mpl.rcParams.update(
{
"text.usetex": False,
"figure.figsize": (9, 6),
# "figure.autolayout": True,
# "font.family": "serif",
# "font.serif": "georgia",
# 'mathtext.fontset': 'cm',
"lines.linewidth": 1.5,
"font.size": fontsize,
"xtick.labelsize": fontsize,
"ytick.labelsize": fontsize,
"legend.fancybox": True,
"legend.fontsize": fontsize,
"legend.framealpha": 0.7,
"legend.handletextpad": 0.5,
"legend.labelspacing": 0.2,
"legend.loc": "best",
"axes.edgecolor": "#b0b0b0",
"grid.color": "#707070", # grid color"
"xtick.color": "#b0b0b0",
"ytick.color": "#b0b0b0",
"savefig.dpi": 80,
"pdf.compression": 9,
}
)2What is light?¶
If we are to understand lasers and optomechanics, we must first have a solid grasp of the the nature of light. What is light? is a simple question without a simple answer.
Loosely, light is an excitation in the electromagnetic field which permeates the universe, carrying energy and information that can be directly sensed by the human eye. Humanity’s close relationship with light drove us to study it closely, teaching us first the secrets of electromagnetism, then plunging us into the unintuitive world of quantum mechanics.
2.1The Duality of Light¶
Light is commonly described to be both an electromagnetic wave and particle. This is our way of relating light to waves and particles, two objects humans can easily understand, and sweeping under the rug the complexities. In reality, light is neither a wave nor a particle, but describing light as a complex traveling oscillation in the electromagnetic wave with indeterminant wavelength is not very useful for most people.
A good intuition can be provided by seeing the wave view vs photon view shown in this interactive demo: Electromagnetic Spectrum.
3Electromagnetism: The Wave Equation¶
Maxwell showed that light was an electromagnetic wave, resulting from the interplay of his famous equations in a vacuum (no charges or currents):
where is the electric field vector, is the magnetic field vector, is a spatial cross-product partial derivative, or curl operator familiar from undergrad E&M, and is the speed of light.
If we take the curl of the equations in (3):
Subbing in Eq. (4) to the right hand side, and using the curl-of-curl identity
plus Eq. (1) yields
3.1One-dimensional Plane-wave solution to the wave equation¶
We are going to solve this differential equation in the classic way: by already knowing the answer. This equation is Helmholtz’s equation.
First, we’ll solve Eqs. (7) and (8) in one dimension, and focus on the electric field at first. We can break up electric field
Recall that the Laplacian
From Gauss’s Law in a vacuum , we know that an electric field cannot propogate in the direction it is pointing. The wave must propogate in a transverse direction.
We will solve for an electric-field in the -direction that is propogating in the -direction:
We’ll first employ separation of variables.
We’ll separate the solution for into a pure time and spatial component:
Applying this separated function
Rearranging:
Both sides of Eq. (14) are independent ordinary differential equations, and will equal the same constant.
For convenience later, we will call this constant .
Then we have
We can then offer two oscillating solutions for Eq. (15):
Similarly for Eq. (16), but we define a new constant for simplicity:
Combining the above solutions back together using (12) gives us the following general solution:
with complex coefficients .
The constant is the wave-number in units of inverse meters,
while the constant is the angular frequency in units of radians / second.
Eq.(19) is generally complex-valued.
However, an electric field must take on a real value, as it is an observable quantity.
To reconcile that, our coefficients must conspire to make real in the end.
Most simply, one could set and , and we’d instantly have
where I’ve assumed the factor of 1/2 into some new and coefficients,
as well as some phases from the complex angles and .
We’ve written the solution this way to emphasize that time always propogates in one direction, but the wave direction can have either sign.
In this case, and would be real-valued to maintain a real electric field.
The two components of the solution represent one field propogating in the positive -direction, and the other field propogating in the negative -direction.
We mention here that these cosine wave solutions are not the only solutions, but they can be summed into any solution that depends on a variable . See Feynman’s Lecture on Physics Volume II Chapter 20, or Griffith’s Electrodynamics Chapter 9.1.1.
Source
fig = plt.figure()
ax = fig.add_subplot()
amp1 = 1.0
amp2 = 1.0
phase1 = 0.0
phase2 = 0.0
kk = 2 * np.pi * 1
omega = 2 * np.pi * 1
time = 0
xx = np.linspace(-1.5, 1.5, 1000)
y1 = amp1 * np.cos(kk * xx - omega * time + phase1)
y2 = amp2 * np.cos(-kk * xx - omega * time + phase2)
y3 = y1 + y2
eline1, = ax.plot(xx, y1, label="A' field (+z)")
eline2, = ax.plot(xx, y2, label="B' field (-z)")
eline3, = ax.plot(xx, y3, label="A' + B' field")
ax.set_xlim([xx[0], xx[-1]])
ax.set_ylim([-2, 2])
ax.legend(loc="upper right")
# ax.set_axis_off()
plt.tight_layout()
def update_standing_waves(
time_slider_value=0,
amp1_slider_value=amp1,
amp2_slider_value=amp2,
phase1_slider_value=phase1,
phase2_slider_value=phase2,
):
"""
Create waves plot with synchronized cosine and sine displays.
"""
time = time_slider_value
amp1 = amp1_slider_value
amp2 = amp2_slider_value
phase1 = phase1_slider_value
phase2 = phase2_slider_value
# Calculate sine
newy1 = amp1 * np.cos(omega * time - kk * xx + phase1)
newy2 = amp2 * np.cos(omega * time + kk * xx + phase2)
newy3 = newy1 + newy2
eline1.set_ydata(newy1)
eline2.set_ydata(newy2)
eline3.set_ydata(newy3)
fig.canvas.draw_idle()
return
# Create interactive widget
time_slider = FloatSlider(
value=0,
min=0,
max=1,
step=0.01,
description='time [s]:',
continuous_update=True, # Only update on release for better performance
orientation='horizontal',
readout=True,
readout_format='.3f',
)
amp1_slider = FloatSlider(
value=amp1,
min=0,
max=1,
step=0.01,
description="A':",
continuous_update=True, # Only update on release for better performance
orientation='horizontal',
readout=True,
readout_format='.3f',
)
amp2_slider = FloatSlider(
value=amp2,
min=0,
max=1,
step=0.01,
description="B':",
continuous_update=True, # Only update on release for better performance
orientation='horizontal',
readout=True,
readout_format='.3f',
)
phase1_slider = FloatSlider(
value=phase1,
min=-np.pi,
max=np.pi,
step=0.01,
description=r"$\phi_+$:",
continuous_update=True, # Only update on release for better performance
orientation='horizontal',
readout=True,
readout_format='.3f',
)
phase2_slider = FloatSlider(
value=phase2,
min=-np.pi,
max=np.pi,
step=0.01,
description=r"$\phi_-$:",
continuous_update=True, # Only update on release for better performance
orientation='horizontal',
readout=True,
readout_format='.3f',
)
interact(
update_standing_waves,
time_slider_value=time_slider,
amp1_slider_value=amp1_slider,
amp2_slider_value=amp2_slider,
phase1_slider_value=phase1_slider,
phase2_slider_value=phase2_slider
)
plt.show()Accompanying Magnetic Field Plane-Wave Solution¶
Recall that our electric field in the x-direction was
To get the magnetic field that accompanies Eq. (20), we go back to Faraday’s Law .
For we have (assuming and , and ):
The above must equal , so we take the antiderivative with respect to time to recover the magnetic field :
The below Figure Notebook-code shows the electric field alongside the magnetic field, propogating only in one direction.
Source
fig_3d = plt.figure()
ax_3d = fig_3d.add_subplot(projection='3d')
amp = 0.7
kk = 2 * np.pi * 1
omega = 2 * np.pi * 1
time = 0
x = np.linspace(-2.5, 2.5, 1000)
y = amp * np.sin(omega * time - kk * x)
z = np.zeros_like(x)
eline, = ax_3d.plot(x, z, y, color="#ff9955", label="E-field")
bline, = ax_3d.plot(x, y, z, color="#5599ff", label="B-field")
ax_3d.plot(1.5*x, z, z, lw=0.5, color="white")
ax_3d.plot(z, np.linspace(-2*amp, 2*amp, len(z)), z, lw=0.5, color="white")
ax_3d.plot(z, z, np.linspace(-2*amp, 2*amp, len(z)), lw=0.5, color="white")
ax_3d.set_xlim([x[0], x[-1]])
ax_3d.set_ylim([-1, 1])
ax_3d.set_zlim([-1, 1])
ax_3d.set_aspect('equal')
ax_3d.legend()
ax_3d.set_axis_off()
def update_waves(
time_slider_value=0,
amp_slider_value=0.7
):
"""
Create waves plot with synchronized cosine and sine displays.
"""
time = time_slider_value
amp = amp_slider_value
# Calculate sine
newy = amp * np.sin(omega * time - kk * x)
eline.set_data_3d(x, z, newy)
bline.set_data_3d(x, newy, z)
# efill = ax_3d.fill_between(x, z, newy, x, z, z, alpha=0.3, color="#ff9955")
# bfill = ax_3d.fill_between(x, newy, z, x, z, z, alpha=0.3, color="#5599ff")
fig_3d.canvas.draw_idle()
return
# Create interactive widget
time_slider = FloatSlider(
value=0,
min=0,
max=3,
step=0.01,
description='time [s]:',
continuous_update=True, # Only update on release for better performance
orientation='horizontal',
readout=True,
readout_format='.3f',
)
amp_slider = FloatSlider(
value=amp,
min=0,
max=1,
step=0.01,
description='amplitude:',
continuous_update=True, # Only update on release for better performance
orientation='horizontal',
readout=True,
readout_format='.3f',
)
interact(update_waves, time_slider_value=time_slider, amp_slider_value=amp_slider)
plt.show()
3.2Generalization in three-dimensions¶
A similar derivation as the plane wave solution above can be performed for and .
We can define a wave-number vector and a radial vector .
Then ,
and we can rewrite the solution in any direction:
where represents the direction the electric field points, and is often called the polarization of the electromagnetic wave.
is a constant, and can be complex if the phase term is nonzero.
To get the actual real electric field, the real part of the complex quantity can be taken:
3.3Spherical Plane Waves¶
Here we introduce the concept of spherical plane waves, following the derivation in Feynman’s Lectures Volume II Chapter 20.
Flat plane waves, like we’ve introduced above, are accurate solutions for continuous sources of single rays of light, or sheets of light propogating in the same direction. However, in some cases point sources serve as the source of our electromagnetic wave, like an oscillating nucleus in a lattice, or a voltage oscillating in an antenna. These point sources correspond to a dipole moment, which emits energy that disperses over 3D space in a nontrivial way.
Here I copy the Feynman lectures derivation of spherical plane waves:



As Feynman states above, The spherical wave amplitude steadily decreases as a function of the distance . This intuitively makes sense, as the energy from the point source becomes spread out over more space, the amplitude of the wave should decay.
The only minor difference between our plane wave solution above and Feynman’s derivation here is Feynman’s plane wave solution is more general than our sinusoidal solutions. Feynman’s solution can represent any arbitrary motion in some medium, like a pulse, so long as it travels along at a speed
We can reconstruct any pulse or wave propogating along at a speed by using some sum of our sinusoids. So, our solutions are valid. The difference between spherical and plane waves can be seen in the two interactive plots below.
Source
# Create figure
fig_2d, axes = plt.subplots(1, 2, figsize=(13, 6))
colormap = 'RdBu_r'
# Create spatial grid
x = np.linspace(-2, 2, 50)
y = np.linspace(-2, 2, 50)
X, Y = np.meshgrid(x, y)
# Wave number
phase = 0
wavelength=1.0
k = 2 * np.pi / wavelength
# Plane wave
Z_plane = np.cos(k * X - phase)
# Spherical wave
R = np.sqrt(X**2 + Y**2)
R = np.where(R < 0.01, 0.01, R)
Z_spherical = np.cos(k * R - phase) / R
# Plane wave
im1 = axes[0].pcolormesh(X, Y, Z_plane, cmap=colormap,
shading='gouraud', vmin=-1, vmax=1)
axes[0].set_xlabel('x', fontsize=12)
axes[0].set_ylabel('y', fontsize=12)
axes[0].set_title(f'Plane Wave (wavelength = {wavelength:.2f})', fontsize=13)
axes[0].set_aspect('equal')
axes[0].grid(True, alpha=0.3)
plt.colorbar(im1, ax=axes[0], label='Amplitude')
# Spherical wave
im2 = axes[1].pcolormesh(X, Y, Z_spherical, cmap=colormap,
shading='gouraud', vmin=-2, vmax=2)
axes[1].set_xlabel('x', fontsize=12)
axes[1].set_ylabel('y', fontsize=12)
axes[1].set_title(f'Spherical Wave (wavelength = {wavelength:.2f})', fontsize=13)
axes[1].set_aspect('equal')
axes[1].grid(True, alpha=0.3)
plt.colorbar(im2, ax=axes[1], label='Amplitude')
plt.tight_layout()
# plt.show()
def plot_both_waves(wavelength=1.0, phase=0.0, colormap='RdBu_r'):
"""
Plot plane and spherical waves side by side.
"""
# Wave number
new_k = 2 * np.pi / wavelength
# Plane wave
new_Z_plane = np.cos(new_k * X - phase)
# Spherical wave
new_Z_spherical = np.cos(new_k * R - phase) / R
im1.set_array(new_Z_plane.ravel())
im2.set_array(new_Z_spherical.ravel())
im1.set_cmap(colormap)
im2.set_cmap(colormap)
fig_2d.canvas.draw_idle()
return
# Interactive widget for side-by-side comparison
interact(plot_both_waves,
wavelength=FloatSlider(min=0.5, max=3.0, step=0.1, value=1.0,
description='Wavelength:',
continuous_update=True),
phase=FloatSlider(min=0, max=2*np.pi, step=0.1, value=0.0,
description='Phase (rad):',
continuous_update=True),
colormap=Dropdown(options=['RdBu_r', 'seismic', 'coolwarm', 'viridis', 'plasma'],
value='RdBu_r',
description='Colormap:')
);
plt.show()Source
fig_1d = plt.figure(figsize=(12, 5))
# Create figure
x = np.linspace(0, 10, 500)
k = 2 * np.pi / wavelength
# Plane wave (constant amplitude)
plane = np.cos(k * x - phase)
# Spherical wave (1/r decay)
x_safe = np.where(x < 0.01, 0.01, x)
spherical = np.cos(k * x - phase) / x_safe
line1, = plt.plot(x, plane, color="#0165fc", linewidth=2, label='Plane Wave')
line2, = plt.plot(x, spherical, 'r-', linewidth=2, label='Spherical Wave (1/r decay)')
line3, = plt.plot(x, 1/x_safe, 'r--', alpha=0.5, linewidth=1, label='1/r envelope')
line4, = plt.plot(x, -1/x_safe, 'r--', alpha=0.5, linewidth=1)
plt.xlabel('Distance from source', fontsize=12)
plt.ylabel('Amplitude', fontsize=12)
plt.title(f'Cross-Section Comparison (wavelength = {wavelength:.2f})', fontsize=13)
plt.grid(True, alpha=0.3)
plt.legend(fontsize=11)
plt.xlim(0, 6)
plt.ylim(-3, 3)
plt.tight_layout()
def plot_cross_section(wavelength=1.0, phase=0.0):
"""
Plot 1D cross-sections of plane and spherical waves.
"""
new_k = 2 * np.pi / wavelength
# Plane wave (constant amplitude)
new_plane = np.cos(new_k * x - phase)
# Spherical wave (1/r decay)
new_spherical = np.cos(new_k * x - phase) / x_safe
line1.set_ydata(new_plane)
line2.set_ydata(new_spherical)
fig_1d.canvas.draw_idle()
# Interactive cross-section plot
interact(plot_cross_section,
wavelength=FloatSlider(min=0.5, max=3.0, step=0.1, value=1.0,
description='Wavelength:',
continuous_update=True),
phase=FloatSlider(min=0, max=2*np.pi, step=0.1, value=0.0,
description='Phase (rad):',
continuous_update=True));
plt.show()Plane Waves, Lasers, and Wavefronts¶
Here we take a brief step back and consider a laser. A laser is a directed coherent beam of light, and is not well described by plane-wave solutions.
We will find later on that the spherical wave representation is extremely useful for describing lasers propogation close to the axis of propogation. The spherical peaks and troughs form what is called a wavefront, a countour of equal phase forming circles around the point source. More will be said when we discuss lasers and the wave equation solutions using the axial approximation.
3.4Poynting Vectors¶
The following is from Griffith’s Chapter 8.1 In your Electrodynamics class, you should have learned that electric and magnetic fields contain and transport energy and momentum.
The energy stored in the field is just the volume integral over the squared fields magnitude:
where is the energy density per unit volume, is the permittivity of free space, is the magnetic permeability of free space, and and are the squared electric and magnetic field magnitudes.
The energy radiated away represents the dynamic energy loss over time from our integrated volume. This is described by the Poynting Vector :
The Poynting vector is an energy density flux, and has units of energy per unit time per unit area, or where is joules and is watts. It can be thought of as a way of quantifying energy exchange between energy stored locally in fields and energy radiated away (or toward) the local volume.
Solution to Exercise 1 #
This solution comes from Griffith’s E&M Section 9.2.3:
From our electric and magnetic field wave equation solutions Eqs. (20) and (23), we focus on the field propogating in the direction, and ignore the phase constant term by setting , letting a magnitude term .
This gives us our nice phasor expressions:
Then the Poynting vector becomes
where we recall the relation in the final line. Note that the Poynting vector value oscillates like , so the value is sometimes zero and sometimes peaks at .
The stored energy in the plane wave relies on and :
so we have
Note again that for a plane wave, the energy stored in the fields oscillates is sometimes exactly zero.
Comparing to Eq. (29) we get the nice relation
In words, this Poynting vector represents the energy transfer of a plane wave through a volume over time. The plane wave can be thought of as propogating through some surface with area at a speed , and the product gives us our volume per unit time. Below is a screenshot from Griffith’s E&M Figure 9.12, illustrating the energy propogation of the plane wave

Intensity¶
The intensity of light is directly related to the Poynting vector . It represents the average power per unit area transfered by the light, and can be found simply by taking the average value of the Poynting vector:
where is the magnitude of the Poynting vector .
As we noted in Exercise 1, the Poynting vector oscillates like for our plane wave solutions, and is sometimes zero and sometimes peaking. The intensity represents the average power transfer over these oscillations.
This is more useful for us, because often relevant electromagnetic oscillations are extremely fast, like in visible lasers with wavelengths on the order of 532 nanometers, the frequency of oscillation is .
Humans cannot yet produce electronics to directly analyze light oscillating this fast, so we are relegated to measuring the light’s power, or intensity integrated over the face of a photodiode.
Radio waves, on the other hand, can often be directly analyzed, like in the movie Contact (see minute 1:59 here).
Solution to Exercise 2 #
The Poynting vector from (29) is
So the intensity becomes
where is the period of one oscillation for our plane wave: .
Here we recall a very convenient integral that we will use very often over this course:
Essentially, this states that the average integral over one cycle of cosine or sine squared is equal to one half. This is related to the root mean square of an average signal, we’ll explore more in depth later.
We can also state another useful integral:
which represents the orthogonality of and over one cycle.
So, for clarity, I like to redefine our integral Eq. (35) over a phase We note that , and that and . Subbing in all of this yields
This is equation 9.63 from Griffith’s E&M, and represents the plane wave intensity.
Radiation Pressure¶
Radiation pressure represents the momentum-transfer from light electric fields to objects the light touches. Pressure is expressed in terms of force per unit area, and so can be simply related to our intensity value , which we recall has units of watts per unit area. Remember that power , so if we assume , and let where is some area, we can write a radiation pressure term:
where is the angle of incidence of the light on the surface .
Often, if an entire laser beam’s power is incident on a surface A, we can divide out that surface and write the radiation pressure force
We note that Equations (40) and (41) are correct for entirely absorbed light. If the light is perfectly reflected, then we get an additional factor of 2 for the momentum change in directions.
3.5Superposition and Interference¶
In a complex world full of electromagnetic waves,
superposition offers a simple way of understanding how to calculate the total electric field.
If I have two sources of electric fields over the same volume ,
then the total electric field is simply their sum:
Destructive Interference¶
Superposition becomes especially useful for calculating the total intensity of two plane-wave electric fields incident upon a photodiode:
There is a non-trivial interaction between the terms in the last line of (43).
If we assume that , then (43) becomes
In this case, some of the expected total intensity is annihilated via destructive interference.
Not all of the intensity we expected was detected on the photodiode, because the component electric fields were out-of-phase.
If we set , then our fields are exactly in-phase and we recover all of the intensity expected.
Beatnote¶
This interference required both to have the same polarization and frequency.
If they had a different frequency and , then we may get an intensity beatnote, where
Beatnotes are crucial tools in the world of interferometry.
Typically, we can use one frequency as a static reference, also known as a local oscillator.
Then, we can use the second frequency as a signal field which acts as a probe, bouncing off some optical element of interest, allowing it to accrue some phase, then combining it back with the local oscillator.
This is known as heterodyne interferometry, and is how your radio works.