【问题标题】:Runge Kutta 4th order PythonRunge Kutta 四阶 Python
【发布时间】:2023-02-18 01:28:07
【问题描述】:

我正在尝试使用 Runge Kutta 四阶来求解这个方程:

在我的程序中应用 d2Q/dt2=F(y,x,v) 和 dQ/dt=u Q=y。

我尝试运行代码,但出现此错误:

Traceback (most recent call last):
  File "C:\Users\Egw\Desktop\Analysh\Askhsh1\asdasda.py", line 28, in <module>
    k1 = F(y, u, x)  #(x, v, t)
  File "C:\Users\Egw\Desktop\Analysh\Askhsh1\asdasda.py", line 13, in F
    return ((Vo/L -(R0/L)*u -(R1/L)*u**3 - y*(1/L*C)))
OverflowError: (34, 'Result too large')

我尝试使用 decimal 库,但我仍然无法使其正常工作。我可能没有正确使用它。

我的代码是这样的:

import numpy as np
from math import pi
from numpy import arange
from matplotlib.pyplot import plot, show
#parameters
R0 = 200
R1 = 250
L = 15
h = 0.002
Vo=1000
C=4.2*10**(-6)
t=0.93

def F(y, u, x):
    return ((Vo/L -(R0/L)*u -(R1/L)*u**3 - y*(1/L*C)))


xpoints = arange(0,t,h)
ypoints = []
upoints = []

y = 0.0
u = Vo/L

for x in xpoints:
    ypoints.append(y)
    upoints.append(u)

    m1 = u
    k1 = F(y, u, x)  #(x, v, t)

    m2 = h*(u + 0.5*k1)
    k2 = (h*F(y+0.5*m1, u+0.5*k1, x+0.5*h))

    m3 = h*(u + 0.5*k2)
    k3 = h*F(y+0.5*m2, u+0.5*k2, x+0.5*h)

    m4 = h*(u + k3)
    k4 = h*F(y+m3, u+k3, x+h)

    y += (m1 + 2*m2 + 2*m3 + m4)/6
    u += (k1 + 2*k2 + 2*k3 + k4)/6

plot(xpoints, upoints)
show()

plot(xpoints, ypoints)
show()

我希望得到 u 和 y 对 t 的图。

【问题讨论】:

  • 如果您正在使用 NumPy 和朋友,我会说您也可以使用 SciPy 的 Runge-Kutta 实现。
  • 发生错误时变量的值是多少?您可以使用调试器来查找,或将调用包装在 try..except 中并打印 except 块中的值。另外 - 1/L*C 中的 C 应该在分母中吗?如果是这样,则您缺少括号。如果不是,可以简化为C/L
  • 使用 try.except 我得到的 k1 值打印为 -4939093.827160495 。 C 也为 1/L*C
  • 如果1/L*C 是正确的,那么为什么要这样写而不是代数等价的C/L?这将使它看起来更类似于表达式中的其他 /L
  • 根据上面的公式,(1/L*C) 是错误的,应该是 1/(L*C)

标签: python ode runge-kutta


【解决方案1】:

原来我搞砸了我用于 Runge Kutta 的方程式

正确的代码如下:

import numpy as np
from math import pi
from numpy import arange
from matplotlib.pyplot import plot, show
#parameters
R0 = 200
R1 = 250
L = 15
h = 0.002
Vo=1000
C=4.2*10**(-6)
t0=0
#dz/dz
def G(x,y,z):
    return Vo/L -(R0/L)*z -(R1/L)*z**3 - y/(L*C)
#dy/dx
def F(x,y,z):
        return z



t = np.arange(t0, 0.93, h)
x = np.zeros(len(t))
y = np.zeros(len(t))
z = np.zeros(len(t))

y[0] = 0.0
z[0] = 0

for i in range(1, len(t)):

        k0=h*F(x[i-1],y[i-1],z[i-1])
        l0=h*G(x[i-1],y[i-1],z[i-1])
        k1=h*F(x[i-1]+h*0.5,y[i-1]+k0*0.5,z[i-1]+l0*0.5)
        l1=h*G(x[i-1]+h*0.5,y[i-1]+k0*0.5,z[i-1]+l0*0.5)
        k2=h*F(x[i-1]+h*0.5,y[i-1]+k1*0.5,z[i-1]+l1*0.5)
        l2=h*G(x[i-1]+h*0.5,y[i-1]+k1*0.5,z[i-1]+l1*0.5)
        k3=h*F(x[i-1]+h,y[i-1]+k2,z[i-1]+l2)
        l3 = h * G(x[i - 1] + h, y[i - 1] + k2, z[i - 1] + l2)

        y[i]=y[i-1]+(k0+2*k1+2*k2+k3)/6
        z[i] = z[i - 1] + (l0 + 2 * l1 + 2 * l2 + l3) / 6
