La méthode d'Euler
1 Principe de la méthode d'Euler
Pour une équation
y0(t) =F(t, y(t)) y(0) =y0 à résoudre sur l'intervalleI= [0, L], on utilise une subdivision deI :
tk= k.L n pour0≤k≤n.
Le pas :
h= L
n =tk+1−tk
On approchey(tk)paryk déni par
yk+1=yk+h.F(tk, yk) Explications
On calculey0(t0)en utilisant l'équation diérentielle, puis y1≈y(t1)
en supposanty0 constante sur[t0, t1]:
y0≈y0(t0), y(t0+h)≈y(t0) +h.y0(t0)
Ensuite, on calculey0(t1)en utilisant l'équation diérentielle (en fait, ce n'est pas exactementy), et y2 en supposanty0 constante sur[t1, t2]...
A chaque étape, on roule tout droit pendant une duréeh, donc on sort de la route, on se retrouve sur une autre route, on recommence...
Remarque
Le point(tk+1, yk+1)est donc sur la tangente au point(tk, yk)à UNE solution.
Remarque
La fonction ypeut être à valeurs scalaires ou vectorielles.
2 Un premier exemple
y0(x) =y(x) y(0) = 1
La solution exacte est bien connue... Que calcule la méthode d'Euler ? Réponse
yk = (1 +h)k ; au pointLpar exemple,yn= 1 +Lnn qui tend bien verseL.
3 Un deuxième exemple
On se propose d'étudier le problème de Cauchy suivant :
y0(x) =y(x)−2.sin (x) y(0) = 1
1
3.1 Calculer la solution exacte et la tracer
La réponse est plus bas...
3.2 Tracer la solution à l'aide de la méthode d'Euler
Dans le cas présent
yk+1=yk+h.(yk−2.sin (xk))
La solution exacte
y(x) = cos (x) + sin (x)
2
# { y' = y - 2.sin(x), y(0) = 1 }
# tracé avec la méthode d'Euler
import numpy as np
import matplotlib.pyplot as plt
def F(x, y):
return y - 2*np.sin(x) L = 5
n = 1000 h = L/n
x = np.linspace(0, L, n+1) y = np.zeros(n+1)
y[0] = 1
for k in range(n):
y[k+1] = y[k] + h*F(x[k], y[k]) plt.plot(x, y,'g')
1
# La précision de la méthode d'Euler :
# Etudier l'erreur en fonction de n.
# { y' = y - 2.sin(x), y(0) = 1 }
import numpy as np from time import clock L = 5
def F(x,y):
return(y - 2*np.sin(x)) exact = np.cos(L) + np.sin(L)
# calcule l'erreur commise par la méthode d'Euler
# en fonction de n, donc en fonction de h.
def erreur(n):
h = L/n x, y = 0, 1
for k in range(n):
y += h*F(x, y) x += h
return y - exact
n = 100
for q in range(10):
n *= 2
print('n = ', n, ', n*erreur = ', n*erreur(n)) print('\n')
n = 100
for q in range(10):
t1 = clock() n *= 2
err = erreur(n) t2 = clock()
print('n = ', n, ', durée = ', t2 - t1, ', durée/n = ', (t2 - t1)/n)
1
Conclusion
Expérimentalement,n∗erreursemble converger vers une limite non nulle.
L'erreur est proportionnelle à n1, donc àh.
On dit que la méthode d'Euler est une méthode d'ordre 1 : si on divise le pas par 2, l'erreur est approximativement divisée par 2.
3.3 La complexité
On étudie le temps de calcul en fonction den.
Comme on pouvait s'y attendre, le temps est proportionnel à n.
4 Une méthode plus précise : Euler modiée
y
k+1= y
k+ h.F x
k+ h
2 , y
k+ h
2 .F (x
k, y
k)
!
Tracer à l'aide de cette méthode et comparer... Il s'agit d'une méthode d'ordre 2.
Un programme
5
# { y' = y - 2.sin(x), y(0) = 1 }
import numpy as np
import matplotlib.pyplot as plt L, n = 7, 100
h = L/n
x = np.linspace(0, L, n+1) print(type(x))
def F(x,y):
return(y - 2*np.sin(x))
# tracé de y(x) = cos(x) + sin(x) (bleu) y = np.cos(x) + np.sin(x)
plt.plot(x,y,'b')
# tracé avec la méthode d'Euler (vert) z = np.zeros(n + 1)
z[0] = 1
for k in range(n):
z[k+1] = z[k] + h*F(x[k],z[k]) plt.plot(x,z,'g')
# tracé avec la méthode d'Euler modifiée (rouge) w = np.zeros(n + 1)
w[0] = 1
for k in range(n):
w[k+1] = w[k] + h*F(x[k] + h/2, w[k] + (h/2)*F(x[k],w[k])) plt.plot(x, w, 'r')
1
Le résultat
7
# La précision de la méthode d'Euler modifiée :
# Etudier l'erreur en fonction de n.
# { y' = y - 2.sin(x), y(0) = 1 } import numpy as np
L = 5
def F(x,y):
return(y - 2*np.sin(x)) exact = np.cos(L) + np.sin(L)
# calcule l'erreur commise par la méthode d'Euler modifiée
# en fonction de n, donc en fonction de h.
def erreur(n):
h = L/n x, y = 0, 1
for k in range(n):
y += h*F(x + h/2, y + (h/2)*F(x, y)) x += h
return y - exact
n = 10
for q in range(10):
n *= 2
print('n = ', n, ', (n**2)*erreur = ', (n**2)*erreur(n))
1
5 Un exemple à deux dimensions
Les équations de Lotka-Volterra sont une modélisation de l'évolution simultanée de deux populations en intéraction.
(modèle proie-prédateur).
Le système
x0(t) =a.x(t)−b.x(t).y(t) y0(t) =−c.y(t) +d.x(t).y(t) xreprésente l'eectif des proies,y l'eectif des prédateurs.
b, par exemple, est le taux de mortalité des proies lié à la prédation.
On suppose a, b, c, detx(t0), y(t0)strictement positifs ; on peut montrer que (x, y)est périodique.
Tracer(x, y)avec les deux méthodes et commenter.
Un programme
9
import numpy as np
import matplotlib.pyplot as plt a, b, c, d = 1, 1, 1, 1
n = 1000 duree = 8
temps = np.linspace(0, duree, n+1) h = duree/n
x = np.zeros(n+1) y = np.zeros(n+1) x[0], y[0] = 1, 2
def f(x, y):
return a*x - b*x*y, -c*y + d*x*y
for k in range(n):
v1, v2 = f(x[k], y[k])
x[k+1], y[k+1] = x[k] + h*v1, y[k] + h*v2
plt.plot(x, y) # tracé avec la méthode d'Euler
x[0], y[0] = 1, 3 h2 = h/2
for k in range(n):
v1, v2 = f(x[k], y[k])
w1, w2 = f(x[k] + h2*v1, y[k] + h2*v2) x[k+1], y[k+1] = x[k] + h*w1, y[k] + h*w2
plt.plot(x, y) # tracé avec la méthode d'Euler modifiée
1
Résultat
Conclusion
Avec la méthode d'Euler, la courbe ne semble pas parfaitement périodique : la méthode d'Euler modiée est nettement plus précise.
Le programme en écriture vectorielle
11
import numpy as np
import matplotlib.pyplot as plt a, b, c, d = 1, 1, 1, 1
n = 1000 duree = 8
temps = np.linspace(0, duree, n+1) h = duree/n
X = np.zeros((n+1, 2)) X[0] = [1, 2]
def f(X):
return np.array([a*X[0] - b*X[0]*X[1], -c*X[1] + d*X[0]*X[1]])
for k in range(n):
V = f(X[k])
X[k+1] = X[k] + h*V
plt.plot(X[:,0],X[:,1]) # tracé avec la méthode d'Euler
X[0] = [1, 3]
h2 = h/2
for k in range(n):
V = f(X[k])
W = f(X[k] + h2*V) X[k+1] = X[k] + h*W
plt.plot(X[:,0], X[:, 1]) # tracé avec la méthode d'Euler modifiée
plt.pause(2) plt.plot(X)
1
6 Equations d'ordre 2
Comment traiter le cas d'une équation scalaire d'ordre 2, y00(t) =F(t, y(t), y0(t)) ? Notonsz(t) =y0(t); on obtient un système :
y0(t) =z(t) z0(t) =F(t, y(t), z(t)) On peut l'écrire
X0(t) =G(t, X(t)) où
X(t) = y(t)
z(t)
On est ramené à une équation diérentielle vectorielle d'ordre 1, analogue au cas précédent (Lotka-Volterra).
D'où la méthode :
yk+1=yk+h.zk
zk+1=zk+h.F(tk, yk, zk) ou :
Xk+1=Xk+h.G(tk, Xk)
Exemple
y00(t) +y(t) = 0 y(0) = 1, y0(0) = 0 Dans ce cas, le système est :
y0(t) =z(t), z0(t) =−y(t) y(0) = 1, z(0) = 0 D'où l'algorithme :
yk+1=yk+h.zk zk+1=zk−h.yk Résultat
Si on trace(y, z), on s'attend à trouver un cercle...
Programme
13