Last active
July 25, 2021 23:01
-
-
Save scottstanie/2afd1ad5398c34e6d5e0816247d1e759 to your computer and use it in GitHub Desktop.
Animated aliasing waves
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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