2

I am trying to use Python and scipy.integrate.odeint to simulate the following dynamical system:

enter image description here

But this integration breaks numerically in Python resulting in the following and similar images (usually even worse than this):

enter image description here

Generated using the following in iPython/Jupyter notebook:

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

f = lambda x,t: -np.sign(x)
x0 = 3
ts = np.linspace(0,10,1000)
xs = odeint(f,x0,ts)
plt.plot(ts,xs)
plt.show()

Any advice how to better simulate such a system with discontinuous dynamics?

Edit #1:

Example result when ran with smaller timestep, ts = np.linspace(0,10,1000000), in response to @Hun's answer. This is also an incorrect result according to my expectations.

enter image description here

3 Answers3

0

I ran your code exactly as shown and this is what I got.

enter image description here

Hun
  • 3,707
  • 2
  • 15
  • 15
0

I also ran it exactly as shown and got:

enter image description here

Ari Cooper-Davis
  • 3,374
  • 3
  • 26
  • 43
0

One approach that can work better is by implementing a custom sgn() function that has epsilon-tolerance around zero, instead of expecting precise equality with zero.

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

sgn = lambda x,eps: (x<-eps)*(-1) + (x>=-eps and x<eps)*0 + (x>=eps)*1
f = lambda x,t: -sgn(x,1e-7)
x0 = 3
ts = np.linspace(0,10,1000)
xs = odeint(f,x0,ts)
plt.plot(ts,xs)
plt.show()

Note that an eps parameter of 1e-7 worked fine for me, but smaller than that seemed to crash. It seems from numpy.finfo and demonstrated here that the machine epsilon of numpy.float32 is around 1e-7, while float is around 1e-16.

Community
  • 1
  • 1