>>> python · niveau 3 · terminale spé PC

Vers l'autonomie

fonctions · while · fichiers · dérivée · polyfit · Euler · dichotomie

Écrire ses propres programmes, du fichier de mesures jusqu'au modèle, sur tout le programme de terminale.

← Le parcours Python

Mode d'emploi

Statut de ce niveau

Ce niveau est en cours d'audit par M. Van Hoorde : il est utilisable, mais pas encore garanti à 100 %. Si un exercice vous semble faux ou bloquant, signalez-le-lui.

Ce niveau suppose acquis les niveaux 1 et 2. Les programmes deviennent plus longs, et le code de départ est parfois presque vide : c'est à vous de l'écrire. On travaille dans l'ordre, chaque étape s'appuie sur les précédentes.

  • Comme avant : ▶ Exécuter (ou Ctrl + Entrée), ↺ Code de départ, 💡 Aide un indice à la fois, solution après un premier essai, ⓘ Rappel de cours.
  • Certains exercices fournissent un fichier de mesures. Son onglet 📄, sous l'éditeur, en affiche le contenu. Python le retrouve à chaque exécution, intact, même si votre programme l'a modifié.
  • Une boucle qui ne s'arrête jamais est coupée au bout de 5 secondes ; le bouton ■ Arrêter le fait aussitôt.

Écrire ses propres fonctions

Depuis le niveau 1, vous utilisez des fonctions écrites par d'autres : print, round, np.sqrt… Écrire les siennes permet de donner un nom à un calcul, puis de le réutiliser autant de fois qu'on veut, avec d'autres valeurs.

À retenir

  • def nom(param1, param2): définit une fonction. Les lignes qui suivent, décalées de quatre espaces (touche ⇥), forment son corps.
  • Définir n'est pas exécuter : le corps ne s'exécute qu'à l'appel, nom(…). Les paramètres reçoivent alors les valeurs données entre parenthèses, dans l'ordre.
  • return valeur renvoie le résultat à l'endroit de l'appel et termine la fonction. On peut ensuite le ranger dans une variable, ou calculer avec.
  • print n'est pas return : print affiche à l'écran, pour vous ; le programme, lui, ne récupère rien. Une fonction sans return renvoie None, la valeur « rien », avec laquelle on ne peut pas calculer.
  • Les variables créées dans une fonction n'existent qu'à l'intérieur : ce sont des variables locales.
def energie_cinetique(m, v):     # m en kg, v en m/s
    Ec = 0.5 * m * v ** 2
    return Ec                    # renvoie Ec, en J

E1 = energie_cinetique(0.60, 7.0)   # le ballon de basket lancé à 7,0 m/s
print(E1)                           # affiche : 14.7
Rappel de cours — Énergies

Pour un système de masse m (en kg), de vitesse v (en m·s⁻¹), à l'altitude z (en m) dans le champ de pesanteur g = 9,81 N·kg⁻¹ :

Ec = 12 × m × v² Epp = m × g × z Em = Ec + Epp

Les énergies s'expriment en joules (J). En l'absence de frottements, l'énergie mécanique se conserve.

1.1 Prédire

Lire ce programme sans l'exécuter, puis répondre au quiz. Pour vérifier, recopiez-le dans l'éditeur et modifiez-le comme indiqué dans chaque question.

def epp(m, z):
    g = 9.81
    return m * g * z

E = epp(1.5, 2.0)
print(E)

Que se passe-t-il ?

Qu'affiche ce programme ?

On supprime la dernière ligne, print(E). Qu'affiche le programme ?

On ajoute print(g) à la fin du programme. Qu'affiche cette ligne ?

Dans la fonction, on remplace return m * g * z par print(m * g * z). Qu'affiche le programme ?

1.2 La demi-vie

Rappel de cours — Décroissance radioactive

Le nombre N de noyaux radioactifs d'un échantillon diminue selon la loi de décroissance radioactive, où λ est la constante radioactive (en s⁻¹) :

N(t) = N0 × e−λt t1/2 = ln 2λ

La demi-vie t1/2 est la durée au bout de laquelle la moitié des noyaux initialement présents se sont désintégrés.

On veut une fonction qui calcule la demi-vie d'un noyau à partir de sa constante radioactive.

  1. Écrire une fonction demi_vie(lam) qui renvoie t1/2 (en s) pour une constante radioactive lam (en s⁻¹).
  2. L'iode 131 a pour constante radioactive λ = 1,0 × 10⁻⁶ s⁻¹. Afficher sa demi-vie en jours, arrondie au dixième.
  1. La fonction a un seul paramètre, lam, et une seule ligne dans son corps : return ….
  2. ln 2 s'écrit np.log(2) : np.log est le logarithme népérien, celui qu'il faut ici.
  3. Un jour dure 24 × 3 600 = 86 400 s : round(demi_vie(1.0e-6) / 86400, 1).
Voir une solution
import numpy as np

def demi_vie(lam):
    return np.log(2) / lam

print(round(demi_vie(1.0e-6) / 86400, 1), 'jours')

Python affiche 8.0 jours : la demi-vie de l'iode 131 vaut 8,02 jours. La même fonction sert pour tous les noyaux : avec λ = 3,83 × 10⁻¹² s⁻¹, le carbone 14, on trouve environ 5 700 ans.

1.3 Un print à la place d'un return

Ce programme calcule l'énergie mécanique d'un ballon de 600 g, à 3,6 m du sol, qui se déplace à 4,0 m·s⁻¹. Il s'arrête sur une erreur.

  1. Exécuter, puis lire la dernière ligne du message de Python : quel mot y désigne la valeur « rien » ?
  2. Corriger la fonction fautive, sans toucher aux trois dernières lignes.
Voir une solution
def energie_potentielle(m, z):
    g = 9.81
    return m * g * z

Le message se termine par unsupported operand type(s) for +: 'float' and 'NoneType' : Python ne peut pas ajouter un nombre et None. La fonction affichait l'énergie potentielle, mais ne la renvoyait pas ; l'appel valait donc None. Avec return, Em = 4,8 + 21,19 ≈ 25,99 J.

