第1章 有限差分法理论基础
1.1 有限差分法概述
有限差分法(Finite Difference Method,FDM)是一种求解微分方程数值解的近似方法,其主要原理是对微分方程中的微分项进行直接差分近似,从而将微分方程转化为代数方程组求解。这里的近似采取的是离散近似,使用某一点周围点的函数值近似表示该点的微分。
有限差分法面对的对象是微分方程,包括常微分方程和偏微分方程。
有限差分法的原理简单,粗暴有效,最早由欧拉(Leonhard Euler,1707-1783)提出,他在1768年给出了一维问题的差分格式。1908年,龙格(Carl Runge,1856-1927)将差分法扩展到了二维问题。但是在那个年代,将微分方程的求解转化为大量代数方程组的求解,无疑是将一个难题转化为另一个难题,因此并未得到大量的应用。随着计算机技术的发展,快速准确地求解庞大的代数方程组成为可能,因此逐渐得到大量的应用。发展至今,有限差分法已成为一个重要的数值求解方法,在工程领域有着广泛的应用背景。
下面将对该方法进行概述。
本文中使用的MATLAB版本是R2024b。
1.2 有限差分法中微分的近似表示
一般地,假设函数u(x)在求解域内连续可导,则由泰勒级数我们可以得到
u(x+h)=u(x)+hu′(x)+2h2u′′(x)+...+k!hku(k)(x)+...(1.1)
基于泰勒级数并做适当的截断,我们就可以得到各阶微分的近似表达式,即“差分公式”。下面主要对一阶和二阶微分的差分公式进行讨论,更高阶的微分可以同理推导得到。
1.2.1 一阶微分的差分公式
我们可以将(1.1)式另写作
u(x+h)=u(x)+hu′(x)+2h2u′′(x)+6h3u′′′(x)+...(1.2)
对上式变形即可以得到一阶微分的向前差分公式
u′(x)=≈hu(x+h)−u(x)−2hu′′(x)−6h2u′′′(x)−...hu(x+h)−u(x)(1.3)
其误差项为
−2hu′′(x)−6h2u′′′(x)−...−(2k−1)!h2k−2u(2k−1)(x)−(2k)!h2k−1u(2k)(x)−...(1.4)
将(1.3)式中的h用−h代替,则可以得到一阶微分的向后差分公式
u′(x)=≈hu(x)−u(x−h)+2hu′′(x)−6h2u′′′(x)+...hu(x)−u(x−h)(1.5)
其误差项为
2hu′′(x)−6h2u′′′(x)+...−(2k−1)!h2k−2u(2k−1)(x)+(2k)!h2k−1u(2k)(x)−...(1.6)
联立(1.3)式与(1.5)式,则可以得到一阶微分的中心差分公式
u′(x)=≈2hu(x+h)−u(x−h)+2hu′′(x)−6h2u′′′(x)−...2hu(x+h)−u(x−h)(1.7)
其误差项为
−6h2u′′′(x)−...−(2k−1)!h2k−2u(2k−1)(x)...(1.8)
在差分公式中,我们关注步长h对差分公式的影响。一阶微分的向前差分公式和向后差分公式的误差项,都是关于h的一次式。而一阶微分的中心差分公式的误差项,是关于h的二次式。故在一阶微分的差分公式中,中心差分公式的误差项次数更高,受步长h的影响更小,精度更高。故在求一阶微分时,往往使用一阶微分的中心差分公式,以求更高的精度。
1.2.2 二阶微分的差分公式
我们可以将(1.1)式另写作
u(x+h)=u(x)+hu′(x)+2!h2u′′(x)+3!h3u′′′(x)+4!h4u(4)(x)+...(1.9)
将(1.9)式中的h用2h代替,
u(x+2h)=u(x)+2hu′(x)+2!(2h)2u′′(x)+3!(2h)3u′′′(x)+4!(2h)4u(4)(x)+...(1.10)
联立(1.9)式与(1.10)式,得二阶微分的向前差分公式
u′′(x)=≈h2u(x)−2u(x+h)+u(x+2h)−3!(23−2)hu′′′(x)−4!(24−2)h2u(4)(x)−...h2u(x)−2u(x+h)+u(x+2h)(1.11)
其误差项为
−3!(23−2)hu′′′(x)−4!(24−2)h2u(4)(x)−...(1.12)
将(1.11)式中的h用−h代替,则可以得到二阶微分的向后差分公式
u′′(x)=≈h2u(x−2h)−2u(x−h)+u(x)+3!(23−2)hu′′′(x)−4!(24−2)h2u(4)(x)+...h2u(x)−2u(x−h)+u(x−2h)(1.13)
其误差项为
3!(23−2)hu′′′(x)−4!(24−2)h2u(4)(x)+...(1.14)
将(1.9)式中的h用−h代替,
u(x−h)=u(x)−hu′(x)+2!h2u′′(x)−3!h3u′′′(x)+4!h4u(4)(x)−...(1.15)
联立(1.9)式与(1.15)式,得二阶微分的中心差分公式
u′′(x)=≈h2u(x+h)−2u(x)+u(x−h)−4!2h2u(4)(x)−...h2u(x+h)−2u(x)+u(x−h)(1.16)
其误差项为
−4!2h2u(4)(x)−...(1.17)
二阶微分的向前差分公式和向后差分公式的误差项,都是关于h的一次式。而二阶微分的中心差分公式的误差项,是关于h的二次式。故在二阶微分的差分公式中,中心差分公式的误差项次数更高,受步长h的影响更小,精度更高。故在求二阶微分时,往往使用二阶微分的中心差分公式,以求更高的精度。
但在这里,我们应题目的需要,采用二阶微分的向前差分公式和向后差分公式,并且忽略误差项。
二阶微分的向前差分公式
u′′(x)=h2u(x)−2u(x+h)+u(x+2h)(1.18)
二阶微分的向后差分公式
u′′(x)=h2u(x−2h)−2u(x−h)+u(x)(1.19)
二阶微分的中心差分公式
u′′(x)=h2u(x+h)−2u(x)+u(x−h)(1.20)
第2章 利用中前(后)差分方法求解齐次一维波动方程
2.1 二阶偏微分的差分公式
由(1.18)式易得二阶偏微分的向前差分公式(u(t,x)u(t,x)情况下):
⎩⎪⎪⎪⎨⎪⎪⎪⎧∂x2∂2u(t,x)=(Δx)2u(t,x)−2u(t,x+Δx)+u(t,x+2Δx)∂t2∂2u(t,x)=(Δt)2u(t,x)−2u(t+Δt,x)+u(t+2Δt,x)(2.1)
由(1.19)式易得二阶偏微分的向后差分公式(u(t,x)u(t,x)情况下):
⎩⎪⎪⎪⎨⎪⎪⎪⎧∂x2∂2u(t,x)=(Δx)2u(t,x−2Δx)−2u(t,x−Δx)+u(t,x)∂t2∂2u(t,x)=(Δt)2u(t−2Δt,x)−2u(t−Δt,x)+u(t,x)(2.2)
由(1.20)式易得二阶偏微分的中心差分公式(u(t,x)u(t,x)情况下):
⎩⎪⎪⎪⎨⎪⎪⎪⎧∂x2∂2u(t,x)=(Δx)2u(t,x−Δx)−2u(t,x)+u(t,x+Δx)∂t2∂2u(t,x)=(Δt)2u(t−Δt,x)−2u(t,x)+u(t+Δt,x)(2.3)
2.2 齐次一维波动方程介绍
我们可以先讨论最简单的情况——齐次一维波动方程。作为更复杂的波动方程的参考。
齐次一维波动方程为:
∂t2∂2u(t,x)=c2⋅∂x2∂2u(t,x)(2.4)
在已知t=0t=0时的波形时,我们可以用中后差分方法。
在已知t=Tt=T(TT为总时间)时的波形时,我们可以用中前差分方法。
2.3 齐次一维波动方程的中后差分方法
2.3.1 中后差分方法与差分方程
中后差分方法是指对空间的二阶导数采用中心差分,对时间的二阶导数采用向后差分。
对空间的中心差分是指利用上一个空间点x−Δx,这个空间点x,下一个空间点x+Δx,前后兼顾,差分算出导数值。
∂x2∂2u(t,x)=(Δx)2u(t,x−Δx)−2u(t,x)+u(t,x+Δx)(2.5)
迭代时,在这个时间点t,往往只知道上一个空间点x−Δx,不知道这个空间点x和下一个空间点x+Δx。我们可以采取用上个时间点t−Δt的空间情况来评估这个时间点t的空间情况。
∂x2∂2u(t,x)≈=∂x2∂2u(t−Δt,x)(Δx)2u(t−Δt,x−Δx)−2u(t−Δt,x)+u(t−Δt,x+Δx)(2.6)
对时间的向后差分是指利用上上个时间点t−2Δt,上个时间点t−Δt,这个时间点t,总结过去与现在的情况(因为未来未知),差分算出导数值。
∂t2∂2u(t,x)=(Δt)2u(t−2Δt,x)−2u(t−Δt,x)+u(t,x)(2.7)
将(2.6)式和(2.7)式带入(2.4)式,并对t和x离散化,可得差分方程
u(t,x)=c2(Δx)2(Δt)2[u(t−1,x−1)−2u(t−1,x)+u(t−1,x+1)]−u(t−2,x)+2u(t−1,x)(2.8)
写成MATLAB代码形式:
1
| u(t, x) = (c * dt / dx) ^ 2 * (u(t - 1, x - 1) - 2 * u(t - 1, x) + u(t - 1, x + 1)) - u(t - 2, x) + 2 * u(t - 1, x)
|
2.3.2 CFL稳定性条件(Courant-Friedrichs-Lewy条件)
观察(2.8)式,取
r=cΔxΔt(2.9)
这里的r即为CFL数(库朗数)。
CFL稳定性条件是数值分析中用于判断有限差分方法求解偏微分方程时稳定性的重要条件,由三位数学家Richard Courant、Kurt Friedrichs和Hans Lewy于1928年提出。其核心思想是:数值解法的信息传播速度必须不小于原方程的物理信息传播速度,否则计算会因“信息滞后”而发散。主要用于确定时间步长和空间步长之间的关系,以确保数值解的稳定性。
在一维波动方程中,CFL稳定性条件要求CFL数(库朗数)r满足:
r=cΔxΔt<1(2.10)
可得
r2=c2(Δx)2(Δt)2<1(2.11)
利用(2.11)式可以判断、、三者间是否合适。
2.3.3 边界条件
对于初始条件(已知t=0t=0时的波形),t=Δtt=Δt时的波形可以认为与t=0t=0时的波形相同。
u(Δt,x)≈u(0,x)(2.12)
另外,认为两端固定,长度为L
u(t,0)=u(t,L)=0(2.13)
>对边界条件利用差分方程,进行若干次迭代差分,即可得到偏微分方程的数值解。具体的MATLAB源代码及其运行结果见下。源代码已上传Github,可以访问链接下载源代码。
2.3.4 MATLAB源代码
已知t=0t=0时的波形为sin(2πx)sin(2πx)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| clc; clear; close all;
L = 1;
T = 1;
c = 1;
nx = 100;
nt = 200;
dx = L / nx;
dt = T / nt;
CFL = c * dt / dx; if CFL > 1 warning('CFL条件不满足,可能导致数值不稳定!'); end
x = linspace(0, L, nx); t = linspace(0, T, nt);
u = zeros(nt, nx);
u(1, :) = sin(2 * pi * x); u(2, :) = u(1, :); u(:, 1) = 0; u(:, end) = 0;
for n = 3 : nt for i = 2 : nx - 1 u(n , i)=CFL ^ 2 * (u(n - 1, i - 1) - 2 * u(n - 1, i)... + u(n - 1,i + 1)) - u(n - 2, i) + 2 * u(n - 1,i); end end
[X, T] = meshgrid(x, t); figure('Position', [100, 100, 800, 600]);
surf(X, T, u, 'EdgeColor', 'none');
colormap(jet);
colorbar;
title('一维波动方程 u(x,t) 的数值解'); xlabel('位置 x'); ylabel('时间 t'); zlabel('位移 u(x,t)'); view(30, 30);
|
2.3.5 MATLAB代码运行结果
2.4 齐次一维波动方程的中前差分方法
2.4.1 中前差分方法与差分方程
中前差分方法的概念与中后差分方法类似,是指对空间的二阶导数采用中心差分,对时间的二阶导数采用向前差分。
对空间的中心差分是指利用上一个空间点x−Δx,这个空间点x,下一个空间点x+Δx,前后兼顾,差分算出导数值。
∂x2∂2u(t,x)=(Δx)2u(t,x−Δx)−2u(t,x)+u(t,x+Δx)(2.14)
迭代时,在这个时间点,往往只知道上一个空间点x−Δx,不知道这个空间点x和下一个空间点x+Δx。我们可以采取用下个时间点t+Δt的空间情况来评估这个时间点的空间情况。
∂x2∂2u(t,x)≈=∂x2∂2u(t+Δt,x)(Δx)2u(t+Δt,x−Δx)−2u(t+Δt,x)+u(t+Δt,x+Δx)(2.15)
对时间的向前差分是指利用下下个时间点t+2Δt,下个时间点t+Δt,这个时间点t,总结未来与现在的情况(因为过去未知),差分算出导数值。
∂t2∂2u(t,x)=(Δt)2u(t,x)−2u(t+Δt,x)+u(t+2Δt,x)(2.16)
将(2.14)式和(2.15)式带入(2.4)式,带入r=cΔxΔt,并对t和x离散化,可得差分方程。
u(t,x)=r2[u(t+1,x−1)−2u(t+1,x)+u(t+1,x+1)]+2u(t+1,x)−u(t+2,x)(2.17)
写成MATLAB代码形式:
1
| u(t, x) = (c * dt / dx) ^ 2 * (u(t + 1, x - 1) - 2 * u(t + 1, x) + u(t + 1, x + 1)) + 2 * u(t + 1, x) - u(t + 2, x)
|
2.4.2 CFL稳定性条件(Courant-Friedrichs-Lewy条件)
与“2.3.2 CFL稳定性条件(Courant-Friedrichs-Lewy条件)”相同。
r=cΔxΔt<1(2.10)
2.4.3 边界条件
对于初始条件(已知t=Tt=T时的波形),t=T−Δtt=T−Δt时的波形可以认为与t=Tt=T时的波形相同。
u(T−Δt,x)≈u(T,x)(2.18)
另外,认为两端固定,长度为L
u(t,0)=u(t,L)=0(2.19)
>对边界条件利用差分方程,进行若干次迭代差分,即可得到偏微分方程的数值解。具体的MATLAB源代码及其运行结果见下。源代码已上传Github,可以访问链接下载源代码。
2.4.4 MATLAB源代码
已知t=Tt=T时的波形为sin(2πx)sin(2πx)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| clc; clear; close all;
L = 1;
T = 1;
c = 1;
nx = 100;
nt = 200;
dx = L / nx;
dt = T / nt;
CFL = c * dt / dx; if CFL > 1 warning('CFL条件不满足,可能导致数值不稳定!'); end
x = linspace(0, L, nx); t = linspace(0, T, nt);
u = zeros(nt, nx);
u(end, :) = sin(2 * pi * x); u(end-1, :) = u(end, :); u(:, 1) = 0; u(:, end) = 0;
for n = nt - 2 : -1 : 1 for i = 2 : nx - 1 u(n, i) = CFL ^ 2 * (u(n + 1, i - 1) - 2 * u(n + 1, i)... + u(n + 1, i + 1)) + 2 * u(n + 1, i) - u(n + 2, i); end end
[X, T] = meshgrid(x, t); figure('Position', [100, 100, 800, 600]);
surf(X, T, u, 'EdgeColor', 'none');
colormap(jet);
colorbar;
title('一维波动方程 u(x,t) 的数值解'); xlabel('位置 x'); ylabel('时间 t'); zlabel('位移 u(x,t)'); view(30, 30);
|
2.4.5 MATLAB代码运行结果
2.5 中前差分方法与中后差分方法的比较
比较2.3.4节和2.4.4节的两块代码,不难发现,两者的基本结构是相同的,只是差分方程和边界条件【在已知t=0时的波形时,我们可以用中后差分方法;在已知t=T(T为总时间)时的波形时,我们可以用中前差分方法】略有不同。后期我们为了研究问题的简便,只讨论中后差分方法。
第3章 利用中后差分方法求解非齐次一维波动方程
3.1 非齐次一维波动方程介绍
在讨论完最简单的情况——齐次一维波动方程之后,我们来讨论非齐次一维波动方程。
非齐次一维波动方程为:
∂t2∂2u(t,x)=c2⋅∂x2∂2u(t,x)+f(t,x)(3.1)
注意,f(t,x)f(t,x)已知。
在已知t=0t=0时的波形时,我们可以用中后差分方法。
在已知t=Tt=T(TT为总时间)时的波形时,我们可以用中前差分方法。
在此,我们只研究第一种情况,原因见2.5节。
3.2 非齐次一维波动方程的中后差分方法
3.2.1 中后差分方法与差分方程
这里的中后差分方法与2.3.1节概念相同,可得
⎩⎪⎪⎪⎨⎪⎪⎪⎧∂x2∂2u(t,x)=(Δx)2u(t−Δt,x−Δx)−2u(t−Δt,x)+u(t−Δt,x+Δx)∂t2∂2u(t,x)=(Δt)2u(t−2Δt,x)−2u(t−Δt,x)+u(t,x)(3.2)
将(3.2)式带入(3.1)式,带入r=cΔxΔt,并对t和x离散化,可得差分方程
u(t,x)=r2[u(t−1,x−1)−2u(t−1,x)+u(t−1,x+1)]−u(t−2,x)+2u(t−1,x)+f(t,x)(3.3)
写成MATLAB代码形式:
1
| u(t, x) = (c * dt / dx) ^ 2 * (u(t - 1, x - 1) - 2 * u(t - 1, x) + u(t - 1, x + 1)) - u(t - 2, x) + 2 * u(t - 1, x) + f(t, x)
|
3.2.2 CFL稳定性条件(Courant-Friedrichs-Lewy条件)
与“2.3.2 CFL稳定性条件(Courant-Friedrichs-Lewy条件)”相同。
r=cΔxΔt<1(2.10)
3.2.3 边界条件
与2.3.3节相同。
对于初始条件(已知t=0t=0时的波形),t=Δtt=Δt时的波形可以认为与t=0t=0时的波形相同。
u(Δt,x)≈u(0,x)(3.4)
另外,认为两端固定,长度为L
u(t,0)=u(t,L)=0(3.5)
对边界条件利用差分方程,进行若干次迭代差分,即可得到偏微分方程的数值解。具体的MATLAB源代码及其运行结果见下。源代码已上传Github,可以访问链接下载源代码。
3.2.4 MATLAB源代码
已知t=0t=0时的波形为sin(2πx)sin(2πx),f(t,x)=xf(t,x)=x。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| clc; clear; close all;
L = 3;
T = 6;
c = 1;
nx = 100;
nt = 200;
dx = L / nx;
dt = T / nt;
CFL = c * dt / dx; if CFL > 1 warning('CFL条件不满足,可能导致数值不稳定!'); end
x = linspace(0, L, nx); t = linspace(0, T, nt);
u = zeros(nt, nx);
u(1, :) = sin(2 * pi * x); u(2, :) = u(1, :); u(:, 1) = 0; u(:, end) = 0;
for n = 3 : nt for i = 2 : nx - 1 u(n, i) = CFL ^ 2 * (u(n - 1, i - 1) - 2 * u(n - 1, i)... + u(n - 1,i + 1)) - u(n - 2, i) + 2 * u(n - 1, i)... + f(n, i); end end
[X, T] = meshgrid(x, t); figure('Position', [100, 100, 800, 600]);
surf(X, T, u, 'EdgeColor', 'none');
colormap(jet);
colorbar;
title('一维波动方程 u(x,t) 的数值解'); xlabel('位置 x'); ylabel('时间 t'); zlabel('位移 u(x,t)'); view(30, 30);
function f=f(t, x) f = x; end
|
3.2.5 MATLAB代码运行结果
3.3 解齐次方程与解非齐次方程的比较
比较2.3.4节和3.2.4节的两块代码,不难发现,两者的基本结构是相同的,只是在3.2.4节的差分方程最后面多了f(t,x)f(t,x)项,在全部代码最后多了一个定义函数f(t,x)f(t,x)的代码块。后期我们为了研究问题的简便,只讨论解齐次方程。
第4章 利用中后差分方法求解齐次二维波动方程
4.1 齐次二维波动方程介绍
我们接下来讨论齐次二维波动方程。
齐次二维波动方程为:
∂t2∂2u(t,x,y)=c2⋅[∂x2∂2u(t,x,y)+∂y2∂2u(t,x,y)](4.1)
在已知t=0t=0时的波形时,我们可以用中后差分方法。
在已知t=Tt=T(T为总时间)时的波形时,我们可以用中前差分方法。
4.2 齐次二维波动方程的中后差分方法
4.2.1 中后差分方法与差分方程
这里的中后差分方法与2.3.1节概念相同,可类比得
⎩⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎧∂x2∂2u(t,x,y)=(Δx)2u(t−Δt,x−Δx,y)−2u(t−Δt,x,y)+u(t−Δt,x+Δx,y)∂y2∂2u(t,x,y)=(Δy)2u(t−Δt,x,y−Δy)−2u(t−Δt,x,y)+u(t−Δt,x,y+Δy)∂t2∂2u(t,x,y)=(Δt)2u(t−2Δt,x,y)−2u(t−Δt,x,y)+u(t,x,y)(4.2)
将(4.2)式带入(4.1)式,并对t、x和y离散化,可得差分方程
u+−(t,x,y)=c2(Δx)2(Δt)2[u(t−1,x−1,y)−2u(t−1,x,y)+u(t−1,x+1,y)]c2(Δy)2(Δt)2[u(t−1,x,y−1)−2u(t−1,x,y)+u(t−1,x,y+1)]u(t−2,x,y)+2u(t−1,x,y)(4.3)
写成MATLAB代码形式:
1
| u(t, x, y) = (c * dt / dx) ^ 2 * (u(t - 1, x - 1, y) - 2 * u(t - 1, x, y) + u(t - 1, x + 1, y)) + (c * dt / dy) ^ 2 * (u(t - 1, x, y - 1) - 2 * u(t - 1, x, y) + u(t - 1, x, y + 1)) - u(t - 2, x, y) + 2 * u(t - 1, x, y)
|
4.2.2 CFL稳定性条件(Courant-Friedrichs-Lewy条件)
在二维波动方程中,CFL稳定性条件要求CFL数r(库朗数)满足:
r=cΔt(Δx)21+(Δy)21<1(4.4)
4.2.3 边界条件
对于初始条件(已知t=0t=0时的波形),t=Δtt=Δt时的波形可以认为与t=0t=0时的波形相同。
u(Δt,x,y)≈u(0,x,y)(4.5)
另外,认为两端固定,x方向长度为Lx,方向长度为Ly
u(t,0,y)=u(t,Lx,y)=u(t,x,0)=u(t,x,Ly)=0(4.6)
对边界条件利用差分方程,进行若干次迭代差分,即可得到偏微分方程的数值解。具体的MATLAB源代码及其运行结果见下。源代码已上传Github,可以访问链接下载源代码。
4.2.4 MATLAB源代码
已知t=0t=0时的波形为e−0.02(x−0.5Lx)2+(y−0.5Ly)2e−0.02(x−0.5Lx)2+(y−0.5Ly)2。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
| clc; clear; close all;
Lx = 1;
Ly = 1;
T = 5;
c = 1;
nx = 100;
ny = 100;
nt = 2000;
dx = Lx/nx;
dy = Ly/ny;
dt = T/nt;
CFL = c*dt*sqrt(1/dx^2 + 1/dy^2); if CFL >= 1 warning('CFL条件不满足,可能导致数值不稳定!'); end
x = linspace(0, Lx, nx); y = linspace(0, Ly, ny); t = linspace(0, T, nt);
u = zeros(nt, nx, ny);
for i = 1 : nx for j = 1 : ny x0 = x(i); y0 = y(j); u(1, i, j) = exp(- ((x0 - 0.5 * Lx) .^ 2... + (y0 - 0.5 * Ly) .^ 2) / 0.02); end end u(2, :, :) = u(1, :, :); u(:, 1, :) = 0; u(:, end, :) = 0; u(:, :, 1) = 0; u(:, :, end) = 0;
for n = 3 : nt for i = 2 : nx - 1 for j = 2 : ny - 1 u(n, i, j) = (c * dt / dx) ^ 2... * (u(n - 1, i - 1, j) - 2 * u(n - 1, i, j)... + u(n - 1, i + 1, j))+ (c * dt / dy) ^ 2... * (u(n - 1, i, j - 1) - 2 * u(n - 1, i, j)... + u(n - 1, i, j + 1)) - u(n - 2, i, j)... + 2 * u(n - 1, i, j); end end end
figure('Position', [100, 100, 800, 600]);
for n = 1 : nt [X, Y] = meshgrid(x, y); u0 = []; for y0 = 1 : ny u0 = [u0; u(n, :, y0)]; end surf(X, Y, u0, 'EdgeColor', 'none'); colormap(jet); colorbar; zlim([-2 2]) title(sprintf('二维波动方程 u(x,y,t) 的数值解 t = %.3f', n*dt)) xlabel('位置 x'); ylabel('位置 y'); zlabel('位移 u(x,y,t)'); view(30, 30); pause(0.001); drawnow limitrate; end
|
4.2.5 MATLAB代码运行结果(精简后)
第5章 总结
根据前面几章的分析,不难看出利用MATLAB的中前(后)差分法求解波动方程是有共性方法的,其MATLAB程序是有共性结构的,这个共性方法在前面几章广泛被提及,此处不再赘述。利用这个共性,我们可以求出非齐次二维波动方程,乃至更高维的(非)齐次波动方程。
另外,在三维波动方程中,CFL稳定性条件要求CFL数(库朗数)r满足:
r=cΔt(Δx)21+(Δy)21+(Δz)21<1(5.1)
致谢
感谢MATLAB老师这一个学期的耐心教导!
感谢父母与朋友在生活中无微的帮助!
在我这么多朋友中,我尤其感谢远在河北某本科上学的异父异母的亲兄弟——Hana,感谢他在编程方面对我的帮助。感谢他凌晨一点半还热心地教我怎样在Github上上传文件,我的博客网站得以建成,他功不可没。