Physique-chimie · Terminale · Enseignement de spécialité · Pour aller plus loin n°3

Charger un condensateur,
sans le résoudre à la main.

Aux bornes d'un condensateur qui se charge à travers une résistance, la tension U(t) obéit à une équation différentielle qu'on sait résoudre sur le papier — mais on peut aussi choisir de ne pas la résoudre à la main, et de laisser l'ordinateur avancer pas à pas grâce à la méthode d'Euler. Tu vas coder cette méthode toi-même, puis comparer ta solution numérique à la solution théorique exacte pour juger de sa qualité.

euler.py — aperçuN = 1000
t U

Objectif de la fiche : utiliser un langage de programmation pour résoudre une équation différentielle grâce à la méthode d'Euler, à travers l'exemple de la charge d'un condensateur, puis comparer le résultat numérique à la solution analytique exacte pour juger de la qualité de la méthode.

Cette fiche est autonome : tu n'as besoin d'aucun autre document. Chaque étape contient un script incomplet à compléter, puis à copier-coller dans Thonny (ou dans la console Basthon tout en bas de la page si tu n'as pas Thonny sous la main).

+

Contexte : simuler une charge sans la résoudre à la main

À savoir
  • On charge un condensateur à travers une résistance, à l'aide d'un générateur idéal de tension E. La tension U aux bornes du condensateur vérifie l'équation différentielle dU/dt = (E - U)/τ, où τ = RC est la constante de temps du circuit.
  • Cette équation possède une solution mathématique exacte (une exponentielle qui tend vers E), mais on va ici la retrouver numériquement, sans la résoudre à la main : c'est l'intérêt de la méthode d'Euler. On comparera ensuite les deux pour juger de la qualité de la méthode.
  • Le principe : on écrit l'équation différentielle sous la forme dU/dt = f(U, t), puis on avance pas à pas depuis la condition initiale, en approchant la courbe solution par une suite de petits segments de droite. Plus le pas est petit, plus l'approximation est fine — mais plus le calcul est long.
00

La fonction f(U,t) et les paramètres

À savoir
  • On simule un condensateur initialement déchargé (U(0) = 0 V), avec un générateur de force électromotrice E = 10 V et une constante de temps τ = 1 s (notée Tau dans le code, car Python n'accepte pas les lettres grecques comme nom de variable usuel).
  • La fonction f(U, t) renvoie la valeur de dU/dt à un instant donné : c'est elle qui encode l'équation différentielle.
  • Le script ci-dessous est déjà complet : copie-le tel quel dans Thonny (ou dans Basthon) pour commencer.
etape0_equation.py
import numpy as np
import matplotlib.pyplot as plt

# bornes de l'intervalle de temps et nombre de pas pour la résolution
t0, tf = 0., 10.
N = 1000
t = np.linspace(t0, tf, N+1)  # liste des dates pour le calcul des solutions approchées

# condition initiale et constantes du circuit
x0 = 0  # tension initiale U(0), en V : le condensateur est déchargé
E = 10  # force électromotrice du générateur, en V
Tau = 1  # constante de temps du circuit RC, en s

def f(U, t):
    return (E-U)/Tau
Indice

Le paramètre t de f(U, t) n'est pas utilisé dans le return ici (l'équation ne dépend pas explicitement du temps), mais il faut tout de même le prévoir dans la signature de la fonction : la méthode d'Euler, plus générale, doit pouvoir fonctionner aussi avec des équations où t intervient.

01

Écrire la fonction euler

À savoir
  • La méthode d'Euler calcule U(i+1) à partir de U(i) grâce à la relation U(i+1) = U(i) + h·f(U(i), t(i)), où h est le pas (la durée entre deux instants successifs).
  • Comme les instants de t sont régulièrement espacés (grâce à np.linspace), h est constant : il suffit de le calculer une seule fois, comme la différence entre les deux premières valeurs de t.
  • La fonction doit fonctionner pour n'importe quelle équation différentielle : c'est pour cela qu'on lui passe la fonction g (qui jouera le rôle de f), la condition initiale x0, et le tableau des instants t, sans jamais écrire f, E ou Tau à l'intérieur.
Consigne
  • Complète la fonction euler ci-dessous, qui renvoie un tableau numpy x contenant la solution approchée à chaque instant de t.
  • N'oublie pas d'initialiser x avec np.zeros(N) avant la boucle : un tableau numpy a une taille fixée dès sa création, contrairement à une liste, on ne peut pas lui ajouter des éléments avec .append(...) au fur et à mesure.
etape1_fonction_euler.py
def euler(g, x0, t):  # méthode d'Euler
    h = t[_] - t[_]  # TODO : pas constant, distance entre les deux premières valeurs de t
    N = len(_)  # on recalcule N en local pour le cas général
    x = np.zeros(_)  # TODO : initialisation obligatoire du tableau numpy
    x[_] = __  # TODO : condition initiale
    for i in range(N-_) :
        x[i+_] = x[_] + h*g(x[_], t[_])  # TODO : définit x[i+1] par Euler
    return x
Indice

range(N-1) permet à i de parcourir 0, 1, ..., N-2 : à chaque tour, on calcule x[i+1], ce qui remplit progressivement le tableau jusqu'au dernier indice N-1, sans jamais chercher à écrire au-delà.

Résultat attendu

Cette fonction ne produit aucun affichage à elle seule (elle se termine par return x) : le résultat se vérifie à l'étape suivante, en l'appliquant au problème de la charge du condensateur.

02

Résoudre avec N = 1000 pas et comparer à la théorie

À savoir
  • Cette équation différentielle a une solution théorique connue : U(t) = E·(1 - e-t/τ). On peut donc la tracer sur le même graphe que la solution d'Euler, pour vérifier que la méthode numérique donne bien le bon résultat.
Consigne
  • Complète la fonction Uthéo(t), qui renvoie la solution théorique E·(1 - e-t/τ) (utilise np.exp pour l'exponentielle).
  • Appelle ta fonction euler avec la fonction f, la condition initiale x0 et le tableau t définis à l'étape 0, et stocke le résultat dans solE.
  • Trace solE en fonction de t, avec des ronds bleus ('bo'), et superpose Uthéo(t) en rouge trait plein ('r-'), chacune avec une légende adaptée.
etape2_resolution_et_theorie.py
# TODO : fonction qui renvoie la solution théorique de l'équation
def Uthéo(t):
    return E*(_-np.exp(-t/___))

# TODO : résous l'équation avec ta fonction euler
solE = euler(_, __, _)

plt.figure()
# TODO : trace solE en fonction de t, en ronds bleus, avec une légende indiquant N
plt.plot(_, ____, '__', label='________________'+str(N))
# TODO : superpose Uthéo(t) en rouge trait plein
plt.plot(_, Uthéo(_), '__', label='__________________')
plt.legend(loc='best')
plt.xlabel('t') ; plt.ylabel('$tension$')
plt.grid()
plt.show()
Indice

Le nombre 1 tout seul, sans unité, joue le rôle du 1 dans (1 - e-t/τ) : ce n'est pas x0 qu'on réutilise ici, mais bien la constante mathématique de la formule.

Résultat attendu

Une courbe qui part de 0 V et remonte rapidement vers 10 V (la tension du générateur), en s'aplatissant progressivement — et les points bleus doivent quasiment se confondre avec la courbe rouge théorique. Pour vérifier ton calcul : solE[1] doit valoir 0,1 (le premier petit pas, de taille h = 0,01).

03

Comparer avec seulement 15 pas

À savoir
  • Ta fonction euler est générique : elle fonctionne avec n'importe quel tableau d'instants t, quelle que soit sa taille. Il suffit de lui fournir un nouveau tableau, construit avec un nombre de pas beaucoup plus petit.
Consigne
  • Crée un second tableau d'instants t2, sur le même intervalle [0, 10], mais avec seulement M = 15 pas.
  • Appelle euler une seconde fois avec ce nouveau tableau, et stocke le résultat dans solE2.
  • Trace solE2 en fonction de t2 avec des ronds bleus ('bo'), et superpose Uthéo(t2) en rouge trait plein, chacune avec une légende indiquant son nombre de pas.
etape3_comparaison_pas.py
# TODO : construis un tableau de 15 pas sur le même intervalle de temps
M = __
t2 = np.linspace(__, __, ____)

# TODO : résous l'équation avec ce nouveau tableau d'instants
solE2 = euler(_, __, __)

plt.figure()
# TODO : trace solE2 en fonction de t2, en ronds bleus, avec une légende indiquant M
plt.plot(__, ______, '__', label='________________'+str(M))
# TODO : superpose Uthéo(t2) en rouge trait plein
plt.plot(__, Uthéo(__), '__', label='__________________')
plt.legend(loc='best')
plt.xlabel('t') ; plt.ylabel('$tension$')
plt.grid()
plt.show()
Indice

Il n'est pas nécessaire de réécrire toute la fonction euler : elle a été conçue pour accepter n'importe quel tableau t en argument, c'est tout l'intérêt de l'avoir rendue générale à l'étape 1.

Résultat attendu

Les points bleus (15 pas) suivent grossièrement la courbe rouge théorique mais s'en écartent nettement au début : avec un pas h beaucoup plus grand (h ≈ 0,67 s au lieu de 0,01 s), chaque segment de droite est une moins bonne approximation de la vraie courbe. Pour vérifier : solE2[1] doit valoir environ 6,7.

+

Conclusion

À retenir
  • La méthode d'Euler permet de résoudre numériquement une équation différentielle, sans avoir besoin d'en connaître la solution mathématique exacte, en avançant pas à pas depuis la condition initiale.
  • Quand on connaît la solution théorique, comme ici, on peut la superposer à la solution numérique pour juger de la qualité de la méthode : avec suffisamment de pas, les deux courbes se confondent.
  • Le choix du pas (ou, de façon équivalente, du nombre de pas N) est déterminant : un pas trop grand donne une solution approchée grossière, qui peut s'écarter significativement de la réalité, en particulier là où la fonction varie vite. C'est une des limites de la méthode d'Euler.
  • Écrire une fonction générique comme euler(g, x0, t), qui ne mentionne jamais explicitement le problème traité, permet de la réutiliser telle quelle pour n'importe quelle équation différentielle du premier ordre, et pour n'importe quel découpage temporel.

Pense-bête — méthode d'Euler

dU/dt=f(U,t)forme générale d'une équation différentielle du 1er ordre
h = t[1]-t[0]pas constant, déduit du tableau des instants
U(i+1)=U(i)+h·f(U(i),t(i))relation d'Euler : avancer d'un pas h
np.zeros(N)crée un tableau numpy de N zéros, à remplir ensuite
np.linspace(a,b,N+1)engendre N+1 instants régulièrement espacés entre a et b
'bo' / 'r-'ronds bleus / ligne rouge continue (couleur + marqueur)

Pas de Thonny sous la main ? Utilise Basthon

Ouvrir dans un nouvel onglet ↗
Basthon est une console Python qui tourne directement dans le navigateur, sans rien installer. Colle ici (avec Ctrl+V ou Cmd+V) le code copié avec les boutons « Copier le code » ci-dessus, puis appuie sur Entrée pour l'exécuter.
La console Basthon n'a pas pu se charger ici (bloquée par ton navigateur ou ton établissement). Ouvre-la directement dans un nouvel onglet.