2017-05-08 3 views
2

Je suis en train de résoudre ce problème:Python: Impossible de résoudre une équation différentielle en utilisant odeint avec fonction Signum

enter image description here

où U est

enter image description here

ici:

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

et

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

et

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

où thetad (thêta désiré) = sin (t) - signal de i.e. à être suivis! J'ai essayé d'abord avec odeint - il a donné une erreur après t = 0.4 qui est thêta (solution de l'équation différentielle ci-dessus) est tombé à plat à 0 et resté par la suite. Cependant quand j'ai essayé d'augmenter mxstep à 5000000 je pourrais obtenir un graphique assez correct jusqu'à t = 4.3s.

Je veux obtenir un graphe sinusoïdal pur. C'est-à-dire que je veux que thêta (solution de l'équation différentielle ci-dessus) trace le thetad i.e sin (t). Mais il n'est pas capable de suivre exactement le temps après t = 4,3 secondes. Après ce temps thêta (solution de l'équation différentielle ci-dessus) tombe simplement à 0 et reste là.

ici est mon 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() 

Répondre

1

L'intégrateur employé par odeint (et probablement tous les intégrateurs vous trouverez IMPLEMENTE) sont basées sur l'hypothèse que votre dérivée (f) est continue (et a un dérivé continu) pendant chaque étape. La fonction signum rompt manifestement cette exigence. Cela entraîne des estimations d'erreur très élevées, quelle que soit la taille du pas, ce qui entraîne une taille de pas trop petite et les problèmes que vous avez rencontrés.

Il existe deux solutions générales à ce:

  1. Choisissez votre taille de pas telle que le flip signe tombe exactement sur une étape. (Cela peut être terriblement ennuyeux.)

  2. Remplacez la fonction Signum par une très raide sigmoid, ce qui devrait être bien et encore plus réaliste pour la plupart des applications. Dans votre code, vous pouvez utiliser

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

    au lieu de np.sign. Le facteur 100 contrôle ici la pente du sigmoïde. Choisissez-le suffisamment haut pour refléter le comportement dont vous avez réellement besoin. Si vous le choisissez trop haut, cela peut affecter négativement votre temps d'exécution car l'intégrateur adaptera la taille du pas pour le rendre inutilement petit.

Dans votre cas, la mise en une petite tolérance absolue semble aussi travailler, mais je ne se baserait pas sur ce point:

sol = odeint(f,y0,t,mxstep=50000,atol=1e-5) 
+0

La fonction ODE doit avoir des dérivées continues de taille modérée jusqu'à l'ordre de la méthode. Quelle "taille modérée" dépend des internes de l'algorithme de taille de pas. Même la première dérivée de la fonction step est un pic delta de Dirac, les plus élevés sont plus mauvais ... – LutzL

+0

Merci beaucoup! Wrzlprmft vous m'avez sauvé beaucoup d'ennuis! Je regardais l'option Vode dans integrate.ode. Cependant Tanh ici m'a vraiment beaucoup aidé! –

+0

Une autre variante est 'le (s) signe (s) de défaut: s * = 1e3; retourne s/(1 + np.abs (s)); Essayez aussi de décaler la fonction sigmoïde pour la rendre asymétrique, 'sign = lambda x: np.tanh (100 * x-5)' ou d'autres petits décalages. Ce n'est que si les solutions sont similaires avec de telles variations que vous pouvez espérer qu'une sorte de solution généralisée existe sur l'intervalle donné. – LutzL