Learning Objectives
By the end of this section you will be able to:
- Replace the continuous wave PDE with its discrete cousin on a space-time grid.
- Derive the explicit five-point stencil and read it as "curvature in space drives curvature in time."
- Prove and feel the CFL bound — the one inequality that decides whether your simulation is a wave or an explosion.
- Handle Dirichlet, Neumann, and absorbing boundary conditions, and explain physically what each one does to a reflected pulse.
- Implement the scheme in plain Python first, then translate it to vectorized PyTorch so it runs on a GPU and plugs into machine-learning pipelines.
Why Go Numerical?
"Analytic solutions are gifts. Numerical solutions are tools."
The previous four sections solved the wave equation by hand — d'Alembert's travelling waves, separation of variables, Fourier series, Bessel functions. Those methods are beautiful, but they only work on clean geometries with clean initial data. Real problems rarely cooperate:
Variable wave speed
Seismic waves slow down in soft sediments and speed up in granite, so changes with position. Fourier modes do not decouple any more — the analytical machinery falls apart.
Irregular geometry
A guitar body, a violin sound box, a human skull. None of these admit a separable solution in any classical coordinate system.
Nonlinear effects
Shock fronts, breaking surface waves, sonic booms. The PDE picks up terms like and superposition stops working.
Arbitrary initial data
You want to drop a Gaussian pulse, pluck a string with a triangle, or hand-draw your initial condition. There is no clean Fourier series for that.
The cure is to discretize: replace the continuous space-time with a finite grid, replace each derivative with a finite difference, and march the solution forward in time. The result is the Finite Difference Method (FDM) — the oldest, simplest, and arguably most pedagogically valuable way to solve a PDE on a computer.
Intuition: imagine the membrane of a drum painted with a grid. At every intersection we track a single number, the height of that pinpoint at a single instant. We then step time forward in tiny ticks. To know tomorrow's height of a point, we only need today's heights of that point and its immediate neighbors. Local rule, global wave. That is the whole game.
Discretizing Space and Time
Pick a spatial step and a temporal step . Replace the continuous function by samples on a lattice:
The superscript is the time row, the subscript is the spatial column. Think of as a giant matrix where each column is one moving point of the string and each row is one snapshot in time.
Approximating the derivatives
Taylor expansion of around a grid point gives, after the linear terms cancel, the famous second-order central differences:
| Continuous | Discrete approximation | Order of accuracy |
|---|---|---|
| ∂²u/∂t² at (x_i, t_n) | (u_i^{n+1} − 2 u_i^{n} + u_i^{n-1}) / Δt² | O(Δt²) |
| ∂²u/∂x² at (x_i, t_n) | (u_{i+1}^{n} − 2 u_i^{n} + u_{i-1}^{n}) / Δx² | O(Δx²) |
| ∂u/∂t at (x_i, t_n) | (u_i^{n+1} − u_i^{n-1}) / (2 Δt) | O(Δt²) |
Each formula has the same shape: the second derivative of a smooth function at a point is, up to an error of order , the difference between the value there and the average of its two neighbors, scaled by . That is geometry: it measures how much the curve bulges away from the straight line through its neighbors. That bulge is curvature, and curvature is what drives the wave.
The discrete wave equation
Plug the two central differences into at the grid point :
Solve for the only unknown, , and introduce the CFL number :
This is the only formula you have to remember. Everything else — stability, accuracy, boundary handling — spins out of this one line.
The Five-Point Stencil
The update rule reads from five grid points: the three neighbors at the current time row, the same point one step in the past, and writes one new value in the future. Drawn on a space-time grid it looks like a plus sign:
Two intuitions sit inside this stencil:
- Spatial part — curvature drives acceleration. The bracket is the discrete Laplacian: positive when the point is below its neighbors, negative when above. The tension wants to pull the membrane back toward the average, and the wave equation says this force is proportional to acceleration.
- Temporal part — momentum. The combination is exactly where the point would be next if there were no force at all (constant velocity extrapolation). It is the discrete version of inertia.
Add inertia to the curvature-driven kick and you get the next time step. That is Newton's second law on a grid.
The First-Step Trick
The stencil needs two previous time rows, but at we only have one. We need a special recipe for the first step.
Use the initial-velocity data and a Taylor expansion in time:
Substitute the wave equation and replace by central differences:
The half in front of is the signature of this special first step — miss it and the whole scheme silently drops to first-order accuracy. Released-from-rest data means and the middle term vanishes.
Worked Example: Step Through By Hand
Take the classic plucked string setup: on with , and fixed ends. The exact solution is — the fundamental mode breathing at frequency one. We will compute three time steps by hand and compare to the exact answer.
► Step-by-step numerical walkthrough (click to expand)
Setup. Use a coarse grid so the arithmetic stays readable: . Then and . CFL is satisfied (0.4 ≤ 1), so we expect a stable march.
Initial row :
| i | x_i | u_i^0 |
|---|---|---|
| 0 | 0.00 | 0.00000 |
| 1 | 0.25 | 0.70711 |
| 2 | 0.50 | 1.00000 |
| 3 | 0.75 | 0.70711 |
| 4 | 1.00 | 0.00000 |
First step: because we use . For :
For : . By symmetry . The exact values at are :
| i | u_i^1 (FDM) | Exact | Error |
|---|---|---|---|
| 1 | 0.67397 | 0.67250 | +0.00147 |
| 2 | 0.95314 | 0.95106 | +0.00208 |
| 3 | 0.67397 | 0.67250 | +0.00147 |
Second step. Now we can use the main rule . For :
| i | u_i^2 (FDM) | Exact at t=0.2 | Error |
|---|---|---|---|
| 1 | 0.57766 | 0.57206 | +0.00560 |
| 2 | 0.81694 | 0.80902 | +0.00792 |
| 3 | 0.57766 | 0.57206 | +0.00560 |
Third step:
| i | u_i^3 (FDM) | Exact at t=0.3 | Error |
|---|---|---|---|
| 1 | 0.42722 | 0.41563 | +0.01159 |
| 2 | 0.60418 | 0.58779 | +0.01639 |
| 3 | 0.42722 | 0.41563 | +0.01159 |
What we observe. The scheme tracks the exact cosine-breathing motion correctly. The amplitude at drops from 1.00000 to 0.95314 to 0.81694 to 0.60418 — matching the sampling of almost exactly. The error grows roughly linearly with , which is the expected behaviour for a second-order scheme on a coarse grid. Refining by a factor of two (keeping fixed) would cut every error in this table by a factor of about four.
The CFL Stability Condition
Why ? The physical intuition is beautiful: information in the wave equation travels at speed . In one numerical time step , the physical wave moves a distance . The numerical stencil gathers information from one grid spacing away.
Courant's rule: the numerical "sight" of one cell per step must reach at least as far as the physical wave front travels. Otherwise the scheme is trying to predict a value the wave has already passed through — information arrives that the stencil has not even looked at yet, and the simulation goes berserk.
Mathematically the same condition pops out of von Neumann stability analysis. Substitute the Fourier mode into the update rule. You get a quadratic in the growth factor :
For every wavenumber , both roots have modulus exactly when the coefficient stays in , which forces . Equality, the so-called magic CFL number, is even better: it makes the FDM update exactly equal to d'Alembert's solution — no dispersion at all.
Push the slider just past and the Gaussian pulse explodes within a few dozen steps. Pull it back and watch the wave snap right back into clean propagation. The transition is razor sharp because the underlying inequality is binary — you are either inside the unit circle or you are not.
Boundary Conditions
The interior stencil has the same shape everywhere, but at and we need to say something about what is beyond the edge. Three flavors cover essentially every classical problem.
Dirichlet (fixed end)
. Force the boundary values to zero every step. A right-moving pulse hits the wall and bounces back upside down.
Neumann (free end)
. Implement by copying the inner neighbor: . Pulses bounce back right-side up.
Absorbing (open)
Mur first-order: . Lets waves leave the domain. Perfect at , slightly leaky otherwise.
The physics: a fixed end is a wall — force the displacement to zero, the wave hands its energy back inverted. A free end is a ring on a frictionless rod — no transverse force, so the slope must be flat. An absorbing end is an imaginary infinite extension — we model what a far-field observer would see at the truncation point.
Interactive 1D Wave Simulator
Time to play. The next panel runs the full FDM scheme live in your browser. Switch initial conditions, slide the CFL number into the danger zone, swap boundary conditions, and observe what each knob does to the physics.
Things worth trying:
- With sine mode + fixed BC, turn on "show exact". At the cyan curve sits exactly on top of the yellow dashed line forever — the magic CFL number.
- Launch a Gaussian with absorbing BCs. The pulse escapes through the boundaries instead of bouncing.
- With two pulses + fixed BCs, watch them collide, pass through each other (linearity!), and rebound off the walls inverted.
- Push the CFL slider past 1. Watch the wave turn red and detonate.
Plain Python Implementation
Now that you have the rule in muscle memory, here is the whole solver as roughly thirty lines of NumPy. Read the explanations and feel how each line maps to a physical idea.
Reading the algorithm in code form makes the trade-off explicit: we traded a clean closed-form Fourier series for a vectorized 3-line update we can run on anything — arbitrary c(x), arbitrary domain shapes, arbitrary forcing.
Vectorized PyTorch Implementation
The NumPy version maxes out a single CPU core. For 2D / 3D wave problems, batch simulation, or for plugging the solver into a neural network, we rewrite the same code in PyTorch. The pleasant surprise: only the import line really changes.
That last function is the bridge to modern research. Once your FDM time step is a , the boundary between "classical PDE solver" and "learnable neural network" collapses. Differentiable solvers, neural operators, and physics-informed networks all start exactly here.
Accuracy, Dispersion, and Error
The scheme is second-order accurate in both and : halving the grid roughly quarters the error.
Numerical dispersion
A subtler issue is numerical dispersion. The exact wave equation has every wavenumber propagating at the same speed . The discrete scheme has a slightly wavenumber-dependent speed:
Long-wavelength components (small ) travel at almost ; short ones lag. The net effect is that a sharp Gaussian pulse spreads out slightly with time — energy at high gets left behind. At the magic value the formula collapses to identically — no dispersion, full agreement with d'Alembert.
How to keep the error small in practice
- Pick the finest your memory allows.
- Pick the largest that still satisfies . Smaller is not always better — it actually increases dispersion.
- Resolve the shortest physical wavelength with at least 10–20 grid points.
- If you need very long-time integration, switch to a higher-order scheme (Crank–Nicolson, spectral, or DG).
Beyond Basic FDM
| Method | Strength | Use it when |
|---|---|---|
| Explicit FDM (this section) | Simple, fast, parallelizable | Linear waves on regular grids |
| Crank-Nicolson / implicit | Unconditionally stable, A-stable | Stiff or diffusive problems |
| Pseudo-spectral | Spectral (exponential) accuracy | Periodic domains, smooth solutions |
| Finite-element method | Handles complex geometries | Irregular domains, structural acoustics |
| Discontinuous Galerkin | High order + shock capturing | Nonlinear / discontinuous data |
| PINN / neural operator | Learns from data + physics | Inverse problems, parameter sweeps |
Every one of these methods sits on the same conceptual chassis as the five-point stencil: replace continuous operators with discrete proxies, respect stability, and march in time. Master the simplest one and the rest will read like dialect.
Connection to Machine Learning
Modern deep-learning research has rediscovered FDM in three flavours, all of which lean on the equation you just implemented:
Differentiable solvers
Wrap the FDM step in PyTorch and you can back-propagate through time. Used in adjoint optimization for waveform inversion in seismology.
Physics-informed neural networks
PINNs minimize the residual on collocation points — the same residual the FDM stencil discretizes.
Neural operators
Fourier and DeepONet operators learn the solution map . FDM provides the ground truth they are trained against.
Common Pitfalls
- Violating CFL by a hair. Set by accident in a test and the simulation looks fine for 50 steps before exploding. Always pin to at most 0.99 in production code.
- Forgetting the first-step factor of one-half. Using the standard rule at drops the scheme to first-order overall and the phase error grows visibly fast.
- Mixing units. , , and must be in consistent units, or your CFL number lies to you. Common SI bug: in m/s, in cm.
- Reflections from open boundaries. Plain Dirichlet turns "outflow" into a wall. Use Mur or PML if you do not want echoes.
- Under-resolved wavelengths. Fewer than ~10 grid points per wavelength makes dispersion catastrophic. Refine the grid or use a higher-order scheme.
Summary
The wave equation, once reserved for clean geometries and clever substitutions, is now in your hands as a thirty-line solver. The ingredients:
- Discretize on a regular grid; approximate and by central differences.
- Solve for the future value to get the five-point stencil .
- Use the half-step Taylor trick for the first iteration so the scheme stays second-order accurate.
- Respect the CFL bound . Magic accuracy at ; explosion just past it.
- Pick a boundary condition that matches your physics: fixed for clamped, Neumann for free, Mur for open.
- Vectorize in NumPy for clarity, port to PyTorch for speed and differentiability, and a Conv1d view drops you straight into modern ML research.
The next sections take this scheme into the wild: musical instruments, electromagnetic waves, and seismic propagation. With the FDM solver in hand, every one of those becomes a small modification, not a new chapter of mathematics.