首页 文章

使用integrate.odeint()的ValueError和odepack.error

提问于
浏览
3

我正在尝试编写一个方程来建模,然后绘制一个积分控制系统(特别是关于巡航控制) . 但是每当我运行它时,我都会收到两个错误:

ValueError:对象太深,无法使用所需的数组odepack.error:函数调用的结果不是正确的浮点数组 .

我读过这些问题:

看起来他们应该有所帮助,但是我不确定如何将这些应用到我的问题中 . 我是python的新手,所以如果我错过了一些明显的东西或做了一些特别愚蠢的事情,请耐心等待 . 我没有绘制它的问题,所以一旦我弄清楚如何实际工作,我想我已经设定好了 .

import numpy as np
import scipy.integrate as integrate

##Parameters

kp=.5 #proportional gain
ki=.1 #integral gain
vr=30 #desired velocity in m/s
Tm=190 #Max Torque in Nm
wm=420 #engine speed
B=0.4 #Beta
an=12 #at gear 4
p=1.3 #air density
Cd=0.32 #Drag coefficient
Cr=.01 #Coefficient of rolling friction
A=2.4 #frontal area

##Variables

m=18000 #weight
v=20 #starting velocity
time=np.linspace(0,10,50) #time
theta=np.radians(4) #Theta

def vderivs(state,t):
    v = state
    vel=[]
    ti=0

    while ti < t:
        v1 = an*controller(ti,vr,v)*torque(v)
        v2 = m*Cr*np.sign(v)
        v3 = 0.5*p*Cd*A*v**2
        v4 = m*np.sin(theta)

        if t < 10:
            vtot = v1+v2+v3
            vfin = np.divide(vtot,m)
        else:
            vtot = v1+v2+v3+v4
            vfin = np.divide(vtot,m)

        vel.append(vfin)
        ti+=1

    trueVel = np.array(vel, float)
    return trueVel

def uderivs(state,t):
    v = state
    deltax = vr - v
    return deltax    

def controller(time,desired,currentV):
    z = integrate.odeint(uderivs, currentV, time)
    u = kp*(vr-currentV)+ki*z
    return u.flatten()

def torque(v):    
    return Tm*(1-B*(np.divide(an*v,wm)-1)**2)   

def velocity(mass,desired,theta,t):
    v = integrate.odeint(vderivs, desired, t)
    return v.flatten()

test = velocity(m,vr,theta,time)
print(test)

如果您还有其他需要,请告诉我!

