简介:这份PPT围绕《数理方程》(数学物理方程)课程整理,面向正在学习偏微分方程基础、准备课程复习或考研梳理的高校理工科学生,重点解决数学模型建立、方程分类与解析求解方法入门等问题。压缩包内共1个ppt文件,体积约1.5MB,内容以课堂讲义形式呈现,结构紧凑,适合直接投屏学习或打印标注。课件从偏微分方程的基本概念讲起,依次梳理方程阶数、线性与非线性(含半线性、拟线性、完全非线性)的区分,常系数与变系数、齐次与非齐次等性质,并给出二阶线性方程按系数矩阵判别双曲型、椭圆型、抛物型的典型例子。后续还涉及叠加原理、波动方程、热传导方程与调和方程的导出思路,以及定解条件和定解问题的提法,并附课程教材、作业与答疑安排。已有439人学习,适合用来建立知识框架、对照课堂查漏补缺。
1. 一套课件值不值得存:先看它把 PDE 讲到哪一层
很多工程口的人对「数理方程」的记忆只停在期末那道分离变量题,考完就归还给老师。真到要建模的时候——比如做热应力仿真、做振动分析、写有限差分求解器——才发现卡住的不是代码,是分不清自己手上这个方程该配几个初始条件、边界条件该给哪一类。这份来自某高校课程的数理方程 PPT,价值恰在这里:它把偏微分方程从定义、阶数、线性与非线性,一路推到三类典型方程的导出和定解条件,是一条完整的、可以反复回看的推导链。
它不能替代教材,但胜在页面短、结论前置,适合两类人:一是想重新捡起解析方法的从业者,二是准备上手数值解、想先把方程类型搞明白再动笔的人。PPT 只给骨,肉得你自己补。
2. 讲义骨架拆解:三类方程的判别式与一个常被抄错的系数
2.1 判别式只有一个,但系数要摆对位置
讲义对两个自变量的二阶线性偏微分方程统一写成下面这个标准形式,后面的分类全建立在这个形式上:
a11·u_xx + 2·a12·u_xy + a22·u_yy + b1·u_x + b2·u_y + c·u = f(x, y)判别式是Δ = a12² − a11·a22,在区域内某点 M 处:
| Δ 的符号 | 方程类型 | 讲义里的代表方程 |
|---|---|---|
| Δ > 0 | 双曲型 | 波动方程 u_tt = a²·u_xx |
| Δ = 0 | 抛物型 | 热传导方程 u_t = a²·u_xx |
| Δ < 0 | 椭圆型 | 拉普拉斯方程 u_xx + u_yy = 0 |
关键在交叉项前面那个2。方程里写成2·a12·u_xy,说明 a12 是 u_xy 系数的一半。我见过太多人拿起u_xx + 4·u_xy + u_yy = 0就直接取 a12 = 4,算出 Δ = 16 − 1 = 15 判成双曲;正确取法是 a12 = 2,Δ = 4 − 1 = 3,仍然是双曲。如果写成u_xx + 4·u_xy + 4·u_yy = 0,a12 = 2、a11 = 1、a22 = 4,Δ = 4 − 4 = 0,这才是抛物型。两种写法只差一个系数,结论就变了。所以别背结论,把标准形式写死,对照着填。
热传导和波动方程要先“对位”再判。热传导 u_t = a²·u_xx,把 t 当作第二个变量 y,移项得 u_xx − (1/a²)·u_t = 0,于是 a11 = 1、a12 = 0、a22 = 0,Δ = 0,抛物型。波动 u_tt = a²·u_xx 移项为 u_xx − (1/a²)·u_tt = 0,a11 = 1、a22 = −1/a²,Δ = 1/a² > 0,双曲型。这个“移项对位”的动作看起来笨,但它是唯一不会出错的路径。
2.2 用 sympy 把判别式跑成可验证脚本
手算十个方程之后一定会烦,尤其是变系数方程,Δ 是个含 x、y 的表达式,符号判断容易糊。我一般会写个小脚本把判别式交给符号计算,只做人眼复核。
import sympy as sp x, y = sp.symbols('x y', real=True) def classify(coeffs, point=None): """ coeffs: dict,键为 'a11' / 'a12' / 'a22',值为 sympy 表达式(可为 x,y 的函数) point : (x0, y0) 元组;给定时在该点求 Δ 的数值,None 时保留符号形式 返回 : (Δ 表达式, 类型字符串) """ a11 = sp.sympify(coeffs['a11']) a12 = sp.sympify(coeffs['a12']) a22 = sp.sympify(coeffs['a22']) # 判别式:注意这里 a12 是交叉项系数的一半 delta = sp.simplify(a12**2 - a11 * a22) if point is not None: delta = sp.simplify(delta.subs({x: point[0], y: point[1]})) if delta.is_positive: kind = '双曲型' elif sp.simplify(delta) == 0: kind = '抛物型' elif delta.is_negative: kind = '椭圆型' else: kind = '符号未定,请给 point 或手工判断' return delta, kind # 三个标准例子 print(classify({'a11': 1, 'a12': 0, 'a22': 1})) # 拉普拉斯 -> Δ=-1 椭圆 print(classify({'a11': 1, 'a12': 0, 'a22': -1})) # 一维波动 -> Δ=1 双曲 print(classify({'a11': 1, 'a12': 0, 'a22': 0})) # 一维热传导 -> Δ=0 抛物 # 变系数例子:x^2·u_xx + 2xy·u_xy + y^2·u_yy = 0 print(classify({'a11': x**2, 'a12': x*y, 'a22': y**2}, point=(2, 3)))这段代码里有两个参数必须交代清楚。coeffs传的是标准形式下的系数,不是原方程字面上的系数——交叉项前面那个 2 已经被吸收进 a12 了,所以u_xx + 2xy·u_xy + …里填的 a12 是 x·y,不是 2xy。point参数是给变系数方程准备的,Δ 里带 x、y 时符号判断常常失灵,is_positive会返回 None,脚本就落到“符号未定”分支。这不是 bug,是提醒你:变系数方程的类型可能随点变化,讲义里那句“在点 M 处”不是客套话。
运行结果里,变系数那个例子 Δ = x²y² − x²y² = 0,全线抛物型,这说明系数看起来花哨,退化性其实很强。碰到这种结论,我习惯再取两三个点手算核对一遍,符号计算给的是结果,不是理解。
2.3 三类方程不只是符号,它们决定了后面所有解法
把类型判出来之后,讲义立刻转向解法,这个顺序是有讲究的。双曲型对应波动方程,扰动以有限速度传播,影响沿特征线走,所以有达朗贝尔解、有依赖区间;抛物型对应热传导,扰动瞬时传遍全域,有极值原理、有平滑效应;椭圆型对应稳态问题,解由边界唯一确定,没有时间方向。
对写代码的人,这个分类直接决定数值格式:波动是显式格式受 CFL 约束,热传导隐式格式可以放大步长,椭圆型是边值问题,得用迭代或直接解法。所以第 2 章这套判别式,不是考试专用,它是后面全部工程选型的分岔口。分类判错,后面解析解、数值解、边界条件全都会跟着错,而且错得很隐蔽——程序能跑,曲线也画出来了,就是和理论对不上。
3. 从弦振动到热传导:把课件里的建模推导自己重走一遍
3.1 弦振动方程的四步推导骨架
讲义里弦振动那段推导占了不小篇幅,因为它把“物理假设如何变成一个 PDE”演示得很完整。我把它压缩成四步,方便自己重走。
第一步,定假设。均匀、细、软、紧的弹性弦,长度 l,线密度 ρ,只做微小横振动。微小意味着弦上任意一点的切线倾角很小,于是 sinθ ≈ tanθ ≈ u_x,这一近似是整个推导能线性化的前提,少了它得到的就不是线性方程。
第二步,取微元做受力分析。在 x 到 x + Δx 之间取一小段,两端受张力 T,方向沿弦的切线。竖直方向的合力是 T·sinθ|{x+Δx} − T·sinθ|{x}。用 tanθ = u_x 代入,得到 T·[u_x(x+Δx) − u_x(x)]。
第三步,写牛顿第二定律。这段微元质量是 ρ·Δx,竖直加速度是 u_tt,于是:
ρ·Δx·u_tt = T·[u_x(x+Δx, t) − u_x(x, t)]第四步,两边除以 Δx 取极限 Δx → 0,右边变成 T·u_xx,得到:
u_tt = a²·u_xx, a² = T / ρ量纲上 a 是速度量,所以它是波速。这个结论不是事先给定的,是从 T/ρ 推出来的——这也是为什么课件强调“弦越紧、越轻,波速越快”。推导里被丢掉的项是 sinθ 展开的高阶项和纵向位移,丢掉它们的代价是方程只在小振幅下成立,振幅一大,非线性效应就冒头,线性模型直接失效。这一点讲义不会反复念,但自己心里要有数。
顺带说一句,讲义里把 a² 写成 T/ρ 而不是直接写 a,是有意留的接口:后续换材料、换张力,只改这个比值就行,方程结构不动。这种“把物理参数集中成一个系数”的写法,在整个数理方程里反复出现。
3.2 热传导与调和方程:从守恒律到散度形式
热传导方程的推导走的是另一条路:守恒律。取一个控制体,热量变化率等于净流入的热流。用傅里叶定律 q = −k·∇u(k 是导热系数,u 是温度),代入守恒方程,得到:
∂u/∂t = a²·∇²u, a² = k / (ρ·c)ρ 是密度,c 是比热容。一维形式就是 u_t = a²·u_xx,三维形式要写拉普拉斯算子。讲义在这里做了一个很值得学的动作——把“稳态”单独拎出来:如果温度不随时间变化,u_t = 0,方程退化成 ∇²u = 0,这就是调和方程,也就是拉普拉斯方程。
同一个物理过程,去掉时间项就从抛物型变成椭圆型,定解条件也跟着从“初始条件 + 边界条件”变成“只要边界条件”。这个对应关系我建议直接记成一句话:抛物型有初值,椭圆型无初值。写代码时忘记给椭圆型问题加初始条件,或者在迭代解法里硬塞一个初值,往往就是收敛异常的根源。
讲义里对边界条件的分类也给得很务实:
| 边界条件类型 | 数学形式 | 物理含义 | 常见场景 |
|---|---|---|---|
| 第一类(Dirichlet) | u|边界 = φ | 端点温度/位移被固定 | 两端固定的弦、恒温端面 |
| 第二类(Neumann) | ∂u/∂n|边界 = ψ | 流入流出的通量给定 | 绝热端面、自由端 |
| 第三类(Robin) | (∂u/∂n + σu)|边界 = ψ | 与外界按温差换热 | 表面对流换热 |
三类边界条件可以混用,一端固定一端自由是常见的组合。混合边界不改变方程类型,但会改变特征值问题的形式,分离变量时特征方程不再是简单的 sin 系列,这一点后面会撞上。
3.3 定解条件的三处细节:数量、相容性、量纲
定解条件不是随手加两条就完事,这里有三处细节讲义写到了,但很容易一带而过。
第一是数量。方程对时间的阶数决定初始条件的个数:波动方程对 t 是二阶,需要 u(x,0) 和 u_t(x,0) 两个初始条件;热传导方程对 t 是一阶,只需要 u(x,0) 一个。给热传导配两个初始条件,数学上多余,数值上会导致格式无解或者发散。
第二是相容性。初始条件和边界条件在角点 (0,0) 和 (l,0) 处必须一致。比如弦两端固定 u(0,t) = 0,而初始位移 f(0) ≠ 0,这个矛盾会让级数解在端点附近收敛极慢,数值解上表现为起始几步出现剧烈振荡。常见做法是先检查 f(0)、f(l) 是否为零,不为零就说明模型描述本身有冲突。
第三是量纲。a² 的单位是长度²/时间,所以 a·t 是长度,和 x 同量纲,这也是波动解里出现 (x − at) 这种组合的原因。分离变量时特征值 λ 的量纲是 1/长度²,所以 λ_n = (nπ/l)² 这个写法是自洽的,自己推导时如果量纲对不上,基本就是系数抄错了。
4. 解析解动手验算:分离变量法的五步与有限差分对照
4.1 分离变量法的标准五步
讲义讲分离变量,流程是固定的,我按两端固定的弦来演示。问题:u_tt = a²·u_xx,0 < x < l,u(0,t) = u(l,t) = 0,u(x,0) = f(x),u_t(x,0) = g(x)。
第一步,设 u(x,t) = X(x)·T(t),代入方程并两边除以 a²XT,得到 T''/(a²T) = X''/X。左边只含 t,右边只含 x,只能等于同一个常数,记为 −λ。
第二步,得到两个常微分方程:X'' + λX = 0,T'' + λa²T = 0。
第三步,把边界条件转给 X:X(0) = X(l) = 0。解这个特征值问题,只有 λ_n = (nπ/l)²,n = 1, 2, 3, … 时才有非零解,X_n = sin(nπx/l)。
第四步,代回时间方程,得到 T_n = A_n·cos(nπat/l) + B_n·sin(nπat/l)。
第五步,叠加并定系数:
u(x,t) = Σ [A_n·cos(nπat/l) + B_n·sin(nπat/l)]·sin(nπx/l) A_n = (2/l)·∫₀ˡ f(s)·sin(nπs/l) ds B_n = (2/(nπa))·∫₀ˡ g(s)·sin(nπs/l) ds注意 B_n 的分母是 nπa,不是 nπa/l 之外的别的形式,这个位置最容易抄漏 l。至于为什么可以逐项叠加,靠的是讲义里那条叠加原理:线性齐次方程的解的线性组合仍是解,级数在一致收敛且可逐项微分两次的条件下仍然成立。这条条件在工程里通常默认,但真要严格,得验证 f 和 g 的光滑性。
4.2 用 sympy 和 numpy 把级数解算出来
理论推完不算数,我习惯把前 50 项算出来画一遍,看图能发现一半的笔误。
import numpy as np from scipy.integrate import quad L, a = 1.0, 1.0 N = 50 def A_n(n, f, L=1.0): """初位移 f 的傅里叶正弦系数,对应 cos 项""" val, _ = quad(lambda s: f(s) * np.sin(n * np.pi * s / L), 0, L, limit=200) return 2.0 / L * val def B_n(n, g, a=1.0, L=1.0): """初速度 g 的傅里叶正弦系数,对应 sin 项;分母含 n*pi*a/L""" val, _ = quad(lambda s: g(s) * np.sin(n * np.pi * s / L), 0, L, limit=200) return 2.0 / (n * np.pi * a / L) * val def u_series(x, t, f, g, N=50, L=1.0, a=1.0): total = np.zeros_like(np.asarray(x, dtype=float)) for n in range(1, N + 1): an = A_n(n, f, L) bn = B_n(n, g, a, L) total += (an * np.cos(n * np.pi * a * t / L) + bn * np.sin(n * np.pi * a * t / L)) * np.sin(n * np.pi * x / L) return total # 试验:三角初位移 f(x)=sin(pi x),零初速度 f = lambda s: np.sin(np.pi * s) g = lambda s: 0.0 xs = np.linspace(0, 1, 200) for t in (0.0, 0.1, 0.25): print(t, np.max(np.abs(u_series(xs, t, f, g))))这里N是截断项数,不是网格数,数值上取到 50 项对光滑初值基本够用;如果 f 有折角(比如三角形初位移),需要加大到 200 以上,否则端点附近会出现吉布斯振荡。quad的limit=200是积分细分数上限,被积函数振荡越剧烈越需要放大这个值,否则 scipy 会给警告,系数算不准。u_series用循环逐项累加,写法笨但好排查,向量化之后出错很难定位是哪一项的问题。
结果会告诉你两件事:t = 0 时最大值应该等于初位移的峰值;t = 0.25 时波形应该还是那条正弦曲线,只是整体移位——如果初值只含一个模态,解就是驻波,周期 2l/a。这是最好的自检手段:先拿单模态验证代码,再换复杂初值。
4.3 用有限差分做交叉验证:误差收敛阶是唯一的判据
解析解算完,我一般会再写一个显式差分的波动方程求解器,两套结果比一比。这一步不是为了替代解析解,是为了验证解析解的系数和差分格式都写对了。
import numpy as np def wave_fd(L=1.0, a=1.0, nx=101, t_end=0.5, courant=0.9): """ nx : 空间节点数 courant : C = a*dt/dx,显式格式要求 C <= 1 """ dx = L / (nx - 1) dt = courant * dx / a nt = int(np.ceil(t_end / dt)) dt = t_end / nt # 回算 dt,保证正好走到 t_end C2 = (a * dt / dx) ** 2 x = np.linspace(0, L, nx) u = np.zeros((nt + 1, nx)) u[0, :] = np.sin(np.pi * x) # 初位移 u[1, :] = u[0, :] # 零初速度:第一步用 u1=u0 近似 u[:, 0] = 0.0 u[:, -1] = 0.0 for n in range(1, nt): u[n + 1, 1:-1] = (2 * u[n, 1:-1] - u[n - 1, 1:-1] + C2 * (u[n, 2:] - 2 * u[n, 1:-1] + u[n, :-2])) return x, u, dt x, u, dt = wave_fd() t_end = 0.5 exact = np.sin(np.pi * x) * np.cos(np.pi * t_end / 1.0) err = np.linalg.norm(u[-1, :] - exact) / np.sqrt(len(x)) print(f"dt={dt:.6f}, L2 误差={err:.6e}")三个参数要说明白。courant就是 CFL 数 C = a·dt/dx,显式格式的硬约束是 C ≤ 1,超过就无条件发散,这不是精度问题,是稳定性问题。上面这个格式在 C = 1 时有特殊性质(数值解与解析解在网格点上重合),所以取 0.9 而不是 1,能看出真正的离散误差。u[1, :] = u[0, :]是零初速度的常用近似,严格做法要用 u_t 的差分起步,差一个 O(dt) 的误差,对二阶格式来说可以接受。np.linalg.norm(...) / sqrt(len(x))是离散 L2 范数,除以节点数开方是为了让误差不随网格数放大,便于和解析解对比时量级可比。
验证方法很简单:把 nx 从 51 加密到 101、201,看误差下降速度。二阶格式的误差应该按 4 倍速下降(网格减半,误差约降到 1/4)。如果只降到 1/2,说明起步那一步的近似降了一阶;如果误差不降反升,先查 CFL,再看边界有没有每一步都更新。
这套“解析解 + 差分 + 收敛阶”的组合,我建议当成习惯。讲义只给解析解,但工程里没人会只用解析解做产品,两边都跑通,才算真懂了这个方程。
5. 用这套课件常踩的五个坑:从判别式到 CFL 的排查清单
5.1 概念层面的三个混淆
坑一:判别式代入时用了原方程的交叉项系数。
现象:u_xx + 4·u_xy + 4·u_yy = 0被判成双曲型,与讲义结论相反。 原因:标准形式里交叉项是 2·a12·u_xy,直接拿 4 当 a12 算,Δ = 16 − 4 = 12 > 0;正确 a12 = 2,Δ = 4 − 4 = 0,是抛物型。 解决:把标准形式写在纸上,逐项对位。我习惯在推导旁标注“交叉项系数除以 2”,写死这个动作,眼睛不看结论也错不了。
坑二:把变系数和线性、非线性混成一锅。
现象:看到系数里有 x、y,就判定为非线性方程,直接放弃叠加原理。 原因:线性与否只看未知函数 u 及其各阶导数的出现方式,系数依赖自变量不改变线性性。x²·u_xx + y·u_y = 0是变系数线性方程,叠加原理照样成立。 解决:判断时只盯着 u 和它的导数,看有没有乘积、幂次、函数套用(sin u、e^u)。系数里出现什么都可以不管。讲义把“变系数线性”和“非线性”放在相邻页,是混淆的主要来源。
坑三:给抛物型方程配了两个初始条件。
现象:热传导问题按惯例写了 u(x,0) 和 u_t(x,0) 两个条件,分离变量时发现时间方程只有一阶,解不出第二个待定系数。 原因:方程对 t 的阶数决定初值个数,一阶给一个,二阶给两个。数量不对,不是解法问题,是问题本身提错了。 解决:动笔前先数时间偏导数的阶数,把它写在问题旁边。这个动作看着多余,能省掉大半天。
5.2 工具与计算层面的两个翻车点
坑四:sympy 化简不到位,判别式判断成“未知”。
现象:变系数方程调用classify返回“符号未定”,但手算明明能判。 原因:a12**2 - a11*a22没有先simplify就送进is_positive,表达式形式复杂时 sympy 判断不出来;或者 Δ 本身确实随点变号,脚本没有能力表达“分区判别”。 解决:先sp.simplify再判断;变系数一律传point参数在具体点求值;如果确实变号,说明方程在区域内是混合型的,需要分区讨论,这不是脚本该背的锅。
坑五:有限差分跑几十步就爆,怀疑是代码写错。
现象:波动方程显式格式,前 10 步正常,之后数值迅速放大到 1e10 量级。 原因:九成是 CFL 违反,a*dt/dx > 1。剩下的一成是边界条件没有在每一步都更新,或者起步那一步用了不匹配的初速度近似。 解决:先把 courant 数打印出来,超过 1 立刻改小 dt;边界条件在每个时间步结束后重新赋值,不要只在初始化时设一次;起步用 u[1] = u[0] 时,确认初速度确实为零,非零初速度要单独处理。
这五个坑的共同点是不报错。代码能跑、图能画、结论能写,但全都是错的,验证起来唯一的办法就是回到定义和守恒量上做自检。从那以后我每次碰新方程,都强制先把类型、定解条件数量、量纲这三项写在最前面,再动键盘。
6. 进阶用法:把 PPT 拆成可检索的本地 PDE 手册
课件翻第二遍的时候,我一般不按页码顺序看,而是把它拆成条目化的本地笔记。PPT 的组织方式适合讲授,不适合检索,直接翻页找“第三类边界条件的表达式”要花很久。
我用的结构是四段式:每个知识点写“定义 → 判别 → 一个正例 → 一个反例”,全部压进一个 Markdown 文件,用标题层级组织。比如“二阶方程分类”这一条,定义写标准形式和判别式,判别写 Δ 的三种符号,正例给波动、热传导、拉普拉斯三个,反例就写那个u_xx + 4·u_xy + 4·u_yy = 0的抛物型误判。反例这一栏是整套笔记里最值钱的部分,因为正例教材里有,反例只有自己踩过才有。
| 条目 | 内容要点 | 适合放在哪一栏 |
|---|---|---|
| 判别式 | Δ = a12² − a11·a22,交叉项系数减半 | 定义 |
| 三类典型方程 | 波动/热传导/拉普拉斯与双曲/抛物/椭圆的对应 | 判别 |
| 定解条件 | 时间阶数决定初值个数,三类边界条件 | 定义 + 判别 |
| 分离变量 | 五步流程、特征值 λ_n、系数公式 | 定义 |
| CFL 条件 | a·dt/dx ≤ 1,显式格式硬约束 | 反例(发散现象) |
建立好之后,检索靠命令行就够:
# 在笔记目录下按关键词找条目,输出文件名和行号 rg -n "第三类边界|Robin|CFL" ./pde-notes --type md # 只找含公式块的段落,快速定位推导 rg -n -A 6 '```' ./pde-notes/classification.mdrg的-n给行号,-A 6表示命中行后再显示 6 行上下文,正好覆盖一个公式块。笔记文件按主题拆开(分类、导出、定解、解析解、数值解),不要全塞一个文件,否则搜出来的上下文全是无关内容。
再进一步,我会给每个条目加一个“可执行验证”字段:分类条目挂上 2.2 那个classify脚本的调用行,分离变量条目挂上 4.2 的u_series,数值条目挂上 4.3 的wave_fd。这样笔记不是死的文字,任何一个结论都能一条命令跑出来复核。做到这一步,这套 PPT 才算真正变成你自己的东西——课件给的是推导骨架,能跑起来的代码和能复现的反例,才是骨架上的肉。
血泪经验是,别一开始就追求笔记完整。先把判别式、定解条件、分离变量这三块拆出来,剩下的边用边补,半年之后回头看,这份手册比原课件好用得多。希望帮到你。
本文还有配套的精品资源,点击获取