1.4 La période d'un satellite

Rappel de cours — Troisième loi de Kepler

Pour un satellite en orbite circulaire de rayon r autour d'un astre de masse M, la période de révolution T vérifie :

T²r³ = 4π²G × M soit T = 2π × √(r³G × M)

G = 6,67 × 10⁻¹¹ N·m²·kg⁻² ; masse de la Terre MT = 5,97 × 10²⁴ kg ; rayon de la Terre RT = 6 371 km. Le rayon de l'orbite vaut r = RT + h, où h est l'altitude.

Une fonction s'applique aussi à un tableau numpy entier, comme np.sqrt. On compare la station spatiale internationale (altitude 420 km), un satellite GPS (20 200 km) et un satellite géostationnaire (35 786 km).

  1. Compléter la fonction periode(r), qui renvoie la période (en s) pour un rayon d'orbite r (en m).
  2. Compléter la ligne T = …… pour calculer d'un coup les trois périodes, puis exécuter. Le satellite géostationnaire fait-il un tour en un jour ?
Voir une solution
def periode(r):
    return 2 * np.pi * np.sqrt(r ** 3 / (G * M_T))

T = periode(R_T + h)

Python affiche périodes : [ 1.5 12. 23.9] h. La fonction a reçu un tableau de trois rayons : elle a calculé les trois périodes d'un coup. G et M_T, définies en dehors de la fonction, y sont lisibles. np.round arrondit chaque valeur d'un tableau, comme round le fait pour un nombre.

Répéter tant que : la boucle while

La boucle for du niveau 2 répète un bloc un nombre de fois connu d'avance. Souvent, on ne le connaît pas : « attendre tant que l'activité est trop forte ». C'est le rôle de la boucle while.

À retenir

  • while condition: répète le bloc décalé tant que la condition est vraie. Elle est testée avant chaque tour.
  • Une variable de la condition doit changer dans le bloc, sinon la condition reste vraie pour toujours : c'est une boucle infinie.
  • Rappels du niveau 2 : for i in range(n): répète le bloc n fois, avec i = 0, 1, …, n − 1 ; L.append(x) ajoute x à la fin de la liste L.
  • np.exp(x) calcule ex, l'exponentielle de x.
n = 0                  # nombre de demi-vies écoulées
reste = 1.0            # fraction des noyaux encore présents
while reste > 0.01:    # tant qu'il en reste plus de 1 %
    reste = reste / 2
    n = n + 1
print(n, 'demi-vies')  # affiche : 7 demi-vies

2.1 Combien de tours ?

Prédire ce qu'affiche chacun de ces quatre programmes, puis vérifier en le recopiant dans l'éditeur.

Programme A

x = 1
while x < 100:
    x = x * 3
print(x)

Programme B

i = 0
while i < 5:
    print('tour')
    i = i + 1

Programme C

i = 10
while i > 0:
    i = i + 1
print(i)

Programme D

for i in range(3):
    print(i)

Qu'affiche Python ?

Qu'affiche le programme A ?

Combien de fois le programme B affiche-t-il tour ?

Qu'affiche le programme C ?

Qu'affiche le programme D ?

2.2 Attendre que l'iode 131 décroisse

Rappel de cours — Activité

L'activité A d'un échantillon est le nombre de désintégrations par seconde, en becquerels (Bq). Elle suit la même loi de décroissance que le nombre de noyaux :

A(t) = A0 × e−λt λ = ln 2t1/2

Après un examen de la thyroïde, des déchets contiennent de l'iode 131 (demi-vie 8,02 jours). On les entrepose jusqu'à ce que leur activité soit passée sous 1 % de l'activité initiale (situation construite pour l'exercice).

  1. Compléter la condition de la boucle et la ligne qui fait avancer le temps d'un jour à chaque tour.
  2. Combien de jours faut-il attendre ?
  1. La boucle doit continuer tant que A est supérieure à 1 % de A0, c'est-à-dire 0.01 * A0.
  2. Avancer d'un jour : t = t + 1.
Voir une solution
while A > 0.01 * A0:
    t = t + 1
    A = A0 * np.exp(-lam * t)

Python affiche 54 jours. On ne savait pas d'avance combien de tours faire : c'est la situation type de la boucle while. On aurait aussi pu résoudre e−λt = 0,01 : t = ln 100λ ≈ 53,3 jours.

2.3 Simuler le hasard des désintégrations

D'après « Loi de décroissance radioactive », ressource du groupe de travail de physique-chimie de l'académie de Strasbourg (2023-2024). Un noyau radioactif se désintègre au hasard : on ne peut pas prévoir quand. Pendant une unité de temps, chaque noyau a une probabilité p = 1/50 de se désintégrer. On simule une population de 1 000 noyaux.

Bon à savoir

np.random.random(N) tire N nombres au hasard entre 0 et 1. tirages < p les compare un à un à p, et np.sum(tirages < p) compte ceux qui sont plus petits : en moyenne N × p. Chacun représente un noyau qui se désintègre.

  1. Compléter la condition (on continue tant qu'il reste des noyaux) et la mise à jour de N. Exécuter plusieurs fois : la courbe change-t-elle ?
  2. Lire sur le graphique la durée au bout de laquelle il reste 500 noyaux.
  3. Recommencer avec N = 10. La courbe ressemble-t-elle encore à une décroissance régulière ?
Voir une solution
while N > 0:
    ...
    N = N - desintegres

Chaque exécution donne une courbe un peu différente : c'est le hasard. Il reste 500 noyaux au bout d'environ 34 unités de temps, quelle que soit l'exécution : c'est la demi-vie. Avec 10 noyaux, on voit des paliers et des chutes brusques ; la loi de décroissance ne décrit bien qu'un grand nombre de noyaux.

La ressource d'origine tire un nombre au hasard par noyau, dans une boucle for. On a regroupé ces tirages avec np.random.random : le résultat est le même, mais le calcul va cent fois plus vite.

Lire un fichier de mesures

En TP, on ne recopie pas des dizaines de mesures à la main : le logiciel d'acquisition ou de pointage vidéo les enregistre dans un fichier texte, le plus souvent au format CSV. Python le lit en une ligne.

À retenir

  • Un fichier CSV contient une mesure par ligne ; les valeurs y sont séparées par un caractère, le séparateur (souvent ; en France). La première ligne, l'en-tête, donne le nom et l'unité de chaque colonne.
  • t, y = np.loadtxt('chute.csv', delimiter=';', skiprows=1, unpack=True) range chaque colonne du fichier dans un tableau numpy : delimiter indique le séparateur, skiprows=1 saute la ligne d'en-tête, unpack=True sépare les colonnes. Il faut autant de variables à gauche que de colonnes.
  • Le nom du fichier est un texte : entre guillemets, avec son extension.

Bon à savoir

  • Sur un ordinateur, le fichier doit se trouver dans le même dossier que le programme. Ici, il est fourni avec l'exercice : son onglet 📄 est sous l'éditeur.
  • numpy ne lit que le point décimal. Si le logiciel a écrit 0,04, choisissez le point dans ses options d'export, ou remplacez les virgules par des points dans un tableur.

Derrière le rideau

np.loadtxt fait ce que vous pourriez écrire vous-même : ouvrir le fichier avec open, le parcourir ligne par ligne, découper chaque ligne au séparateur, convertir chaque morceau en nombre avec float.

t = []
with open('chute.csv') as f:      # ouvre le fichier en lecture
    f.readline()                  # lit et jette la ligne d'en-tête
    for ligne in f:               # puis une ligne par tour : '0.04;1.493'
        morceaux = ligne.split(';')        # ['0.04', '1.493']
        t.append(float(morceaux[0]))

3.1 La chute d'une balle

Une balle est lâchée sans vitesse initiale. Le pointage d'une vidéo (25 images par seconde) donne sa hauteur y au cours du temps, dans le fichier chute.csv (valeurs construites pour l'exercice).

  1. Ouvrir l'onglet 📄 chute.csv : quel est le séparateur ? Compléter la ligne de lecture, puis exécuter.
  2. Tracer y en fonction de t, en points, avec des axes légendés.
Voir une solution
t, y = np.loadtxt('chute.csv', delimiter=';', skiprows=1, unpack=True)
print(len(t), 'mesures')
plt.plot(t, y, 'b+')
plt.xlabel('t (s)')
plt.ylabel('y (m)')
plt.show()

Le séparateur est le point-virgule. La hauteur diminue de plus en plus vite : la balle accélère. L'étape suivante calcule sa vitesse à partir de ces mesures.

3.2 Trois erreurs de lecture

Chacun de ces programmes lit le fichier de l'exercice précédent et contient une erreur. Exécuter, lire le message, corriger.

Voir une solution

1. ValueError: could not convert string 't (s)' to float64 : sans skiprows=1, numpy tente de lire l'en-tête comme des nombres. 2. FileNotFoundError : faute de frappe dans l'extension. 3. not enough values to unpack (expected 3, got 2) : trois variables, mais deux colonnes seulement.

3.3 La deuxième loi de Kepler

Rappel de cours — Lois de Kepler

Première loi

Dans le référentiel géocentrique, la trajectoire d'un satellite de la Terre est une ellipse dont le centre de la Terre occupe un foyer.

Deuxième loi, la loi des aires

Le segment qui relie le centre de la Terre au satellite balaie des aires égales pendant des durées égales. Conséquence : le satellite va plus vite quand il est proche de la Terre.

Outil mathématique

L'aire du triangle de sommets O (l'origine), M1(x1 ; y1) et M2(x2 ; y2) vaut :

aire = 12 × | x1 × y2 − x2 × y1 |

Le fichier satellite.csv donne les positions d'un satellite toutes les 1 000 s, sur un tour complet ; la Terre est à l'origine du repère (valeurs construites pour l'exercice). Entre deux positions voisines, l'aire balayée est presque celle du triangle formé avec la Terre.

  1. Compléter la ligne qui calcule la distance r du satellite au centre de la Terre. La distance est-elle constante ?
  2. Compléter la fonction aire, qui renvoie l'aire du triangle formé par l'origine et deux positions.
  3. Exécuter : les aires balayées toutes les 1 000 s sont-elles égales ?
  1. Le théorème de Pythagore : r = np.sqrt(x ** 2 + y ** 2) calcule les 37 distances d'un coup.
  2. La valeur absolue s'écrit abs(…) (niveau 2).
  3. min et max donnent la plus petite et la plus grande valeur d'une liste ; np.min et np.max font de même pour un tableau numpy.
Voir une solution
r = np.sqrt(x ** 2 + y ** 2)

def aire(x1, y1, x2, y2):
    return 0.5 * abs(x1 * y2 - x2 * y1)

La distance va de 16 800 à 31 185 km, mais les aires restent comprises entre 4,60 × 10⁷ et 4,66 × 10⁷ km² : égales à 1 % près. Le petit écart vient de l'approximation du triangle, moins bonne près de la Terre, où le satellite tourne vite.

À l'ECE, le pointage d'une vidéo ou une acquisition peut être exporté en fichier texte, que le programme fourni lit. On vous demande alors de vérifier le nom du fichier et son séparateur : deux sources d'erreur très fréquentes.

Dériver des mesures : vitesse, accélération

La vitesse est la dérivée de la position, l'accélération celle de la vitesse. Avec des mesures, on ne connaît la position qu'à certaines dates : on approche la dérivée par un taux de variation entre deux mesures voisines.

Rappel de cours — Vitesse et accélération

Les coordonnées du vecteur vitesse sont les dérivées des coordonnées du vecteur position, celles du vecteur accélération les dérivées des coordonnées du vecteur vitesse :

vx = dxdt ax = dvxdt (de même selon y)

À retenir

  • Méthode centrée : la vitesse à la date ti est estimée avec les mesures qui l'encadrent.

vi ≈ xi+1 − xi−1ti+1 − ti−1

  • Avec des tranches, numpy calcule toutes les vitesses d'un coup : x[2:] (tout sauf les deux premières valeurs), x[:-2] (tout sauf les deux dernières), x[1:-1] (tout sauf la première et la dernière). Un indice négatif compte depuis la fin : x[-1] est la dernière valeur.
  • Il n'y a pas de vitesse à la première ni à la dernière date : le tableau des vitesses a deux valeurs de moins que celui des positions. Ses dates sont t[1:-1].
  • L'accélération s'obtient de la même façon, à partir des vitesses.
vx = (x[2:] - x[:-2]) / (t[2:] - t[:-2])   # vitesses, en m/s
tv = t[1:-1]                               # leurs dates

4.1 La vitesse de la balle

On reprend le pointage de la balle lâchée (exercice 3.1).

  1. Compléter la ligne qui calcule la vitesse verticale vy par la méthode centrée.
  2. Compléter la ligne qui trace vy en fonction de ses dates. Comment la vitesse évolue-t-elle ?
Voir une solution
vy = (y[2:] - y[:-2]) / (t[2:] - t[:-2])
plt.plot(tv, vy, 'b+')

14 positions, 12 vitesses. Les points sont alignés sur une droite qui passe presque par l'origine : la vitesse est proportionnelle au temps, signe d'une accélération constante. Tracer vy en fonction de t donnerait une ValueError : 14 dates pour 12 vitesses.

Le même calcul s'écrit avec une boucle, comme dans certains sujets d'ECE : for i in range(1, len(t) - 1): puis vy.append((y[i + 1] - y[i - 1]) / (t[i + 1] - t[i - 1])), avec vy = [] au départ.

4.2 Les vecteurs accélération d'un ballon

Au programme de terminale

« Représenter, à l'aide d'un langage de programmation, des vecteurs accélération d'un point lors d'un mouvement. » (capacité numérique, mouvement dans un champ uniforme)

Le fichier lancer.csv donne le pointage d'un ballon de basket lancé vers le panier, 20 images par seconde (valeurs construites pour l'exercice). Le programme calcule les vitesses et trace des flèches.

Bon à savoir

plt.quiver(X, Y, U, V, …) dessine, au point (X ; Y), une flèche de coordonnées (U ; V). Avec angles='xy', scale_units='xy', scale=30, une accélération de 30 m·s⁻² est représentée par une flèche de 1 m sur le graphique. plt.axis('equal') donne la même échelle aux deux axes, pour que les directions soient justes.

  1. Compléter les lignes qui calculent ax et ay, puis exécuter. Que dire de la direction et du sens des vecteurs accélération ? Comparer ay moyen à g = 9,81 m·s⁻².
  2. Ajouter les vecteurs vitesse en bleu (scale=10), placés aux points x[1:-1], y[1:-1].
  1. Même méthode centrée, appliquée aux tableaux vx et vy, avec leurs dates tv.
  2. ax = (vx[2:] - vx[:-2]) / (tv[2:] - tv[:-2]).
  3. Pour les vitesses, recopiez la ligne plt.quiver et changez les positions, les coordonnées des flèches, la couleur et l'échelle.
Voir une solution
ax = (vx[2:] - vx[:-2]) / (tv[2:] - tv[:-2])
ay = (vy[2:] - vy[:-2]) / (tv[2:] - tv[:-2])
...
plt.quiver(x[1:-1], y[1:-1], vx, vy, color='blue', angles='xy', scale_units='xy', scale=10)

Les vecteurs accélération sont tous verticaux, dirigés vers le bas, de même longueur aux erreurs de pointage près : ay moyen ≈ −9,83 m·s⁻², proche de −g. C'est la deuxième loi de Newton : le ballon n'est soumis qu'à son poids, donc son accélération est égale au champ de pesanteur. Dériver deux fois amplifie les petites erreurs de pointage : les flèches ne sont pas toutes rigoureusement égales.

4.3 La vitesse volumique de disparition

Au programme de terminale

« À l'aide d'un langage de programmation et à partir de données expérimentales, tracer l'évolution temporelle d'une concentration, d'une vitesse volumique d'apparition ou de disparition et tester une relation donnée entre la vitesse volumique de disparition et la concentration d'un réactif. »

Rappel de cours — Vitesse volumique

La vitesse volumique de disparition d'un réactif R est l'opposé de la dérivée de sa concentration par rapport au temps, en mol·L⁻¹·s⁻¹ :

vd(t) = − d[R]dt

D'après ECE PC, banque 2026, sujet n° 49. Les ions peroxodisulfate S2O82− réagissent avec les ions iodure I−, en excès, pour former du diiode, jaune. Un spectrophotomètre enregistre l'absorbance A toutes les 20 s dans absorbance.csv (valeurs construites). D'après la loi de Beer-Lambert, la concentration en ions peroxodisulfate vaut alors :

[S2O82−] = c0 × (1 − AAf)

où c0 = 0,50 mmol·L⁻¹ est la concentration initiale et Af = 0,850 l'absorbance finale, mesurée au bout d'une heure.

  1. Compléter la ligne qui calcule la concentration c ; exécuter pour tracer son évolution.
  2. Compléter la ligne qui calcule la vitesse volumique de disparition v. Comment évolue-t-elle au cours du temps ?
Voir une solution
c = c0 * (1 - A / Af)
v = -(c[2:] - c[:-2]) / (t[2:] - t[:-2])

La concentration diminue de plus en plus lentement, et la vitesse de disparition diminue avec elle : plus il reste de réactif, plus la réaction est rapide. Est-ce une proportionnalité ? Réponse à l'exercice 5.3.

Modéliser par une droite avec np.polyfit

Quand des points semblent alignés, on cherche la droite qui passe au plus près d'eux : c'est la modélisation que fait le tableur ou le logiciel de TP. En Python, une seule fonction suffit.

À retenir

  • a, b = np.polyfit(x, y, 1) renvoie le coefficient directeur a et l'ordonnée à l'origine b de la droite y = a × x + b la plus proche des points. Le 1 est le degré : une droite.
  • On trace la droite modèle avec plt.plot(x, a * x + b, 'r-'), par-dessus les points de mesure.
  • Pour tester une proportionnalité y = k × x : les points doivent être alignés et b doit être très petit devant les valeurs de y.
  • Pour une loi exponentielle y = y0 × e−λx, on linéarise : ln y = ln y0 − λ × x. Les points (x ; ln y) sont alignés et le coefficient directeur vaut −λ.
a, b = np.polyfit(tv, vy, 1)              # droite vy = a × t + b
print('a =', a, 'b =', b)
plt.plot(tv, vy, 'b+', label='mesures')
plt.plot(tv, a * tv + b, 'r-', label='modèle')

5.1 Mesurer g

Rappel de cours — Chute libre

Un objet en chute libre n'est soumis qu'à son poids. D'après la deuxième loi de Newton, son accélération est égale au champ de pesanteur : ay = −g sur un axe vertical vers le haut. Lâché sans vitesse initiale, sa vitesse vaut :

vy(t) = −g × t

On reprend les vitesses de la balle de l'exercice 4.1.

  1. Compléter la ligne a, b = …… pour modéliser vy en fonction de tv par une droite.
  2. Compléter le tracé du modèle. Le coefficient directeur est-il conforme à la valeur de g, 9,81 m·s⁻² ?
Voir une solution
a, b = np.polyfit(tv, vy, 1)
plt.plot(tv, a * tv + b, 'r-', label='modèle')

a ≈ −9,79 m·s⁻² : la balle tombe avec une accélération très proche de g, les frottements de l'air sont négligeables. b ≈ −0,005 m·s⁻¹ est presque nul : la balle était bien lâchée sans vitesse.

5.2 Peser le Soleil

Au programme de terminale

« Exploiter, à l'aide d'un langage de programmation, des données astronomiques ou satellitaires pour tester les deuxième et troisième lois de Kepler. »

Rappel de cours — Troisième loi de Kepler

Le carré de la période de révolution T d'une planète est proportionnel au cube du demi-grand axe a de son orbite :

T²a³ = k avec k = 4π²G × M

M est la masse du Soleil, G = 6,67 × 10⁻¹¹ N·m²·kg⁻².

Le fichier planetes.csv donne, pour les huit planètes, le demi-grand axe en unités astronomiques (1 UA = 1,496 × 10¹¹ m) et la période en années (1 an = 3,156 × 10⁷ s). Données de la NASA (fiches planétaires).

  1. Compléter la ligne qui modélise T² en fonction de a³ par une droite. La troisième loi est-elle vérifiée ?
  2. En déduire la masse M du Soleil.
  1. np.polyfit(X, Y, 1), avec X = a ** 3 et Y = T ** 2, donne k et b.
  2. Isolez M dans k = 4π² / (G × M) : M = 4π² / (G × k).
Voir une solution
k, b = np.polyfit(X, Y, 1)
M = 4 * np.pi ** 2 / (G * k)

k ≈ 2,97 × 10⁻¹⁹ s²·m⁻³ et M ≈ 1,99 × 10³⁰ kg. L'ordonnée à l'origine, b ≈ 8 × 10¹³ s², est négligeable devant les valeurs de T², jusqu'à 2,7 × 10¹⁹ s² : T² est proportionnel à a³, la troisième loi est vérifiée. Les quatre planètes proches du Soleil se serrent près de l'origine : a³ s'étend sur cinq ordres de grandeur.

5.3 Tester une loi de vitesse

Rappel de cours — Loi de vitesse d'ordre 1

Une réaction suit une loi de vitesse d'ordre 1 par rapport au réactif R si sa vitesse volumique de disparition est proportionnelle à la concentration de R, avec k la constante de vitesse (en s⁻¹) :

vd = k × [R]

On reprend la réaction des ions peroxodisulfate (exercice 4.3, d'après le sujet d'ECE n° 49). Le programme recalcule la concentration et la vitesse de disparition.

  1. Compléter la ligne qui modélise v en fonction de la concentration par une droite. Attention : il faut la concentration aux mêmes dates que les vitesses.
  2. La réaction suit-elle une loi d'ordre 1 ? Donner la valeur de k.
Voir une solution
k, b = np.polyfit(cv, v, 1)

Les points sont alignés sur une droite qui passe par l'origine (b est cent fois plus petit que les vitesses) : la réaction est d'ordre 1 par rapport aux ions peroxodisulfate, avec k ≈ 2,5 × 10⁻³ s⁻¹. Les points les plus dispersés sont ceux de fin de réaction : la dérivée y est calculée sur de petites variations, plus sensibles aux erreurs de mesure.

5.4 Linéariser une décroissance

Un minigénérateur fournit du baryum 137m, radioactif. Un compteur Geiger enregistre le nombre de désintégrations détectées en 10 s, toutes les 30 s, dans comptages.csv (valeurs construites). Ce nombre est proportionnel à l'activité : il suit la loi de décroissance N = N0 × e−λt. La ressource de l'académie de Strasbourg (exercice 2.3) ajuste cette exponentielle avec curve_fit, de la bibliothèque scipy ; on obtient le même résultat en linéarisant.

  1. Compléter la ligne qui calcule ln N, puis celle qui en déduit λ à partir du coefficient directeur.
  2. En déduire la demi-vie du baryum 137m, et la comparer à la valeur tabulée : 2,55 min.
  1. ln s'écrit np.log.
  2. Le coefficient directeur de la droite ln N = f(t) vaut −λ : lam = -p.
Voir une solution
lnN = np.log(N)
lam = -p
t12 = np.log(2) / lam
print('t½ =', round(t12), 's =', round(t12 / 60, 2), 'min')

λ ≈ 4,6 × 10⁻³ s⁻¹ et t1/2 ≈ 150 s ≈ 2,5 min, à 2 % de la valeur tabulée. Les derniers points s'écartent un peu plus de la droite : avec peu de désintégrations comptées, le hasard pèse davantage (exercice 2.3).

Résoudre une équation différentielle : la méthode d'Euler

Plusieurs lois du programme sont des équations différentielles : la dérivée d'une grandeur y dépend de la grandeur elle-même. La méthode d'Euler les résout pas à pas, sans chercher la solution exacte : c'est ainsi que les ordinateurs simulent la plupart des phénomènes physiques.

À retenir

  • Pour une équation de la forme y′ = a × y + b, si l'on connaît y à la date t, on estime y un petit peu plus tard, à la date t + Δt :

y(t + Δt) ≈ y(t) + y′(t) × Δt soit y(t + Δt) ≈ y(t) + (a × y(t) + b) × Δt

  • On part de la valeur initiale y(0) et on répète ce calcul avec une boucle, en rangeant chaque valeur dans une liste.
  • Δt est le pas. Plus il est petit, plus la solution approchée est proche de la solution exacte, mais plus il faut de calculs.
for i in range(n):
    y = y + (a * y + b) * dt     # un pas d'Euler
    liste_y.append(y)

Derrière le rideau

Leonhard Euler a décrit cette méthode en 1768, deux siècles avant les ordinateurs : on la faisait à la main. Elle figure parmi les exemples d'algorithmes du programme de mathématiques de terminale (« résolution par la méthode d'Euler de y′ = ay + b ») et elle est au programme de toutes les classes préparatoires scientifiques. Les simulations de la météo ou des crash-tests reposent sur des méthodes plus précises, mais de la même famille.

6.1 La décroissance pas à pas

Rappel de cours — Équation de la décroissance radioactive

Le nombre N de noyaux radioactifs vérifie l'équation différentielle ci-dessous ; c'est la forme y′ = ay + b, avec a = −λ et b = 0. Sa solution exacte est la loi de décroissance.

dNdt = −λ × N et N(t) = N0 × e−λt

On reprend le baryum 137m de l'exercice 5.4 : λ = 4,53 × 10⁻³ s⁻¹, avec 1 000 noyaux au départ.

  1. Compléter la ligne de la méthode d'Euler, puis exécuter.
  2. Compléter la ligne qui trace la solution exacte. Les deux courbes sont-elles proches ?
  3. Remplacer le pas par 60 s, et le nombre de tours par 10. Que constatez-vous ?
Voir une solution
N = N + (-lam * N) * dt
plt.plot(t, 1000 * np.exp(-lam * t), 'r-', label='solution exacte')

Avec un pas de 10 s, les deux courbes sont presque confondues : 62 noyaux au bout de 600 s par Euler, 66 d'après la loi exacte. Avec un pas de 60 s, les points d'Euler passent nettement sous la courbe : à chaque pas, la méthode utilise la pente du début du pas, plus forte que la pente moyenne.

6.2 La charge du défibrillateur

Rappel de cours — Charge d'un condensateur

Dans un circuit RC série alimenté par un générateur de tension E, la tension uC aux bornes du condensateur vérifie, avec τ = R × C la constante de temps :

duCdt = E − uCτ et uC(t) = E × (1 − e−tτ)

C'est la forme y′ = ay + b, avec a = −1τ et b = Eτ. À la date τ, uC atteint 63 % de E.

D'après ECE PC, banque 2026, sujet n° 41 : un défibrillateur est modélisé par un circuit RC. Ici, E = 12 V, R = 10 kΩ et C = 2 200 µF (valeurs construites pour l'exercice). Le condensateur est déchargé à t = 0.

  1. Écrire la méthode d'Euler pour calculer uC de 0 à 140 s, avec un pas de 1 s. Ranger les tensions dans une liste u_liste et les dates dans t_liste.
  2. Tracer la tension obtenue et la solution exacte sur le même graphique.
  1. Avant la boucle : u = 0, t = 0, u_liste = [u], t_liste = [t].
  2. 140 pas de 1 s : for i in range(140):.
  3. Dans la boucle : u = u + (E - u) / tau * dt, t = t + dt, puis les deux append.
  4. La solution exacte se calcule sur un tableau numpy : ts = np.array(t_liste), puis E * (1 - np.exp(-ts / tau)).
Voir une solution
u = 0
t = 0
u_liste = [u]
t_liste = [t]
for i in range(140):
    u = u + (E - u) / tau * dt
    t = t + dt
    u_liste.append(u)
    t_liste.append(t)

ts = np.array(t_liste)
plt.plot(t_liste, u_liste, 'b.', label='Euler')
plt.plot(ts, E * (1 - np.exp(-ts / tau)), 'r-', label='solution exacte')
plt.xlabel('t (s)')
plt.ylabel('uC (V)')
plt.legend()
plt.show()

Au bout de 5τ = 110 s, le condensateur est chargé à plus de 99 %. Le sujet d'ECE obtient la courbe par l'expérience, puis la modélise ; ici, on la calcule à partir de l'équation différentielle.

6.3 Le choix du pas

Le programme ci-dessous reprend la charge du condensateur (τ = 22 s) avec un pas dt que l'on peut changer. Essayer successivement 1 s, 10 s, 20 s, 30 s et 50 s, puis répondre.

Le pas et la précision

Pour lequel de ces pas la tension calculée dépasse-t-elle E = 12 V dès le premier pas ?

D'où vient ce comportement ?

Résoudre une équation par dichotomie

Quand on ne sait pas isoler l'inconnue d'une équation, Python peut l'encadrer de plus en plus finement. La dichotomie (« couper en deux ») utilise la boucle while et une fonction.

À retenir

  • On écrit l'équation sous la forme f(x) = 0. Si f(a) et f(b) sont de signes contraires, une solution se trouve entre a et b.
  • On coupe l'intervalle en son milieu m. Si f(a) × f(m) ≤ 0, le changement de signe est dans [a ; m] : on remplace b par m. Sinon, il est dans [m ; b] : on remplace a par m.
  • On recommence tant que l'intervalle est plus large que la précision voulue. Chaque tour divise sa largeur par deux : 20 tours la divisent par un million.
def f(t):                   # à quelle date uC atteint-elle 10 V ?
    return 12 * (1 - np.exp(-t / 22)) - 10

a, b = 0, 140               # f(0) < 0 et f(140) > 0
while b - a > 0.001:
    m = (a + b) / 2
    if f(a) * f(m) <= 0:
        b = m
    else:
        a = m
print(round((a + b) / 2, 2), 's')   # affiche : 39.42 s

7.1 Quand le ballon touche-t-il le sol ?

On reprend le ballon de l'exercice 4.2, s'il manque le panier. Sa hauteur vaut y(t) = 2,00 + 5,734 × t − 4,905 × t² (en m, t en s). Il est en l'air à t = 0,5 s ; à t = 2,0 s, la formule donne une hauteur négative.

  1. Compléter la dichotomie, puis exécuter.
  2. Combien de tours de boucle a-t-il fallu ? Ajouter un compteur pour le savoir.
Voir une solution
n = 0
while b - a > 1e-6:
    m = (a + b) / 2
    if y(a) * y(m) <= 0:
        b = m
    else:
        a = m
    n = n + 1
print(n, 'tours')

t ≈ 1,4502 s, en 21 tours : 1,5 / 2²¹ ≈ 7 × 10⁻⁷ s. Ici, une équation du second degré aurait suffi ; la dichotomie, elle, marche aussi quand aucune formule n'existe.

7.2 Le taux d'avancement final

Au programme de terminale

« Déterminer, à l'aide d'un langage de programmation, le taux d'avancement final d'une transformation, modélisée par la réaction d'un acide sur l'eau. »

Rappel de cours — Acide faible dans l'eau

Un acide AH réagit partiellement sur l'eau : AH + H2O ⇄ A− + H3O+. À l'état final, pour une concentration apportée c, [A−] = [H3O+] = x et [AH] = c − x (concentrations en mol·L⁻¹, c° = 1 mol·L⁻¹) :

KA = x²c − x donc x² + KA × x − KA × c = 0 τ = xc

On dissout de l'acide éthanoïque (pKA = 4,76) à c = 1,0 × 10⁻² mol·L⁻¹. La solution x est entre 0 et c.

  1. Écrire la dichotomie qui trouve x = [H3O+] à 10⁻⁹ mol·L⁻¹ près.
  2. Calculer le taux d'avancement final τ, et le pH.
  1. Recopiez la boucle de l'exercice 7.1 : seuls la fonction, l'intervalle de départ et la précision changent.
  2. Au départ : a, b = 0, c ; la boucle tourne while b - a > 1e-9:.
  3. Après la boucle : x = (a + b) / 2, puis tau = x / c et pH = -np.log10(x).
Voir une solution
a, b = 0, c
while b - a > 1e-9:
    m = (a + b) / 2
    if f(a) * f(m) <= 0:
        b = m
    else:
        a = m
x = (a + b) / 2
tau = x / c
print('[H3O+] =', x, 'mol/L ; tau =', round(tau, 3), '; pH =', round(-np.log10(x), 2))

[H3O+] ≈ 4,08 × 10⁻⁴ mol·L⁻¹, τ ≈ 0,041 et pH ≈ 3,39 : à peine 4 % des molécules d'acide ont réagi. Une précision de 10⁻⁹ mol·L⁻¹ est nécessaire ici : la solution elle-même ne vaut que 4 × 10⁻⁴.

7.3 Une dichotomie réutilisable

Plutôt que de recopier la boucle à chaque fois, on la range dans une fonction. Une fonction peut recevoir une autre fonction en paramètre : on écrit son nom, sans parenthèses, comme dans dichotomie(y, 0.5, 2.0, 1e-6).

  1. Compléter le corps de la fonction dichotomie(f, a, b, precision), qui renvoie le milieu de l'intervalle final. Le premier appel doit retrouver le résultat de l'exercice 7.1.
  2. Utiliser dichotomie pour trouver la date à laquelle la tension du défibrillateur (exercice 6.2) atteint 11 V.
  1. Le corps de la fonction, c'est la boucle while de l'exercice 7.1, avec precision à la place de 1e-6, et f à la place de y.
  2. Pour la question 2, définissez une fonction g(t) qui renvoie 12 * (1 - np.exp(-t / 22)) - 11, et cherchez la solution entre 0 et 140 s.
Voir une solution
def dichotomie(f, a, b, precision):
    while b - a > precision:
        m = (a + b) / 2
        if f(a) * f(m) <= 0:
            b = m
        else:
            a = m
    return (a + b) / 2

def g(t):
    return 12 * (1 - np.exp(-t / 22)) - 11

print('11 V à t =', round(dichotomie(g, 0, 140, 1e-3), 1), 's')

11 V est atteint à t ≈ 54,7 s. La fonction dichotomie s'écrit une fois, se vérifie une fois, puis sert pour toutes les équations : c'est tout l'intérêt d'écrire ses propres fonctions.

Écrire un programme complet

Deux projets inspirés de sujets d'ECE, dans lesquels c'est vous qui écrivez l'essentiel du programme. Chaque projet se valide étape par étape : rien ne presse, la solution reste disponible après un premier essai.

8.1 Les quantités de matière au cours d'un titrage

Au programme de terminale

« Représenter, à l'aide d'un langage de programmation, l'évolution des quantités de matière des espèces en fonction du volume de solution titrante versé. »

Rappel de cours — Titrage et équivalence

À l'équivalence, les réactifs ont été introduits dans les proportions stœchiométriques de la réaction support du titrage. Avant l'équivalence, le réactif titrant versé est entièrement consommé ; après, c'est le réactif titré qui a disparu, et le titrant s'accumule.

CH3COOH + HO− → CH3COO− + H2O à l'équivalence : n0(HO−) = cA × VE

D'après ECE PC, banque 2026, sujet n° 3. On titre V0 = 20,0 mL de soude diluée (ions Na+ et HO−, cB = 5,0 × 10⁻² mol·L⁻¹) par du vinaigre dilué, une solution d'acide éthanoïque CH3COOH de concentration cA = 0,10 mol·L⁻¹ (valeurs construites). Une concentration en mol·L⁻¹ multipliée par un volume en mL donne une quantité en mmol.

  1. Compléter la fonction n_hydroxyde(V), qui renvoie la quantité d'ions HO− (en mmol) quand on a versé V mL d'acide.
  2. Écrire la fonction n_acide(V) pour l'acide éthanoïque.
  3. Écrire la fonction n_ethanoate(V) pour les ions éthanoate, puis exécuter et interpréter le graphique.
  1. Avant l'équivalence, chaque mmol d'acide versée consomme une mmol d'ions HO− : n0 - cA * V. Après, il n'en reste plus.
  2. L'acide versé avant l'équivalence est consommé : il n'en reste pas. Après, ce qui est versé en plus de cA * VE s'accumule : cA * V - n0.
  3. Les ions éthanoate se forment à mesure que l'acide réagit : cA * V avant l'équivalence ; après, leur quantité ne change plus.
Voir une solution
def n_hydroxyde(V):
    if V < VE:
        return n0 - cA * V
    else:
        return 0

def n_acide(V):
    if V < VE:
        return 0
    else:
        return cA * V - n0

def n_ethanoate(V):
    if V < VE:
        return cA * V
    else:
        return n0

Les quatre courbes changent de pente à VE = 10,0 mL : les ions HO− disparaissent, l'acide commence à s'accumuler, les ions éthanoate cessent de se former. Les ions Na+, spectateurs, restent à 1,0 mmol. Ce sont ces changements de pente qu'exploite un titrage conductimétrique.

8.2 Projet : le record de plongeon

Au programme de terminale

« Représenter, à partir de données expérimentales variées, l'évolution des grandeurs énergétiques d'un système en mouvement dans un champ uniforme à l'aide d'un langage de programmation ou d'un tableur. »

D'après ECE PC, banque 2026, sujet n° 34. En 2015, un plongeur a battu le record du monde de plongeon de haut vol : 58,8 m. On annonce une chute de 3,58 s et une entrée dans l'eau à 123 km/h, dans un bassin de 8 m de profondeur. Le fichier plongeon.csv donne l'altitude z du plongeur au-dessus de l'eau, pointée sur la vidéo (valeurs construites d'après le sujet). Masse du plongeur et de sa combinaison : m = 73 kg ; leur volume : V = 76 L.

Étape 1 — L'énergie mécanique se conserve-t-elle ?

  1. Compléter les deux fonctions et les lignes qui calculent vz, Ec et Epp, puis exécuter.
  2. L'énergie mécanique est-elle constante ? Le modèle de la chute libre convient-il ?

Étape 2 — La vitesse d'entrée dans l'eau

  1. Modéliser vz en fonction du temps par une droite, et comparer le coefficient directeur à g.
  2. Calculer la vitesse à t = 3,58 s avec ce modèle, et l'afficher en km/h. L'annonce de 123 km/h est-elle crédible ?

Étape 3 — Et dans l'eau ?

Rappel de cours — Poussée d'Archimède

Un corps immergé subit la poussée d'Archimède, verticale vers le haut, de valeur PA = ρeau × V × g, avec ρeau = 1,0 kg·L⁻¹ et V en litres. S'il n'est soumis qu'à son poids et à cette poussée, son accélération est constante, et sa profondeur maximale vaut :

a = PA − Pm zmin = − v0²2 × a

  1. Calculer le poids P, la poussée d'Archimède P_A et l'accélération a dans l'eau.
  2. Calculer la profondeur atteinte z_min avec la vitesse d'entrée de l'étape 2. Le bassin de 8 m suffit-il ? Qu'est-ce que ce modèle oublie ?
Voir une solution
# étape 1
def energie_cinetique(m, v):
    return 0.5 * m * v ** 2

def energie_potentielle(m, z):
    return m * g * z

vz = (z[2:] - z[:-2]) / (t[2:] - t[:-2])
Epp = energie_potentielle(m, z[1:-1])

# étape 2
a, b = np.polyfit(tv, vz, 1)
v = a * 3.58 + b
print('a =', round(a, 2), 'm/s² ; v =', round(abs(v) * 3.6), 'km/h')

# étape 3
P = m * g
P_A = rho * V * g
a = (P_A - P) / m
z_min = -v0 ** 2 / (2 * a)
print('a =', round(a, 2), 'm/s² ; z_min =', round(z_min), 'm')

Étape 1 : Em ≈ 42 000 J, constante aux erreurs de pointage près ; elle vaut bien m × g × 58,8 m. Étape 2 : a ≈ −9,82 m·s⁻², et v(3,58 s) ≈ 35,1 m·s⁻¹ ≈ 127 km/h. Étape 3 : a ≈ 0,40 m·s⁻², donc zmin ≈ −1 530 m. Ce résultat absurde montre que le poids et la poussée d'Archimède ne suffisent pas : dans l'eau, les frottements sont considérables, et ce sont eux qui arrêtent le plongeur en quelques mètres.

À l'ECE, ces programmes sont fournis presque complets, et on vous demande d'en compléter quelques lignes. Savoir les écrire en entier, c'est comprendre chaque ligne qu'on vous donne, et repérer celle qui est fausse.

Bilan du niveau 3

Ce que je sais faire

  • Écrire une fonction avec def et return, l'appeler, et ne pas confondre return avec print.
  • Répéter un calcul tant qu'une condition est vraie, avec while, sans boucle infinie.
  • Lire un fichier de mesures avec np.loadtxt, en réglant le séparateur et la ligne d'en-tête.
  • Calculer une vitesse, une accélération ou une vitesse volumique à partir de mesures, par la méthode centrée.
  • Modéliser des points par une droite avec np.polyfit, et linéariser une exponentielle.
  • Résoudre une équation différentielle y′ = ay + b par la méthode d'Euler, en choisissant un pas adapté.
  • Résoudre une équation par dichotomie, et ranger l'algorithme dans une fonction réutilisable.
  • Écrire un programme complet qui part d'un fichier de mesures pour conclure sur un modèle physique.

Le niveau 4 ouvre sur les classes préparatoires et les BUT : régression raisonnée avec les incertitudes, simulations de Monte-Carlo, bibliothèque scipy, et ce que chaque formation attend.