# Oscillation
## Microsim
### Live player
<div class="microsim-player">
<iframe src="https://editor.p5js.org/sciencenibber/full/Q21EyK7NF" width="100%" height="620" frameborder="0" sandbox="allow-scripts allow-same-origin"></iframe>
</div>
<div class="microsim-fallback">
<img src="Microsims/thumbs/Oscillation.png" alt="Oscillation microsim poster" style="width:100%;border:1px solid #4445;border-radius:6px;">
<p><em>Live microsim (desktop) · <a href="https://editor.p5js.org/sciencenibber/sketches/Q21EyK7NF">open sketch in the p5.js editor</a></em></p>
</div>
**Editor URL:** https://editor.p5js.org/sciencenibber/sketches/Q21EyK7NF
**Description (100 words):**
Three single-degree-of-freedom oscillator archetypes integrated side-by-side under a common time step: a linear damped harmonic oscillator (`x'' + 2 zeta omega x' + omega^2 x = 0`), a real pendulum with full sine restoring (`theta'' + (g/L) sin(theta) = 0`), and a Van der Pol self-sustained oscillator (`x'' - mu (1 - x^2) x' + x = 0`). Each row pairs a time-domain scope with a phase portrait. Three sliders (`zeta`, `theta_max`, `mu`) and pause/reset buttons let the reader watch isochronism in linear motion, period growth with amplitude in the pendulum, and the limit-cycle [[Attractor|attractor]] of Van der Pol emerge from any non-trivial start.
```js
// =====================================================================
// Wikitube microsim - Oscillation
// Slug: Oscillation
// URL: en.wikitube.io/wiki/Oscillation
// Pattern: A reskin - Classical mechanics constructions (Energy room)
//
// What it shows
// Three single-degree-of-freedom oscillator archetypes integrated
// side-by-side under a common time step so the reader can compare
// their characters at a glance:
//
// 1. Linear x'' + 2 zeta omega x' + omega^2 x = 0
// sinusoidal, isochronous (period independent of
// amplitude), elliptical phase portrait.
// 2. Nonlinear theta'' + (g/L) sin(theta) = 0 (real pendulum)
// anharmonic; period stretches with amplitude;
// phase portrait curves into the pendulum "eye".
// 3. Self- x'' - mu (1 - x^2) x' + x = 0 (Van der Pol)
// sustained energy fed in for small x, dissipated for large
// x, so the trajectory falls onto a limit cycle
// from any non-trivial initial condition.
//
// Each oscillator gets its own row: a time-domain scope on the left
// and a phase portrait on the right. A run/pause and reset button,
// plus three sliders that drive the meaningful parameter of each
// row, sit in a dedicated bottom band that does not collide with
// the readouts (cf. pitfalls.md, slider-thumb-vs-readout entry).
//
// Live readouts (bottom-left, above the slider band)
// row 1 (linear): omega, zeta, T = 2 pi / omega_d
// row 2 (pendulum): theta_max, T_pendulum, T0 / T0 (period growth)
// row 3 (Van der Pol): mu, period_estimate from zero crossings
//
// Pattern A reskin (Energy room)
// Each "body" is rendered as a labelled point. The rig sketches are
// suppressed (the room already has Vibration, Harmonic_oscillator,
// Pendulum, Pendulum_(mechanics) microsims that show rigs); here the
// point is the universal common shape across regimes, which lives in
// the phase portraits. Conservation visibly drifts on the linear and
// pendulum traces under nonzero damping; the Van der Pol trajectory
// pumps itself onto its limit cycle.
//
// Pitfall guards (Skills/P5js Microsim Standards/pitfalls.md)
// - p5.disableFriendlyErrors = true (no FES noise)
// - all canvas-side strings ASCII; Unicode lives only in comments
// (so "omega", "zeta", "theta", "mu", "pi" not the Greek letters)
// - sliders sit in a dedicated bottom band so the slider thumb
// does not float over readout text
// - ring buffers capped so memory does not grow unbounded
// - velocity-Verlet for the conservative oscillators; explicit-Euler
// is fine for the dissipative Van der Pol since it is bounded by
// its own attractor
// =====================================================================
const ARTICLE = "Oscillation";
p5.disableFriendlyErrors = true;
// ---------- Energy palette (Articles/P5_JS_EDITOR.md, section 4) -----
const BG = 18;
const FG = 240;
const HOT = [220, 110, 60]; // pendulum trace
const COLD = [ 60, 130, 220]; // linear trace
const STRUCT = [120, 130, 150]; // axes, structural lines
const TRAJ = [240, 220, 80]; // current-state dot
const GAUGE = [120, 220, 140]; // Van der Pol trace
// ---------- Controls (created in setup) ------------------------------
let zetaSlider, thetaSlider, muSlider;
let runBtn, resetBtn;
let isRunning = true;
// ---------- State ----------------------------------------------------
// Linear oscillator (x1, v1)
// Nonlinear pendulum (theta, omegaP) theta in radians
// Van der Pol (x3, v3)
let x1 = 1.0, v1 = 0.0;
let theta = 0.6, omegaP = 0.0;
let x3 = 0.1, v3 = 0.0;
let t = 0;
// Ring buffers of {t, x, v} for each oscillator
const N_BUF = 600;
const buf1 = [];
const buf2 = [];
const buf3 = [];
// Period estimation for Van der Pol: track zero crossings of x3.
let lastZeroT = -1;
let lastPeriod = 0;
let prevX3 = x3;
let prevTh0 = 0.6; // last seen pendulum-amplitude slider value
// Pendulum "small-amplitude" reference period.
const G_OVER_L = 4.0; // omega0^2 = g/L; omega0 = 2 rad/s
function setup() {
createCanvas(windowWidth, windowHeight);
pixelDensity(2);
// --- Bottom slider band (below the readout band) -------------------
zetaSlider = createSlider(0.0, 0.6, 0.05, 0.01).position(180, height - 90).size(180);
thetaSlider = createSlider(0.05, 3.0, 0.6, 0.05).position(180, height - 60).size(180);
muSlider = createSlider(0.0, 4.0, 1.5, 0.05).position(180, height - 30).size(180);
runBtn = createButton("pause").position(420, height - 30);
runBtn.mousePressed(() => {
isRunning = !isRunning;
runBtn.html(isRunning ? "pause" : "run");
});
resetBtn = createButton("reset").position(490, height - 30);
resetBtn.mousePressed(() => {
x1 = 1.0; v1 = 0.0;
theta = thetaSlider.value(); omegaP = 0.0;
x3 = 0.1; v3 = 0.0;
t = 0;
buf1.length = 0; buf2.length = 0; buf3.length = 0;
lastZeroT = -1; lastPeriod = 0; prevX3 = x3;
});
}
function draw() {
background(BG);
// ---- read parameters once at top of draw (Energy room convention) -
const zeta = zetaSlider.value();
const th0 = thetaSlider.value(); // current pendulum amplitude target
const mu = muSlider.value();
const dt = isRunning ? min(deltaTime / 1000, 0.05) : 0;
// If the user moved the amplitude slider, re-seed the pendulum from
// rest at the new amplitude so the "period grows with amplitude"
// lesson is one slider drag away. We watch th0 itself rather than
// the live pendulum state, so a swinging pendulum reaching its
// (mirrored) apex does not retrigger this and freeze the motion.
if (abs(th0 - prevTh0) > 1e-3) {
theta = th0; omegaP = 0.0; buf2.length = 0;
prevTh0 = th0;
}
// ---- integrate ---------------------------------------------------
// Run several substeps per frame so the oscillator periods (a few
// seconds of simulation time each) finish in one or two seconds of
// wall-clock time. Without this the trace looks suspiciously flat
// even though the math is correct.
const SUBSTEPS = 6;
const dts = dt / SUBSTEPS;
// Speed multiplier: 1 wall-clock second ~ SPEEDUP simulation seconds.
const SPEEDUP = 8.0;
if (dt > 0) {
for (let s = 0; s < SUBSTEPS; s++) {
const h = dts * SPEEDUP;
// Linear: m=1, omega=1, damping zeta. Velocity-Verlet.
const a1 = -x1 - 2 * zeta * v1;
v1 += a1 * h * 0.5;
x1 += v1 * h;
const a1b = -x1 - 2 * zeta * v1;
v1 += a1b * h * 0.5;
// Pendulum: full sine restoring, light velocity damping.
const aT = -G_OVER_L * sin(theta) - 2 * zeta * omegaP;
omegaP += aT * h * 0.5;
theta += omegaP * h;
const aTb = -G_OVER_L * sin(theta) - 2 * zeta * omegaP;
omegaP += aTb * h * 0.5;
// Van der Pol: x'' = mu(1 - x^2) x' - x. Symplectic-ish midpoint.
const a3 = mu * (1 - x3 * x3) * v3 - x3;
v3 += a3 * h;
x3 += v3 * h;
t += h;
// zero-crossing period estimate for Van der Pol
if (prevX3 < 0 && x3 >= 0) {
if (lastZeroT > 0) lastPeriod = 2 * (t - lastZeroT);
lastZeroT = t;
}
prevX3 = x3;
// Sample to buffers AT EACH SUBSTEP, not just once per frame.
// If the iframe gets throttled to a lower frame rate the
// per-frame sampling aliases the oscillation into a slow decay.
buf1.push({ t, x: x1, v: v1 }); if (buf1.length > N_BUF) buf1.shift();
buf2.push({ t, x: theta, v: omegaP }); if (buf2.length > N_BUF) buf2.shift();
buf3.push({ t, x: x3, v: v3 }); if (buf3.length > N_BUF) buf3.shift();
}
}
// ---- layout -------------------------------------------------------
const padTop = 60; // leave room for HUD title block
const padBot = 130; // leave room for readouts + sliders
const rowH = (height - padTop - padBot) / 3;
const scopeW = (width - 60) * 0.55;
const phaseW = (width - 60) * 0.45 - 40;
for (let r = 0; r < 3; r++) {
const y0 = padTop + r * rowH + 10;
const buf = [buf1, buf2, buf3][r];
const col = [COLD, HOT, GAUGE][r];
const xLim = [2.0, 3.4, 2.5][r];
const vLim = [2.0, 3.4, 4.0][r];
const label = ["linear x(t)", "pendulum theta(t)", "Van der Pol x(t)"][r];
const phaseLabel = ["phase (x, v)", "phase (theta, omega)", "phase (x, v)"][r];
drawScope(20, y0, scopeW, rowH - 20, buf, col, xLim, label);
drawPhase(40 + scopeW, y0, phaseW, rowH - 20, buf, col, xLim, vLim, phaseLabel);
}
// ---- readouts and HUD --------------------------------------------
drawReadouts(zeta, mu);
drawSliderLabels();
drawHud();
drawEquationFooter();
}
function drawScope(x0, y0, w, h, buf, col, xLim, label) {
push(); translate(x0, y0);
stroke(STRUCT[0], STRUCT[1], STRUCT[2], 80); strokeWeight(1); noFill();
rect(0, 0, w, h);
line(0, h / 2, w, h / 2);
if (buf.length >= 2) {
const tMin = buf[0].t, tMax = buf[buf.length - 1].t;
stroke(col[0], col[1], col[2]); strokeWeight(2); noFill();
beginShape();
for (const s of buf) {
vertex(map(s.t, tMin, tMax, 0, w), map(s.x, -xLim, xLim, h, 0));
}
endShape();
}
noStroke(); fill(STRUCT[0], STRUCT[1], STRUCT[2]); textSize(11);
textAlign(LEFT, TOP); text(label, 8, 6);
pop();
}
function drawPhase(x0, y0, w, h, buf, col, xLim, vLim, label) {
push(); translate(x0, y0);
stroke(STRUCT[0], STRUCT[1], STRUCT[2], 80); strokeWeight(1); noFill();
rect(0, 0, w, h);
line(0, h / 2, w, h / 2);
line(w / 2, 0, w / 2, h);
if (buf.length >= 2) {
stroke(col[0], col[1], col[2]); strokeWeight(1.4); noFill();
beginShape();
for (const s of buf) {
vertex(map(s.x, -xLim, xLim, 0, w), map(s.v, -vLim, vLim, h, 0));
}
endShape();
// current-state dot
const last = buf[buf.length - 1];
noStroke(); fill(TRAJ[0], TRAJ[1], TRAJ[2]);
circle(map(last.x, -xLim, xLim, 0, w), map(last.v, -vLim, vLim, h, 0), 7);
}
noStroke(); fill(STRUCT[0], STRUCT[1], STRUCT[2]); textSize(11);
textAlign(LEFT, TOP); text(label, 8, 6);
pop();
}
function drawReadouts(zeta, mu) {
// canonical-symbol readouts in a band just above the slider band.
// omega for linear is fixed = 1 rad/s by construction.
const omega = 1.0;
const T_lin = (2 * PI) / omega;
// pendulum period estimate from current theta apex (small amplitude
// reference T0 = 2 pi / sqrt(g/L)). Use the elliptic-K-free first
// correction T = T0 * (1 + theta_max^2 / 16).
const omega0 = sqrt(G_OVER_L);
const T0 = (2 * PI) / omega0;
const thMax = max(abs(theta), 1e-6);
const T_pend = T0 * (1 + (thMax * thMax) / 16);
const stretch = T_pend / T0;
push();
noStroke(); fill(STRUCT[0], STRUCT[1], STRUCT[2]); textSize(12);
textAlign(LEFT, BOTTOM);
text("linear: omega = " + nf(omega, 1, 2) +
" zeta = " + nf(zeta, 1, 2) +
" T = " + nf(T_lin, 1, 2) + " s",
16, height - 110);
text("pendulum: theta_max = " + nf(thMax, 1, 2) +
" rad T0 = " + nf(T0, 1, 2) +
" T/T0 = " + nf(stretch, 1, 3),
16, height - 96);
text("Van der Pol: mu = " + nf(mu, 1, 2) +
" period ~ " + nf(lastPeriod, 1, 2) + " s",
16, height - 82);
pop();
}
function drawSliderLabels() {
// labels sit just left of each slider, right-aligned
push();
noStroke(); fill(STRUCT[0], STRUCT[1], STRUCT[2]); textSize(12);
textAlign(RIGHT, CENTER);
text("zeta (damping)", 170, height - 80);
text("theta_max (pend amp)", 170, height - 50);
text("mu (Van der Pol)", 170, height - 20);
pop();
}
function drawHud() {
push();
// top-left: title + wikitube URL line. The Energy palette sets
// BG = 18 (near-black) so the title needs a light fill, not the
// near-black fill(20) the standards spec assumes for a light bg.
noStroke(); fill(FG); textSize(20); textAlign(LEFT, TOP);
text("Oscillation", 20, 16);
fill(170); textSize(12);
text("Wikitube microsim - en.wikitube.io/wiki/" + ARTICLE, 20, 40);
// top-right: control hints
fill(150); textSize(11); textAlign(RIGHT, TOP);
text("sliders: zeta, theta_max, mu (per row)", width - 20, 16);
text("buttons: pause / reset; rows: linear, pendulum, Van der Pol",
width - 20, 32);
pop();
}
function drawEquationFooter() {
push();
noStroke(); fill(160); textSize(11); textAlign(RIGHT, BOTTOM);
text("x'' + 2 zeta omega x' + omega^2 x = 0 | theta'' + (g/L) sin(theta) = 0 | x'' - mu (1 - x^2) x' + x = 0",
width - 20, height - 110);
pop();
}
function windowResized() {
resizeCanvas(windowWidth, windowHeight);
// re-pin the controls after a resize
zetaSlider.position(180, height - 90);
thetaSlider.position(180, height - 60);
muSlider.position(180, height - 30);
runBtn.position(420, height - 30);
resetBtn.position(490, height - 30);
}
```
## Links (Wikipedia order)
<!-- injected from _registry/childlinks/Oscillation.json (2026-07-30T02:09:12Z) -->
`Aerodynamics` · `Aircraft` · [[Alternating_current]] · `Angle_of_attack` · `Anisotropy` · `Anti-vibration_compound` · `Antiresonance` · `Armstrong_oscillator` · `Arnold_tongue` · `Asteroseismology` · `Astronomy` · `Atlantic_multidecadal_oscillation` · `BIBO_stability` · `Beat_(acoustics)` · `Belousov–Zhabotinsky_reaction` · `Blocking_oscillator` · `Bray–Liebhafsky_reaction` · `Briggs–Rauscher_reaction` · `Business_cycle` · `Butler_oscillator` · `Cepheid_variable` · `Chandler_wobble` · [[Christiaan_Huygens]] · `Circadian_rhythm` · `Clapp_oscillator` · `Classical_limit` · `Colpitts_oscillator` · `Continuum_mechanics` · [[Control_theory]] · `Critical_speed` · `Crystal_oscillator` · `Cycle_(music)` · `Degrees_of_freedom_(physics_and_chemistry)` · `Delay-line_oscillator` · `Double_pendulum` · [[Dynamical_system]] · [[Dynamics_(mechanics)]] · [[Earthquake_engineering]] · [[Ecology]] · `Economics` · `Electromagnetic_field` · `Electronic_circuit` · `Electronic_oscillator` · `Exponential_decay` · `Extended_interaction_oscillator` · [[Feedback]] · `Fluid` · [[Force]] · `Foucault_pendulum` · `Fourier_transform` · `Frequency` · `Friction` · `Function_(mathematics)` · `Generation_gap` · `Geology` · `Geyser` · `Gravity` · `Guitar` · `Harmonic_oscillator` · `Hartley_oscillator` · `Helioseismology` · `Helmholtz_resonance` · `Hooke's_law` · `Hunting_oscillation` · `Infinity` · `Injection_locking` · `Interval_(mathematics)` · `Isotropy` · `Kepler_orbit` · `Kinetic_energy` · `Laser` · [[Least-squares_spectral_analysis]] · `Lennard-Jones_potential` · `Lever_escapement` · `Local_oscillator` · `Madden–Julian_oscillation` · `Mechanical_equilibrium` · `Mercury_beating_heart` · `Momentum` · `Neural_oscillation` · `Neutral_particle_oscillation` · `Neutrino_oscillation` · `Normal_mode` · `Open_set` · `Oscillating_gene` · `Oscillation_(mathematics)` · `Oscillator_(cellular_automaton)` · `Oscillator_(disambiguation)` · `Oscillator_phase_noise` · `Oscillistor` · `Pacific_decadal_oscillation` · [[Pendulum]] · `Periodic_function` · `Phase-shift_oscillator` · `Phase_noise` · `Phugoid` · `Pierce_oscillator` · `Pilot-induced_oscillation` · `Potential_energy` · `Puberty` · `Quantum_harmonic_oscillator` · `Quantum_optics` · `Quasi-biennial_oscillation` · `Quasiperiodic_function` · `Quasiperiodicity` · `RLC_circuit` · `Real_number` · `Reciprocating_motion` · `Relaxation_oscillator` · `Resonance` · `Resonator` · `Rhythm` · `Route_flapping` · `Royer_oscillator` · `Seasonality` · `Self-oscillation` · `Self-pulsation` · [[Sequence]] · `Signal_generator` · [[Simple_harmonic_motion]] · [[Sine_wave]] · `Sliding_mode_control` · `Spring_(device)` · `Squegging` · `Stability_theory` · `Statics` · `Stiffness` · `String_instrument` · `Structural_stability` · `Swing_(seat)` · `Tension_(physics)` · `Time` · `Torsional_vibration` · `Tuned_mass_damper` · `Tuning_fork` · `Valve` · `Vibrate_(disambiguation)` · `Vibration` · `Vibrations_(disambiguation)` · `Vibrator_(mechanical)` · `Water` · [[Wave]] · [[Wayback_Machine]] · `Weight` · `Wien_bridge_oscillator` · `Wilberforce_pendulum` · `Wing`
## Media (PD/CC)
<!-- MEDIA-DEPLOY:Oscillation/Animated-mass-spring.gif -->
!Gif Library/Oscillation/Animated-mass-spring.gif
*Animated-mass-spring.gif · Svjo · CC BY-SA 3.0 · [source](https://commons.wikimedia.org/wiki/File:Animated-mass-spring.gif)*
<!-- /MEDIA-DEPLOY -->
<!-- SIGN-SYSTEMS:START -->
**Semiotic universals** (the notations and alphabet letters this article speaks — each opens its canonical card): oscillation · energy · amplitude · cycle · damping. Index: the glyph gallery · SEMIOTICS PORTAL.
<!-- SIGN-SYSTEMS:END -->
> **Room:** [[Energy]] · **Status:** ✅ shipped
## Overview
Oscillation is the repetitive variation of a quantity about a central value, the most universal idiom in [[Physics|physics]]: anywhere a [[System|system]] has a restoring tendency and a way to store energy, it oscillates. The mathematical skeleton is one second-order [[Ordinary_differential_equation|ordinary differential equation]] in time, x'' = f(x, x'), whose qualitative behaviour falls into three families that dominate the room. Linear oscillation, where the restoring [[Force|force]] is strictly proportional to displacement (x'' + omega^2 x = 0), produces sinusoids whose frequency is independent of amplitude: the regime of small-angle pendula, mass-spring rigs, LC circuits, and tuning forks. Nonlinear oscillation, where the restoring force bends (x'' + sin(x) = 0 for a real [[Pendulum|pendulum]], x'' + x + alpha x^3 = 0 for the Duffing oscillator), produces periodic but anharmonic motion whose period grows with amplitude and whose phase portraits curve into eyes, figure-eights, or scroll patterns. Self-sustained oscillation, where a system pumps energy into itself against dissipation (x'' - mu (1 - x^2) x' + x = 0 for Van der Pol), produces a limit cycle the trajectory falls onto from anywhere: the regime of heart pacemaker cells, tube oscillators, and the cocktail-party hum of a vibrating reed. Coupled oscillators add normal modes, beats, and synchronisation; chaotic oscillation breaks period altogether. The single-DoF picture is the universal first chapter.
## See also
- Room hub: [[Energy]]
- p5.js Editor conventions: P5 JS EDITOR
- Wiki root: MAIN
---
*Scaffolded by `generative-microsim` from row 0 of the Energy sheet on 2026-04-30T08:51:48Z.*
Letters: oscillation · energy · amplitude · cycle · damping · harmonic · attractor_chaos · flow
<!-- CRAFT-LINK:START g12 -->
*Built to the [[WT!P5_js_Microsim_Master_Class|p5.js Master Class]].*
<!-- CRAFT-LINK:END -->
<!-- ACOUSIM:BEGIN g22 — Acoustics portal microsim (framework build, specs/acoustics/sims/Oscillation.json); do not hand-edit inside -->
**Microsim — three.js (Wikitube framework):** *Oscillation*
<div class="wt-sim" data-src="https://wikitube-3d-microsims.netlify.app/acoustics/Oscillation.html" data-title="Oscillation"></div>
*Built from `MICROSIM_GUIDE/specs/acoustics/sims/Oscillation.json`; part of the [[PORTAL_Acoustics|Acoustics portal]] spine (section sims and See-also variants).*
<!-- ACOUSIM:END -->
## Wikipedia : Wikitube
**Strict pair:** [Wikipedia](https://en.wikipedia.org/wiki/Oscillation) : [Wikitube](https://en.wikitube.io/wiki/Oscillation)
## Previous hub tags
Tree parents: [[Complex_system]] · [[Dynamical_system]] · [[Feedback]].
Legacy hubs: `GENERATIVE`.
---
*Sources: 1 legacy note. Minted wave 1, 2026-07-30 (v1.6 order).*