Q=y 
I=z 
plot(t, Q)
show()

plot(t, I)
show()

【讨论】:

  • 这并没有解决相同的初始值问题。在原件中,您有 z[0]=u=Vo/L,它会产生刚度,因此由于三次项而导致数值不稳定,需要 h=2e-5 才能进行稳定的计算。这里有 z[0]=0.0,其中三次项仍然很小。
  • 我的初始值也犯了一个错误。根据问题Q=0和dQ/dt=0。我的y=Q和dQ/dt=z。
【解决方案2】:

如果我可以提请你注意这 4 行

    m1 = u
    k1 = F(y, u, x)  #(x, v, t)

    m2 = h*(u + 0.5*k1)
    k2 = (h*F(y+0.5*m1, u+0.5*k1, x+0.5*h))

您应该注意到前两行和第二对行之间的基本结构差异。

您还需要在第一对中乘以步长h


下一个问题是步长和三次项。它为 Lipschitz 常数贡献了一个大小为3*(R1/L)*u^2 ~ 50*u^2 的项。在带有u=Vo/L ~ 70 的问题的原始 IVP 中,该术语的大小为2.5e+5。为了仅补偿该项以保持在方法的稳定区域中,步长必须更小1e-5

在初始条件为 u=0 的初始条件下,速度 u 仍然低于 0.001,因此三次项不能确定稳定性,现在由贡献 Lipschitz 项 1/sqrt(L*C) ~ 125 的最后一项控制。稳定性的步长现在是0.020.002可以期待定量有用的结果。

【讨论】:

  • 是的,我在数学上犯了一个错误。你是对的,先生。
【解决方案3】:

您可以使用 decimal 库以获得更高的精度(处理更多数字),但是每个值都应该是同一类(decimal.Decimal)有点烦人。

例如:

import numpy as np
from math import pi
from numpy import arange
from matplotlib.pyplot import plot, show

# Import decimal.Decimal as D
import decimal
from decimal import Decimal as D

# Precision
decimal.getcontext().prec = 10_000_000

#parameters

# Every value should be D class (decimal.Decimal class)
R0 = D(200)
R1 = D(250)
L = D(15)
h = D(0.002)
Vo = D(1000)
C = D(4.2*10**(-6))
t = D(0.93)

def F(y, u, x):
    # Decomposed for use D
    a = D(Vo/L)
    b = D(-(R0/L)*u)
    c = D(-(R1/L)*u**D(3))
    d = D(-y*(D(1)/L*C))
    return ((a + b + c + d ))


xpoints = arange(0,t,h)
ypoints = []
upoints = []

y = D(0.0)
u = D(Vo/L)

for x in xpoints:
    ypoints.append(y)
    upoints.append(u)

    m1 = u
    k1 = F(y, u, x)  #(x, v, t)

    m2 = (h*(u + D(0.5)*k1))
    k2 = (h*F(y+D(0.5)*m1, u+D(0.5)*k1, x+D(0.5)*h))

    m3 = h*(u + D(0.5)*k2)
    k3 = h*F(y+D(0.5)*m2, u+D(0.5)*k2, x+D(0.5)*h)

    m4 = h*(u + k3)
    k4 = h*F(y+m3, u+k3, x+h)

    y += (m1 + D(2)*m2 + D(2)*m3 + m4)/D(6)
    u += (k1 + D(2)*k2 + D(2)*k3 + k4)/D(6)

plot(xpoints, upoints)
show()

plot(xpoints, ypoints)
show()

但即使有千万精度,我仍然会遇到溢出错误。检查公式的组成部分,它们的值太高了。您可以提高处理它们的精度,但您会注意到计算它们需要时间。

