Phyein Usul← All simulations

Fig. 8 · Fourier analysis · discrete Fourier transform

Draw & Decompose.

Draw any closed shape with one stroke. Its Fourier transform turns it into a list of spinning circles, and the circles, chained tip to tail, draw it back.

Fig. 8a · \(z(t) = \sum_k c_k\, e^{ikt}\) · draw a shape —
Fig. 8b · amplitude spectrum \(|c_k|\), \(-60 \le k \le 60\) · burgundy = terms in use —

Lecture note · Fig. 8 · Fourier analysis

Drawing with circles: the Fourier series of a closed curve

Numa Koudsie · for school students and first- and second-year undergraduates

Abstract. Any closed curve you can draw is the path of a pen carried by a chain of circles, each turning a whole number of times per loop. This note writes the curve as a periodic complex function, finds the circles by averaging (the Fourier coefficients), replaces the average by a sum over 256 points (the discrete Fourier transform), and uses Parseval’s theorem to say exactly how much of the shape is lost when only the K largest circles are kept, which is why the page sorts them by size. It then shows why corners cost many circles and smooth curves few, and how the page turns a pen stroke into numbers and pixels. Sections marked ★ carry the heavier mathematics and can be skipped on a first reading without losing the thread.

01A drawing made of circles

Animations in which a chain of spinning circles draws a portrait, a signature or the outline of a country are shared widely online. Each circle turns at a steady rate, carried on the rim of the one before it, and the last one holds a pen. The figure above makes such a chain for any shape you draw.

The idea is older than it looks. A music equaliser splits a sound into frequency bands and gives each band its own slider; a sound is a sum of steady tones, and the sliders set how loud each tone is. JPEG pictures and MP3 songs go one step further. They store a picture or a sound as a list of frequency components and round the small ones away, because the eye and the ear hardly miss them, and the file becomes much smaller. The Circles K slider of this page is the same move applied to a drawing: it keeps the K largest circles and silences the rest.

A physical picture helps. Bend a thin wire of uniform density into the shape you drew and slide a bead around it at constant speed, once per loop. The bead’s motion is periodic, and any periodic motion is a sum of harmonics, like the overtones of a plucked string. In the plane each harmonic is a uniform circular motion that turns a whole number of times per loop, anticlockwise or clockwise. The page finds those circles and chains them tip to tail (Figure 1), so the last tip rides the wire again. This is Fig. 7 run backwards: there the circles are given and the shape follows; here the shape is given and the circles follow.

Most of a shape lives in a few slow, large circles: the two circles that turn once per loop, one each way, already draw an ellipse of roughly the right size and tilt. Faster, smaller circles add corners and wiggles. Fig. 8b lists the circle radii, and the K slider decides how many are kept. The description is kinematics, not dynamics. No force makes the bead move this way; the circles describe the motion completely without explaining it. That is also why Ptolemy’s epicycles, circles riding on circles, could follow the planets so well without being the right physics.

Re z Im z θ1 |ck1| z(t) each arm turns at its own rate arm 1 k1 = 1 one turn per loop, anticlockwise arm 2 k2 = −2 two turns per loop, clockwise arm 3 k3 = 4 four turns per loop, anticlockwise angle of arm j at time t θj = kj t + arg ckj the pen is the sum of the arms z(t) = Σj ckj ei kj t
Figure 1Three circles chained tip to tail (a schematic, not one of the presets). The first circle is centred on the origin, and each later circle is centred on the tip of the arm before it. Arm \(j\) has length \(|c_{k_j}|\) and makes \(k_j\) turns per loop; its angle is \(\theta_j\). The pen at the last tip traces the burgundy curve. With \(k = 1, -2, 4\), after a third of a loop the whole chain has the same shape turned through \(120^\circ\), so the curve has three-fold symmetry.

02The model

