python 中复微分方程的 Runge-Kutta 4 方法

Runge-Kutta 4 method for complex differential equations in python

提问人:Fentse 提问时间:9/30/2023 最后编辑:SternKFentse 更新时间:10/1/2023 访问量:95

问:

我正在尝试使用 python 中的 RK4- 方法求解复杂系统的运动方程,但我对这种方法不是很熟悉,需要帮助来修复我的代码。微分方程为:

等式的第一部分:

First part of equations

方程的下一部分:

next part of equations

我写的代码是:

import numpy as np

p = 7.850
A = (0.01) ** 2
m1 = 1
m3 = 1
g = 9.81

r2 = 1

r3 = 1

r1 = 1

rcm = r1

r = 4 * r2

m2 = 1


def equations(t,y):
    theta, phi1, phi2, x1, w1, p1 = y

    f0 = x1
    f1 = w1
    f2 = p1  # Corrected the variable name to p1

    # Calculate f4 and f5 separately
    f4 = ((m1 * r2 * rcm * x1**2 * np.sin(theta + phi1)) - (m3 * r3 * (r-r2) * p1**2 * np.sin(phi2 - phi1)) - (g * m1 * r2 * np.sin(phi1)) + (g * m2 * ((r/2)-r2) * np.sin(phi1)) + (g * m3 * (r-r2) * np.sin(phi1)) - (m1 * r2 * rcm * np.cos(theta + phi1) * f3) + (m3 * r3 * (r-r2) * np.cos(phi2-phi1) * f5))/((m1 * r2**2))
    f5 = ((m3 * r3 * (r-r2) * np.sin(phi2 - phi1) * w1**2) + (g * m3 * r3 * np.sin(phi2)) + (m3 * r3 * (r-r2) * np.cos(phi2-phi1)))/(m3 * r3**2)

    # Calculate f3 using the previously calculated f4 and f5
    f3 = ((m1 * r2 * rcm * w1**2 * np.sin(theta + phi1)) + (g * m1 * rcm * np.sin(theta)) - (m1 * r2 * rcm * np.cos(theta + phi1) * f4))/(m1 * r2**2)
    theta1, phi1, phi2, x1, w1, p1 = y
    return np.array([f0, f1, f2, f3, f4, f5])


def RK4(t, y, h, f):
    theta, phi1, phi2, x1, w1, p1 = y
    # Runge Kutta standard calculations
    k1 = f(t, y)
    k2 = f(t + h/2, y + h/2 * k1)
    k3 = f(t + h/2, y + h/2 * k2)
    k4 = f(t + h, y + h * k3)

    return 1/6 * (k1 + 2 * k2 + 2 * k3 + k4)

def main():
    
     # Specify time interval and number of domain subintervals
    t0 = 0
    T = 100
    n = 10000
    # initial conditions
    y0 = [np.pi - np.arccos((2 - 1.5) / r2), np.arccos((2 - 1.5) / r2), np.arcsin(1.5/(r-r2)), 0, 0, 0]

    # Domain discretization
    t_n = np.linspace(t0, T, n)
    y_n = [np.array(y0)]

    # Step size
    h = (T - t0) / n

    while t_n[-1] < T:
        # Keep going until T is reached.
        # Store numerical solutions into y_n
        y_n.append(y_n[-1] + h * RK4(t_n[-1], y_n[-1], h, equations))
        t_n = np.append(t_n, t_n[-1] + h)

    print(y_n)

if __name__ == "__main__":
    main()

运行此代码,我收到输出:

[array([2.0943951 , 1.04719755, 0.52359878, 0.        , 0.        ,
       0.        ])]

这看起来像是返回初始条件,这意味着系统保持不变,这不是我想要的结果。任何帮助和/或替代方法将不胜感激,因为我也想模拟系统。先谢谢你。

Python ODE 微分 方程求解 Runge-kutta

评论

0赞 lord_haffi 9/30/2023
查看您尝试模拟的方程会很方便。我也想知道为什么你的输出只包含一个元素?你只发布了最后一个吗?
0赞 Fentse 9/30/2023
方程式在链接中,但我很快就会发布图片,不,我发布了我使用的整个代码,这是我运行代码后收到的唯一输出。
1赞 lord_haffi 9/30/2023
我尝试了您的代码,发现输出确实只有一个元素。这是因为您正在初始化,然后在 while 循环中将其视为开始时为空,并向 .t_nt_n
0赞 lord_haffi 9/30/2023
对不起,我的错,没有看链接。以为,它们是 Runge-Kutta 方程。
1赞 Lutz Lehmann 10/1/2023
更糟糕的是,确切地说,循环条件从一开始就是假的,没有进入循环,并且打印了原始未更改的初始状态。对于简短的解决方案,请初始化 ,不要使用 .t_n[-1]Tt_n=[t0]linspace

答:

0赞 Lutz Lehmann 10/1/2023 #1

使用 sympy 或您选择的 CAS 自动校正欧拉-拉格朗日系统中的许多导数。

保守系统中的大多数机械拉格朗日函数可分为动力学项和势项

L(x,Dx) = 1/2*Dx^T*M(x)*Dx - V(x),   D=d/dt the time derivative

然后,动力学方程可以写成

p = M(x)*Dx
Dp = -grad V(x)

使用脉冲变量会导致汉密尔顿形式主义。然而,这里的目的是使用二阶导数,即一阶导数作为状态的组成部分。为此,取第一个方程的时间导数来得到p

Dp = M1(x;Dx)*Dx + M(x)*DDx

其中 是矩阵值函数在方向上的方向导数。M1(x;Dx)M(x)Dx

M(x)*DDx = -grad V(x) - M1(x;Dx)*Dx

现在是二阶导数的线性系统,可以用线性代数模块的方法求解。DDx

因此,如果你能从给定的拉格朗日量中识别出来,你就可以跳过导数的手动计算,并系统地实现ODE系统。M(x)V(x)

评论

0赞 Fentse 10/2/2023
我已经尝试过使用这种方法,但我决定使用一组更简单的方程,一旦我对 python 和数值求解器更加熟悉,我将尝试更复杂的系统。感谢您的帮助,它真的帮助我更好地理解了。
0赞 Lutz Lehmann 10/2/2023
如果不是对角线,就像从双摆开始的耦合机械结构一样,那么幼稚的 approch 将导致循环依赖关系。人们只能通过用耦合方程组的一般方法处理这种系统来打破它们。解公式可以存在,就像克莱默规则一样,但相对于程序方法,它们很快就会变得非常庞大和昂贵。这看起来像 stackoverflow.com/a/70236831/3088138,我使用状态来包含脉冲变量而不是速度。两者的位置曲线相同。M(x)