PL. 73 · CURVES / SERIES / FOURIER PARTIAL SUM
Gibbs Phenomenon
Henry Wilbraham, 1848 · J. Willard Gibbs, 1899 · named by Maxime Bôcher, 1906
OPEN THE LIVE PLATE ▸DEFINITION
fₙ(x) = (4/π) Σₖ₌₁ⁿ sin((2k−1)x)/(2k−1) peak → (2/π)·Si(π) ≈ 1.178980 overshoot → 0.0894899 of the jump it never dies — it only narrows
NOTES
Sum the odd harmonics of a square wave and the corners grow horns: about nine per cent of the jump, and adding terms makes them thinner but never shorter — the partial sums converge everywhere except in the one sense the eye measures. The name is the least accurate part of it. Wilbraham had published the whole effect fifty years earlier and been ignored; Gibbs came to it through the Nature argument over Michelson’s harmonic analyser, and his first note there missed the overshoot entirely — it was his 1899 correction that described it. The name was Bôcher’s, seven years later still. The credit line here runs in the order the work actually happened. The swept harmonic count is the exhibit: watch the wave sharpen and the horns refuse to leave.
PROVENANCE
- Origin
- H. Wilbraham, "On a certain periodic function", Cambridge & Dublin Math. Journal 3 (1848), 198–201, unnoticed for decades; the effect resurfaced in the 1898 Nature exchange between A. A. Michelson and A. E. H. Love over Michelson’s harmonic analyser. J. W. Gibbs, "Fourier’s Series", Nature 59 (1898), 200, did not yet identify the overshoot; his correction, Nature 59 (1899), 606, did. M. Bôcher, "Introduction to the theory of Fourier’s series", Annals of Mathematics (2) 7 (1906), 81–152, gave the first full treatment and coined "Gibbs phenomenon"
- Standing
- Public domain — 19th-century analysis
- Constants
- The square wave underneath is the target the sums chase; it stays faint so the horns read against it. The limit peak is (2/π)·Si(π), the Wilbraham–Gibbs constant
HOUDINI · VEX
The same published mathematics as a Detail Wrangle body. Paste it into a Wrangle with Run Over set to Detail; every constant is the published value plus a tweak channel, so Create Spare Parameters gives a slider that starts where the paper does.
// FORMA — PL. 73 · GIBBS PHENOMENON — Henry Wilbraham, 1848 · J. Willard Gibbs, 1899 · named by Maxime Bôcher, 1906
// fₙ(x) = (4/π) Σₖ₌₁ⁿ sin((2k−1)x)/(2k−1)
// peak → (2/π)·Si(π) ≈ 1.178980
// overshoot → 0.0894899 of the jump
// it never dies — it only narrows
// Paste into a Detail Wrangle (Run Over: Detail), no inputs needed.
// Written from the published mathematics, not adapted from any code.
// Constants arrive at their published values. Press the node's Create
// Spare Parameters button and every tweak becomes a slider — starting
// at 0, the published figure, and moving in the constant's own units.
// https://forma-gen.com/#plate=gibbs
float p_terms = 24 + chf('terms_tweak'); // n — odd harmonics · live 1 .. 48
float p_cycles = 2 + chf('cycles_tweak'); // cycles shown · live 1 .. 4
// The plate's own colour: FORMA's CURVES accent as a cosine ramp,
// brightest near t = 0 and t = 1, near-black around t = 0.5.
vector forma_ramp(float t){
return set(
0.11 + 0.1196 * cos(6.28318530718 * (t + 0)),
0.46 + 0.5 * cos(6.28318530718 * (t + 0.05)),
0.2453 + 0.2667 * cos(6.28318530718 * (t + 0.1)));
}
// The square wave faint underneath — the structure the sums are chasing —
// and the partial sum over it, normalised so the square sits at ±1. The
// horns overshoot by design: ~8.9% of the jump, and adding terms only
// narrows them. It never dies. Alpha carries the plate's own layering.
int forma_n = 1200;
float TAU = 6.28318530718;
int terms = max(1, int(rint(p_terms)));
// the target square wave, faint
int under = addprim(0, "polyline");
for (int i = 0; i <= forma_n; i++){
float x = p_cycles * TAU * float(i) / float(forma_n);
float s = sin(x);
float sq = s == 0.0 ? 1.0 : sign(s);
int pt = addpoint(0, set(float(i) / float(forma_n), sq, 0.0));
setpointattrib(0, "Cd", pt, forma_ramp(0.95));
setpointattrib(0, "Alpha", pt, 0.16);
addvertex(0, under, pt);
}
// the partial sum — the graph is drawn y-up already; no flip needed
int prim = addprim(0, "polyline");
for (int i = 0; i <= forma_n; i++){
float x = p_cycles * TAU * float(i) / float(forma_n);
float y = 0.0;
for (int k = 1; k <= terms; k++)
y += sin(float(2 * k - 1) * x) / float(2 * k - 1);
int pt = addpoint(0, set(float(i) / float(forma_n), y * 4.0 / 3.14159265359, 0.0));
setpointattrib(0, "Cd", pt, forma_ramp(0.94));
setpointattrib(0, "Alpha", pt, 1.0);
addvertex(0, prim, pt);
}
AFTER EFFECTS · EXPRESSION
The same published mathematics as a Shape Layer path expression. Paste it onto a Path property; every constant is the published value plus a Slider Control named
// FORMA — PL. 73 · GIBBS PHENOMENON — Henry Wilbraham, 1848 · J. Willard Gibbs, 1899 · named by Maxime Bôcher, 1906
// fₙ(x) = (4/π) Σₖ₌₁ⁿ sin((2k−1)x)/(2k−1)
// peak → (2/π)·Si(π) ≈ 1.178980
// overshoot → 0.0894899 of the jump
// it never dies — it only narrows
// After Effects port — paste onto a Shape Layer's Path property
// (Contents › Shape › Path). Written from the published mathematics, not
// adapted from any code. Constants arrive at their published values; add a
// Slider Control (Effect › Expression Controls) named <k>_tweak and that
// constant moves in its own units, starting at 0 — the published figure.
// The plate's comet and its reveal are Trim Paths; the stroke colour is
// FORMA's CURVES accent, #3DFF88. Animation runs on time.
// This plate draws 2 separate paths at its published constants:
// duplicate the group (Contents › Group) that many times and each copy draws
// its own part, read from its position in the layer. A Slider Control named
// "part" on the layer pins one instead.
// https://forma-gen.com/#plate=gibbs
// A missing slider reads 0, so a bare paste already draws the figure.
function forma_tweak(n){ try { return effect(n)("Slider"); } catch (e){ return 0; } }
var p_terms = 24 + forma_tweak("terms_tweak"); // n — odd harmonics · live 1 .. 48
var p_cycles = 2 + forma_tweak("cycles_tweak"); // cycles shown · live 1 .. 4
// The frame: the plate's W × H canvas is this comp, with the origin at the
// layer's anchor; canvas y already runs down, as After Effects' does.
var forma_W = thisComp.width, forma_H = thisComp.height, forma_t = time;
var forma_phase = 0.0330388976726681; // this plate's own fixed phase, as the page has it
function forma_pt(x, y){ return [x - forma_W / 2, y - forma_H / 2]; }
function forma_partIndex(){
try { return Math.round(effect("part")("Slider")); } catch (e){}
try { return thisProperty.propertyGroup(3).propertyIndex - 1; } catch (e){ return 0; }
}
var forma_part = forma_partIndex();
// The Gibbs phenomenon: the partial Fourier sum of a square wave,
// Σ sin((2k−1)x)/(2k−1) over the first `terms` odd harmonics, normalised by
// 4/π so the square wave sits at ±1 — the horns overshoot it by about 9% no
// matter how many terms, which is the phenomenon. 1,200 samples over `cycles`
// periods, as the page draws. Part 0 is the partial sum; part 1 is the target
// square wave, the faint structure the sums are chasing — the second copy of
// the group, lowered in opacity.
// parts: 2
var N = 1200, terms = Math.max(1, Math.round(p_terms));
var x0 = forma_W * 0.05, xw = forma_W * 0.9, ym = forma_H * 0.5, ys = forma_H * 0.3;
var pts = [];
for (var i = 0; i <= N; i++){
var x = p_cycles * Math.PI * 2 * i / N, y;
if (forma_part === 1){
var sg = Math.sin(x);
y = (sg === 0 ? 1 : (sg > 0 ? 1 : -1));
} else {
y = 0;
for (var k = 1; k <= terms; k++) y += Math.sin((2 * k - 1) * x) / (2 * k - 1);
y *= 4 / Math.PI;
}
pts.push(forma_pt(x0 + xw * i / N, ym - y * ys));
}
createPath(pts, [], [], false);