We keep only the shape of the drawing and ask for the motion of a bead that runs once around it at constant speed. Put the drawing in the complex plane, \(z = x + iy\), with \(x\) to the right, \(y\) up and \(i^2 = -1\). Let \(s\) be the distance travelled along the curve from its start and \(L\) its total length, and use the loop parameter \(t = 2\pi s/L\), which runs from \(0\) to \(2\pi\) once around. Here \(t\) is not a clock: the animation plays one loop in \(T_\text{loop}\) seconds, set by the Time per loop slider (\(12\ \mathrm{s}\) by default). A closed curve is then a \(2\pi\)-periodic function, and any such function whose squared size has a finite average has a Fourier series, which approaches it in the mean-square sense as more terms are added:

\[ z(t) = \sum_{k=-\infty}^{\infty} c_k\, e^{ikt}, \qquad z(t + 2\pi) = z(t) . \tag{1} \]

The integer \(k\) counts whole turns per loop. Each term is a phasor exactly as in Fig. 7: writing the complex number \(c_k = |c_k|\,e^{i\arg c_k}\), the term \(c_k e^{ikt} = |c_k|\,e^{i(kt + \arg c_k)}\) is an arrow of length \(|c_k|\) that starts at angle \(\arg c_k\) and turns \(k\) times per loop, anticlockwise for \(k > 0\) and clockwise for \(k < 0\). For a real signal, such as the air pressure of a sound, \(c_{-k}\) is the complex conjugate of \(c_k\) and the two counter-rotating arrows pair up into an oscillation along a line. A curve in the plane is complex, so here \(c_{-k}\) and \(c_k\) are independent: clockwise and anticlockwise circles are separate pieces of information, and both are needed.

The term with \(k = 0\) does not turn at all: \(c_0\) is the average of \(z\) over one loop. Because equal steps of \(t\) are equal lengths of wire, and so equal masses, \(c_0\) is the centre of mass of the wire. The page subtracts the finite sample mean. That approximates the uniform wire’s centre of mass; its resampling repeats the endpoint (section 7.1), so the equivalence is not exact. The centred sample mean is zero. Figure 2 shows both steps on a real stroke: the even spacing that makes \(t\) proportional to distance, and the centring.

as drawn: uneven spacing start end z0 zN−1 zn Δs centre, the mean closing step resampled: equal steps along the stroke
Figure 2Left: a closed stroke as the pointer records it; the points bunch where the hand slowed down. Right: the same stroke resampled at \(N\) points a distance \(\Delta s\) apart along it (\(N = 16\) here so they can be told apart; the page uses \(N = 256\)), computed with the page’s own resampling routine. The cross is the mean of the samples, an approximation to the centre of mass of a uniform wire of this shape, and the arrow from it is one centred sample \(z_n\). A hand-drawn stroke rarely closes exactly, so the series has to step from \(z_{N-1}\) back to \(z_0\) (dashed).

03Each circle is an average

Stand at the centre of a roundabout that turns with one of the circles, \(k\) times per loop. That circle’s arrow stands still in front of you. Every other arrow turns relative to you a whole number of times per loop, points in every direction equally often, and averages to nothing. In symbols, multiplying by \(e^{-ikt}\) turns the picture backwards at rate \(k\), and the exponentials are orthogonal over one loop:

\[ \frac{1}{2\pi}\int_0^{2\pi} e^{ijt}\, e^{-ikt}\,\mathrm{d}t = \delta_{jk} = \begin{cases} 1, & j = k, \\ 0, & j \ne k . \end{cases} \tag{2} \]

For \(j \ne k\) the integrand \(e^{i(j-k)t}\) goes round the unit circle \(|j-k|\) times and its average vanishes. Multiply the series (1) by \(e^{-ikt}\), average over one loop and use (2) term by term: only \(c_k\) survives.

\[ c_k = \frac{1}{2\pi}\int_0^{2\pi} z(t)\, e^{-ikt}\,\mathrm{d}t . \tag{3} \]

Each coefficient is therefore computed on its own, from the curve alone, without knowing any of the others. Adding a circle never changes the circles already found. That property is what makes the K slider cheap: changing K only decides how many of a fixed list are drawn.

04From an integral to 256 samples★