3 回答

  • 1

    将此作为单独发布,因为我让您的代码工作 . 好吧,运行并产生输出:P

    实际上一个大问题是我没有注意到的一些隐形广播,但是我一路上改变了很多其他的东西 .

    首先隐身广播是如果你将1d函数与一个参数集成, odeint 返回一个列向量,然后当你用这个结果作为行向量的东西时,你得到一个二维数组(矩阵) . 例如:

    In [704]: a
    Out[704]: array([0, 1, 2, 3, 4])
    
    In [705]: b
    Out[705]: 
    array([[0],
           [1],
           [2]])
    
    In [706]: a+b
    Out[706]: 
    array([[0, 1, 2, 3, 4],
           [1, 2, 3, 4, 5],
           [2, 3, 4, 5, 6]])
    

    您获得的速度输出是 b 之类的列向量,并将其添加到其他时间函数中,并获得矩阵 .


    关于递归,我想我已经解决了这个问题 . 两个导数函数应采用单个标量 t ,此时它们计算导数 . 要做到这一点, vderivs 需要做积分,它应该一直做到 t . 所以我重新定义了它们:

    dt = .1   # another global constant parameter
    
    def vderivs(v, t):
        ts = np.arange(0, t, dt)
        v1 = an * controller(v, ts) * torque(v)
        v2 = m*Cr*np.sign(v)
        v3 = 0.5*p*Cd*A*v**2 
        v4 = m*np.sin(theta)
        vtot = v1+v2+v3+v4*(ts>=10) # a vector of times includes incline only after ts = 10
        return vtot/m
    

    当然 uderivs 很好,但可以写得更简单:

    def uderivs(v, t):
        return vr - v
    

    然后,确保 velocitycontroller 传递正确的值(使用 v0 而不是 v 作为起始速度):

    def controller(currentV, time):
        z = integrate.odeint(uderivs, currentV, time)
        return kp*(vr-currentV) + ki*z.squeeze()
    
    def velocity(desired, theta, time):
        return integrate.odeint(vderivs, desired, time)
    

    谁知道物理学是否正确,但这给出了:

    short time

    请注意,它没有达到所需的速度,因此我增加了解决它的时间

    time = np.linspace(0,50,50) #time
    

    long time

    这是我运行的所有代码:

    import matplotlib.pylab as plt
    import numpy as np
    import scipy.integrate as integrate
    
    ##Parameters
    kp = .5 #proportional gain
    ki = .1 #integral gain
    vr = 30 #desired velocity in m/s
    Tm = 190 #Max Torque in Nm
    wm = 420 #engine speed
    B = 0.4 #Beta
    an = 12 #at gear 4
    p = 1.3 #air density
    Cd = 0.32 #Drag coefficient
    Cr = .01 #Coefficient of rolling friction
    A = 2.4 #frontal area
    
    ##Variables
    m = 18000.0 #weight
    v0 = 20. #starting velocity
    t = np.linspace(0, 20, 50) #time
    dt = .1
    theta = np.radians(4) #Theta
    
    def torque(v):    
        return Tm * (1 - B*(an*v/wm - 1)**2)  
    
    def vderivs(v, t):
        ts = np.arange(0, t, dt)
        v1 = an * controller(v, ts) * torque(v)
        v2 = m*Cr*np.sign(v)
        v3 = 0.5*p*Cd*A*v**2
        v4 = m*np.sin(theta)
        vtot = v1+v2+v3+v4*(ts>=10)
        return vtot/m
    
    def uderivs(v, t):
        return vr - v
    
    def controller(currentV, time):
        z = integrate.odeint(uderivs, currentV, time)
        return kp*(vr-currentV) + ki*z.squeeze()
    
    def velocity(desired, theta, time):
        return integrate.odeint(vderivs, desired, time)
    
    plt.plot(t, velocity(v0, theta, t), 'k-', lw=2, label='velocity')
    plt.plot(t, controller(v0, t), 'r', lw=2, label='controller')
    plt.legend()
    plt.show()
    
  • 1

    这不是一个真正的答案,而是我注意到的一些关于你的代码的评论 .

    正如@qmorgan指出的那样,你已经在 controller 函数中命名了一个与另一个函数相同的参数: velocity 尝试在变量名中保持一致以避免这种情况 . 例如,所有常量都是简写缩写 . 所以,当你在函数中命名参数时,也许会使用单词,这样你就可以使用'll have a habit of knowing where you' .

    你've made a few similar mistakes where you have a parameter for something in your function but you ignore it in the body of the function, and instead use a constant. For example, you'已经定义了 velocity 来取 (mass, desired, theta, t) 但你传递了 (m, v, theta, time) ,其中 v 是你的起始速度 . 小心!你没有注意到这个错误,因为事实上, velocity 忽略 desired 而只是使用 vr 全局常量 . 相反,这整个应该有类似的东西

    def velocity(mass, desired, theta, t):
        return integrate.odeint(vderivs, desired, t)
    
    plt.plot(time, velocity(m, vr, theta, time), 'k-')
    

    要将列表转换为numpy数组,您可以使用 np.array(vel, float) 而不是 np.array([x for x in vel], float) ,因为 [x for x in vel]vel 本身相同 .


    vderivs 中,通过 t 的循环可能已完全消除,但至少我认为它应该更像是:

    ti = 0
    while ti < t:
        ...
        ti += 1
    

    哪个不会忽略输入 t .


    就目前而言, uderivs 采用当前速度和全局定义的所需速度并返回它们的差异:

    def uderivs(v, t):  
        return vr - v
    

    但是你总是传递它 vr (参见 controller 的定义),所以每次集成它时,它只会返回一个长度为 t.size 且值为 vr 的扁平数组 .


    而不是 theta = 4 你可能想要 theta = np.radians(4)


    numpy中已存在函数 np.sign ,无需实现自己的 .

  • -1

    我看到的一个错误是函数 controller ;您试图从整数( vr )中减去一个函数( velocity ),这可能是某些问题的根源 .

    "object too deep for desired array"错误可能来自一个单独的问题,其中函数 controllervelocity 的返回形状错误;它们需要是一维的numpy数组 . 您可以使用 flatten() 方法解决此问题:

    In [82]: z.shape
    Out[82]: (50, 1)
    
    In [83]: z_flat=z.flatten()
    
    In [84]: z_flat.shape
    Out[84]: (50,)
    

    但是为了完全调试,您需要在控制器功能中修复上述错误 .

相关问题