3

I am trying to solve this problem:

enter image description here

where U is

enter image description here

here:

s=c*e(t)+e_dot(t)

and

e(t)=theta(t)-thetad(t) 

and

e_dot(t)=theta_dot(t)-thetad_dot(t)

where thetad(theta desired)=sin(t)-- i.e signal to be tracked! and thetad_dot=cos(t),J=10,c=0.5,eta=0.5

I tried first with odeint- it gave error after t=0.4 that is theta(solution of above differential equation) fell flat to 0 and stayed thereafter. However when I tried to increase mxstep to 5000000 I could get somewhat correct graph till t=4.3s.

I want to get a pure sinusoidal graph. That is I want theta(solution of the above differential equation) to track thetad i.e sin(t). But it is not able to accurately track thetad after t=4.3sec. After this time theta(solution of the above differential equation) simply falls off to 0 and stays there.

here is my code-

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

c=0.5
eta=0.5
def f(Y,t):
    x=Y[0]
    y=Y[1]
    e=x-np.sin(t)
    de=y-np.cos(t)
    s=c*e+de
    return [y,-c*(de)-np.sin(t)-eta*np.sign(s)]

t=np.linspace(0,10,1000)
y0=[0.5,1.0]
sol=odeint(f,y0,t,mxstep=5000000)
#sol=odeint(f,y0,t)
print(sol)
angle=sol[:,0]
omega=sol[:,1]
error=angle-np.sin(t)
derror=omega-np.cos(t)
plt.subplot(4,2,1)
plt.plot(t,angle)
plt.plot(t,error,'r--')
plt.grid()
plt.subplot(4,2,2)
plt.plot(t,omega)
plt.plot(t,derror,'g--')
plt.grid()
plt.subplot(4,2,3)
plt.plot(angle,omega)
plt.grid()
plt.subplot(4,2,4)
plt.plot(error,derror,'b--')
plt.savefig('signum_graph.eps')
plt.show()
Amardeep Mishra
  • 129
  • 1
  • 4
  • 16

1 Answers1

3

The integrator employed by odeint (and probably all integrators you find implemented) are based on the assumption that your derivative (f) is continuous (and has a continuous derivative) during each step. The signum function obviously breaks this requirement. This causes the error estimates to be very high, no matter how small the step size, which in turn leads to an overly small step size and the problems you have been experiencing.

There are two general solutions to this:

  1. Choose your step size such that the sign flip exactly falls on a step. (This may be horribly tedious.)

  2. Replace the signum function with a very steep sigmoid, which should be fine and even more realistic for most applications. In your code, you could use

    sign = lambda x: np.tanh(100*x)
    

    instead of np.sign. The factor 100 here controls the steepness of the sigmoid. Choose it sufficiently high to reflect the behaviour you actually need. If you choose it excessively high, this may negatively affect your runtime as the integrator will adapt the step size to be unnecessarily small.

In your case, setting a small absolute tolerance also seems to be working, but I would not rely on this:

sol = odeint(f,y0,t,mxstep=50000,atol=1e-5)
Wrzlprmft
  • 4,234
  • 1
  • 28
  • 54
  • The ODE function should have continuous derivatives of moderate size up to the order of the method. What "moderate size" is depends on the internals of the step size algorithm. Even the first derivative of the step function is a Dirac delta peak, the higher ones are worse... – Lutz Lehmann May 08 '17 at 09:12
  • Thanks a lot! Wrzlprmft you saved me a lot of trouble! I was looking at Vode option in integrate.ode. However tanh here indeed helped me a lot! – Amardeep Mishra May 08 '17 at 09:35
  • Another variants is `def sign(s): s *= 1e3; return s/(1+np.abs(s));`. Also try to shift the sigmoid function to make it asymetrical, `sign = lambda x: np.tanh(100*x-5)` or other small offsets. Only if the solutions are similar under such variations you can hope that some kind of generalized solution exists over the given interval. – Lutz Lehmann May 09 '17 at 10:59