A computer cannot integrate a hand-drawn curve, but it can add up samples. The page takes \(N = 256\) samples \(z_n = z(t_n)\) at equal steps \(t_n = 2\pi n/N\), \(n = 0, 1, \dots, N-1\) (very nearly: the page spaces them \(L/(N-1)\) apart along the stroke, so that the last repeats the first, Section 7.1), and replaces the integral (3) by a sum, the discrete Fourier transform normalised by \(1/N\):

\[ c_k \approx \frac{1}{N}\sum_{n=0}^{N-1} z_n\, e^{-2\pi i k n/N} . \tag{4} \]

Keep the two meanings separate. The integral coefficient in (3) describes the continuous parametrised curve. The finite sum in (4) is an exact orthogonal-coordinate calculation for the sampled sequence, apart from rounding, and only an approximation to the integral coefficient. In the discrete reconstruction and error formulas, \(c_k\) means this computed coefficient; the alias identity (6) explicitly compares the finite sum with the continuum coefficients.

4.1Orthogonality on the samples is exact

The sum (4) is more than an approximation. On the sample points, the exponentials are orthogonal without any error. Put \(w = e^{2\pi i (j-k)/N}\), so that \(w^N = 1\). If \(j - k\) is not a multiple of \(N\), then \(w \ne 1\) and the finite geometric series gives

\[ \frac{1}{N}\sum_{n=0}^{N-1} e^{2\pi i (j-k) n/N} = \frac{1}{N}\sum_{n=0}^{N-1} w^n = \frac{1}{N}\,\frac{1 - w^N}{1 - w} = 0 . \tag{5} \]

The picture is the one of Fig. 7: \(N\) unit arrows, equally spaced in angle, close into a regular polygon and add to zero. So keeping all \(N\) coefficients of \(N\) neighbouring frequencies reproduces every sample exactly, \(z_n = \sum_k c_k\, e^{2\pi i k n/N}\). To see it, put (4) in for each \(c_k\): the sum over the \(N\) frequencies is the same geometric series as (5), with \(k\) and \(n\) trading places, and it wipes out every sample except \(z_n\) itself.

4.2Aliasing: only N frequencies exist on N samples

Since \(e^{2\pi i (k+N) n/N} = e^{2\pi i k n/N}\) for every whole \(n\), a circle that turns \(k + N\) times per loop passes through the same sample points as one that turns \(k\) times. The sum (4) cannot tell them apart and returns their total. Substituting (1) into (4) and using (5),

\[ \frac{1}{N}\sum_{n=0}^{N-1} z_n\, e^{-2\pi i k n/N} = \sum_{m=-\infty}^{\infty} c_{k + mN} = c_k + c_{k+256} + c_{k-256} + \dots \tag{6} \]

The page uses only \(-60 \le k \le 60\), below \(N/2 = 128\), so every computed coefficient is one true coefficient plus small aliases. Where it matters they are negligible: compared with a transform of \(65\,536\) samples, the aliases change the radii of the heart’s three largest circles by less than \(0.1\,\%\). Near \(|k| = 60\) they change the heart’s radii by about \(20\,\%\) and the open wave’s by \(10\,\%\), but those circles are tiny.

4.3The sum the page computes

Write \(z_n = x_n + i y_n\) and \(a_n = 2\pi k n/N\). Since \(e^{-ia} = \cos a - i\sin a\), the real and imaginary parts of (4) are

\[ \begin{aligned} \operatorname{Re} c_k &= \frac{1}{N}\sum_{n} \left( x_n\cos a_n + y_n\sin a_n \right), \\ \operatorname{Im} c_k &= \frac{1}{N}\sum_{n} \left( y_n\cos a_n - x_n\sin a_n \right), \end{aligned} \tag{7} \]

and these two lines are exactly what the page’s dft() adds up. For 120 frequencies and 256 samples that is \(30\,720\) complex products, done once per shape. A fast Fourier transform would be quicker for large \(N\), but at this size the direct sum is fast and easier to read: in headless Chromium on our test machine it took about \(1\ \mathrm{ms}\), and the whole decomposition of a shape about \(8\ \mathrm{ms}\).

05Parseval’s theorem and the error

