4. 打靶法计算任意一维势的束缚态能级

打靶法求解一维束缚态:从试探能量到能级匹配

打靶法把定态薛定谔方程当作初值问题处理:给定试探能量 E,从势阱一侧的物理边界出发,用数值积分把波函数推到另一侧,检查它是否满足另一侧的边界条件。对束缚态而言,波函数在两侧无穷远处都必须衰减到零;在有限计算区间 [-L, L] 上,这等价于要求外侧边界处的对数导数与衰减解匹配。能量偏离本征值时,波函数会在远端“发散”或“过零”,只有本征能量才让远端值趋于零。

本节采用无量纲形式,令 ħ = 1, m = 1,方程为 ψ'' = 2(V(x) - E)ψ。用四阶龙格–库塔法从 x = -L 出发,取 ψ(-L) = ε(小量)、ψ'(-L) = κ ε,其中 κ = sqrt(2(V(-L) - E)) 是外侧衰减指数,这样初始条件本身就满足左边界。积分到 x = +L 后,用右端失配函数 f(E) = ψ'(L) + κ ψ(L) 判断:f(E) = 0 即命中本征能量。由于 f(E) 随 E 单调变号,用二分法在区间内扫描即可稳定收敛。

打靶迭代:试探能量 → 积分 → 失配判据 给定试探能量 E 区间 [-L, L] 左边界初值 ψ(-L)=ε, ψ'=κε κ=√(2(V₋-E)) RK4 积分 ψ'' = 2(V(x)-E)ψ 右端失配 f(E)=ψ'(L)+κψ(L) 目标 f(E)=0 二分更新 E |f(E)| < 1e-8 收敛 未收敛则继续 双势阱:能级分裂的数值识别 x V 左阱 右阱 势垒 E₁ 对称 E₂ 反对称 ΔE = E₂ - E₁ ψ₁ 偶宇称 ψ₂ 奇宇称 识别要点:扫描 E 时 f(E) 出现两个相邻零点, 间距即分裂量 ΔE;波函数节点数区分宇称。 势垒越高/越宽,ΔE 越小(趋于简并)。

实现:失配函数与二分扫描

下面给出可直接运行的完整实现。势函数用参数化双势阱 V(x) = a(x² - b²)² / b⁴,在 x = ±b 处有两个极小值,中间 x = 0 处为势垒,高度为 a。通过调节 a 可以观察分裂量 ΔE 的变化。

import numpy as np

def V(x, a=6.0, b=1.5):
    """双势阱:极小值在 ±b,势垒高度 a(无量纲)"""
    return a * (x**2 - b**2)**2 / b**4

def rhs(x, y, E, a, b):
    """y = [psi, psi'],返回导数"""
    psi, dpsi = y
    return np.array([dpsi, 2.0 * (V(x, a, b) - E) * psi])

def rk4_step(x, y, h, E, a, b):
    k1 = rhs(x, y, E, a, b)
    k2 = rhs(x + h/2, y + h/2*k1, E, a, b)
    k3 = rhs(x + h/2, y + h/2*k2, E, a, b)
    k4 = rhs(x + h, y + h*k3, E, a, b)
    return y + h/6.0 * (k1 + 2*k2 + 2*k3 + k4)

def mismatch(E, L=6.0, N=4000, a=6.0, b=1.5):
    """从 -L 积分到 +L,返回右端失配 f(E)"""
    x = -L
    h = 2.0 * L / N
    kappa = np.sqrt(max(2.0 * (V(-L, a, b) - E), 1e-12))
    y = np.array([1e-6, kappa * 1e-6])   # 满足左边界衰减
    for _ in range(N):
        y = rk4_step(x, y, h, E, a, b)
        x += h
    psi_R, dpsi_R = y
    return dpsi_R + kappa * psi_R

def find_levels(Emin, Emax, nscan=400, **kw):
    """扫描失配函数变号区间,二分求根"""
    Es = np.linspace(Emin, Emax, nscan)
    fs = np.array([mismatch(E, **kw) for E in Es])
    roots = []
    for i in range(len(Es) - 1):
        if fs[i] * fs[i+1] < 0:
            lo, hi = Es[i], Es[i+1]
            for _ in range(60):
                mid = 0.5 * (lo + hi)
                if mismatch(lo, **kw) * mismatch(mid, **kw) <= 0:
                    hi = mid
                else:
                    lo = mid
            roots.append(0.5 * (lo + hi))
    return roots

levels = find_levels(0.0, 6.0, a=6.0, b=1.5)
print("能级:", [f"{e:.6f}" for e in levels])
if len(levels) >= 2:
    print("分裂 ΔE =", f"{levels[1] - levels[0]:.6e}")

运行后应得到两个低能级,且 levels[1] - levels[0] 是一个小量。若把 a 从 6 增大到 12,势垒变高,分裂量会显著减小;把 b 增大使两阱远离,同样使 ΔE 减小。这正是双势阱中隧穿耦合导致能级分裂的数值体现。

失配函数在扫描区间内必须单调变号才能被二分捕获。若 nscan 太小,两个靠得很近的零点可能落在同一格点区间内而被漏掉。对双势阱,建议先用较粗扫描确认 f(E) 的符号序列,再在疑似区间加密。

波函数重建与宇称判读

求得本征能量后,用同一积分器保存整条轨迹即可得到波函数。双势阱的两个低能态分别具有偶宇称(无节点,两阱同号)与奇宇称(中间一个节点,两阱反号)。判读时统计区间内的过零次数:偶宇称态过零 0 次,奇宇称态过零 1 次,这是区分 E₁ 与 E₂ 最直接的数值证据。

def wavefunction(E, L=6.0, N=4000, a=6.0, b=1.5):
    x = -L
    h = 2.0 * L / N
    kappa = np.sqrt(max(2.0 * (V(-L, a, b) - E), 1e-12))
    y = np.array([1e-6, kappa * 1e-6])
    xs, psis = [x], [y[0]]
    for _ in range(N):
        y = rk4_step(x, y, h, E, a, b)
        x += h
        xs.append(x); psis.append(y[0])
    xs, psis = np.array(xs), np.array(psis)
    psis /= np.sqrt(np.trapz(psis**2, xs))   # 归一化
    return xs, psis

for E in levels[:2]:
    xs, psi = wavefunction(E)
    nodes = int(np.sum(np.sign(psi[:-1]) * np.sign(psi[1:]) < 0))
    print(f"E={E:.6f}  节点数={nodes}  宇称={'偶' if nodes % 2 == 0 else '奇'}")
有限区间 L 必须足够大,使外侧波函数已衰减到可忽略。若 L 过小,右端失配函数会被截断误差污染,导致能级偏高或出现伪根。可逐步增大 L 观察能级是否稳定,以此确认区间足够。

收敛性与参数检查

检查项做法通过判据
积分步长固定 L,把 N 从 2000 增到 8000能级变化小于 1e-6
区间长度把 L 从 4 增到 8能级趋于稳定值
失配收敛检查二分后 |f(E)|小于 1e-8
分裂识别比较 E₂ - E₁ 随 a 的变化势垒升高时 ΔE 单调减小

打靶法的优势在于只需一维积分、无需构造矩阵,对任意形状的势都适用;代价是每次求根都要重新积分,且对深束缚态需要更长的区间与更细的步长。对双势阱这类近简并情形,关键是扫描密度足够高,确保两个相邻零点都被捕获,再用节点数确认宇称归属。