在瀏覽器中求解薛定諤方程,並讓量子穿隧結果符合理論
Solving the Schrödinger equation in the browser and matching tunneling to theory
瀏覽器頁面以 Visscher 方法數值求解一維薛定諤方程,模擬量子穿隧並把透射率與教科書公式比較。作者按網格單元與勢壘的重疊比例設定邊緣高度,修正薄勢壘厚度被 dx = 0.25 取整造成的偏差。能量 E = 0.6、勢壘厚度 1.25 時,模擬透射率約 33.8%,理論值為 34.0%。
A particle hits a wall it should not be able to climb, and still gets through with some probability. That is quantum tunneling.
I made a page that shows this by solving the 1D Schrödinger equation numerically, as is. It uses Canvas 2D and no libraries.
https://sishiya.github.io/manabi-lab/quantum/?lang=en#tunnel
When a wave packet hits the wall, part of it bounces back and part leaks through to the other side. At the end, the probability of getting through is compared with the textbook formula.
This post covers the method (Visscher's method) and how I fixed the place where it disagreed with theory.
Equation and units
In units of ħ = 1 and mass m = 1, the equation is:
i ∂ψ/∂t = H ψ, H = −(1/2) ∂²/∂x² + V(x)
The grid has N = 2000 points, dx = 0.25, time step dt = 0.02, and 80 steps per frame. The wall height is V₀ = 1.
Visscher's method: step the real and imaginary parts in turn
Splitting ψ = R + iI gives two equations:
∂R/∂t = H I
∂I/∂t = −H R
Visscher's method updates R and I staggered by half a step, in turn: once R is new, the new R is used to advance I. It is about as simple as Euler's method, yet with a small enough time step it is stable and nearly conserves probability.
const c = 0.5 / (dx * dx);
for (let i = 1; i < N - 1; i++) R[i] += dt * (-c * (I[i+1] - 2*I[i] + I[i-1]) + V[i] * I[i]);
for (let i = 1; i < N - 1; i++) I[i] -= dt * (-c * (R[i+1] - 2*R[i] + R[i-1]) + V[i] * R[i]);
Just two loops. The second loop reads the R that the first loop just rewrote.
The initial wave packet is a Gaussian times a wave with momentum k₀ = √(2E), normalized so the total probability is 1:
const g = Math.exp(-((x - X0) ** 2) / (4 * SIG * SIG));
R[i] = g * Math.cos(k0 * x);
I[i] = g * Math.sin(k0 * x);
Absorbing the wave at the edges
If the wave bounces off the grid edges, the transmitted part comes back and spoils the count. So the 160 points at each end form an absorbing layer that shrinks the amplitude a little at a time.
The absorbed probability is summed separately for the left and right edges. What disappears on the left counts as "bounced back", and on the right as "got through", in the final fractions.
for (let j = 0; j < ABS; j++) {
const f = 1 - 0.006 * ((ABS - j) / ABS) ** 2;
for (const i of [j, N - 1 - j]) {
const p = R[i] * R[i] + I[i] * I[i];
R[i] *= f; I[i] *= f;
const lost = p * (1 - f * f) * dx;
if (i < N / 2) absL += lost; else absR += lost;
}
}
Comparing with theory
For E < V₀, the textbook formula gives the probability of passing a wall of height V₀ and thickness a:
T = 1 / (1 + V₀² sinh²(κa) / (4E(V₀ − E))), κ = √(2(V₀ − E))
This formula is for a wave with a single energy, though. The simulated packet has a small spread of energies, so it will not match exactly. The page labels it "theory (approximate)".
Where I got stuck: thin walls were way off
At first, grid points inside the wall had V = 1 and the rest 0. Then the thinner the wall, the further it drifted from theory.
The cause was that the wall thickness was being rounded to the grid spacing dx = 0.25. Tunneling depends exponentially on thickness, so even one cell at the edge makes a big difference.
So cells on the wall's edge now get a height proportional to how much of the cell overlaps the wall:
// cells at the wall's edge get partial height, so the thickness isn't rounded to the grid
const ov = Math.max(0, Math.min(x + dx/2, BC + w/2) - Math.max(x - dx/2, BC - w/2));
V[i] = V0 * ov / dx;
After that, it agrees well with theory:
| Energy E | Wall thickness | Simulation | Theory |
|---|---|---|---|
| 0.6 | 3 | about 1.9% | 1.8% |
| 0.6 | 1.25 | about 33.8% | 34.0% |
| 0.4 | 0.75 | about 53% | 53.3% |
| 1.2 (above the wall) | 1.25 | about 64% | 65.5% |
The last row shows that even with energy above the wall, not all of it gets over: about a third bounces back. In classical mechanics it would always get over.
You can check the same values from the browser console:
const E = __qx.EXPS.tunnel; E.T.E = 0.6; E.T.w = 1.25; E.fireNew();
while (E.T.running) E.step();
E.parts(); // [bounced back, inside the wall, got through] → got through ≈ 0.338
Bonus: a Bell test fools you unless you use many pairs
The same page has a Bell test (CHSH) for entanglement. Quantum mechanics predicts S = 2√2 ≈ 2.83, while a "hidden variables" model gives S ≤ 2.
At first I used 2000 pairs each. Then even the hidden-variables model sometimes showed S = 2.06, above 2. That was just statistical scatter.
So I raised it to 20,000 pairs each and also show the standard error of S, √(Σ(1 − E²)/N). Now quantum gives S ≈ 2.83 and hidden variables S ≈ 2.0. When you say "it exceeded 2", you have to show the size of the scatter too.
Main sources
- P. B. Visscher (1991) Computers in Physics 5, 596 (the time-stepping method)
- D. J. Griffiths, D. F. Schroeter (2018) Introduction to Quantum Mechanics, 3rd ed., Cambridge University Press
- R. P. Feynman, R. B. Leighton, M. Sands (1965) The Feynman Lectures on Physics, Vol. III
- J. S. Bell (1964) Physics 1, 195
- J. F. Clauser, M. A. Horne, A. Shimony, R. A. Holt (1969) Physical Review Letters 23, 880
This page is part of Manabi Lab, a series of small learning apps that run in the browser (English and Japanese). It also has double-slit, polarizer and uncertainty-principle experiments. The code and this post were written together with AI (Claude).
來源:DEV Community · dev.to