Now the central quantity of the page: how far the redrawn curve lies from the drawing when only some circles are kept. Two facts from Section 4 carry it, and both can be taken on trust: the coefficients (4) of \(N\) neighbouring frequencies redraw the \(N\) samples exactly, \(z_n = \sum_k c_k\,e^{2\pi i k n/N}\) (the page computes 120 of them, \(|k| \le 60\)); and on the samples two different frequencies among those \(N\) average to zero, \(\tfrac1N\sum_n e^{2\pi i (j-k) n/N} = 0\), which is equation (5), the sampled twin of (2). Square the discrete series, \(|z_n|^2 = z_n z_n^{*} = \sum_j\sum_k c_j c_k^{*}\, e^{2\pi i (j-k) n/N}\), where the star is the complex conjugate, and average over the samples. By (5) every cross term with \(j \ne k\) averages to zero, leaving Parseval’s theorem:

\[ \langle |z|^2 \rangle \equiv \frac{1}{N}\sum_{n=0}^{N-1} |z_n|^2 = \sum_{k} |c_k|^2 , \tag{8} \]

the sum running over \(N\) neighbouring frequencies. The left side is the mean squared distance of the samples from the centre. For equal point masses placed at the centred sample positions, it is exactly their moment of inertia divided by total mass, \(I/m\). It approximates the same quantity for a uniform wire; the repeated endpoint prevents exact equal-arc-length sampling of the closed loop. Parseval says that each circle carries the share \(|c_k|^2\) of it, with no cross terms. The same bookkeeping is called energy in acoustics and optics, where \(|c_k|^2\) is the power carried by one frequency, and that is why the error below is often called the dropped energy.

Keep only a set \(S\) of \(K\) circles and call the redrawn samples \(\tilde z_n = \sum_{k\in S} c_k\, e^{2\pi i k n/N}\). The difference \(z_n - \tilde z_n\) is the sum of the dropped circles, so (8) applied to it gives the root-mean-square (RMS) error at the samples:

\[ e_K^2 \equiv \frac{1}{N}\sum_{n=0}^{N-1} |z_n - \tilde z_n|^2 = \sum_{k \notin S} |c_k|^2 = \langle |z|^2 \rangle - \sum_{k\in S} |c_k|^2 . \tag{9} \]
Keep the largest circles

By (9), the squared error is the sum of the squared radii you drop. To make it as small as possible with \(K\) circles, drop the smallest ones: keep the \(K\) largest \(|c_k|\). Within the 120 nonzero-frequency components computed by the page, no other choice of \(K\) circles comes closer to the samples in the least-squares sense. This is not a search over all 256 DFT bins. That is why the page sorts the circles by radius, and the same idea lies behind JPEG and MP3.

The RMS compares corresponding samples: sample \(n\) with the reconstruction at the same parameter value. It does not measure the shortest distance between two outlines, and it says nothing about the curve between the samples.

The panel shows this result twice. RMS error is measured sample by sample from the redrawn curve, and … by Parseval is the right side of (9). Over every \(K\) from 1 to 120 they agree to within \(3\) parts in \(10^{10}\) for the default heart (measured in the page itself); the remaining difference comes from subtracting two nearly equal numbers in (9). The readout \(\langle |z|^2\rangle\) kept is the share \(\sum_{k\in S}|c_k|^2 / \langle |z|^2\rangle\), and the relative error follows from it with a square root:

\[ \frac{e_K}{\sqrt{\langle |z|^2\rangle}} = \sqrt{1 - \frac{\sum_{k\in S}|c_k|^2}{\langle |z|^2\rangle}} . \tag{10} \]

The square root matters. For the heart a single circle (\(k = -1\): the preset is traced clockwise) keeps \(94.3\,\%\) of \(\langle |z|^2\rangle\), yet the relative error is \(\sqrt{0.057} = 24\,\%\). At the default \(K = 24\) the panel reads \(99.99\,\%\) kept and an RMS error of \(0.00541\), which is still \(0.75\,\%\) of the heart’s RMS size \(\sqrt{0.5150} = 0.718\). Figure 3 follows the relative error over every K, and Figure 4 shows what it looks like.

