从微分方程系统函数中绘制变量

时间:2019-01-08 10:15:43

标签: python-2.7 plot differential-equations

我在一个函数(subsystem4)中具有4-4个微分方程组,并且使用odeint函数进行求解。我设法绘制了系统的结果。我的问题是我想绘制和包含在同一函数(subsystem4)中的其他一些方程式(例如x,y,vcxdot ...),但出现NameError:名称'vcxdot'未定义。另外,我想将其中的一些方程(不仅是方程系统的结果)用作以下微分方程系统的输入,并在相同的时间段(t)中绘制所有方程。我已经使用Matlab-Simulink做到了这一点,但是由于Simulink块,它要容易得多。如何获得和绘制函数(子系统4)的所有方程式并将它们用作后续系统的输入?我是python的新手,并且使用python 2.7.12。先感谢您!

import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt

def subsystem4(u,t):
    added_mass_x = 0.03 # kg
    added_mass_y = 0.04
    mb = 0.3 # kg
    m1 = mb-added_mass_x
    m2 = mb-added_mass_y
    l1 = 0.07 # m
    l2 = 0.05 # m
    J = 0.00050797 # kgm^2
    Sa = 0.0110 # m^2
    Cd = 2.44
    Cl = 3.41
    Kd = 0.000655 # kgm^2
    r = 1000 # kg/m^3
    f = 2 # Hz
    c1 = 0.5*r*Sa*Cd
    c2 = 0.5*r*Sa*Cl
    c3 = 0.5*mb*(l1**2)
    c4 = Kd/J
    c5 = (1/(2*J))*(l1**2)*mb*l2
    c6 = (1/(3*J))*(l1**3)*mb


    vcx = u[0]
    vcy = u[1]
    psi = u[2]
    wz = u[3]

    x = 3 + 0.3*np.cos(t)
    y = 0.5 + 0.3*np.sin(t)
    xdot = -0.3*np.sin(t)
    ydot = 0.3*np.cos(t)
    xdotdot = -0.3*np.cos(t)
    ydotdot = -0.3*np.sin(t)
    vcx = xdot*np.cos(psi)-ydot*np.sin(psi)
    vcy = ydot*np.cos(psi)+xdot*np.sin(psi)

    psidot = wz
    vcxdot = xdotdot*np.cos(psi)-xdot*np.sin(psi)*psidot-ydotdot*np.sin(psi)-ydot*np.cos(psi)*psidot
    vcydot = ydotdot*np.cos(psi)-ydot*np.sin(psi)*psidot+xdotdot*np.sin(psi)+xdot*np.cos(psi)*psidot
    g1 = -(m1/c3)*vcxdot+(m2/c3)*vcy*wz-(c1/c3)*vcx*np.sqrt((vcx**2)+(vcy**2))+(c2/c3)*vcy*np.sqrt((vcx**2)+(vcy**2))*np.arctan2(vcy,vcx)
    g2 = (m2/c3)*vcydot+(m1/c3)*vcx*wz+(c1/c3)*vcy*np.sqrt((vcx**2)+(vcy**2))+(c2/c3)*vcx*np.sqrt((vcx**2)+(vcy**2))*np.arctan2(vcy,vcx)

    A = 12*np.sin(2*np.pi*f*t+np.pi)
    if A>=0.1:
        wzdot = ((m1-m2)/J)*vcx*vcy-c4*wz**2*np.sign(wz)-c5*g2-c6*np.sqrt((g1**2)+(g2**2))
    elif A<-0.1:
        wzdot = ((m1-m2)/J)*vcx*vcy-c4*wz**2*np.sign(wz)-c5*g2+c6*np.sqrt((g1**2)+(g2**2))
    else:
        wzdot = ((m1-m2)/J)*vcx*vcy-c4*wz**2*np.sign(wz)-c5*g2


    return [vcxdot,vcydot,psidot,wzdot]

u0 = [0,0,0,0]
t = np.linspace(0,15,1000)
u = odeint(subsystem4,u0,t)

vcx = u[:,0]
vcy = u[:,1]
psi = u[:,2]
wz = u[:,3]

plt.figure(1)
plt.subplot(211)
plt.plot(t,vcx,'r-',linewidth=2,label='vcx')
plt.plot(t,vcy,'b--',linewidth=2,label='vcy')
plt.plot(t,psi,'g:',linewidth=2,label='psi')
plt.plot(t,wz,'c',linewidth=2,label='wz')
plt.xlabel('time')
plt.legend()
plt.show()

1 个答案:

答案 0 :(得分:0)

对于绘制导数的直接问题,您可以通过直接在解决方案上再次调用ODE函数来获得速度

u = odeint(subsystem4,u0,t)
udot = subsystem4(u.T,t)

并通过

获得单独的速度阵列
vcxdot,vcydot,psidot,wzdot = udot

在这种情况下,该函数涉及分支,这对它的矢量化调用不是很友好。有多种矢量化分支的方法,但是最简单的解决方法是手动遍历解决方案点,这比有效的矢量化实现要慢。这将再次产生一个像odeint这样的元组列表,因此必须将结果作为一个列表元组进行转置,以便“轻松”分配给单个数组变量。

udot = [ subsystem4(uk, tk) for uk, tk in zip(u,t) ]; 
vcxdot,vcydot,psidot,wzdot = np.asarray(udot).T

extended plot


这似乎会使计算量增加一倍,但实际上不是两倍,因为通常从求解器的内部步长点插入求解点。集成期间对ODE功能的评估通常会在与解决方案不同的地方进行。

对于其他变量,将位置和速度的计算提取到函数中以仅将常数和组成放在一个位置:

def xy_pos(t): return 3 + 0.3*np.cos(t), 0.5 + 0.3*np.sin(t)
def xy_vel(t): return -0.3*np.sin(t), 0.3*np.cos(t) 
def xy_acc(t): return -0.3*np.cos(t), -0.3*np.sin(t)

或类似的东西,然后可以在ODE函数内部和准备绘图时使用。


Simulink最有可能做的是收集所有块的所有方程式,并将其组成一个大的ODE系统,然后立即为整个状态求解。您将需要实现类似的东西。一个大的状态向量,每个子系统都知道其各自的状态响应。导数向量,以从中获取其特定状态变量并将其写入。然后可以使用子系统之间传递的值来计算导数。

您试图做的,分别解决子系统的问题,仅适用于响应。可能会导致1阶积分方法。所有高阶方法都需要能够同时从该方法的先前阶段计算出的某个方向上转移状态,并在那里评估整个系统。