四阶龙格-库塔法——以2022年高教杯数学建模A题为例

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

在微分方程的数值求解当中,四阶龙格-库塔法(Runge-Kutta methods)是用于非线性常微分方程的解的重要的一类隐式或显式迭代法。本文以2022年高教杯数学建模A题为例,详细讲解四阶龙格-库塔法的原理及其python实现。


一、原理

假设我们求解以下微分方程
{ d y d t = f ( y , t ) y ( 0 ) = y 0 \left\{\begin{aligned}&\frac{dy}{dt}=f(y,t) \\&y(0)=y_0\end{aligned}\right. dtdy=f(y,t)y(0)=y0
由中值定理可得
y n + 1 = y n + f ( y ε , t ε ) Δ t y_{n+1}=y_{n}+f(y_{\varepsilon },t_{\varepsilon })\Delta t yn+1=yn+f(yε,tε)Δt
其中, f ( y ε , t ε ) f(y_{\varepsilon },t_{\varepsilon }) f(yε,tε) 为区间 ( t n , t n + 1 ) (t_n,t_{n+1}) (tn,tn+1) 上的平均斜率。四阶龙格-库塔法的基本思想,就是找一个容易计算且与 f ( y ε , t ε ) f(y_{\varepsilon },t_{\varepsilon }) f(yε,tε) 相差极小的值来代替 f ( y ε , t ε ) f(y_{\varepsilon },t_{\varepsilon }) f(yε,tε) 进行运算。

四阶龙格-库塔法的表达式为
y n + 1 = y n + Δ t 6 ( k 1 + 2 k 2 + 2 k 3 + k 4 ) y_{n+1}=y_{n}+\frac{\Delta t}{6}(k_{1}+2k_{2}+2k_{3}+k_{4}) yn+1=yn+6Δt(k1+2k2+2k3+k4)
其中
k 1 = f ( y n , t n ) k 2 = f ( y n + k 1 Δ t 2 , t n + Δ t 2 ) k 3 = f ( y n + k 2 Δ t 2 , t n + Δ t 2 ) k 4 = f ( y n + k 3 Δ t , t n + Δ t ) \begin{aligned} &k_1=f(y_n,t_n) \\ &k_2=f\left(y_n+k_1\frac {\Delta t}2,t_n+\frac {\Delta t}2\right) \\ &k_3=f\left(y_n+k_2\frac {\Delta t}2,t_n+\frac {\Delta t}2\right) \\ &k_4=f\left(y_n+k_3\Delta t,t_n+\Delta t\right) \end{aligned} k1=f(yn,tn)k2=f(yn+k12Δt,tn+2Δt)k3=f(yn+k22Δt,tn+2Δt)k4=f(yn+k3Δt,tn+Δt)
四阶龙格-库塔法的总体截断误差: ∝ Δ t 4 \propto\Delta t^4 Δt4

二、示例

2022年高教杯数学建模A题求解问题1.(1)的微分方程为(推导过程略)
( m f + m a ) d 2 z f d t 2 = f cos ⁡ ω t − c a d z f d t − k f z f − c p ( d z f d t − d z v d t ) − k s ( z f − z v ) , m v d 2 z v d t 2 = − c p ( d z v d t − d z f d t ) − k s ( z v − z f ) , \begin{aligned} (m_{f}+m_{a})\frac{\mathrm{d}^{2}z_{f}}{\mathrm{d}t^{2}}& =f\cos\omega t-c_{a}\frac{\mathrm{d}z_{f}}{\mathrm{d}t}-k_{f}z_{f}-c_{p}\left(\frac{\mathrm{d}z_{f}}{\mathrm{d}t}-\frac{\mathrm{d}z_{v}}{\mathrm{d}t}\right)-k_{s}(z_{f}-z_{v}), \\ m_v\frac{\mathrm{d}^2z_v}{\mathrm{d}t^2}& =-c_p\left(\frac{\mathrm{d}z_v}{\mathrm{d}t}-\frac{\mathrm{d}z_f}{\mathrm{d}t}\right)-k_s(z_v-z_f), \end{aligned} (mf+ma)dt2d2zfmvdt2d2zv=fcosωtcadtdzfkfzfcp(dtdzfdtdzv)ks(zfzv),=cp(dtdzvdtdzf)ks(zvzf),
初始条件为
t = 0 : z f ( 0 ) = z v ( 0 ) = d z f d t ( 0 ) = d z v d t ( 0 ) = 0. t=0:\quad z_f(0)=z_v(0)=\frac{\mathrm{d}z_f}{\mathrm{d}t}(0)=\frac{\mathrm{d}z_v}{\mathrm{d}t}(0)=0. t=0:zf(0)=zv(0)=dtdzf(0)=dtdzv(0)=0.
将其化为一阶常微分方程
d z 1 d t = v 1 , d v 1 d t = 1 m f + m a [ f cos ⁡ ω t − c a v 1 − k f z 1 − c p ( v 1 − v 2 ) − k s ( z 1 − z 2 ) ] , d z 2 d t = v 2 , d v 2 d t = − 1 m v [ c p ( v 2 − v 1 ) + k s ( z 2 − z 1 ) ] . \begin{aligned} &\frac{\mathrm{d}z_1}{\mathrm{d}t} =v_{1}, \\ &\frac{\mathrm{d}v_1}{\mathrm{d}t} =\frac1{m_f+m_a}[f\cos\omega t-c_av_1-k_fz_1-c_p(v_1-v_2)-k_s(z_1-z_2)], \\ &\frac{\mathrm{d}z_2}{\mathrm{d}t} =v_2, \\ &\frac{\mathrm{d}v_2}{\mathrm{d}t} =-\frac1{m_v}[c_p(v_2-v_1)+k_s(z_2-z_1)]. \end{aligned} dtdz1=v1,dtdv1=mf+ma1[fcosωtcav1kfz1cp(v1v2)ks(z1z2)],dtdz2=v2,dtdv2=mv1[cp(v2v1)+ks(z2z1)].
根据四阶龙格-库塔法,我们可以列出 z 1 z_1 z1 的递推公式
z 1 n + 1 = z 1 n + Δ t 6 ( k 1 + 2 k 2 + 2 k 3 + k 4 ) z1_{n+1}=z1_{n}+\frac{\Delta t}{6}(k_{1}+2k_{2}+2k_{3}+k_{4}) z1n+1=z1n+6Δt(k1+2k2+2k3+k4)
其中
f ( v 1 v ) = v 1 n g ( z 1 n , v 1 n , z 2 n , v 2 n , t n ) = 1 m f + m a [ f cos ⁡ ω t − c a v 1 n − k f z 1 n − c p ( v 1 n − v 2 n ) − k s ( z 1 n − z 2 n ) ] \begin{aligned} &f(v1_v)=v1_n\\ &g\left(z1_n,v1_n,z2_n,v2_n,t_n\right)=\frac1{m_f+m_a}[f\cos\omega t-c_av1_n-k_fz1_n-c_p(v1_n-v2_n)-k_s(z1_n-z2_n)] \end{aligned} f(v1v)=v1ng(z1n,v1n,z2n,v2n,tn)=mf+ma1[fcosωtcav1nkfz1ncp(v1nv2n)ks(z1nz2n)]
k 1 = f ( v 1 n ) k 2 = f ( v 1 n + l 1 Δ t 2 ) k 3 = f ( v 1 n + l 2 Δ t 2 ) k 4 = f ( v 1 n + l 3 Δ t ) \begin{aligned} &k_1=f\left(v1_n\right) \\ &k_2=f\left(v1_n+l_1\frac {\Delta t}2\right) \\ &k_3=f\left(v1_n+l_2\frac {\Delta t}2\right)\\ &k_4=f\left(v1_n+l_3\Delta t\right) \end{aligned} k1=f(v1n)k2=f(v1n+l12Δt)k3=f(v1n+l22Δt)k4=f(v1n+l3Δt)

l 1 , l 2 , l 3 l_1,l_2,l_3 l1,l2,l3 v 1 v1 v1 的增长率,由 g ( z 1 , v 1 , z 2 , v 2 , t ) g\left(z1,v1,z2,v2,t\right) g(z1,v1,z2,v2,t) 得到。同理,我们可以得到其它三个变量的递推公式。

四阶龙格-库塔法写出各变量的递推式后,我们可以开始编辑python代码。以下是一个示例

import numpy as np
import matplotlib.pyplot as pl
pl.rcParams['font.sans-serif'] = ['SimHei']
pl.rcParams['axes.unicode_minus'] = False
# 相关参数
omega = 1.4005
mf = 4866
ma = 1335.535
mv = 2433
f = 6250
ca = 656.3616
kf = 1025 * 9.8 * np.pi * 1 ** 2
cp = 10000
ks = 80000

# 步长和迭代次数
dt = 0.2
n = 600

# 初始条件
z1 = 0
z2 = 0
v1 = 0
v2 = 0
t = 0

z1_list = [0]
z2_list = [0]
v1_list = [0]
v2_list = [0]
t_list = [0]

# v1的增长率
def function1(z1,v1,z2,v2,t):
    dv1 = 1/(mf+ma)*(f*np.cos(omega*t)-ca*v1-kf*z1-cp*(v1-v2)-ks*(z1-z2))
    return dv1

# v2的增长率
def function2(z1,v1,z2,v2,t):
    dv2 = -1/mv*(cp*(v2-v1)+ks*(z2-z1))
    return dv2

# 四阶龙格-库塔法
for i in range(n):
    dz1_1 = v1
    dz2_1 = v2
    dv1_1 = function1(z1,v1,z2,v2,t)
    dv2_1 = function2(z1,v1,z2,v2,t)

    dz1_2 = v1 + dv1_1 * dt / 2
    dz2_2 = v2 + dv2_1 * dt / 2
    dv1_2 = function1(z1 + dz1_1 * dt / 2, v1 + dv1_1 * dt / 2, z2 + dz2_1 * dt / 2, v2 + dv2_1 * dt / 2, t + dt / 2)
    dv2_2 = function2(z1 + dz1_1 * dt / 2, v1 + dv1_1 * dt / 2, z2 + dz2_1 * dt / 2, v2 + dv2_1 * dt / 2, t + dt / 2)

    dz1_3 = v1 + dv1_2 * dt / 2
    dz2_3 = v2 + dv2_2 * dt / 2
    dv1_3 = function1(z1 + dz1_2 * dt / 2, v1 + dv1_2 * dt / 2, z2 + dz2_2 * dt / 2, v2 + dv2_2 * dt / 2, t + dt / 2)
    dv2_3 = function2(z1 + dz1_2 * dt / 2, v1 + dv1_2 * dt / 2, z2 + dz2_2 * dt / 2, v2 + dv2_2 * dt / 2, t + dt / 2)

    dz1_4 = v1 + dv1_3 * dt
    dz2_4 = v2 + dv2_3 * dt
    dv1_4 = function1(z1 + dz1_3 * dt, v1 + dv1_3 * dt, z2 + dz2_3 * dt, v2 + dv2_3 * dt, t + dt)
    dv2_4 = function2(z1 + dz1_3 * dt, v1 + dv1_3 * dt, z2 + dz2_3 * dt, v2 + dv2_3 * dt, t + dt)

    z1 = z1 + dt / 6 * (dz1_1 + 2 * dz1_2 + 2 * dz1_3 + dz1_4)
    z2 = z2 + dt / 6 * (dz2_1 + 2 * dz2_2 + 2 * dz2_3 + dz2_4)
    v1 = v1 + dt / 6 * (dv1_1 + 2 * dv1_2 + 2 * dv1_3 + dv1_4)
    v2 = v2 + dt / 6 * (dv2_1 + 2 * dv2_2 + 2 * dv2_3 + dv2_4)
    t = t + dt

    z1_list.append(z1)
    z2_list.append(z2)
    v1_list.append(v1)
    v2_list.append(v2)
    t_list.append(t)

print(t_list[50],z1_list[50],v1_list[50],z2_list[50],v2_list[50])
print(t_list[100],z1_list[100],v1_list[100],z2_list[100],v2_list[100])
print(t_list[200],z1_list[200],v1_list[200],z2_list[200],v2_list[200])
print(t_list[300],z1_list[300],v1_list[300],z2_list[300],v2_list[300])
print(t_list[500],z1_list[500],v1_list[500],z2_list[500],v2_list[500])

fig = pl.figure(figsize=(10,4))
ax1 =fig.add_subplot(1,2,1)
ax2 =fig.add_subplot(1,2,2)

ax1.plot(t_list, z1_list, 'b-', label='浮子',linewidth=1.0)
ax2.plot(t_list, z2_list, 'r-', label='振子',linewidth=1.0)

pl.subplots_adjust(left=0.15,bottom=0.1,top=0.9,right=0.95, \
                   hspace=0.35,wspace=0.3)
ax1.set_ylabel('z/m')
ax1.set_xlabel('T/s')
ax1.set_xlim(0,120)
ax1.set_ylim(-1.0,1.0)
ax2.set_ylabel('z/m', )
ax2.set_xlabel('T/s')
ax2.set_xlim(0,120)
ax2.set_ylim(-1.0,1.0)
ax1.legend(loc='upper right')
ax2.legend(loc='upper right')
pl.show()

结果展示:
在这里插入图片描述

时间(s)浮子位移(m)浮子速度(m/s)振子位移(m)振子速度(m/s)
10-0.1905-0.6429-0.2114-0.6959
20-0.59052-0.2432-0.6339-0.2753
400.28590.31150.29700.3313
60-0.3143-0.4807-0.3311-0.5171
100-0.0835-0.6048-0.0839-0.6435

(顺带吐槽一下,很多数学建模的优秀范文都没有考虑到“有效位数”,按照题目给出的数据,最终得到的结果根本达不到他们给出的那个精度。)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值