10⁻⁴ 10⁻³ 10⁻² 10⁻¹ 10⁰ 0 20 40 60 80 100 120 circles kept K relative RMS error K = 24, the page’s default Heart (the default drawing) Square
Figure 3Relative RMS error (10) against the number of circles kept, for the page’s Heart and Square presets, computed for every K from 1 to 120 with a Python transcription of the page’s own steps: 256 samples at equal arc length, centred, \(-60 \le k \le 60\), sorted by \(|c_k|\). For the heart the error falls from \(24\,\%\) at \(K = 1\) to \(2.9\,\%\) at \(K = 10\), \(0.75\,\%\) at \(K = 24\) and \(0.23\,\%\) at \(K = 50\), roughly as \(K^{-3/2}\) in the middle. Beyond \(K \approx 80\) both curves flatten near \(10^{-3}\): the circles still left to add are tiny, and what is missing lies beyond \(|k| = 60\), where the page computes nothing.
−1.00 −0.50 0 0.50 1.00 −1.00 −0.50 0 0.50 1.00 Re z Im z samples K = 3 K = 10 K = 50
−1.00 −0.50 0 0.50 1.00 −1.00 −0.50 0 0.50 1.00 Re z Im z samples K = 3 K = 10 K = 50
Figure 4The heart and the square redrawn with their \(K = 3\), \(10\) and \(50\) largest circles, 601 points per loop as the Full K-term curve switch draws them, over the 256 centred samples (dashed). With three circles the heart has only a shallow dip where the notch should be and a rounded bottom; with ten the notch and the point appear; with fifty the curve covers the samples at this scale. The square, whose circles all sit at every fourth frequency, reaches a given error down to about \(10^{-3}\) with fewer circles than the heart (Figure 3), but its corners stay rounded: at \(K = 10\) the curve passes \(0.019\) to \(0.022\) units inside each corner.
Exercise 5.1 · on the figure above

Press Square and set Circles K to 1. The panel reads \(98.52\,\%\) kept and an RMS error of \(0.09831\). Check (10): divide \(0.09831\) by \(\sqrt{0.6546} = 0.8091\), the RMS size of this square, square the result and subtract it from 1; you get back the kept share, \(0.9852\). Now set K to 4: in Fig. 8b only every fourth bar is burgundy, at \(k = 1, -3, 5, -7\), because a square traced at constant speed looks the same after a quarter of a loop turned by a right angle, \(z(t + \pi/2) = i\,z(t)\), and by (3) only frequencies with \(e^{ik\pi/2} = i\), that is \(k = 1 - 4m\), survive this symmetry. Compare the two error readouts at every K you try.

06Corners cost circles★

Figure 3 shows that some shapes need many more circles than others. The reason is how fast the radii \(|c_k|\) fall as \(k\) grows, and that is set by how smooth the curve is. Integrate (3) by parts. The boundary term vanishes because \(z\) is periodic, and the derivative \(\dot z = \mathrm{d}z/\mathrm{d}t\) is the bead’s velocity:

\[ c_k = \frac{1}{ik}\,\frac{1}{2\pi}\int_0^{2\pi} \dot z(t)\, e^{-ikt}\,\mathrm{d}t . \tag{11} \]

Each time the curve can be differentiated once more without a jump, integration by parts can be repeated and another factor \(1/k\) appears. The bead moves at constant speed \(v = L/2\pi\) per unit of \(t\). At a corner its velocity jumps: it keeps its speed but changes direction at once. If the velocity jumps by \(\Delta\dot z_j\) at the loop positions \(t_j\), a second integration by parts of (11) gives

\[ c_k \approx -\frac{1}{2\pi k^2}\sum_j \Delta\dot z_j\, e^{-ikt_j} , \tag{12} \]

with equality for a polygon, whose velocity is constant between corners. If instead the position itself jumps by \(\Delta z\), as it does where the series closes an open stroke, one integration by parts is enough and

\[ |c_k| \approx \frac{|\Delta z|}{2\pi |k|} . \tag{13} \]

6.1Square, heart and open wave

