数值方法2:龙格库塔法在解微分方程中的应用

初学练习,看b站课程,教学为matlab代码,自己写的Python代码,后面会放b站课程链接,感兴趣的同学可以学习观看。

说明:Python初学者,代码可能不够漂亮,欢迎大家批评指正。本系列代码用notebook写的,有些图片显示的命令在pycharm中可能会报错,注释掉就行。

理论部分是课程笔记,有不明白的地方可以看b站课程(一位宝藏老师)。
数值方法2:误差分析,龙格库塔法_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1AE411s7e6?spm_id_from=333.999.0.0数值方法2:龙格库塔法,混沌现象_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1iE411g7xn?spm_id_from=333.999.0.0

指数函数,这里按照龙格库塔法推导后,又将k1、k2代入、化简,公式变得和二阶欧拉法一样

#!/usr/bin/env python
# coding: utf-8

# 数值方法2:龙格库塔法(Runge-Kutta)

import numpy as np
import matplotlib.pyplot as plt

# 参数
T = 5
N = 100
dt = T/N
t = np.linspace(0,T,N+1)
y0 = 1

# 初始化
y = [] # 欧拉一阶
y.append(y0)
# print(y[0])
y1 = []
y1.append(y0) # 欧拉二阶==Runge-Kutta

# 求解
for i in range(len(t)-1):
    y.append(y[i]+y[i]*dt)
    y1.append(y1[i]+y1[i]*dt+y1[i]*dt*dt/2)

# 绘图
plt.plot(t,y,label='Euler')
plt.plot(t,y1,label='Runge-Kutta')

# 图例,位置在左上角
plt.plot(t,np.exp(t),label='Real')
plt.legend(loc = 'upper left')

plt.title("Runge-Kutta")

plt.savefig("Runge-Kutta.png")  # 保存图片

plt.show()

 指数函数,这里按照四阶龙格库塔法推导后,又将k1~k4代入、化简,公式和欧拉法一样

#!/usr/bin/env python
# coding: utf-8

# 数值方法2:龙格库塔法(Runge-Kutta)

import numpy as np
import matplotlib.pyplot as plt

# 参数
T = 5
N = 100
dt = T/N
t = np.linspace(0,T,N+1)
y0 = 8

# 初始化
y = [] # Runge-Kutta2
y.append(y0)

y1 = []
y1.append(y0) # Runge-Kutta4

# 求解
for i in range(len(t)-1):
    y.append(y[i]+y[i]*dt+y[i]*dt*dt/2)
    y1.append(y1[i]+y1[i]*dt+y1[i]*dt*dt/2
              +y1[i]*dt*dt*dt/6+y1[i]*dt*dt*dt*dt/24)

# 绘图
plt.plot(t,y,label='Runge-Kutta2')
plt.plot(t,y1,label='Runge-Kutta4')

# 图例,位置在左上角
plt.plot(t,8*np.exp(t),label='Real')
plt.legend(loc = 'upper left')

plt.title("Runge-Kutta2vs4")

plt.savefig("Runge-Kutta4.png")  # 保存图片

plt.show()

 

 洛伦兹系统

#!/usr/bin/env python
# coding: utf-8

# 数值方法2:龙格库塔法(Runge-Kutta)
# 洛伦兹系统
# 初值发生一点点改变,随着时间,值会发生很大变化,即对初值敏感,称为混沌现象

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits import mplot3d

# 参数
T = 30
N = 10000
dt = T/N
t = []
t = np.linspace(0,T,N+1)
# print(t,len(t))

s = 10
b = 8/3
r = 28

# 初始条件
y = []
y.append([-1.6,-0.5,21])
# print(y)

for n in range(N):
    k1=[]
    k2=[]
    k3=[]
    k4=[]
    
    k1.append(s*(y[n][1]-y[n][0]))
    k1.append(r*y[n][0]-y[n][1]-y[n][0]*y[n][2])
    k1.append(-b*y[n][2]+y[n][0]*y[n][1])
#     print(k1)

