# 2D Schrödinger Wave Packet

> A Gaussian wave packet in 2D drifts, spreads and splits at a potential bump; brightness shows |ψ|² and colour shows the quantum phase.

- Category: Physics › Quantum Mechanics
- Level: advanced
- Tags: quantum, schrodinger, wave-packet, scattering, pde
- Updated: 2026-11-01
- URL: https://gdcs.coody.app/physics/quantum-mechanics/schrodinger-2d

## What it is

In two dimensions the wavefunction `ψ(x, y, t)` is a complex field over the plane. Its magnitude squared `|ψ|²` is the probability density (where the particle is likely to be found), and its phase `arg ψ` encodes momentum: phase stripes perpendicular to the motion, spaced one de Broglie wavelength apart.

A **Gaussian wave packet** is the most localized state you can build. It moves at the group velocity `ħk/m` and spreads as it goes, because its momentum components travel at different speeds. A narrower start spreads faster, which is the uncertainty principle at work. When it meets a potential bump, part of it is reflected, part goes through, and the pieces carry curved phase fronts.

To get this exactly you have to solve the PDE on a grid. Split-step Fourier and Crank–Nicolson are the usual unconditionally stable choices. The visual here is an **illustrative** model: the packet motion, spreading and split are scripted from analytic pieces rather than integrated. Start from the 1D [particle in a box](https://gdcs.coody.app/physics/quantum-mechanics/particle-in-box) and [tunneling](https://gdcs.coody.app/physics/quantum-mechanics/quantum-tunneling) to see the exact results this scene stylizes.

## Key formulas

- **Time-dependent Schrödinger equation (2D):** $i\hbar\,\partial_t \psi = -\frac{\hbar^2}{2m}\left(\partial_x^2 + \partial_y^2\right)\psi + V(x,y)\,\psi$
- **Initial Gaussian packet:** $\psi_0(x,y) = \frac{1}{\sqrt{2\pi}\,\sigma_0}\, e^{-\frac{(x-x_0)^2 + (y-y_0)^2}{4\sigma_0^2}}\, e^{i k_0 x}$
- **Free spreading:** $\sigma(t) = \sigma_0 \sqrt{1 + \left(\frac{\hbar t}{2 m \sigma_0^2}\right)^2}$
- **Normalization and momentum:** $\iint |\psi|^2\,dx\,dy = 1,\qquad p = \hbar k_0,\quad \lambda = \frac{2\pi}{k_0}$

## Rules of thumb

- Resolve the wavelength: `k_0·Δx ≤ 1` (6+ grid points per wavelength), or the phase aliases and the packet stalls.
- Split-step Fourier is exact for free motion and norm-preserving. Step size is limited by accuracy, not stability.
- Pad the domain or add an absorbing layer (complex potential) at the edges, or the packet wraps or reflects back.
- CPU grids of 64² update easily at 60 fps; a real 256² solver belongs in a GPU compute or ping-pong shader.
- Check that ∑|ψ|²·Δx·Δy stays at 1 to within 1e-6 per step, which catches most integrator bugs.

## Implementation

Write |ψ|² into heights and phase into colour, in place (no per-frame allocation):

```ts
// pos: xyz per vertex of a grid in the XZ plane; col: rgb per vertex.
export function paintPacket(
  pos: Float32Array, col: Float32Array,
  x0: number, sigma: number, k0: number, t: number,
  a: [number, number, number], b: [number, number, number] // phase ramp
) {
  const inv = 1 / (2 * sigma * sigma)
  for (let i = 0; i < pos.length; i += 3) {
    const x = pos[i], z = pos[i + 2]
    const rho = Math.exp(-((x - x0) ** 2 + z * z) * inv) // |ψ|², peak 1
    const phase = k0 * x - 0.5 * k0 * k0 * t // free plane-wave phase
    const m = 0.5 + 0.5 * Math.cos(phase)
    pos[i + 1] = rho * 1.7
    for (let c = 0; c < 3; c++) col[i + c] = (a[c] + (b[c] - a[c]) * m) * rho
  }
}
```

## Common mistakes

- Integrating with explicit Euler: the norm grows every step and the field blows up, whatever Δt you pick.
- Plotting Re ψ and calling it the density. Use |ψ|², and show the phase separately with hue or a second ramp.
- Undersampling the carrier wave (k₀Δx > 1), which makes the packet drift at the wrong speed.
- Letting the packet hit hard grid edges and reading the bounce as physics.

## Interactive visual

Surface height and brightness are |ψ|², and the cyan-to-violet stripes are the phase fronts. The red ring is the circular potential. Raise the potential strength to reflect more of the packet, and widen the initial spread to slow its spreading. The split is illustrative, not a PDE solve.

## Prompt

```text
Build a 2D time-dependent Schrödinger solver in TypeScript using the split-step Fourier method on an N×N periodic grid (N a power of two, ħ = m = 1). Inputs: grid size, domain length, Δt, a potential V(x,y) (Float32Array), and an initial Gaussian packet (x0, y0, σ0, k0). Each step: half-step potential phase e^{−iVΔt/2}, FFT, kinetic phase e^{−ik²Δt/2}, inverse FFT, half-step potential. Use preallocated Float32Array real/imag buffers. Render |ψ|² as heights of a Three.js PlaneGeometry (≤ 64² vertices) and phase as colour. Add an absorbing edge layer. Tests: norm stays 1 ± 1e-6 over 500 steps with V = 0, and a free packet's width follows σ(t) = σ0√(1 + (t/(2σ0²))²) within 2 %.
```

## Related

- [Quantum Tunneling](https://gdcs.coody.app/physics/quantum-mechanics/quantum-tunneling.md) — A quantum packet hitting a barrier higher than its energy still partly gets through: transmission falls off exponentially with barrier width.
- [Particle in a Box](https://gdcs.coody.app/physics/quantum-mechanics/particle-in-box.md) — A particle trapped between hard walls can only hold standing waves, so its energy is quantized as n² and superpositions slosh at beat frequencies.
- [Heat Diffusion](https://gdcs.coody.app/physics/thermodynamics/heat-diffusion.md) — Heat flows down temperature gradients at a rate set by the Laplacian. The explicit grid update is four lines of code, and is stable only if αΔt/Δx² ≤ ¼.

## Further reading

- [OpenStax University Physics Vol. 3 — The Schrödinger Equation](https://openstax.org/books/university-physics-volume-3/pages/7-3-the-schrodinger-equation)

---
Source: Game Development Cheat Sheet (https://gdcs.coody.app)