The Square preset has side \(1.4\) and length \(L = 5.6\). At each of its four corners the velocity turns through a right angle, \(|\Delta\dot z_j| = \sqrt2\,v\). The corners sit a quarter loop apart, \(t_j = j\pi/2\), and each jump is the one before turned by a right angle, \(\Delta\dot z_j = i^j\,\Delta\dot z_0\), so term \(j\) of (12) is \(\Delta\dot z_0\,(i\,e^{-ik\pi/2})^j\). For \(k = 1 - 4m\) the bracket is \(1\): the four terms point the same way and add. For every other \(k\) it is \(-1\) or \(\pm i\), and the four terms close up and cancel, like the arrows of (5). So

\[ |c_k| = \frac{4\sqrt2\, v}{2\pi k^2} = \frac{\sqrt2\, L}{\pi^2 k^2} = \frac{0.802}{k^2}, \qquad k = 1, -3, 5, -7, \dots \tag{14} \]

exact even for \(k = 1\). The page finds \(0.803\), \(0.0903\) and \(0.0317\) for \(k = 1, -3, 5\), against \(0.802\), \(0.0892\) and \(0.0321\) from (14); the scatter of about one per cent has a cause described in section 7.

The Heart preset looks smooth but is not. At the notch and at the point, both derivatives of its parametric formula vanish, and the curve has a cusp: the bead arrives moving straight down and leaves moving straight up, so its velocity jumps by \(2v\). The two cusps sit half a loop apart, at \(t = 0\) and \(t = \pi\). By (12) their contributions add for even \(k\), giving \(|c_k| \approx 4v/(2\pi k^2) = L/(\pi^2 k^2) = 0.550/k^2\) with \(L = 5.428\), and cancel at leading order for odd \(k\). The page’s radii agree: \(k^2|c_k| = 0.550\), \(0.552\) and \(0.544\) for \(k = 10\), \(20\) and \(30\). Radii falling as \(1/k^2\) leave a tail \(\sum_{|k| > K/2} |c_k|^2\) that shrinks as \(K^{-3}\), hence the error \(e_K \propto K^{-3/2}\) seen for the heart in Figure 3.

The Open wave preset is not closed: it ends \(1.7\) units from where it starts, and the series must jump back. By (13), \(|c_k| \approx 1.7/(2\pi|k|) = 0.271/|k|\); the page finds \(|k|\,|c_k| = 0.271\) at \(k = 10\). The tail now shrinks only as \(K^{-1}\), so the error falls as \(K^{-1/2}\): \(20\,\%\) at \(K = 24\), \(14\,\%\) at \(K = 50\) and still \(8.4\,\%\) at \(K = 120\). A smooth closed curve, such as the Figure eight, has every derivative continuous, and its radii fall faster than any power of \(k\). Computed from the shape itself, without the sampling detail of section 7, its largest radius is \(0.40\) at \(k = \pm1\), and \(|c_k|\) is \(5.8\times10^{-4}\) at \(k = 10\), \(8.1\times10^{-5}\) at \(20\), \(1.0\times10^{-5}\) at \(30\) and \(1.3\times10^{-6}\) at \(40\): seven to nine times smaller for every ten steps in \(k\). Figure 5 shows the three behaviours side by side, as the page computes them.

10⁻⁵ 10⁻⁴ 10⁻³ 10⁻² 10⁻¹ 10⁰ 10¹ 0 10 20 30 40 50 60 |k|, turns per loop radius of the circle (larger of ±k) Open wave, all k Heart, even k Square, k = 1 − 4m Figure eight |Δz| / 2π|k| √2 L / π2k2
Figure 5Radius \(|c_k|\) against \(|k|\), the larger of \(c_k\) and \(c_{-k}\), computed with the page’s algorithm for four presets. For the heart only even \(k\) are shown and for the square only \(k = 1 - 4m\), the frequencies (12) singles out. Dotted: the predictions (13) for the open wave and (14) for the square. The open wave falls as \(1/|k|\), the heart and the square as \(1/k^2\); the smooth figure eight falls much faster until it meets a floor near \(10^{-4}\) that comes from the sampling, not from the shape (section 7).

