-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathODE.tex
299 lines (263 loc) · 13.3 KB
/
ODE.tex
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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
\documentclass[twoside]{ctexart}
\usepackage{ODE}
\title{常微分方程数值解课程报告}
\author{柏香宇, 陈晨, 孙忠豪, 张慧敏, 张梦晴, 赵权}
\date{}
\begin{document}
\maketitle
\tableofcontents
\clearpage
本次研究的方程为
\begin{align}\label{eq:目标}
\begin{cases}
x'(t) = -2x(t) + \sin(\sqrt{t}), & t\in [t_{0}, t_{0}+10]\\
x(t_{0}) = t_{0}
\end{cases}
\end{align}
由常数变易法可知该方程的解析解为
\begin{align*}
x(t) = \me^{-2t}\qty(\int_{t_{0}}^{t}\me^{2\tau}\sin(\sqrt{\tau})\dd{\tau} + x_{0}\me^{2t_{0}})
\end{align*}
这里我们取 $ t_{0}=0,\ x(t_{0})=x_{0}=1 $.
本次实验使用的软件为 MATLAB 2021a.
\section{显式欧拉法 (Explicit Euler Methods)}
\subsection{介绍}
首先给出微分方程
\begin{align}\label{eq:一般方程}
\begin{cases}
x'(t)=f(x(t), t), & t\in[t_{0}, T]\\
x(t_{0})=x_{0}.
\end{cases}
\end{align}
将 $ [t_{0}, T] $ 分为 $ n $ 个区间:
\begin{align*}
t_{0}=t_{0}<t_{1}<\dots<t_{n}=T,
\end{align*}
对每个 $ j=1, 2, \dots, n $, 记步长 $ h_{j}=t_{j}-t_{j-1} $. 如果将 $ [t_{0}, T] $ 等分, 那么记步长为 $ h $.
对方程 \eqref{eq:一般方程} 的两侧同时对 $ t $ 求积分可得:
\begin{align*}
x(t_{i+1})-x(t_{i})=\int_{t_{i}}^{t_{i+1}}x'(t)\dd{t} = \int_{t_{i}}^{t_{i+1}} f(x, t)\dd{t},\quad \forall i=0, 1, \dots, n-1
\end{align*}
我们用 $ x_{i} $ 记 $ x(t_{i}) $ 对应的数值解, 并用左矩形公式代替右侧的积分, 就有显式欧拉法:
\begin{align}
x_{i+1} = x_{i} + h_{i+1}f(x_{i}, t_{i}), \quad \forall i=0, 1, \dots, n-1
\end{align}
对于方程 \eqref{eq:目标}, 可以构造数值格式:
\begin{minted}[frame=none, autogobble=false]{matlab}
x(i+1) = x(i) + h*(-2*x(i) + sin(sqrt(t(i))))
\end{minted}
\subsection{算法}
\begin{algorithm}[H]
\SetAlgoLined
\KwIn{\mintinline{text}{f, N, StartTime, EndTime, InitialValue}}
\KwOut{\mintinline{text}{x=x(EndTime)}}
Initialization\;
use \mt{StartTime}, \mt{EndTime} and \mt{N} to compute step \mt{h}\;
\mm{t = StartTime:h:EndTime}\;
\While{\mm{t(i)} $ \ne $ \mm{EndTime} }{
\mm{x(i+1) = EEM(x(i), t(i))}\;
}
\caption{EEM}
\end{algorithm}
\subsection{程序}
先写出使用显式欧拉法求解方程 \eqref{eq:一般方程} 的函数:
{\small \inputminted{matlab}{./codes/EEM.m}}
再使用如下脚本文件测试显式欧拉法的收敛阶:
{\small \inputminted{matlab}{./codes/testEEM.m}}
\subsection{输出及结论}
得到输出结果
\begin{center}
\begin{tabular}{*{4}{>{$}c<{$}}}\toprule
N_{i} & e:\abs{x_{N+1}-x(t_{N+1})}(\num{e-4}) & \text{GE}: \log_{2}(e_{i}/e_{i+1})\\\midrule
200 & 0.3120 & - \\
400 & 0.1547 & 1.0118 \\
800 & 0.0770 & 1.0060 \\
1600 & 0.0384 & 1.0030 \\
3200 & 0.0192 & 1.0015 \\\bottomrule
\end{tabular}
\captionof{table}{显式欧拉法}\label{tab:EEM}
\end{center}
由 \mm{GE} 的值可知\textbf{显式欧拉法的收敛阶为 1}.
图 \ref{fig:EEM} 为 $ N=1600 $ 时数值解的 $ t-x $ 图.
\begin{center}
\includegraphics[width=.4\textwidth]{figs/EEM.pdf}
\captionof{figure}{显式欧拉法, $ N=1600 $ } \label{fig:EEM}
\end{center}
\section{隐式欧拉法 (Implicit Euler Methods)}
\subsection{介绍}
与显式欧拉法相同, 只是将积分 $ \int_{t_{i}}^{t_{i+1}} f(x, t)\dd{t} $ 用右矩形公式替换为 $ h_{i+1}f(x(t_{i+1}), t_{i+1}) $, 再用数值解 $ x_{i} $ 代替真解 $ x(t_{i}) $, 就可以得到隐式欧拉法:
\begin{align}\label{eq:IEM}
x_{i+1} = x_{i} + h_{i+1}f(x_{i+1}, t_{i+1}), \quad \forall i=0, 1, \dots, n-1
\end{align}
对于方程 \eqref{eq:目标}, 可以构造数值格式:
\begin{align*}
x_{i+1} = x_{i} + h\qty(-2x_{i+1}+\sin(\sqrt{t_{i+1}}))
\end{align*}
为了方便计算, 通过移项可以整理为如下的格式:
\begin{minted}[frame=none, autogobble=false]{matlab}
x(i+1) = 1 / (1 + 2*h) * (x(i) + h*sin(sqrt(t(i+1))))
\end{minted}
当然并不是所有隐式方程都可以解成 $ x_{i+1}=F(x_{i}, t_{i+1}) $ 的形式, 那么可以使用 Newton 迭代法来求 $ x_{i+1} $ 的近似值. 要在方程 \eqref{eq:IEM} 中解出 $ x_{i+1} $, 即求非线性方程
\begin{align*}
g(y)=y - x_{i} - hf(y, t_{i+1})=0
\end{align*}
的根, 其中 $ x_{i} $ 与 $ t_{i+1} $ 均为已知, 取 $ y=x_{i} $ 为迭代初值 $ y_{0} $, 按
\begin{align*}
y_{j+1} = y_{j}-\frac{g(y_{j})}{g'(y_{j})}=y_{j}-\frac{y_{j}-hf(y_{j}, t_{i+1})-x_{i}}{g'(y_{j})},\quad \forall j\in \N
\end{align*}
来对 $ g(y)=0 $ 的根进行迭代, 一般进行 10 次即可满足需求. 于是对于方程 \eqref{eq:目标} 只要求出 $ g'(y) $ 即可, 而显然有 $ g'(y)=1+h $.
下面将给出两种方法的程序与收敛阶的验证, 并进行对比.
\subsection{算法}
\begin{algorithm}[H]
\KwIn{\mintinline{text}{f, N, StartTime, EndTime, InitialValue}}
\KwOut{\mintinline{text}{x=x(EndTime)}}
Initialization\;
use \mt{StartTime}, \mt{EndTime} and \mt{N} to compute step \mt{h}\;
\mm{t =StartTime:h:EndTime}\;
\While{\mm{t(i)} $ \ne $ \mm{EndTime} }{
\mm{x(i+1) = F(x(i), t(i+1))};
}
\caption{显式解出 $ x_{i+1}=F(x_{i}, t_{i+1}) $ }
\end{algorithm}
\begin{algorithm}[H]
\KwIn{\mintinline{text}{f, N, StartTime, EndTime, InitialValue}}
\KwOut{\mintinline{text}{x=x(EndTime)}}
Initialization\;
use \mt{StartTime}, \mt{EndTime} and \mt{N} to compute step \mt{h}\;
\mm{t =StartTime:h:EndTime}\;
compute \mm{dg}\;
\While{\mm{t(i)} $ \ne $ \mm{EndTime} }{
\mm{y = x(i)}\;
\Repeat(Newton's Method){\mm{|y(j+1)-y(j)|<ErrorValue}, 10 times of iteration are enough often.}{\mm{y(j+1) = y(j) - g(y_{j})/dg(y_{j})}}
\mm{x(i+1) = y}\;
}
\caption{使用牛顿迭代法求 $ x_{i+1} $ }
\end{algorithm}
\subsection{程序}
由于隐式欧拉法需要解方程来求得 \mm{x(i)} 的下一步 \mm{x(i+1)}, 而计算机不擅长这个工作, 所以函数 \mt{IEM.m} 只为方程 \eqref{eq:目标} 设计, 函数如下
{\small\inputminted{matlab}{./codes/IEM.m}\captionof{code}{显式解出 $ x_{i+1}=F(x_{i}, t_{i+1}) $ }}
{\small\inputminted{matlab}{./codes/IEMNT.m}\captionof{code}{使用牛顿迭代法求 $ x_{i+1} $ }}
并且使用如下脚本测试收敛阶:
{\small\inputminted{matlab}{./codes/testIEM.m}}
\subsection{输出及结论}
沿用表 \ref{tab:EEM} 的记号, 将输出整理为表格可得
\begin{center}
\begin{tabular}{*{6}{>{$}c<{$}}}\toprule
N_{i} & \abs{x_{i}-y_{i}} (\num{e-14}) & e_{x} (\num{e-4}) & e_{y} (\num{e-4}) & \text{GE}_{x} & \text{GE}_{y}\\\midrule
200 & 0.2717 & 0.3017 & 0.3017 & - & - \\
400 & 0.0059 & 0.1521 & 0.1521 & 0.9877 & 0.9877 \\
800 & 0.0284 & 0.0764 & 0.0764 & 0.9939 & 0.9939 \\
1600 & 0.0337 & 0.0383 & 0.0383 & 0.9970 & 0.9970 \\
3200 & 0.1481 & 0.0192 & 0.0192 & 0.9985 & 0.9985 \\\bottomrule
\end{tabular}
\captionof{table}{IEM}\label{IEM}
\end{center}
可见即使用牛顿法进行迭代出的近似值与显式解出 $ x_{i+1} $ 得到的值的差距极小, 故在解一般的隐式方程的时候, 可以使用牛顿法来求解, 而不用担心误差过大. 同样从 \mm{GE} 的值可以看出\textbf{隐式欧拉法的收敛阶为 1}.
图 \ref{fig:IEM} 为使用牛顿法迭代法 $ N = 1600 $ 时数值解的 $ t-x $ 图.
\begin{center}
\includegraphics[width=.4\textwidth]{figs/IEMNT.pdf}
\captionof{figure}{隐式欧拉法, $ N=1600 $} \label{fig:IEM}
\end{center}
\section{RK 法 (Runge-Kutta Methods)}
\subsection{介绍}
RK 法是一个一步法, 包含了很多级 (stage). 显式欧拉法 EEM 与 RK 法都是用一条经过 $ (t_{n}, x(t_{n})) $ 的直线 $ \ell_{n} $ 来决定 $ t_{n+1} $ 点的值, 关键是这条直线的斜率应该如何选择才能让 $ t_{n+1} $ 点的值更接近真实的值. 在 EEM 中仅用了 $ (t_{n}, x(t_{n})) $ 点的斜率 $ f(x(t_{n}), t_{n}) $ 来作为 $ \ell_{n} $ 的斜率. 而 $ s $ 级 RK 法 ($ s $-stage RK method) 选取 $ [t_{n}, t_{n+1}] $ 中的 $ s $ 个点的斜率的近似值进行加权平均来作为 $ \ell_{n} $ 的斜率来提高精度, 它通常被写为
\begin{align}\label{eq:RKi+1}
x_{n+1} = x_{n} + h\Sum{i=1}{s}b_{i}k_{i}
\end{align}
其中 $ \qty{k_{i}} $ 是各斜率的近似值:
\begin{align}
k_{i} & := f\qty(x(t_{n}+c_{i}h), t_{n}+c_{i}h)\notag\\
& \approx f\qty(x_{n}+h\Sum{j=1}{s}a_{i, j}k_{j}, t_{n}+c_{i}h), \quad i=1, 2, \dots, s,\label{eq:RK}
\end{align}
而又易证
\begin{align*}
c_{i} = \Sum{j=1}{s}a_{i, j},\quad i = 1, 2, \dots, s,
\end{align*}
于是只要给定了级数 $ s $, 那么一个 $ s $-级的 RK 法就可以用一个 Butcher 表 \ref{eq:fullbutcher} 表示出来
\begin{align*}
\begin{NiceArray}{c|*{4}{c}}
c_{1} & a_{1, 1} & a_{1, 2} & \cdots & a_{1, s}\\
c_{2} & a_{2, 1} & a_{2, 2} & \cdots & a_{2, s}\\
\vdots & \vdots & \vdots & \ddots & \vdots\\
c_{s} & a_{s, 1} & a_{s, 2} & \cdots & a_{s, s}\\\hline
& b_{1} & b_{2} & \cdots & b_{s}
\end{NiceArray}
\end{align*}
\captionof{table}{Butcher 表}\label{eq:fullbutcher}
可以将它简记为 $ \begin{NiceArray}{c|c}
c & A\\\hline
& b^{\top}
\end{NiceArray} $, 于是我们可以看到, 显式欧拉法 EEM 是一个一级的 RK 法, 即
\begin{align*}
\begin{cases}
x_{n+1} = x_{n} + hk\\
k = f(x_{n}, t_{n})
\end{cases}
\end{align*}
如果与 Buther 表对应, 那么 $ A = \qty(a_{11})=\qty(0), b = \qty(1), c = \qty(0) $. 特别地, 如果
\begin{align*}
A = \begin{pNiceArray}{ccc}
0 & \Cdots & 0\\
\Block{2-2}<\Large>{*} & \Ddots & \Vdots\\
& & 0
\end{pNiceArray}
\end{align*}
那么这个方法是 $ s $ 级 ERK 法 (Explicit Runge-Kutta Methods). 这次报告以经典的 3 级 3 阶 RK 法与 4 级 4 阶 RK 法为例进行编程, 它们的 Butcher 表分别为
\begin{align*}
\begin{NiceArray}{c|ccc}
0 & & & \\
\frac{1}{2} & \frac{1}{2} & & \\
1 & -1 & 2 & \\\hline
& \frac{1}{6} & \frac{2}{3} & \frac{1}{6}
\end{NiceArray}\qquad
\begin{NiceArray}{c|cccc}
0 & & & & \\
\frac{1}{2} & \frac{1}{2} & & & \\
\frac{1}{2} & 0 & \frac{1}{2} & & \\
1 & 0 & 0 & 1 & \\\hline
& \frac{1}{6} & \frac{1}{3} & \frac{1}{3} & \frac{1}{6}
\end{NiceArray}
\end{align*}
\subsection{算法}
\begin{algorithm}[H]
\KwIn{\mintinline{text}{f, N, StartTime, EndTime, InitialValue, Index}}
\KwOut{\mintinline{text}{x=x(EndTime)}}
Initialization\;
use \mt{StartTime}, \mt{EndTime} and \mt{N} to compute step \mt{Step}\;
use \mt{Index} to get matrix \mt{A, b, c}\;
\mm{Time =StartTime:h:EndTime}\;
\While{\mm{t(i)} $ \ne $ \mm{EndTime} }{
\For{every row \mm{A(j)} in \mm{A}}{
compute \mm{K(j)} with eq \eqref{eq:RK}\;
}
compute \mm{x(i+1) = x(i) + Step * b' * k}\;
}
\caption{ERK 法}
\end{algorithm}
\subsection{程序}
先编写函数 \mt{Method.m} 来存储 3 级与 4 级 RK 法的 Butcher 表的矩阵 $ A, b, c $:
{\small\inputminted{matlab}{./codes/Method.m}}
再编写函数 \mt{ERK.m} 来使用 \mt{Index} 作为 RK 法的索引:
{\small\inputminted{matlab}{./codes/ERK.m}}
最后编写函数 \mt{testERK.m} 来测试两种 RK 法的收敛阶:
{\small\inputminted{matlab}{./codes/testERK.m}}
\subsection{输出及结论}
沿用表 \ref{tab:EEM} 的记号, 将输出整理为表格可得
\begin{center}
\begin{tabular}{*{5}{>{$}c<{$}}}\toprule
N_{i} & e_{x} (\num{e-7}) & e_{y} (\num{e-9}) & \text{GE}_{x} & \text{GE}_{y}\\\midrule
200 & 0.2652 & 0.7428 & - & - \\
400 & 0.0326 & 0.0454 & 3.0259 & 4.0333 \\
800 & 0.0040 & 0.0027 & 3.0130 & 4.0492 \\
1600 & 0.0005 & 0.0001 & 3.0061 & 4.2270 \\
3200 & 0.0001 & 0.0000 & 3.0018 & 7.9296 \\\bottomrule
\end{tabular}
\captionof{table}{ERK}\label{ERK}
\end{center}
可见 3 级的 RK 法精度比 4 级 RK 法要低, 但是误差远小于欧拉法, 这说明增加中间值对于 1 步法来说是有必要的, 同时由 \mt{GEx} 与 \mt{GEy} 的值可以看出 \textbf{Kutta 3 级 RK 法的收敛阶为 3}, \textbf{经典 4 级 RK 法的收敛阶为 4}.
图 \ref{fig:ERK} 为 $ N=3200 $ 时经典 4 级 RK 法的数值解的 $ t-x $ 图.
\begin{center}
\includegraphics[width=.4\textwidth]{figs/ERK.pdf}
\captionof{figure}{RK Methods}\label{fig:ERK}
\end{center}
\end{document}