# 量子力学入门:用Python模拟海森堡不确定性原理(附代码)
很多对物理和编程都感兴趣的朋友,可能都曾有过这样的念头:那些听起来玄之又玄的量子力学概念,能不能用我们熟悉的代码“跑”出来看看?理论公式固然优美,但亲手写几行程序,看着图表动态生成,那种“眼见为实”的体验,往往能带来更深刻的理解。今天,我们就来尝试用Python这个强大的工具,把量子力学中最著名的原理之一——海森堡不确定性原理,从抽象的数学不等式,变成一个可以交互、可以调整、可以直观感受的模拟实验。
这篇文章面向的,正是那些有一定Python基础(熟悉NumPy和Matplotlib即可),并对量子世界充满好奇的开发者、学生或科技爱好者。我们不会陷入复杂的数学推导,而是聚焦于如何用编程思维来构建物理模型。你将看到,如何用一个高斯波包来代表一个“粒子”的状态,如何通过傅里叶变换在位置和动量两个“视角”间切换,并最终通过计算和可视化,亲眼见证位置测量越精确,动量就越模糊这一反直觉的量子现象。整个过程,就像在代码中搭建一个微型的量子实验室。
## 1. 从经典直觉到量子现实:为什么需要模拟?
在开始敲代码之前,我们得先理清一个根本性的思维转换。在经典物理的世界里,比如描述一个飞行的棒球,我们可以同时知道它某一时刻精确的位置(在球场的哪个坐标)和精确的动量(速度乘以质量)。理论上,只要测量仪器足够精密,这两个值可以无限精确地确定。我们的直觉也建立在这种“确定性”之上。
然而,进入微观的量子世界,比如一个电子,这套直觉就完全失灵了。海森堡不确定性原理指出,对于像位置(x)和动量(p)这样的一对“共轭”物理量,你无法同时无限精确地知道它们。这种限制不是因为我们仪器太烂,而是自然法则本身设下的底线。其数学表达是一个不等式:
\[
\sigma_x \cdot \sigma_p \geq \frac{\hbar}{2}
\]
这里,\(\sigma_x\) 和 \(\sigma_p\) 分别代表位置和动量的标准差,即“不确定性”的度量。\(\hbar\)(读作“h-bar”)是约化普朗克常数,一个极其微小的数(约 \(1.054 \times 10^{-34} J \cdot s\)),但它却是量子世界的“刻度尺”。这个不等式告诉我们,两者不确定度的乘积有一个最小值。试图压扁其中一个,另一个就必然会膨胀。
> 注意:你可能会看到有些资料用 \(\Delta x\) 和 \(\Delta p\) 表示测量误差。在更严格的量子力学表述中,我们通常用波函数的标准差 \(\sigma\) 来定义这种内在的不确定性,这比“测量误差”的表述更本质。
那么,如何“看到”这个原理呢?这正是编程模拟的魅力所在。我们将用量子力学中描述粒子状态的核心工具——波函数 \(\psi(x)\) 来构建模型。波函数绝对值的平方 \(|\psi(x)|^2\) 给出了在位置x处找到粒子的概率密度。而通过傅里叶变换,我们可以得到动量空间的波函数 \(\phi(p)\),其绝对值的平方 \(|\phi(p)|^2\) 则给出了粒子具有动量p的概率密度。我们的模拟,就是围绕构建和操作这个波函数展开的。
## 2. 构建我们的量子实验室:环境与波函数初始化
工欲善其事,必先利其器。我们的模拟将完全在Python环境中进行,主要依赖两个库:`NumPy` 负责所有数组运算和数学计算,`Matplotlib` 负责将结果可视化。如果你还没有安装,可以通过pip快速安装:
```bash
pip install numpy matplotlib
```
首先,我们来搭建模拟的“舞台”。在量子力学中,我们通常在一个有限的、离散化的空间网格上进行计算。这就像用像素点来描绘一幅连续的画面。
```python
import numpy as np
import matplotlib.pyplot as plt
# 设置模拟参数
N = 1024 # 空间网格点数,越多越精确,但计算量越大
L = 100.0 # 模拟空间的长度(任意单位,如纳米)
x = np.linspace(-L/2, L/2, N) # 从 -L/2 到 L/2 均匀分布的位置坐标数组
dx = x[1] - x[0] # 网格间距
```
接下来,我们要创造一个具体的量子态。为了便于理解和计算,我们选择**高斯波包**作为初始波函数。它是一个在位置空间呈高斯分布(钟形曲线)的波函数,具有明确的中心位置和宽度,是量子力学教科书中最常见的模型之一。
高斯波函数的形式为:
\[
\psi(x) = \frac{1}{(2\pi\sigma_x^2)^{1/4}} \exp\left(-\frac{(x-x_0)^2}{4\sigma_x^2} + i k_0 x\right)
\]
别被这个公式吓到,我们拆解一下:
- 指数部分的实部 `-(x-x_0)^2/(4\sigma_x^2)` 控制着波包在位置空间的形状。\(x_0\) 是波包的中心位置,\(\sigma_x\) 就是位置的不确定度,即波包的宽度。
- 指数部分的虚部 `i k_0 x` 赋予了波包一个整体的运动趋势。其中 \(k_0 = p_0 / \hbar\) 是波数,与粒子的平均动量 \(p_0\) 相关。
- 前面的系数是为了让波函数满足归一化条件(总概率为1)。
让我们用代码来实现它:
```python
def gaussian_wavepacket(x, x0, sigma_x, k0):
"""
生成一个高斯波包。
参数:
x: 位置坐标数组
x0: 波包中心位置
sigma_x: 位置空间的标准差(宽度)
k0: 中心波数 (p0 / hbar)
返回:
psi: 复数形式的波函数数组
"""
# 归一化系数
normalization = (1.0/(2*np.pi*sigma_x**2))**0.25
# 高斯包络部分
envelope = np.exp(-(x - x0)**2 / (4.0 * sigma_x**2))
# 平面波部分(提供动量)
plane_wave = np.exp(1j * k0 * x) # 1j是Python中虚数单位i
psi = normalization * envelope * plane_wave
return psi
# 设置波包参数
x0 = 0.0 # 初始中心在原点
sigma_x = 2.0 # 位置不确定度(波包宽度)
k0 = 1.0 # 初始波数,决定平均动量
hbar = 1.0 # 为了简化,令约化普朗克常数 hbar = 1(自然单位)
# 生成波函数
psi_x = gaussian_wavepacket(x, x0, sigma_x, k0)
```
现在,`psi_x` 就是我们粒子在位置空间的“状态描述”了。我们可以先可视化一下它的概率密度:
```python
plt.figure(figsize=(10, 4))
plt.subplot(1, 2, 1)
plt.plot(x, np.abs(psi_x)**2, 'b-', linewidth=2, label=r'$|\psi(x)|^2$')
plt.fill_between(x, 0, np.abs(psi_x)**2, alpha=0.3)
plt.xlabel('位置 (x)')
plt.ylabel('概率密度')
plt.title('位置空间的概率分布(高斯波包)')
plt.grid(True, alpha=0.3)
plt.legend()
# 为了更直观,也看看波函数的实部和虚部(它是个复数!)
plt.subplot(1, 2, 2)
plt.plot(x, psi_x.real, 'r-', label='实部')
plt.plot(x, psi_x.imag, 'g-', label='虚部')
plt.xlabel('位置 (x)')
plt.ylabel('振幅')
plt.title('波函数的实部与虚部')
plt.grid(True, alpha=0.3)
plt.legend()
plt.tight_layout()
plt.show()
```
运行这段代码,你会看到两个图。左边是熟悉的钟形曲线,表示在中心点附近找到粒子的概率最大,越往两边概率越小。右边则展示了波函数作为复函数的振荡特性,那个振荡的频率就隐含了动量信息。
## 3. 切换视角:傅里叶变换与动量空间
量子力学的一个美妙之处在于,位置和动量描述是等价的,可以通过傅里叶变换相互转换。这就像看待同一个物体的两张不同照片:一张是正面照(位置空间),一张是侧面照(动量空间)。NumPy提供的 `np.fft.fft`(快速傅里叶变换)函数正是我们切换视角的“魔法镜”。
在量子力学中,动量空间的波函数 \(\phi(p)\) 是位置空间波函数 \(\psi(x)\) 的傅里叶变换(差一个常数因子):
\[
\phi(p) = \frac{1}{\sqrt{2\pi\hbar}} \int_{-\infty}^{\infty} \psi(x) e^{-i p x / \hbar} dx
\]
而 \(|\phi(p)|^2\) 就是在动量p处找到粒子的概率密度。
对于我们在离散网格上计算的 `psi_x`,需要进行离散傅里叶变换(DFT)。这里有几个技术细节需要注意:
1. **fft的频率顺序**:`np.fft.fft` 输出的默认频率顺序是0到正频率,再到负频率。我们需要用 `np.fft.fftshift` 将其调整为零频率在中心的顺序,这样画图更直观。
2. **动量坐标的生成**:动量网格与空间网格的间距满足傅里叶变换的互易关系。
3. **归一化**:DFT的结果需要乘以一个尺度因子才能得到正确的 \(\phi(p)\)。
下面的函数封装了这些步骤:
```python
def position_to_momentum(psi_x, dx, hbar=1.0):
"""
通过傅里叶变换将位置空间波函数转换到动量空间。
参数:
psi_x: 位置空间波函数(复数数组)
dx: 位置网格间距
hbar: 约化普朗克常数
返回:
p: 动量坐标数组
phi_p: 动量空间波函数(复数数组)
"""
N = len(psi_x)
# 执行傅里叶变换并调整频率顺序
fft_result = np.fft.fftshift(np.fft.fft(psi_x))
# 生成对应的动量坐标
# 动量网格的间距 dp = 2πħ / (N * dx)
dp = 2 * np.pi * hbar / (N * dx)
# 生成以0为中心的动量数组
p = np.fft.fftshift(np.fft.fftfreq(N, d=dx/(2*np.pi*hbar)))
# 对FFT结果进行归一化,使其满足量子力学中的傅里叶变换定义
phi_p = fft_result * dx / np.sqrt(2 * np.pi * hbar)
return p, phi_p
# 转换到动量空间
p, phi_p = position_to_momentum(psi_x, dx, hbar)
# 计算位置和动量的不确定度(标准差)
# 位置不确定度:sigma_x = sqrt(<x^2> - <x>^2)
prob_x = np.abs(psi_x)**2
x_mean = np.sum(x * prob_x) * dx # 位置期望值 <x>
x2_mean = np.sum(x**2 * prob_x) * dx # <x^2>
sigma_x_calculated = np.sqrt(x2_mean - x_mean**2)
# 动量不确定度:sigma_p = sqrt(<p^2> - <p>^2)
prob_p = np.abs(phi_p)**2
dp_value = p[1] - p[0] # 动量网格间距
p_mean = np.sum(p * prob_p) * dp_value # 动量期望值 <p>
p2_mean = np.sum(p**2 * prob_p) * dp_value # <p^2>
sigma_p_calculated = np.sqrt(p2_mean - p_mean**2)
print(f"理论设定的位置不确定度 sigma_x: {sigma_x:.4f}")
print(f"从波函数计算的位置不确定度 sigma_x: {sigma_x_calculated:.4f}")
print(f"从波函数计算的动量不确定度 sigma_p: {sigma_p_calculated:.4f}")
print(f"两者的乘积 sigma_x * sigma_p: {sigma_x_calculated * sigma_p_calculated:.4f}")
print(f"海森堡极限 ħ/2: {hbar/2:.4f}")
```
运行后,控制台会输出计算的不确定度及其乘积。对于一个理想的高斯波包,这个乘积会精确等于 \(\hbar/2\),达到不确定性原理所允许的最小值,我们称这样的波包为**最小不确定度波包**。现在,让我们把位置和动量两个空间的概率分布画在一起对比:
```python
plt.figure(figsize=(12, 5))
# 位置空间分布
plt.subplot(1, 2, 1)
plt.plot(x, np.abs(psi_x)**2, 'b-', linewidth=2)
plt.fill_between(x, 0, np.abs(psi_x)**2, color='blue', alpha=0.3)
plt.axvline(x=x_mean, color='red', linestyle='--', label=f'均值 = {x_mean:.2f}')
plt.axvline(x=x_mean - sigma_x_calculated, color='orange', linestyle=':', label=f'±σ_x = {sigma_x_calculated:.2f}')
plt.axvline(x=x_mean + sigma_x_calculated, color='orange', linestyle=':')
plt.xlabel('位置 (x)')
plt.ylabel('概率密度')
plt.title(f'位置空间分布 (σ_x = {sigma_x_calculated:.3f})')
plt.legend()
plt.grid(True, alpha=0.3)
# 动量空间分布
plt.subplot(1, 2, 2)
plt.plot(p, np.abs(phi_p)**2, 'g-', linewidth=2)
plt.fill_between(p, 0, np.abs(phi_p)**2, color='green', alpha=0.3)
plt.axvline(x=p_mean, color='red', linestyle='--', label=f'均值 = {p_mean:.2f}')
plt.axvline(x=p_mean - sigma_p_calculated, color='orange', linestyle=':', label=f'±σ_p = {sigma_p_calculated:.2f}')
plt.axvline(x=p_mean + sigma_p_calculated, color='orange', linestyle=':')
plt.xlabel('动量 (p)')
plt.ylabel('概率密度')
plt.title(f'动量空间分布 (σ_p = {sigma_p_calculated:.3f})')
plt.legend()
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
```
这张对比图是理解不确定性原理的关键。左边,位置概率分布是一个狭窄的峰(由我们设定的 `sigma_x=2.0` 决定)。右边,动量概率分布也是一个高斯峰,但其宽度 \(\sigma_p\) 被“挤”了出来。两者的形状恰好呈现出一种“互补”关系。
## 4. 动态演示:改变宽度,观察不确定性“跷跷板”
理论告诉我们,\(\sigma_x\) 和 \(\sigma_p\) 像坐跷跷板,一个下去,另一个就得上来。现在,让我们用交互式模拟来亲身体验这种关系。我们将创建一系列不同初始宽度 \(\sigma_x\) 的高斯波包,计算它们对应的动量分布,并观察两者不确定度的变化。
为了方便演示,我们写一个函数来执行单次模拟和绘图:
```python
def simulate_uncertainty(sigma_x_val, k0=1.0):
"""模拟给定位置不确定度下的波包,并计算其动量不确定度"""
# 生成波函数
psi = gaussian_wavepacket(x, x0=0.0, sigma_x=sigma_x_val, k0=k0)
# 转换到动量空间
p_vals, phi = position_to_momentum(psi, dx, hbar)
# 计算不确定度
prob_x = np.abs(psi)**2
x_mean = np.sum(x * prob_x) * dx
x2_mean = np.sum(x**2 * prob_x) * dx
sigma_x_calc = np.sqrt(x2_mean - x_mean**2)
prob_p = np.abs(phi)**2
dp_val = p_vals[1] - p_vals[0]
p_mean = np.sum(p_vals * prob_p) * dp_val
p2_mean = np.sum(p_vals**2 * prob_p) * dp_val
sigma_p_calc = np.sqrt(p2_mean - p_mean**2)
return sigma_x_calc, sigma_p_calc, psi, phi, p_vals
# 测试一组不同的sigma_x值
sigma_x_list = [0.5, 1.0, 2.0, 4.0, 8.0]
results = []
for sx in sigma_x_list:
sx_calc, sp_calc, psi_temp, phi_temp, p_temp = simulate_uncertainty(sx)
results.append((sx_calc, sp_calc, psi_temp, phi_temp, p_temp))
print(f"设定 σ_x={sx:.1f}: 计算 σ_x={sx_calc:.3f}, σ_p={sp_calc:.3f}, 乘积={sx_calc*sp_calc:.4f}")
```
输出会显示,无论 \(\sigma_x\) 如何变化,两者的乘积始终围绕 \(\hbar/2 = 0.5\) 波动(由于数值离散化,会有微小误差)。为了更生动地展示,我们可以把不同宽度波包的位置和动量分布画在一张图上进行对比:
```python
fig, axes = plt.subplots(2, len(sigma_x_list), figsize=(16, 6))
colors = plt.cm.viridis(np.linspace(0, 1, len(sigma_x_list)))
for idx, (sx_calc, sp_calc, psi_temp, phi_temp, p_temp) in enumerate(results):
color = colors[idx]
# 绘制位置分布
ax_pos = axes[0, idx]
ax_pos.plot(x, np.abs(psi_temp)**2, color=color, linewidth=2)
ax_pos.fill_between(x, 0, np.abs(psi_temp)**2, color=color, alpha=0.4)
ax_pos.set_title(f'σ_x = {sx_calc:.2f}')
ax_pos.set_xlabel('x')
ax_pos.grid(True, alpha=0.3)
if idx == 0:
ax_pos.set_ylabel('|ψ(x)|²')
# 绘制动量分布
ax_mom = axes[1, idx]
ax_mom.plot(p_temp, np.abs(phi_temp)**2, color=color, linewidth=2)
ax_mom.fill_between(p_temp, 0, np.abs(phi_temp)**2, color=color, alpha=0.4)
ax_mom.set_title(f'σ_p = {sp_calc:.2f}')
ax_mom.set_xlabel('p')
ax_mom.grid(True, alpha=0.3)
if idx == 0:
ax_mom.set_ylabel('|φ(p)|²')
plt.suptitle('位置不确定度 σ_x 与动量不确定度 σ_p 的互补关系', fontsize=14)
plt.tight_layout()
plt.show()
```
观察这组对比图,规律一目了然:**第一行**,位置空间的波包从左到右逐渐“展宽”(\(\sigma_x\) 增大)。**第二行**,对应的动量空间波包则从左到右逐渐“变窄”(\(\sigma_p\) 减小)。最左边一列,位置波包非常尖锐(位置很确定),但动量波包非常弥散(动量极不确定)。最右边一列则相反,位置很模糊,但动量很确定。这完美诠释了“鱼与熊掌不可兼得”的量子版本。
为了定量验证不确定性关系,我们可以绘制 \(\sigma_x\) 与 \(\sigma_p\) 以及它们乘积的关系曲线:
```python
# 收集更多数据点进行平滑绘图
sigma_x_range = np.linspace(0.3, 10, 50)
sigma_p_vals = []
products = []
for sx_val in sigma_x_range:
sx_c, sp_c, _, _, _ = simulate_uncertainty(sx_val, k0=0) # 令k0=0,让波包静止,简化分析
sigma_p_vals.append(sp_c)
products.append(sx_c * sp_c)
plt.figure(figsize=(12, 4))
# 子图1: σ_p 随 σ_x 的变化
plt.subplot(1, 3, 1)
plt.plot(sigma_x_range, sigma_p_vals, 'b-o', markersize=3, linewidth=2)
plt.xlabel('位置不确定度 σ_x')
plt.ylabel('动量不确定度 σ_p')
plt.title('σ_p 与 σ_x 的关系')
plt.grid(True, alpha=0.3)
plt.axhline(y=0.5, color='gray', linestyle='--', alpha=0.5) # ħ/2 线
# 子图2: 乘积 σ_x * σ_p
plt.subplot(1, 3, 2)
plt.plot(sigma_x_range, products, 'r-s', markersize=3, linewidth=2)
plt.axhline(y=hbar/2, color='k', linestyle='--', label='ħ/2')
plt.xlabel('位置不确定度 σ_x')
plt.ylabel('乘积 σ_x * σ_p')
plt.title('不确定性乘积')
plt.legend()
plt.grid(True, alpha=0.3)
# 子图3: 双对数坐标下的反比关系
plt.subplot(1, 3, 3)
plt.loglog(sigma_x_range, sigma_p_vals, 'g-^', markersize=3, linewidth=2)
# 绘制一条斜率为-1的参考线,表示反比关系 y ∝ 1/x
ref_x = np.array([0.5, 5])
ref_y = 0.5 / ref_x # 因为 σ_x * σ_p ≈ 0.5
plt.loglog(ref_x, ref_y, 'k:', label='斜率 -1 (反比)')
plt.xlabel('σ_x (对数坐标)')
plt.ylabel('σ_p (对数坐标)')
plt.title('对数坐标:σ_p ∝ 1/σ_x')
plt.legend()
plt.grid(True, alpha=0.3, which='both')
plt.tight_layout()
plt.show()
```
从这三个图中,我们可以清晰地看到:
1. **反比趋势**:\(\sigma_p\) 随着 \(\sigma_x\) 增大而单调减小。
2. **乘积守恒**:无论 \(\sigma_x\) 如何变化,\(\sigma_x \cdot \sigma_p\) 的乘积始终在 \(\hbar/2\) 这条线上下轻微波动(数值误差导致)。
3. **反比关系的对数证据**:在双对数坐标下,两者关系接近一条斜率为-1的直线,这正是反比关系 \(y \propto 1/x\) 的特征。
## 5. 超越高斯波包:探索更一般的量子态
高斯波包是一个特例,它达到了不确定性原理的下限。但量子态可以有无穷多种形式,它们的不确定度乘积通常**大于** \(\hbar/2\)。我们可以通过构造非高斯的波函数来验证这一点。例如,考虑一个“双峰”波函数,或者一个在有限区间内均匀分布的波函数。
让我们尝试一个简单的非高斯态:**无限深方势阱中的基态波函数**。在区间 \([-a, a]\) 内,其波函数为 \(\psi(x) = \frac{1}{\sqrt{a}} \cos(\frac{\pi x}{2a})\),之外为0。这个波函数不是高斯型的,我们预期它的不确定度乘积会更大。
```python
def infinite_well_ground_state(x, a=5.0):
"""
无限深方势阱(宽度为2a)的基态波函数。
在 |x| < a 内为 cos(πx/(2a)),之外为0。
"""
psi = np.zeros_like(x, dtype=complex)
inside = np.abs(x) < a
psi[inside] = (1/np.sqrt(a)) * np.cos(np.pi * x[inside] / (2*a))
# 归一化检查(数值积分)
norm = np.sqrt(np.sum(np.abs(psi)**2) * dx)
psi = psi / norm # 数值归一化
return psi
# 生成势阱基态波函数
a = 5.0
psi_well = infinite_well_ground_state(x, a)
# 转换到动量空间
p_well, phi_well = position_to_momentum(psi_well, dx, hbar)
# 计算不确定度
prob_x_well = np.abs(psi_well)**2
x_mean_well = np.sum(x * prob_x_well) * dx
x2_mean_well = np.sum(x**2 * prob_x_well) * dx
sigma_x_well = np.sqrt(x2_mean_well - x_mean_well**2)
prob_p_well = np.abs(phi_well)**2
dp_well = p_well[1] - p_well[0]
p_mean_well = np.sum(p_well * prob_p_well) * dp_well
p2_mean_well = np.sum(p_well**2 * prob_p_well) * dp_well
sigma_p_well = np.sqrt(p2_mean_well - p_mean_well**2)
product_well = sigma_x_well * sigma_p_well
print(f"无限深势阱基态:")
print(f" 位置不确定度 σ_x: {sigma_x_well:.4f}")
print(f" 动量不确定度 σ_p: {sigma_p_well:.4f}")
print(f" 乘积 σ_x * σ_p: {product_well:.4f}")
print(f" 是否大于 ħ/2 ({hbar/2:.4f})? {product_well > hbar/2}")
```
计算结果显示,这个波函数的不确定度乘积确实显著大于0.5。我们可以将其与高斯波包进行对比可视化:
```python
# 选择一个宽度类似的高斯波包进行对比
sigma_x_gauss = sigma_x_well # 让位置不确定度大致相同
psi_gauss_compare = gaussian_wavepacket(x, x0=0.0, sigma_x=sigma_x_gauss, k0=0)
p_gauss, phi_gauss_compare = position_to_momentum(psi_gauss_compare, dx, hbar)
# 计算高斯波包的不确定度(应接近ħ/2)
prob_x_g = np.abs(psi_gauss_compare)**2
x2_mean_g = np.sum(x**2 * prob_x_g) * dx
sigma_x_g = np.sqrt(x2_mean_g) # 均值为0
prob_p_g = np.abs(phi_gauss_compare)**2
dp_g = p_gauss[1] - p_gauss[0]
p2_mean_g = np.sum(p_gauss**2 * prob_p_g) * dp_g
sigma_p_g = np.sqrt(p2_mean_g)
product_gauss = sigma_x_g * sigma_p_g
fig, axes = plt.subplots(2, 2, figsize=(11, 8))
# 位置空间对比
axes[0, 0].plot(x, np.abs(psi_well)**2, 'b-', label='势阱基态', linewidth=2)
axes[0, 0].plot(x, np.abs(psi_gauss_compare)**2, 'r--', label='高斯波包', linewidth=2)
axes[0, 0].set_xlabel('位置 (x)')
axes[0, 0].set_ylabel('概率密度')
axes[0, 0].set_title('位置空间分布对比')
axes[0, 0].legend()
axes[0, 0].grid(True, alpha=0.3)
# 动量空间对比
axes[0, 1].plot(p_well, np.abs(phi_well)**2, 'b-', label='势阱基态', linewidth=2)
axes[0, 1].plot(p_gauss, np.abs(phi_gauss_compare)**2, 'r--', label='高斯波包', linewidth=2)
axes[0, 1].set_xlabel('动量 (p)')
axes[0, 1].set_ylabel('概率密度')
axes[0, 1].set_title('动量空间分布对比')
axes[0, 1].legend()
axes[0, 1].grid(True, alpha=0.3)
axes[0, 1].set_xlim([-5, 5]) # 限制范围以便观察
# 文本信息对比
axes[1, 0].axis('off')
info_text = f"""
**无限深势阱基态**:
σ_x = {sigma_x_well:.3f}
σ_p = {sigma_p_well:.3f}
乘积 = {product_well:.3f}
**高斯波包 (σ_x相近)**:
σ_x = {sigma_x_g:.3f}
σ_p = {sigma_p_g:.3f}
乘积 = {product_gauss:.3f}
海森堡下限 (ħ/2) = {hbar/2:.3f}
"""
axes[1, 0].text(0.1, 0.5, info_text, fontsize=12, verticalalignment='center', family='monospace')
# 不确定性关系图示
axes[1, 1].scatter([sigma_x_well, sigma_x_g], [sigma_p_well, sigma_p_g], s=100, color=['blue', 'red'])
axes[1, 1].plot([0, 10], [hbar/2/10, hbar/2/0.1], 'k--', label='σ_x · σ_p = ħ/2', alpha=0.7) # 双曲线 σ_p = (ħ/2)/σ_x
axes[1, 1].set_xlabel('σ_x')
axes[1, 1].set_ylabel('σ_p')
axes[1, 1].set_title('不确定性关系图')
axes[1, 1].set_xlim(0, sigma_x_well*1.5)
axes[1, 1].set_ylim(0, sigma_p_well*1.5)
axes[1, 1].legend()
axes[1, 1].grid(True, alpha=0.3)
# 标记点
axes[1, 1].annotate('势阱基态', (sigma_x_well, sigma_p_well), xytext=(10, 10), textcoords='offset points')
axes[1, 1].annotate('高斯波包', (sigma_x_g, sigma_p_g), xytext=(10, -15), textcoords='offset points')
plt.tight_layout()
plt.show()
```
这张对比图清晰地展示了关键区别:虽然我们构造的势阱基态波函数在位置空间(左上图)的宽度(不确定度)与高斯波包相似,但它在动量空间(右上图)的分布却**宽得多**。结果就是,它的不确定度乘积(蓝点)远高于代表最小不确定度的高斯波包(红点),并且红点恰好落在代表下限 \(\sigma_x \cdot \sigma_p = \hbar/2\) 的双曲线上,而蓝点则高高在上。这验证了不确定性原理是一个**不等式**,高斯波包是能达到这个下限的“最紧凑”的状态,而其他状态只会更“不确定”。
## 6. 从模拟到洞察:理解ℏ的意义与测量诠释
通过上面的模拟,我们不仅看到了不确定性关系的数学形式,更能直观感受其物理内涵。那个看似微不足道的常数 \(\hbar\)(在我们的模拟中设为1),实际上是划定经典与量子界限的“标尺”。在宏观世界,\(\hbar\) 的量级(\(10^{-34}\))小到可以忽略,因此 \(\sigma_x \cdot \sigma_p \geq 0\) 在实际上等同于没有限制,我们感觉不到这种不确定性。但在原子、电子等微观尺度,\(\hbar\) 的大小变得举足轻重,这个下限约束就凸显出来,从根本上限制了我们对微观世界的认知精度。
> 提示:你可以尝试在代码中将 `hbar` 改为一个更大的值(比如10或100),重新运行模拟。你会发现位置和动量的分布会随之发生显著变化,乘积的下限变大了。这相当于我们想象一个“ħ更大的宇宙”,在那里量子效应在更宏观的尺度上就会显现出来。
最后,关于“测量”的常见误解需要澄清。我们的模拟展示的是量子态**固有的**不确定性,它存在于测量之前。波函数本身就已经包含了这种概率分布。海森堡最初的“显微镜思想实验”容易让人误解,以为是测量动作的干扰(如用光子轰击电子)导致了不确定性的产生。虽然测量确实会扰动系统,但不确定性原理揭示的是更深层的东西:某些成对的物理量(如位置和动量)在量子力学中由**不对易**的算符描述(\([\hat{x}, \hat{p}] = i\hbar\)),这种数学结构决定了它们没有共同的本征态,因此无法同时拥有确定值。我们的模拟没有引入任何“测量过程”,只是展示了不同量子态本身的性质,这恰恰说明了不确定性是状态的内禀属性。
动手模拟到这里,你可能已经对量子力学的这种“模糊性”有了更具体的认识。它不再是书本上一个生硬的公式,而是一个你可以用代码操控、观察甚至“玩”起来的动态关系。这种从抽象到具象的转化,正是计算物理和科学模拟最吸引人的地方。你可以基于本文的代码框架继续探索,比如模拟波包随时间的演化(加入薛定谔方程的时间项),或者尝试其他有趣的初始波函数,看看它们如何 dance on the edge of uncertainty。