Pixels2GenAI
Path i Foundations
M 02 · 2.3.3 · hands-on

2.3.3 Harmonograph Simulation

Add exponential damping to two perpendicular sinusoids and the Lissajous figures from the previous lesson start to spiral inward — the same effect that gives Victorian harmonographs their characteristic decaying motion.

Duration18–22 min
Levelbeginner-intermediate
Load3 core concepts
Prereqs2.3.1 (Lissajous curves), exponential functions

Overview

A harmonograph is a Victorian drawing machine — two pendulums, one driving the pen along x and the other along y, leaving an ink trace on a sheet of paper [1]. The two pendulums oscillate at slightly different frequencies and lose energy slowly to friction, so the resulting trace is a Lissajous figure that spirals inward as the swings die out. Mathematically you add one factor to the Lissajous equations from 2.3.1 — an exponential decay exp(-d·t) — and the curve picks up that same drift toward the centre. The harmonograph belongs to a pattern you will meet again throughout this module: complex behaviour emerging from two simple oscillations plus a slow dissipation.

Learning objectives

  1. Extend the Lissajous parametric equations with exponential damping exp(-d·t) to model real pendulum decay.
  2. Predict the basic harmonograph pattern from the frequency ratio (the musical interval analogy).
  3. Tune the damping coefficient d to control how fast the pattern spirals into the centre.
  4. Interpolate stroke colour by the decay factor to visualise energy dissipation along the curve.

Quick start — a 3:2 harmonograph

python · quick_start.py
import numpy as np
from PIL import Image, ImageDraw

CANVAS_SIZE = 512
CENTER = CANVAS_SIZE // 2

# Two pendulums — X and Y
FREQ_X, AMP_X, PHASE_X = 3, 200, 0
FREQ_Y, AMP_Y, PHASE_Y = 2, 200, np.pi / 2

DAMPING = 0.002

t = np.linspace(0, 100, 5000)
decay = np.exp(-DAMPING * t)

x = CENTER + AMP_X * np.sin(FREQ_X * t + PHASE_X) * decay
y = CENTER + AMP_Y * np.sin(FREQ_Y * t + PHASE_Y) * decay

image = Image.new('RGB', (CANVAS_SIZE, CANVAS_SIZE), (10, 10, 20))
draw = ImageDraw.Draw(image)
points = list(zip(x.astype(int), y.astype(int)))
draw.line(points, fill=(100, 200, 255), width=1)
image.save('simple_harmonograph.png')
A cyan harmonograph pattern with characteristic interlocking loops, slowly spiraling inward toward the centre of the dark canvas
Fig. 1 A 3:2 harmonograph. Same Lissajous DNA, plus the `exp(-d·t)` decay that creates the inward spiral.

Core concepts

Concept 1 — Two damped pendulums

A pendulum swinging in real air loses a small fraction of its energy each cycle to friction. The textbook model is the damped sinusoid:

x(t) = A · sin(f·t + φ) · exp(-d·t), y(t) = B · sin(g·t + ψ) · exp(-d·t).

A, B are the amplitudes; f, g are the angular frequencies; φ, ψ are the phases; d is the damping coefficient. Without the e^{-dt} factor this is exactly the Lissajous parametric equation from 2.3.1. The exponential multiplier scales both axes uniformly — so the shape of the Lissajous figure stays the same; only its overall size shrinks with time [2].

python · pendulum_demo.py
t = np.linspace(0, 100, 5000)
decay = np.exp(-0.002 * t)        # exponential energy loss

x = 200 * np.sin(3 * t)              * decay
y = 200 * np.sin(2 * t + np.pi/2)    * decay
A three-panel diagram showing the X oscillation as a damped sine wave over time, the Y oscillation as a separate damped sine wave, and the resulting joint X-Y trajectory as an inward-spiraling pattern
Fig. 2 X and Y as separate damped sines on top, the joint trajectory at the bottom. Two simple decays combine into one complex curve.

Concept 2 — Frequency ratios as musical intervals

The character of the pattern is determined almost entirely by the frequency ratio f : g. The match with music is no accident: a 3:2 frequency ratio sounds as a perfect fifth on a piano, and it traces as a three-lobed harmonograph. The Greeks called this correspondence the music of the spheres — small-integer frequency ratios are the same thing whether the medium is air pressure or pen position [1, 3].

RatioVisual patternMusical interval
1:1Circle or ellipseUnison
2:1Figure-8Octave
3:2Three-lobe patternPerfect fifth
4:3Four-lobe patternPerfect fourth
5:4Five-lobe patternMajor third
A two-by-three grid of harmonograph patterns showing frequency ratios from one-to-one to seven-to-five, each producing a distinctly different lobe structure
Fig. 3 Six frequency ratios — same code, six musical intervals visualised as ink on paper.

The simpler the ratio, the simpler the figure. Irrational ratios (say, f = √2) never close — the curve eventually fills its bounding rectangle just like an irrational Lissajous.

Concept 3 — Damping and the inward spiral