【讨论】:

    【解决方案4】:

    使用 scipy.integrate.odeint 和 scipy.integrate.solve_ivp 实现问题。

    import numpy as np
    import matplotlib.pyplot as plt
    from scipy.integrate import odeint, solve_ivp
    
    # Input data initial conditions
    ti = 0.0
    tf = 0.5
    N  = 10000
    h  = (tf-ti)/N
    
    u0 = 0.0
    Q0 = 1.0e-3
    
    t_span = np.linspace(ti,tf,N)
    r0     = np.array([Q0,u0])
    
    # Parameters
    R0 = 200
    R1 = 250
    L  = 15
    C  = 4.2*10**(-6)
    V0 = 1000
    
    # Systems of First Order Equations
    
    # This function is used with odeint, as specified in the documentation for scipy.integrate.odeint
    def f(r,t,R0,R1,L,C,V0):
        Q,u = r
        ode1 = u
        ode2 = -((R0/L)*u)-((R1/L)*u**3)-((1/(L*C))*Q)+(V0/L)
        return np.array([ode1,ode2])
    
    # This function is used in our 4Order Runge-Kutta implementation and in scipy.integrate.solve_ivp
    def F(t,r,R0,R1,L,C,V0):
        Q,u = r
        ode1 = u
        ode2 = -((R0/L)*u)-((R1/L)*u**3)-((1/(L*C))*Q)+(V0/L)
        return np.array([ode1,ode2])
    
    # Resolution with oedint
    sol_1 =    odeint(f,r0,t_span,args=(R0,R1,L,C,V0))
    sol_2 = solve_ivp(F,t_span, r0, method='RK45',args=(R0,R1,L,C,V0))
    
    Q_odeint, u_odeint       = sol_1[:,0], sol_1[:,1]
    Q_solve_ivp, u_solve_ivp = sol_1[:,0], sol_1[:,1]
    
    # Figures
    plt.figure(figsize=[30.0,10.0])
    plt.subplot(3,1,1)
    plt.grid(color = 'red',linestyle='--',linewidth=0.4)
    plt.plot(t_span,Q_odeint,'r',t_span,u_odeint,'b')
    plt.xlabel('t(s)')
    plt.ylabel('Q(t), u(t)')
    
    plt.subplot(3,1,2)
    plt.plot(t_span,Q_solve_ivp,'g',t_span,u_solve_ivp,'y')
    plt.grid(color = 'yellow',linestyle='--',linewidth=0.4)
    plt.xlabel('t(s)')
    plt.ylabel('Q(t), u(t)')
    
    plt.subplot(3,1,3)
    plt.plot(Q_solve_ivp,u_solve_ivp,'green')
    plt.grid(color = 'yellow',linestyle='--',linewidth=0.4)
    plt.xlabel('t(s)')
    plt.ylabel('Q(t), u(t)')
    

    实现基于四阶龙格-库塔算法的 python 代码。

    # Code development of Runge-Kutta 4 Order
    # Input data initial conditions #
    ti = 0.0
    tf = 0.5
    N  = 10000
    h  = (tf-ti)/N
    
    u0 = 0.0
    Q0 = 1.0e-3
    
    # Parameters
    R0 = 200
    R1 = 250
    L  = 15
    C  = 4.2*10**(-6)
    V0 = 1000
    
    # First order ordinary differential equations
    def f1(t,Q,u):
        return u
    
    def f2(t,Q,u):
        return -((R0/L)*u)-((R1/L)*u**3)-((1/(L*C))*Q)+(V0/L)
    
    t = np.zeros(N); Q = np.zeros(N); u = np.zeros(N)
    t[0] = ti
    Q[0] = Q0
    u[0] = u0
    
    for i in range(0,N-1,1):
    
        k1 = h*f1(t[i],Q[i],u[i])
        l1 = h*f2(t[i],Q[i],u[i])
    
        k2 = h*f1(t[i]+(h/2),Q[i]+(k1/2),u[i]+(l1/2))
        l2 = h*f2(t[i]+(h/2),Q[i]+(k1/2),u[i]+(l1/2))
    
        k3 = h*f1(t[i]+(h/2),Q[i]+(k2/2),u[i]+(l2/2))
        l3 = h*f2(t[i]+(h/2),Q[i]+(k2/2),u[i]+(l2/2))
    
        k4 = h*f1(t[i]+h,Q[i]+k3,u[i]+l3)
        l4 = h*f2(t[i]+h,Q[i]+k3,u[i]+l3)
    
        Q[i+1] = Q[i] + ((k1+2*k2+2*k3+k4)/6)
        u[i+1] = u[i] + ((l1+2*l2+2*l3+l4)/6)
        t[i+1] = t[i] + h
    
    plt.figure(figsize=[20.0,10.0])
    plt.subplot(1,2,1)
    plt.plot(t,Q_solve_ivp,'r',t,Q_odeint,'y',t,Q,'b')
    plt.grid(color = 'yellow',linestyle='--',linewidth=0.4)
    plt.xlabel('t(s)')
    plt.ylabel(r'$Q(t)_{Odeint}$, $Q(t)_{RK4}$')
    
    plt.subplot(1,2,2)
    plt.plot(t,Q_solve_ivp,'g',t,Q_odeint,'y',t,Q,'b')
    plt.grid(color = 'yellow',linestyle='--',linewidth=0.4)
    plt.xlabel('t(s)')
    plt.ylabel(r'$Q(t)_{solve_ivp}$, $Q(t)_{RK4}$')
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-02-10
      • 1970-01-01
      • 2011-07-25
      • 2020-08-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-21
      相关资源
      最近更新 更多