#     y[n][0] => (y[n][0]+k1[0]*dt/2); 
#     y[n][1] => (y[n][1]+k1[1]*dt/2); 
#     y[n][2] => (y[n][2]+k1[2]*dt/2); 
    k2.append(s*((y[n][1]+k1[1]*dt/2)-y[n][0]+k1[0]*dt/2))
    k2.append(r*(y[n][0]+k1[0]*dt/2)-(y[n][1]+k1[1]*dt/2)-(y[n][0]+k1[0]*dt/2)*(y[n][2]+k1[2]*dt/2))
    k2.append(-b*(y[n][2]+k1[2]*dt/2)+(y[n][0]+k1[0]*dt/2)*(y[n][1]+k1[1]*dt/2))
#     print(k2)
    
#     k1 => k2; 
    k3.append(s*((y[n][1]+k2[1]*dt/2)-y[n][0]+k2[0]*dt/2))
    k3.append(r*(y[n][0]+k2[0]*dt/2)-(y[n][1]+k2[1]*dt/2)-(y[n][0]+k2[0]*dt/2)*(y[n][2]+k2[2]*dt/2))
    k3.append(-b*(y[n][2]+k2[2]*dt/2)+(y[n][0]+k2[0]*dt/2)*(y[n][1]+k2[1]*dt/2))
#     print(k3)

#     k2 => k3; dt/2 => dt;
    k4.append(s*((y[n][1]+k3[1]*dt)-y[n][0]+k3[0]*dt))
    k4.append(r*(y[n][0]+k3[0]*dt)-(y[n][1]+k3[1]*dt)-(y[n][0]+k3[0]*dt)*(y[n][2]+k3[2]*dt))
    k4.append(-b*(y[n][2]+k3[2]*dt)+(y[n][0]+k3[0]*dt)*(y[n][1]+k3[1]*dt))
#     print(k4)

    y_n = []
    for m in range(3):
        y_n.append(y[n][m]+1/6*(k1[m]+2*k2[m]+2*k3[m]+k4[m])*dt)
    y.append(y_n)
# print(y)

Y = np.array(y)
X = np.array(t)
# 绘图
plt.plot(X,Y[:,0])
plt.plot(X,Y[:,1])
plt.plot(X,Y[:,2])

plt.title("Lorentz System")

plt.savefig("LorentzSystem.png")  # 保存图片
plt.show()

#三维
ax = plt.axes(projection='3d')
ax.plot3D(Y[:,0],Y[:,1],Y[:,2])

plt.savefig("LorentzSystemPhaseSpace.png")  # 保存图片
plt.show()

  • 0
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
龙格-(Runge-Kutta method)是一种常用的数值微分方程方法,可以用于二阶微分方程。在MATLAB,可以通过编写代码来实现龙格-。 以下是使用龙格-二阶微分方程的MATLAB代码示例: ```matlab function [t, y] = runge_kutta_method(f, tspan, y0, h) % 输入参数: % f: 函数句柄,表示二阶微分方程 dy^2/dt^2 = f(t, y, dy/dt) % tspan: 时间范围,例如 [t0, tf] % y0: 初始条件,例如 [y0, dy0/dt] % h: 步长 t0 = tspan(1); tf = tspan(2); t = t0:h:tf; n = length(t); y = zeros(n, 2); y(1, :) = y0; for i = 1:n-1 k1 = h * f(t(i), y(i, 1), y(i, 2)); k2 = h * f(t(i) + h/2, y(i, 1) + h/2 * y(i, 2), y(i, 2) + h/2 * k1); k3 = h * f(t(i) + h/2, y(i, 1) + h/2 * y(i, 2) + h^2/4 * k1, y(i, 2) + h/2 * k2); k4 = h * f(t(i) + h, y(i, 1) + h * y(i, 2) + h^2/2 * k2, y(i, 2) + h * k3); y(i+1, 1) = y(i, 1) + h * y(i, 2) + h^2/6 * (k1 + k2 + k3); y(i+1, 2) = y(i, 2) + h/6 * (k1 + 2*k2 + 2*k3 + k4); end end ``` 在上述代码,`f`表示二阶微分方程的右侧函数,`tspan`表示时间范围,`y0`表示初始条件,`h`表示步长。函数返回的`t`是时间数组,`y`是的数组,其`y(:, 1)`表示的值,`y(:, 2)`表示的导数值。 使用该函数可以二阶微分方程。你需要根据具体的二阶微分方程编写对应的右侧函数 `f(t, y, dy/dt)`,并提供时间范围、初始条件和步长作为输入参数。 希望以上信息对你有帮助!如果有任何问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值