6.2Overshoot near corners and jumps

Near a corner or a jump the truncated series does not settle on the curve; it rings. At a corner the ringing is small: for the square at \(K = 10\) the curve crosses the line of a side by at most \(0.010\) units, close to a corner, and at \(K = 50\) by \(0.0038\). At a jump it is large and stubborn. With the Open wave at \(K = 24\), \(50\) and \(120\) the redrawn curve shoots past each end of the wave by \(5.9\,\%\), \(7.9\,\%\) and \(9.5\,\%\) of the \(1.7\)-unit jump. Adding circles makes the overshoot narrower, not smaller; for a jump the classical limit is about \(9\,\%\) (the Gibbs phenomenon).

Exercise 6.1 · on the figure above

Press Open wave, switch on Full K-term curve and move Circles K from 24 to 120. Watch the pink curve at the two ends of the wave: the overshoot grows to about \(0.16\) units and crowds closer to the ends. Then press Heart and step through \(K = 3\), \(10\) and \(50\), and compare with Figure 4.

07What the page computes

Everything above becomes five steps, run once each time a shape is decomposed, plus one cheap step per frame.

  • Resample at equal arc length. The raw stroke is unevenly spaced, because you draw faster in some places (Figure 2). The page adds up the lengths of the stroke’s straight pieces, \(s_i = \sum_{j \le i} |p_j - p_{j-1}|\) for the stroke points \(p_j\), takes the total length \(L\) and the spacing \(\Delta s = L/(N-1)\), and places sample \(n\) at distance \(n\,\Delta s\) along the stroke by linear interpolation, for \(n = 0, \dots, 255\). Equal arc length means the pen moves at constant speed, so \(t\) is proportional to distance travelled.
  • Centre. The mean of the samples is subtracted, so \(c_0 = 0\) and the shape is drawn about the centre of the figure. The page stores \(\langle |z|^2\rangle\) at this point.
  • Transform. The sums (7) for every \(k\) from \(-60\) to \(60\) except \(0\): 120 coefficients.
  • Sort. The coefficients are sorted by \(|c_k|\), largest first. The first K are used, and the largest circle sits at the centre of the chain.
  • Rebuild whenever K changes: the kept share, the error by Parseval (9), the error measured at the 256 samples, and 601 points of the K-term curve.

Every frame the loop parameter advances and the chain is evaluated in closed form,

\[ t \leftarrow t + \frac{2\pi\,\Delta t}{T_\text{loop}}, \qquad z(t) = \sum_{\text{rank} < K} |c_k|\, e^{i(kt + \arg c_k)} , \tag{15} \]

with \(\Delta t\) the real time since the last frame, at most \(0.05\ \mathrm{s}\). The partial sums of (15) are the joints of the chain, and the last one is the pen. There is no integration and therefore no accumulated error: after every loop the pen returns to the same place.

7.1Accuracy

An independent Python transcription of these steps reproduces the page’s stored numbers to the last digit or two of double precision: for the default heart, \(\langle |z|^2\rangle = 0.515044672459522\) and, at \(K = 24\), \(e_K = 0.005405966670666\) in both. The two error readouts agree as described in section 5.

One detail of the resampling leaves a visible mark. The first and last samples are the two ends of the stroke, and the presets close exactly, so for them \(z_{255}\) lands on \(z_0\): one of the 256 steps around the loop has zero length, as if the bead paused there. Like any jump in the parametrisation, this one-step pause adds radii that fall only as \(1/|k|\), of about \(\Delta s/(2\pi|k|)\). For the figure eight, with \(\Delta s = 0.0203\), that estimate gives \(5.4\times10^{-5}\) at \(|k| = 60\), and the page finds \(5.9\times10^{-5}\): the floor in Figure 5. The pause also breaks the square’s four-fold symmetry slightly, giving frequencies such as \(k = 2\) and \(k = -1\), which should be absent, radii of \(2.5\times10^{-3}\), and it is the cause of the one-per-cent scatter noted under (14). A hand-drawn stroke rarely closes, and the gap you leave between its end and its start plays the same role: by (13), a gap of length \(g\) adds radii of about \(g/(2\pi|k|)\). Sampling the loop at spacing \(L/N\) without repeating the start point would remove the floor: for the figure eight our computation gives a relative error at \(K = 120\) of \(1.5\times10^{-6}\) instead of \(8.4\times10^{-4}\).

