Computing Library › Worked Examples
Worked Examples

Finite-Differencing the 1D Wave Equation

March a vibrating string forward with a leapfrog scheme and meet the Courant condition that keeps it stable.

The equation

The wave equation u_tt = c^2 u_xx models a string under tension. Unlike diffusion it is second order in time, so we need two time levels of history to start.

Leapfrog scheme

Kronos motion — meet hyperion

Centered second differences in both time and space give u_new[i] = 2u[i] - u_old[i] + C^2 (u[i+1] - 2u[i] + u[i-1]), where the Courant number C = c dt/dx. The first step uses the initial velocity to bootstrap u_old.

Courant condition

Stability requires C <= 1: a wave must not cross more than one grid cell per time step. At C = 1 the scheme is exact for the pure advection pieces; above 1 it blows up. This CFL limit governs every explicit hyperbolic solver.

python
import numpy as np
nx=201; dx=1/(nx-1); c=1.0; C=0.9; dt=C*dx/c
x=np.linspace(0,1,nx)
u=np.exp(-300*(x-0.5)**2); u[0]=u[-1]=0
uold=u.copy()                       # zero initial velocity
for n in range(400):
    unew=np.zeros_like(u)
    unew[1:-1]=2*u[1:-1]-uold[1:-1]+C*C*(u[2:]-2*u[1:-1]+u[:-2])
    uold,u=u,unew
print('energy roughly conserved; peak',round(u.max(),3))

Behaviour

A Gaussian pulse splits into two half-amplitude pulses travelling left and right at speed c, reflecting off the fixed ends with a sign flip. Unlike the heat equation nothing decays - the scheme should conserve energy up to small dispersion, which is a useful sanity check on your implementation.