跳到正文
格致开物MATHWIKI

谱方法

谱方法(spectral method)用一组覆盖整个计算区域的基函数近似未知函数,再确定这些基函数的系数。常见选择包括周期区间上的 Fourier 基和有限区间上的正交多项式。对光滑解,系数常迅速衰减,增加少量模式就可能明显提高精度;对不连续解,全球基函数也会把局部跳跃传播成振荡。

把一个边值问题拆成几种波

考虑 [0,2π] 上的周期问题 −u″(x)=sin⁡2x+12cos⁡3x,∫02πu(x)dx=0. 因为 −(sin⁡kx)″=k2sin⁡kx,每个频率只需除以对应的平方,得到 u(x)=14sin⁡2x+118cos⁡3x. 代回可分别得到 sin⁡2x 和 12cos⁡3x,平均值也为零。这个小例子展示了谱方法的核心:微分算子在合适基下变得简单,而不是先在许多相邻点之间作差分。

周期右端和解的 Fourier 模式对比,较高频率经 Poisson 逆算子后衰减更多
右端含频率二和三,解中相应系数分别除以四和九。图示同一周期上的 f 与 u,纵轴尺度相同。

Fourier–Galerkin 离散

对周期平方可积函数,定义复 Fourier 系数 f^k=12π∫02πf(x)e−ikxdx,k∈ℤ. 取有限维空间 VN=span⁡{eikx:|k|≤N}。Galerkin 条件要求残差与该空间中的测试函数正交。对 −u″=f,这给出 k2u^k=f^k,0<|k|≤N. 零频率要求 f^0=0,这是存在周期解的相容条件:积分方程左边得到 −u′(2π)+u′(0)=0,所以右边平均必须为零。常数又在微分算子的核中,需额外指定 u^0,本例规定为零。若右端改成 1+sin⁡2x,周期问题无解,不能将零频率简单删去后宣称解出了原方程。

对实值函数有 f^−k=f^k‾,因此也可使用等价的正弦余弦实基。教材中的三角插值和 Fourier 离散说明了这两种表示的关系。[1]

截断误差的完整估计

用归一化范数 ‖u‖22=(2π)−1∫02π|u|2dx。Fourier 正交投影 PNu 只保留 |k|≤N 的系数。Parseval 等式给出 ‖u−PNu‖22=∑|k|>N|u^k|2. 若周期函数具有有限的 s 阶 Sobolev 范数,s>0,则在被删掉的模式上有 |k|2s≥(N+1)2s。逐项乘除这个权重便得 ‖u−PNu‖22≤(N+1)−2s∑|k|>N|k|2s|u^k|2≤(N+1)−2s‖u‖Hs2. 取平方根得到代数收敛界。若解析延拓进一步保证 |u^k|≤Ce−σ|k|,尾和才给指数级收敛。光滑性和区域的周期衔接都是条件;“谱精度”并不表示所有函数都按指数速度收敛。

对当前 Poisson 例子,N=2 时漏掉 cos⁡3x/18。由于 ‖cos⁡3x‖2=1/2,归一化误差恰为 1/(182)≈0.0392837101;N≥3 时所有非零模式都已保留,精确算术下误差为零。这是有限模态的特殊精确性。

正交投影、配点与边界的区别

Galerkin 法通过积分正交条件选系数;配点谱法通过若干节点上的残差为零选系数。对某些线性常系数周期问题,它们可以给出相同代数结构,但对非线性乘积或近似积分未必相同。伪谱方法经常在节点上计算非线性项,再变换回系数,需要处理混叠。

非周期区间通常改用 Chebyshev 或 Legendre 基,并把边界条件纳入试探空间、约束方程或弱形式。若把非周期函数硬接成周期函数,端点跳跃会产生 Gibbs 现象:提高阶数能缩窄振荡区域,却不消除跳跃附近的固定相对过冲。间断问题可能更适合分域谱法、滤波或局部高阶方法。

一个可运行的有限模态解算器

以下代码接受有限个非零整数频率的正弦、余弦系数,解零均值周期 Poisson 问题,并返回求值函数。这里不通过采样估计系数,输入本身就是已知模态;构造成本为 O(M),每次求值成本为 O(M),其中 M 是输入模式数。FFT 求系数是另一项计算,不能将本实现称为 FFT 解算器。

Python 3
import math


def periodic_poisson_modes(sines, cosines):
    def prepare(coefficients):
        result = []
        for k, value in coefficients.items():
            if not isinstance(k, int) or k <= 0:
                raise ValueError("positive integer frequencies required")
            value = float(value)
            if not math.isfinite(value):
                raise ValueError("finite coefficients required")
            result.append((k, value / (k * k)))
        return result

    sine_modes, cosine_modes = prepare(sines), prepare(cosines)

    def solution(x):
        x = float(x)
        if not math.isfinite(x):
            raise ValueError("finite x required")
        return (sum(c * math.sin(k*x) for k, c in sine_modes)
                + sum(c * math.cos(k*x) for k, c in cosine_modes))
    return solution


u = periodic_poisson_modes({2: 1}, {3: 0.5})
print(u(0))           # 1/18 = 0.05555555555555555
print(u(math.pi/4))   # 1/4 - sqrt(2)/36 = 0.2107162899340807

有解变式把右端改成 3sin⁡x−2cos⁡4x。分别除以 12 和 42,零均值解为 3sin⁡x−cos⁡4x/8。代入一次即可检查符号;这一验证比只看一条平滑的数值曲线更可靠。

参考资料

  1. ↑ Tobin A. Driscoll, Richard J. Braun. Fundamentals of Numerical Computation: Trigonometric interpolation,周期模式与三角插值。