08From units to pixels

The drawing is stored in scale-free units: one unit is \(0.46\) of the shorter side of the figure, with the origin at its centre and \(y\) pointing up, so resizing the window never distorts a shape. While you draw, a pointer position closer than \(0.006\) units to the previous one is skipped.

After decomposition the page finds the outermost point drawn over a whole loop, \(R\): the distance of each circle’s centre (a joint of the chain) from the origin plus its radius, over all circles in use at 256 instants around the loop, or the distance of any point of your centred drawing, whichever is larger. The view is then scaled so that

\[ \text{pixels per unit} = \frac{0.46\,\min(w, h)}{\max(1,\ R_\text{view})}\times\text{zoom} , \tag{16} \]

where \(w\) and \(h\) are the width and height of the figure in pixels and \(R_\text{view}\) follows \(R\): it jumps up at once when \(R\) grows and relaxes down with a time constant of \(0.4\ \mathrm{s}\) when you lower K. At zoom \(1\times\) nothing leaves the figure. The Zoom slider, the mouse wheel or a pinch set zoom from \(1\times\) to \(10^{1.8} \approx 63\times\), and dragging pans the view; Follow the pen keeps the tip of the chain at the centre, so the smallest circles stay in sight while they turn. Zoom and pan change only the view, never the coefficients.

The traced reconstruction is burgundy and fades over the last loop, in 24 segments whose opacity rises from \(0.16\) to \(1\). Your drawing shows the 256 centred samples joined by a dashed ink line, Component circles draws each circle in rose, and Tip-to-tail vectors draws the arms in four alternating colours, the first twelve numbered by rank. Full K-term curve adds the 601-point curve in pink. In Fig. 8b each stem is \(|c_k|\) divided by the largest radius, placed at its \(k\) from \(-60\) to \(60\), burgundy if the circle is among the K in use and tan if not.

09What the model leaves out

  • Only \(|k| \le 60\) is computed, so even \(K = 120\) is not exact. The \(\langle |z|^2\rangle\) kept readout tells you how much is missing; for the heart at \(K = 120\) the relative error is still \(0.068\,\%\).
  • The error is measured at the 256 samples. Between them a truncated series can overshoot, most visibly next to corners and jumps (section 6.2).
  • The series always closes the stroke. An open stroke is closed with a straight jump from its end to its start, and the ringing there narrows as K grows but does not shrink.
  • Arc-length resampling cuts corners by at most one sample spacing, \(\Delta s = L/255\); for the heart that is \(0.021\) units.
  • Constant speed is a choice. The same shape traced at a different pace, for example with the timing of your own hand, would give a different set of circles. The page’s choice makes \(\langle |z|^2\rangle\) very nearly the moment of inertia per unit mass of a uniform wire and makes the circles depend on the shape alone.
  • The circles describe the motion; they do not explain it. A Fourier series fits any periodic path, which is why fitting one proves nothing about the forces behind it.

9.1Further reading

  1. M. L. Boas, Mathematical Methods in the Physical Sciences, 3rd edition, Wiley, 2006: chapter 7, Fourier series and transforms, including Parseval’s theorem.
  2. E. Kreyszig, Advanced Engineering Mathematics, 10th edition, Wiley, 2011: chapter 11, Fourier analysis.
  3. E. M. Stein and R. Shakarchi, Fourier Analysis: An Introduction, Princeton University Press, 2003: chapters 2 and 3 (Fourier series and their convergence) and 7 (finite Fourier analysis).
  4. W. H. Press, S. A. Teukolsky, W. T. Vetterling and B. P. Flannery, Numerical Recipes: The Art of Scientific Computing, 3rd edition, Cambridge University Press, 2007 (readable online): chapters 12 and 13, the fast Fourier transform and its applications.