The damping coefficient d controls how fast both pendulums lose amplitude. With decay = exp(-d·t):

  • t = 0 → decay = 1.0 (full amplitude).
  • t = 1/d → decay ≈ 0.37 (one e-fold).
  • t = 3/d → decay ≈ 0.05 (essentially at rest).

Three rough regimes for a t = 0..100 sweep:

  • Low damping (d ≈ 0.001) — many loops trace before any visible shrinkage; the pattern fills its bounding rectangle.
  • Medium damping (d ≈ 0.005) — clear spiral inward over the visible sweep; the pattern reads as a Lissajous slowly winding into the centre.
  • High damping (d ≈ 0.01) — the pen reaches the centre well before the time sweep ends; only the first few cycles are visible.

Without damping, the same equations produce a normal (un-spiraling) Lissajous curve, traced indefinitely on top of itself [2].

python · damping_demo.py
for d in [0.001, 0.005, 0.01]:
    decay = np.exp(-d * t)
    # plot — slow / medium / fast spiral inward

Exercises

Three exercises in Execute → Modify → Create order: run a 3:2 harmonograph, swap frequency ratios and damping, then colour-fade the stroke by decay.

EXECUTE I.

Run the 3:2 harmonograph

Run simple_harmonograph.py from the quick start. Inspect the output.

Reflection questions

  • What frequency ratio is in the script, and how is that ratio visible in the picture?
  • Where does the pattern begin (at t = 0) and where does it end?
  • What would happen if PHASE_Y were set to 0 rather than π/2?
MODIFY II.

Three pattern variations

Edit simple_harmonograph.py to produce these three pictures.

Goals

  1. Figure-8 — pick a frequency ratio that traces a figure-8.
  2. Five-lobe — pick a frequency ratio that produces a pattern with five visible lobes.
  3. Faster decay — increase the damping so the pattern collapses to the centre much sooner.
CREATE III.

Colour-fading harmonograph

Render the harmonograph with a stroke that fades from bright cyan to dark blue as the pendulum loses energy. Use the decay factor to drive the colour interpolation.

python · exercise3_starter.py
import numpy as np
from PIL import Image, ImageDraw

CANVAS_SIZE = 512
CENTER = CANVAS_SIZE // 2

START_COLOR = (100, 255, 255)   # bright cyan (full energy)
END_COLOR   = (20, 40, 80)      # dark blue (decayed)

def faded_color(decay_value):
    # TODO 1: interpolate between START_COLOR (decay = 1) and END_COLOR (decay → 0).
    # Result: tuple of three uint8s.
    pass

t = np.linspace(0, 100, 5000)
decay = np.exp(-0.003 * t)
x = CENTER + 200 * np.sin(5 * t) * decay
y = CENTER + 200 * np.sin(4 * t + np.pi / 2) * decay

image = Image.new('RGB', (CANVAS_SIZE, CANVAS_SIZE), (10, 10, 20))
draw = ImageDraw.Draw(image)

# TODO 2: per-segment loop: for each i, colour = faded_color(decay[i]),
# then draw.line from (x[i-1], y[i-1]) to (x[i], y[i]) with that colour.

image.save('colored_harmonograph.png')

Make it your own

  • Three pendulums. Add a third frequency: x = ... + AMP_Z * np.sin(FREQ_Z * t + PHASE_Z) * decay. The visual gains an extra layer of structure.
  • Musical scale. Render six harmonographs side by side with the frequency ratios of the major scale (1:1, 9:8, 5:4, 4:3, 3:2, 5:3, 15:8, 2:1).
  • Animation. Render only the first N points, then N+50, then N+100, … and assemble a GIF. The viewer watches the pendulums lose energy in real time.

Downloads

simple_harmonograph.py — 3:2 quick start harmonograph_variations.py — frequency-ratio panel colored_harmonograph_solution.py — colour-faded reference

Summary

Common pitfalls to avoid

  • Both phases equal — the figure collapses to a diagonal line.
  • Damping too high — the pattern collapses to a single point before any structure is traced.
  • Damping zero — the curve traces the same Lissajous indefinitely on top of itself, no inward spiral.
  • Too few sample points — high frequency ratios alias. 5000 points covers ratios up to about 7:5 cleanly.

References

  1. [1] Ashton, A. (2003). Harmonograph: A Visual Guide to the Mathematics of Music (2nd ed.). Walker & Company.
  2. [2] Cundy, H. M., & Rollett, A. P. (1961). Mathematical Models (2nd ed.). Oxford University Press.
  3. [3] Klemens, B. (2010). The harmonograph. Make Magazine, 23, 124–127.
  4. [4] Weisstein, E. W. (2024). Lissajous curve. MathWorld — A Wolfram Web Resource. mathworld.wolfram.com/LissajousCurve
  5. [5] NumPy Community. (2024). numpy.exp. NumPy Documentation. numpy.org
  6. [6] Pearson, M. (2011). Generative Art: A Practical Guide Using Processing. Manning.
  7. [7] Foley, J. D., van Dam, A., Feiner, S. K., & Hughes, J. F. (1990). Computer Graphics: Principles and Practice (2nd ed.). Addison-Wesley.