Note
Click here to download the full example code
Reflections¶
Reflections and focal points for different mirror geometries.

import numpy as np
import matplotlib.pyplot as plt
def reflect(x, surface):
# note: this assumes concave-up surface
h = 1e-3
dy = surface(x+h) - surface(x-h)
dx = 2*h
normal = np.array([-dy, dx])
normal /= np.linalg.norm(normal)
incident = np.array([0, -1])
reflected = incident - 2 * np.dot(incident, normal) * normal
return reflected
def plot_surface(surface_fn, xlim=(-1, 1), ax=None):
if ax is None:
_, ax = plt.subplots()
# plot surface curve
x = np.linspace(-1.09, 1.09, 100)
y = surface_fn(x)
ax.plot(x, y)
# plot rays
for x in np.linspace(xlim[0], xlim[1], 50):
reflected = reflect(x, surface_fn)
reflected *= -x / reflected[0] # scale so reflected vector ends at x=0
y = surface_fn(x)
kwargs = dict(c='r', lw=1, alpha=0.1)
ax.plot([x, x], [2.0, y], **kwargs) # incident ray
ax.plot([x, x+reflected[0]], [y, y+reflected[1]], **kwargs) # reflected ray
ax.axis('square')
functions = {
# parabolic mirror -- unique focal point
'parabolic': lambda x: x**2,
# circular mirror -- abberation as collimation width approaches mirror diameter
'circular': lambda x: 1 - (1.1**2 - x**2)**0.5,
# corner retroreflector -- no focus
'corner': lambda x: abs(x)
}
bounds = [(-0.2, 0.2), (-0.5, 0.5), (-0.9, 0.9)]
fig, axes = plt.subplots(len(bounds), len(functions), sharex=True, sharey=True, figsize=(9, 9))
for i, (label, function) in enumerate(functions.items()):
axes[0, i].set_title(label)
for (lo, hi), ax in zip(bounds, axes[:, i]):
plot_surface(function, (lo, hi), ax)
fig.tight_layout()
Total running time of the script: ( 0 minutes 2.011 seconds)