Question

Yesterday I posted a question here: ValueError and odepack.error using integrate.odeint() which I thought had been successfully answered. However I have since noticed a couple of things.

  1. When running this program it does not tend towards the desired velocity vr
  2. When running the program and varying the angle (representing the pitch of the road) as the time changes it does not always return to desired velocity vr, or even to the previous steady state.

This program is intended to model an integral control system (specifically cruise control). It currently starts from velocity v0, runs at that speed for some time, and then has the cruise control engaged. At this point we should see a change in velocity (we do) that eventually stabilizes on the desired velocity vr. It doesn't. It reaches some other value for reasons unknown, and this value is different depending on the gradient of the rode. Regardless of the initial velocity it still fails to reach the desired velocity

I've played around with the different parameters and variables to no avail. I think the issue is that the controller is not being passed the correct current velocity, however I'm unsure of how to address that issue.

If you need additional information let me know. If I should have edited the previous question just let me know and I'll do that instead, sorry in advance.

Here is my code:

import matplotlib.pylab as plt
import numpy as np
import scipy.integrate as integrate

##Parameters
kp = .5 #proportional gain
ki = .1 #integral gain
vr = 25 #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(61, 500, 5000) #time
theta = np.radians(4) #Theta

def torque(v):    
    return Tm * (1 - B*(an*v/wm - 1)**2)  

def vderivs(v, t):
    v1 = an * controller(v, t) * 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*(t>=200)
    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)

t0l = [i for i in range(61)]
vf=[v0 for i in range(61)]+[v for v in velocity(v0,theta,t)]
tf=t0l+[time for time in t]

plt.plot(tf, vf, 'k-', label=('V(0) = '+str(v0)))

v0=35.
vf=[v0 for i in range(61)]+[v for v in velocity(v0,theta,t)]
plt.plot(tf, vf, 'b-', label=('V(0) = '+str(v0)))

v0=vr
vf=[v0 for i in range(61)]+[v for v in velocity(v0,theta,t)]
plt.plot(tf, vf, 'g-', label=('V(0) = Vr'))

plt.axhline(y=vr, xmin=0, xmax=1000, color='r', label='Desired Velocity')
plt.legend(loc = "upper right")
plt.axis([0,500,18,36])
plt.show()

This is what is plotted running the program as is, using a range of initial velocities Cruise Control

The first sharp change in velocity is when the cruise control is initiated, and the second is when the gradient of the rode changes

Was it helpful?

Solution

Your guess is correct. The target system and the PI controller is integrated, you can't separate it into two odeint. I modified your code, that the system has two status variables: one for the velocity of the system, one for the integration of the control error:

import matplotlib.pylab as plt
import numpy as np
import scipy.integrate as integrate

##Parameters
kp = .5 #proportional gain
ki = .1 #integral gain
vr = 25 #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(61, 500, 5000) #time
theta = np.radians(4) #Theta

def torque(v):    
    return Tm * (1 - B*(an*v/wm - 1)**2)  

def vderivs(status, t):
    v, int_err = status

    err = vr - v
    control = kp * err + ki * int_err

    v1 = an * control * 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*(t>=200)
    return vtot/m, err

def velocity(desired, theta, time):
    return integrate.odeint(vderivs, [desired, 0], time)[:, 0]

t0l = [i for i in range(61)]
vf=[v0 for i in range(61)]+[v for v in velocity(v0,theta,t)]
tf=t0l+[time for time in t]

plt.plot(tf, vf, 'k-', label=('V(0) = '+str(v0)))

v0=35.
vf=[v0 for i in range(61)]+[v for v in velocity(v0,theta,t)]
plt.plot(tf, vf, 'b-', label=('V(0) = '+str(v0)))

v0=vr
vf=[v0 for i in range(61)]+[v for v in velocity(v0,theta,t)]
plt.plot(tf, vf, 'g-', label=('V(0) = Vr'))

plt.axhline(y=vr, xmin=0, xmax=1000, color='r', label='Desired Velocity')
plt.legend(loc = "upper right")
plt.axis([0,500,18,36])
plt.show()

output:

enter image description here

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top