Skip to content

Instantly share code, notes, and snippets.

@scottstanie
Last active July 25, 2021 23:01
Show Gist options
  • Save scottstanie/2afd1ad5398c34e6d5e0816247d1e759 to your computer and use it in GitHub Desktop.
Save scottstanie/2afd1ad5398c34e6d5e0816247d1e759 to your computer and use it in GitHub Desktop.
Animated aliasing waves
import numpy as np
import matplotlib.pyplot as plt
# Knobs to twiddle:
# 1. sine frequencies: `f1`, `f2`
# 2. spacing between vectical bars: `rect_spacing`
# (You can also change `rect_width`, but the frequency/spacing are more interesting)
f1 = 7.5 # Twiddle with the red sine frequency!
f2 = 7.0 # Slightly different frequency
xx = np.linspace(0, 5, 500)
# Make 2 sine waves, offset vertically, with different frequencies
A = 0.5 # Make it about half the height of the plot
y1 = A * np.sin(2 * np.pi * f1 * xx) + 1.2 * A
y2 = A * np.sin(2 * np.pi * f2 * xx) - 1.2 * A
fig, ax = plt.subplots(1, 1, figsize=(8, 4))
# Plot the red sine waves
ax.plot(xx, y1, "r", lw=2)
ax.plot(xx, y2, "r", lw=2)
rect_spacing = 0.16
num_rects = 20
x_rects = np.arange(0, num_rects * rect_spacing, rect_spacing)
rect_width = 11 # Possible knob to twiddle, but only values ~10-13 seem interesting
height = 1.5
# zorder makes sure the these are on top of the sine wave lines
rects = ax.vlines(x_rects, -height, height, lw=rect_width, color="k", zorder=5)
ymax = 0.8 * height
xmax = 5
ax.set_ylim((-ymax, ymax))
ax.set_xlim((0, xmax))
ax.set_axis_off()
# Get the [(x, y), ...] positions of the vectical rectangles
segments = rects.get_segments()
# For interactive version with a slider, which works in jupyter notebooks
# import ipywidgets
# xstart = 0
# @ipywidgets.interact(xstart=(xx[0]-2, xx[-1], rect_spacing/10))
# def move_rects(xstart=-2):
# global segments
# rects.set_paths([np.array([xstart, 0]) + a for a in segments])
# For saved animation:
from matplotlib.animation import FuncAnimation
def init():
ax.set_ylim((-ymax, ymax))
ax.set_xlim((0, xmax))
return (rects,)
# Receives the value from the `frames` iterable
def update(x_start):
# move the `segments` slightly to the right by adding `frame` to the x values
rects.set_paths([np.array([x_start, 0]) + a for a in segments])
return (rects,)
interval_ms = 100
x_start_positions = np.linspace(-2, 3, 200)
ani = FuncAnimation(
fig,
update,
frames=x_start_positions,
init_func=init,
blit=True,
interval=interval_ms,
);
# Save as a gif, noting what frequency was used
ani.save(f"aliasing_freqs_{f1}_{f2}_width_{rect_width}_dx_{rect_spacing}.gif");
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment