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

Mini-projets d'ECE

if · for · tranches · hasard · six situations d'ECE

Les outils du niveau 1, rassemblés dans des programmes complets, comme le jour de l'épreuve. À la fin de ce niveau, la partie Python d'une ECE ne vous réserve plus de surprise.

← 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 %. Une consigne obscure, une correction qui refuse une réponse juste ? Signalez-le en classe.

Ce niveau suppose le niveau 1 acquis. Les trois premières étapes présentent les derniers outils : décider avec if, répéter avec for, découper une série et tirer des valeurs au hasard. Les six suivantes sont des mini-projets : chacun reprend une situation d'ECE complète, avec un programme fourni presque terminé, à compléter, exécuter et exploiter. La dernière étape prépare le jour de l'épreuve.

  • Comme au niveau 1 : ▶ Exécuter (ou Ctrl + Entrée), ↺ Code de départ pour recommencer, 💡 Aide pour un indice à la fois, ⓘ Rappel de cours pour la notion révisée.
  • Les lignes à compléter contiennent ……. Tant qu'il en reste une, Python refuse d'exécuter le programme : c'est normal.
  • Un mini-projet se mène comme à l'ECE : lire tout le programme d'abord, compléter, exécuter, puis répondre aux questions d'exploitation, par écrit.

Décider : comparer, puis choisir

Un programme d'ECE doit parfois choisir : conclure « compatibles » ou non selon un z-score, choisir le modèle qui convient aux mesures. Python compare deux valeurs, puis exécute un bloc de lignes ou un autre.

À retenir

  • Les comparaisons : < > <= (≤) >= (≥) == (égal) != (différent). Python répond True (vrai) ou False (faux).
  • = range une valeur, == compare deux valeurs : ne pas les confondre.
  • abs(x) donne la valeur absolue de x : abs(-0.05) vaut 0.05. C'est une fonction intégrée, comme round.
  • if (si), elif (sinon, si) et else (sinon) : chaque ligne se termine par deux-points :, et les lignes du bloc sont décalées de quatre espaces. Python teste les conditions dans l'ordre et n'exécute que le premier bloc dont la condition est vraie ; else sert quand aucune ne l'est.
  • Un décalage oublié provoque une IndentationError.
pH = 8.2
if pH < 7:
    print('solution acide')
elif pH == 7:
    print('solution neutre')
else:
    print('solution basique')     # affiche : solution basique

1.1 Vrai ou faux ?

Tapez ces comparaisons dans la console, puis répondez au quiz. Chaque réponse se vérifie dans la console.

Que répond Python ?

3 < 5

10 != 10

abs(-4.5)

abs(7.62 - 7.65) < 0.05

5 = 5

1.2 Compatible ou non ? Le z-score

Rappel de cours — Comparer à une valeur de référence

On compare une valeur expérimentale xexp, d'incertitude-type u(x), à une valeur de référence xréf à l'aide du z-score :

z = |xexp − xréf|u(x)

Critères retenus en terminale

z < 1 : l'écart est plus petit que l'incertitude, valeurs très compatibles.
1 ≤ z < 2 : l'écart est du même ordre que l'incertitude, valeurs compatibles.
z ≥ 2 : valeurs non compatibles.

Un titrage des ions chlorure donne Cexp = 2,05 × 10⁻² mol·L⁻¹, avec u(C) = 0,10 × 10⁻² mol·L⁻¹. La valeur de référence vaut Créf = 2,10 × 10⁻² mol·L⁻¹ (application de la fiche de cours).

  1. Compléter la ligne z = …….
  2. Compléter les deux conditions, d'après le rappel de cours, puis exécuter.
  3. Remplacer C_exp par 2,25 × 10⁻² mol·L⁻¹ et exécuter de nouveau.
  4. Remplacer C_exp par 2,32 × 10⁻² mol·L⁻¹ et exécuter de nouveau.
  1. Le numérateur du z-score est une valeur absolue : abs(C_exp - C_ref).
  2. La première condition teste le cas z < 1. Si elle est fausse, on sait déjà que z ≥ 1 : la deuxième n'a plus qu'à tester z < 2.
  3. Le cas z ≥ 2 n'a pas besoin de condition : c'est le else.
Voir une solution
z = abs(C_exp - C_ref) / u_C
print('z =', round(z, 2))

if z < 1:
    print('valeurs très compatibles')
elif z < 2:
    print('valeurs compatibles')
else:
    print('valeurs non compatibles')

z = 0,5 : très compatibles. Avec 2,25 × 10⁻², z = 1,5 : compatibles. Avec 2,32 × 10⁻², z = 2,2 : non compatibles. Le elif n'est testé que si z < 1 est faux : inutile d'écrire z >= 1 and z < 2. L'ordre des conditions compte : si l'on testait z < 2 en premier, un z de 0,5 serait déclaré seulement « compatible ».

1.3 Trois erreurs dans un test

Ce programme indique si une solution est acide, neutre ou basique (à 25 °C). Il contient trois erreurs. Exécuter, lire le message, corriger, et recommencer jusqu'à ce que le programme tourne.

  1. Corriger les trois erreurs : le vinaigre blanc (pH = 2,9) doit être déclaré acide.
  2. Remplacer le pH par celui de l'eau de mer, 8,2, et vérifier la réponse.
Voir une solution
pH = 2.9

if pH < 7:
    print('solution acide')
elif pH == 7:
    print('solution neutre')
else:
    print('solution basique')

Ligne 3 : il manque les deux-points (SyntaxError: expected ':'). Ligne 5 : = range une valeur, il faut == pour comparer (SyntaxError). Ligne 8 : le print du else n'est pas décalé (IndentationError). Python s'arrête à la première erreur rencontrée : il faut donc corriger, exécuter, et recommencer.

Répéter un calcul : la boucle for

Un tableau numpy calcule sur toutes les valeurs d'un coup. Mais il faut parfois traiter les mesures une à une : afficher une ligne par mesure, tester chacune, ou construire une liste au fur et à mesure. C'est le rôle de la boucle for.

À retenir

  • for x in liste: répète le bloc décalé de quatre espaces, une fois pour chaque élément ; x prend tour à tour chaque valeur de la liste.
  • range(4) donne les entiers 0, 1, 2, 3 : quatre valeurs, de 0 à 4 exclu. range(1, 4) donne 1, 2, 3.
  • for i in range(len(c)): parcourt les rangs d'une liste c ; c[i] est alors l'élément de rang i.
  • resultats = [] crée une liste vide ; resultats.append(x) ajoute x à la fin de la liste.
f = 440                   # fréquence du fondamental, en Hz
frequences = []           # liste vide
for n in range(1, 4):     # n vaut 1, puis 2, puis 3
    frequences.append(n * f)
print(frequences)         # hors de la boucle : affiche [440, 880, 1320]

2.1 Prédire ce que fait une boucle

Pour chaque programme, prédire l'affichage. Pour vérifier, copier le programme dans l'éditeur et l'exécuter.

Qu'affiche Python ?

for x in [1, 2, 3]:
print(x * 10)

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

for x in [1, 2]:
print(x)
print('fin')

L = []
for n in range(1, 4):
L.append(n * 2)
print(L)

2.2 Les harmoniques audibles

Rappel de cours — Son complexe et harmoniques

Un son complexe de fréquence fondamentale f1 contient des harmoniques de fréquences fn = n × f1, où n est un entier appelé rang. L'oreille humaine perçoit les sons de 20 Hz à 20 000 Hz.

Une note de flûte a pour fréquence fondamentale f1 = 2 400 Hz. On cherche lesquels de ses douze premiers harmoniques sont audibles.

  1. Compléter la ligne qui calcule la fréquence fn de l'harmonique de rang n.
  2. Compléter la condition, pour ne garder que les harmoniques audibles. Combien y en a-t-il ?
  1. Dans la boucle, n prend les valeurs 1 à 12 : fn s'écrit avec n et f1.
  2. Un harmonique est audible si sa fréquence ne dépasse pas 20 000 Hz.
  3. La condition compare fn à 20000, avec <=.
Voir une solution
for n in range(1, 13):
    fn = n * f1
    if fn <= 20000:
        audibles.append(fn)

Huit harmoniques sont audibles, de 2 400 Hz à 19 200 Hz. L'append est décalé de huit espaces : il fait partie du bloc du if, lui-même dans la boucle. Il n'est donc exécuté que pour les harmoniques audibles.

2.3 Le pH d'un acide fort, mesure par mesure

TP6 — pH d'une solution aqueuse
Rappel de cours — pH d'une solution d'acide fort

Un acide fort réagit totalement avec l'eau : la concentration en ions oxonium à l'état final est égale à la concentration apportée en acide, C. Ainsi :

pH = −log(Cc0) avec c0 = 1 mol·L⁻¹

Au TP6, on a mesuré le pH de cinq solutions d'un acide fort. Le programme affiche, pour chaque solution, le pH mesuré et le pH théorique. On veut signaler les mesures qui s'écartent de plus de 0,05 unité pH de la théorie.

  1. Compléter la ligne pH_theo = ……, puis exécuter.
  2. Compléter la condition, pour qu'un message s'affiche quand l'écart dépasse 0,05. Quelles mesures faudrait-il vérifier ?
  1. Dans la boucle, la concentration de la solution de rang i est c[i].
  2. Le log du cours est np.log10, et il y a un signe moins devant.
  3. La condition compare la variable ecart à 0.05.
Voir une solution
for i in range(len(c)):
    pH_theo = -np.log10(c[i])
    ecart = abs(pH[i] - pH_theo)
    print('C =', c[i], 'mol/L   pH mesuré :', pH[i], '  pH théorique :', round(pH_theo, 2))
    if ecart > 0.05:
        print('   à vérifier : écart de', round(ecart, 2))

Deux mesures s'écartent de plus de 0,05 : à 0,010 mol·L⁻¹ (écart 0,08) et à 0,005 mol·L⁻¹ (écart 0,05, un peu plus). range(len(c)) donne les rangs 0 à 4 : on lit ainsi c[i] et pH[i], deux valeurs qui vont ensemble.

Découper une série, tirer au hasard

Deux derniers outils. Une tranche extrait une partie d'une série de mesures sans la recopier. Les tirages au hasard de numpy simulent des mesures : c'est le principe de la méthode de Monte-Carlo, présente dans plusieurs sujets d'ECE.

À retenir — les tranches

  • x[:5] : les 5 premiers éléments, de rang 0 à 4. x[5:] : tous les éléments à partir du rang 5.
  • x[2:4] : les éléments de rang 2 et 3. Comme pour range, le rang de fin est exclu.
  • x[-1] : le dernier élément.
  • Une tranche d'une liste est une liste ; une tranche d'un tableau numpy est un tableau.

3.1 Le pH de l'eau du robinet

Un groupe a mesuré vingt fois le pH de l'eau du robinet au pH-mètre. Prédire ce que vaut chaque expression, puis vérifier dans l'éditeur, en changeant le contenu du print.

Que vaut…

mesures[:3]

mesures[2:4]

mesures[-1]

mesures[18:]

len(mesures[:5])

À retenir — les tirages au hasard

  • np.random.normal(10.00, 0.02, 1000) : un tableau de 1000 valeurs tirées au hasard selon une loi normale (en cloche), de moyenne 10,00 et d'écart-type 0,02. On l'utilise quand on connaît l'incertitude-type d'une grandeur.
  • np.random.uniform(9.98, 10.02, 1000) : 1000 valeurs tirées au hasard selon une loi uniforme, entre 9,98 et 10,02, toutes les valeurs de l'intervalle ayant la même chance. On l'utilise pour une tolérance « ± » de fabricant.
  • Chaque exécution tire de nouvelles valeurs : les résultats changent légèrement.

3.2 Une pipette jaugée, au hasard

Le fabricant d'une pipette jaugée de 10 mL garantit un volume de (10,00 ± 0,02) mL. On simule 10 000 volumes délivrés de deux façons : par une loi normale d'écart-type 0,02 mL, puis par une loi uniforme entre 9,98 et 10,02 mL.

  1. Compléter la ligne V_uniforme = ……, puis exécuter.
  2. Exécuter de nouveau : qu'est-ce qui change ? qu'est-ce qui reste ?
  3. Comparer la forme des deux histogrammes et les deux écarts-types.
  1. La ligne ressemble à celle de V_normale, avec np.random.uniform.
  2. np.random.uniform attend les deux bornes de l'intervalle, puis le nombre de tirages N.
Voir une solution
V_uniforme = np.random.uniform(9.98, 10.02, N)

À chaque exécution, les moyennes et les écarts-types changent dans le 4ᵉ chiffre après la virgule, mais restent proches : 10,00 mL ; 0,020 mL pour la loi normale, 0,012 mL pour la loi uniforme. L'histogramme normal est en cloche et déborde un peu de l'intervalle ± 0,02 ; l'uniforme est plat, sans aucune valeur au-delà des bornes.

Derrière le rideau

L'écart-type d'une loi uniforme de demi-largeur a vaut a / √3 : ici 0,02 / √3 ≈ 0,012 mL. C'est pourquoi certains sujets divisent une tolérance par √3 pour obtenir une incertitude-type. Quant au « hasard » de l'ordinateur, il n'en est pas un : c'est une suite de calculs si embrouillée que ses résultats ont l'air imprévisibles. Les physiciens l'appellent pseudo-aléatoire, et s'en servent depuis les années 1940 : la méthode de Monte-Carlo, du nom du célèbre casino, est née pendant la mise au point des premiers ordinateurs.

Projet 1 — Superposer deux signaux synchrones

Deux haut-parleurs, branchés sur le même générateur, émettent des sons de même fréquence : ils sont synchrones. Un microphone placé devant eux reçoit la somme des deux signaux. Selon le décalage entre les deux, cette somme est forte, faible ou nulle : ce sont les interférences.

Au programme de terminale

Capacité numérique : « Représenter, à l'aide d'un langage de programmation, la somme de deux signaux sinusoïdaux périodiques synchrones en faisant varier la phase à l'origine de l'un des deux. »

À retenir

  • np.sin(x) calcule le sinus de x, en radians ; π rad correspondent à 180°.
  • Un signal sinusoïdal d'amplitude A, de fréquence f et de phase à l'origine φ s'écrit A * np.sin(2 * np.pi * f * t + phi).
  • np.max(u) donne la plus grande valeur du tableau u : pour un signal sinusoïdal, son amplitude.
Rappel de cours — Interférences et déphasage

Deux ondes de même nature, synchrones (même fréquence) et cohérentes interfèrent : la perturbation résultante est la somme des deux perturbations.

Déphasage

0 rad : ondes en phase, la somme a une amplitude maximale, interférences constructives.
π rad : ondes en opposition de phase, la somme est minimale, nulle si les deux amplitudes sont égales : interférences destructives.

4.1 En phase, en opposition

Les deux signaux ont la même amplitude A = 1,0 V et la même fréquence f = 440 Hz. Le second est déphasé de φ par rapport au premier.

  1. Compléter les lignes u2 = …… et u = ……, puis exécuter avec φ = 0. Relever l'amplitude de la somme.
  2. Remplacer phi = 0 par phi = np.pi. Exécuter et décrire la somme.
  3. Essayer phi = np.pi / 2. L'amplitude est-elle maximale, nulle, ou entre les deux ?
  4. Relier les questions 1 et 2 aux interférences constructives et destructives.
  1. u2 s'écrit comme u1, avec + phi à l'intérieur du sinus.
  2. La superposition est la somme des deux signaux : u1 + u2.
Voir une solution
u2 = A * np.sin(2 * np.pi * f * t + phi)
u = u1 + u2

Pour φ = 0, les deux signaux sont confondus et la somme atteint 2,0 V : interférences constructives. Pour φ = π, les crêtes de l'un tombent sur les creux de l'autre : la somme est nulle à chaque instant, interférences destructives. Pour φ = π/2, l'amplitude vaut 1,41 V : un cas intermédiaire. Dans tous les cas, la somme reste un signal sinusoïdal de même fréquence, 440 Hz.

4.2 Faire varier le déphasage

On fait varier φ de 0 à 2π rad, en 25 valeurs. Pour chacune, le programme calcule l'amplitude de la somme et la range dans une liste, puis trace l'amplitude en fonction du déphasage.

  1. Compléter la ligne amplitudes.append(……), puis exécuter. Pour quels déphasages l'amplitude est-elle maximale ? nulle ?
  2. Compléter la première condition, pour signaler le déphasage où les interférences sont destructives (amplitude inférieure à 0,01 V).
  3. Compléter la seconde condition, pour signaler les déphasages où elles sont constructives (amplitude supérieure à 1,99 V).
  1. Dans la boucle, l'amplitude de la somme est np.max(u), comme dans le print de l'exercice 4.1.
  2. Une fois ajoutée, cette amplitude est aussi le dernier élément de la liste : amplitudes[-1].
  3. Première condition : np.max(u) < 0.01.
Voir une solution
    amplitudes.append(np.max(u))
    if np.max(u) < 0.01:
        print('φ =', round(phi, 2), 'rad : interférences destructives')
    elif np.max(u) > 1.99:
        print('φ =', round(phi, 2), 'rad : interférences constructives')

L'amplitude vaut 2,0 V pour φ = 0 et φ = 2π (les signaux sont en phase), et 0 pour φ = π (opposition de phase). Entre les deux, elle varie continûment. Déphaser de 2π revient à décaler d'une période entière : les deux signaux sont de nouveau en phase. Le seuil de 0,01 V plutôt que 0 évite un piège : le calcul en virgule flottante donne une amplitude de l'ordre de 10⁻¹⁶ V, pas exactement 0.

Projet 2 — La longueur d'onde d'un laser, par diffraction

Comme au TP1, un laser éclaire des fentes de largeurs différentes, et l'on mesure la largeur de la tache centrale sur un écran. C'est le chapitre le plus présent dans les sujets d'ECE avec Python : on y teste un modèle, puis on en tire la longueur d'onde et son incertitude.

TP1 — Diffraction de la lumière
Rappel de cours — Diffraction par une fente

Pour une fente de largeur a éclairée en lumière de longueur d'onde λ, l'angle caractéristique θ vérifie, pour de petits angles :

θ ≈ λa θ ≈ L2D

On en déduit la largeur de la tache centrale : L = 2λD × 1a. L est donc proportionnelle à 1/a, avec un coefficient k = 2λD. Toutes les longueurs en mètres.

D'après ECE PC, banque 2026, sujets n° 52, 59, 78 et 89 : saisir les largeurs a et L mesurées, convertir les unités, choisir la grandeur portée en abscisse, puis lire la longueur d'onde et son incertitude.

5.1 Quel modèle ?

Mesures du TP1 : λ = 650 nm, D = 1,50 m. Le programme trace L en fonction d'une grandeur x à choisir, avec la droite passant par l'origine la plus proche des points ; son coefficient directeur k est calculé par une ligne fournie, comme dans les sujets 59 et 89.

  1. Compléter les deux conversions en mètres.
  2. Compléter x = …… avec 1/a, et légender l'axe des abscisses. Exécuter : le modèle convient-il ?
  3. Remplacer x par 1/a², et l'abscisse en conséquence. Que devient l'accord entre les points et la droite ?
  4. Revenir à x = 1/a. Ajouter une ligne qui calcule la longueur d'onde lam à partir de k et de D, et l'afficher en nm.
  1. 1 µm = 10⁻⁶ m et 1 cm = 10⁻² m : on multiplie par 1e-6 et par 1e-2.
  2. a² s'écrit a ** 2, et 1/a² s'écrit 1 / a ** 2 : la puissance passe avant la division.
  3. Puisque k = 2λD, λ = k / (2D). Attention aux parenthèses.
Voir une solution
a = a_um * 1e-6
L = L_cm * 1e-2
x = 1 / a
...
plt.xlabel('1/a (1/m)')

lam = k / (2 * D)
print('λ =', round(lam * 1e9, 1), 'nm')

Avec x = 1/a, les sept points sont alignés sur une droite passant par l'origine : L est proportionnelle à 1/a, comme le prévoit le cours. Avec 1/a², les points dessinent une courbe et la droite passe loin de la plupart d'entre eux : ce modèle est rejeté. k ≈ 1,96 × 10⁻⁶ m², d'où λ ≈ 653 nm. Au sujet 52, on ajuste k à la main jusqu'à ce que la droite passe au plus près des points : la démarche est la même.

5.2 λ mesure par mesure, et sa comparaison

Rappel de cours — Incertitude de type A

Pour n valeurs d'une même grandeur, de moyenne x̄ et d'écart-type expérimental s(x) :

u(x̄) = s(x)√n

Le z-score compare ensuite x̄ à la valeur de référence : voir l'exercice 1.2.

Comme dans le sujet 78, on calcule λ pour chaque fente, puis la moyenne et son incertitude-type, et l'on compare à la longueur d'onde indiquée sur le laser, 650 nm.

  1. Compléter la ligne lam = …… d'après le rappel du projet, puis exécuter : la boucle affiche λ pour chaque fente.
  2. Compléter lam_moy et u_lam. Écrire le résultat avec le bon nombre de chiffres significatifs.
  3. Compléter z, puis écrire les lignes qui concluent avec if, elif et else, comme à l'exercice 1.2.
  1. De L = 2λD / a, on tire λ = L × a / (2D) : les tableaux L et a se multiplient valeur par valeur.
  2. np.mean, puis np.std(lam, ddof=1) / np.sqrt(n).
  3. Pour la conclusion, recopiez le test de l'exercice 1.2 et adaptez les messages.
Voir une solution
lam = L * a / (2 * D)
...
lam_moy = np.mean(lam)
u_lam = np.std(lam, ddof=1) / np.sqrt(n)
...
z = abs(lam_moy - lam_ref) / u_lam
print('z =', round(z, 2))
if z < 1:
    print('valeurs très compatibles')
elif z < 2:
    print('valeurs compatibles')
else:
    print('valeurs non compatibles')

Python affiche λ moyenne = 652,9 nm et u = 2,9 nm. On arrondit l'incertitude à un chiffre significatif, à l'excès : 3 nm, puis la valeur au même rang : λ = (653 ± 3) nm. z ≈ 0,97 < 1 : la mesure est très compatible avec la valeur du laser. Le programme fait en une fois ce que le tableur fait colonne par colonne.

Projet 3 — Un acide faible dans l'eau

L'acide éthanoïque, l'acide du vinaigre, forme avec l'ion éthanoate le couple CH3COOH / CH3COO⁻, de pKA = 4,8. Deux capacités numériques du programme portent sur ce chapitre : tracer le diagramme de distribution d'un couple, et calculer le taux d'avancement final de la réaction d'un acide sur l'eau.

Au programme de terminale

« Tracer, à l'aide d'un langage de programmation, le diagramme de distribution des espèces d'un couple acide-base de pKA donné. » — « 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. »

D'après ECE PC, banque 2026, sujet n° 3 : le programme simule une courbe de titrage avec ce même couple, de pKA = 4,8. On y saisit des concentrations et un volume, on complète le titre et les axes, puis on lit le graphique.

6.1 Le diagramme de distribution

Rappel de cours — Prédominance et distribution

Pour un couple AH / A⁻ : pH = pKA + log([A⁻][AH]). Si pH < pKA, l'acide AH prédomine ; si pH > pKA, la base A⁻ prédomine.

Le diagramme de distribution donne les pourcentages des deux espèces en fonction du pH. On en déduit :

%AH = 1001 + 10pH − pKA %A⁻ = 100 − %AH

À l'intersection des deux courbes, les deux pourcentages valent 50 % : pH = pKA.

  1. Compléter les lignes p_acide et p_base, puis exécuter.
  2. Remplacer les …… du titre par un titre qui convient.
  3. Compléter la condition, pour que le programme indique l'espèce qui prédomine dans le vinaigre blanc, de pH 2,9.
  4. Remplacer pH_sol par 7,6, le pH de l'eau du robinet, et exécuter de nouveau.
  5. Lire sur le graphique le pH où les deux courbes se croisent. Le résultat était-il prévisible ?
  1. 10 puissance x s'écrit 10 ** x : ici 10 ** (pH - pKa), avec des parenthèses.
  2. Le pourcentage de la base se déduit de celui de l'acide.
  3. L'acide prédomine quand le pH de la solution est inférieur au pKA.
Voir une solution
p_acide = 100 / (1 + 10 ** (pH - pKa))
p_base = 100 - p_acide
...
plt.title("Diagramme de distribution du couple CH3COOH / CH3COO-")
...
if pH_sol < pKa:
    print('l’acide prédomine')

Dans le vinaigre (pH 2,9), 98,8 % de l'acide reste sous forme CH3COOH. Dans l'eau du robinet (pH 7,6), il n'en reste que 0,2 % : l'ion éthanoate prédomine. Les courbes se croisent à pH = 4,8 = pKA, comme le prévoit le cours.

6.2 Le taux d'avancement final

Rappel de cours — Taux d'avancement final

Le taux d'avancement final vaut τ = xfxmax. Pour un acide fort, τ = 1 ; pour un acide faible, τ < 1.

Pour un acide AH de concentration apportée C, on note x la concentration finale en ions oxonium. Le tableau d'avancement donne [A⁻] = [H3O+] = x et [AH] = C − x, donc :

KA = [A⁻] × [H3O+][AH] = x²C − x et τ = xC

L'équation à résoudre

x est solution de l'équation du second degré x² + KAx − KAC = 0, de la forme ax² + bx + c = 0 avec a = 1, b = KA et c = −KAC. Son discriminant vaut Δ = b² − 4ac, et sa seule racine positive :

x = −b + √Δ2a

On dissout de l'acide éthanoïque dans l'eau : C = 1,0 × 10⁻² mol·L⁻¹, pKA = 4,8.

  1. Compléter les lignes delta, x et tau, puis exécuter.
  2. L'acide éthanoïque est-il un acide fort ou faible ? Vérifier la valeur de τ avec la relation τ = 10−pH / C.
  1. Avec a = 1, b = KA et c = −KAC : Δ = KA² + 4 KAC, soit Ka ** 2 + 4 * Ka * C.
  2. La racine positive : (-Ka + np.sqrt(delta)) / 2.
  3. τ est le rapport de x à C.
Voir une solution
delta = Ka ** 2 + 4 * Ka * C
x = (-Ka + np.sqrt(delta)) / 2
tau = x / C

Python affiche [H3O+] ≈ 3,9 × 10⁻⁴ mol·L⁻¹, pH = 3,41 et τ = 3,9 % : moins de 4 molécules d'acide sur 100 ont réagi avec l'eau. τ < 1 : l'acide éthanoïque est un acide faible. Vérification : 10−3,41 / 0,010 ≈ 0,039. Sans Python, on résoudrait la même équation à la calculatrice ; le programme, lui, se réutilise pour n'importe quelle concentration.

6.3 Diluer l'acide

On reprend le calcul de l'exercice 6.2 pour quatre concentrations, de 10⁻¹ à 10⁻⁴ mol·L⁻¹.

  1. Compléter les trois lignes de la boucle, en recopiant celles de l'exercice 6.2, puis exécuter.
  2. Comment évolue le taux d'avancement final quand on dilue l'acide ?
  1. Les trois lignes sont identiques à celles de 6.2 : à chaque tour, C prend une nouvelle valeur, et les calculs suivent.
  2. Elles doivent rester décalées de quatre espaces, pour faire partie de la boucle.
Voir une solution
for C in concentrations:
    delta = Ka ** 2 + 4 * Ka * C
    x = (-Ka + np.sqrt(delta)) / 2
    tau = x / C
    print('C =', C, 'mol/L   τ =', round(tau * 100, 1), '%')

τ vaut 1,3 % ; 3,9 % ; 11,8 % puis 32,7 %. Plus on dilue, plus la réaction de l'acide faible avec l'eau avance, sans jamais être totale. La force d'un acide se compare donc à concentrations égales.

Projet 4 — Incertitudes : mesurer plus, ou simuler

Deux façons d'évaluer une incertitude avec Python. Quand on peut répéter la mesure : l'incertitude de type A, qui diminue avec le nombre de mesures. Quand le résultat se calcule à partir de plusieurs grandeurs mesurées : la simulation de Monte-Carlo.

Au programme de terminale

« Représenter l'histogramme associé à une série de mesures à l'aide d'un tableur ou d'un langage de programmation. » — « Simuler, à l'aide d'un langage de programmation, un processus aléatoire illustrant la détermination de la valeur d'une grandeur avec incertitudes-types composées. »

7.1 Combien de mesures faut-il ?

Rappel de cours — Incertitude de type A

u(x̄) = s(x)√n

L'incertitude-type de la moyenne s'écrit avec un seul chiffre significatif, arrondi à l'excès ; la moyenne est arrondie au même rang.

On reprend les vingt mesures du pH de l'eau du robinet (exercice 3.1). La première partie du programme trace l'histogramme et calcule le résultat. La seconde calcule l'incertitude-type en ne gardant que les 5, 10, 15 puis 20 premières mesures.

  1. Exécuter. Écrire le résultat de la mesure du pH.
  2. Compléter les deux lignes de la boucle, puis exécuter de nouveau.
  3. Comment l'incertitude évolue-t-elle avec le nombre de mesures ? Combien de fois plus de mesures faut-il, environ, pour la diviser par deux ?
  1. Les n premières mesures forment la tranche mesures[:n].
  2. Leur incertitude-type : np.std(serie, ddof=1) / np.sqrt(n).
Voir une solution
for n in nombres:
    serie = mesures[:n]
    incertitudes.append(np.std(serie, ddof=1) / np.sqrt(n))

Avec les vingt mesures : moyenne 7,618, u = 0,0093, d'où pH = 7,62 ± 0,01. L'histogramme montre les mesures regroupées autour de 7,62. L'incertitude passe de 0,023 (5 mesures) à 0,014, 0,011 puis 0,009 (20 mesures) : quatre fois plus de mesures la divisent par 2 environ, comme le prévoit le √n de la formule. Mesurer plus améliore la précision, mais de moins en moins vite.

7.2 Monte-Carlo : les fentes de Young

Rappel de cours — Composer des incertitudes

Pour une grandeur obtenue par produit ou quotient, λ = i × bD, on compose les incertitudes relatives :

u(λ) = λ × √(u(i)i)² + (u(b)b)² + (u(D)D)²

Méthode de Monte-Carlo

On tire au hasard des valeurs possibles de chaque grandeur, selon son incertitude ; on recalcule le résultat un grand nombre de fois ; l'écart-type des résultats obtenus est l'incertitude-type du résultat.

Application de la fiche de cours : avec des fentes de Young distantes de b = 0,50 mm (u = 0,01 mm), à D = 1,00 m de l'écran (u = 0,01 m), on mesure l'interfrange i = 2,20 mm (u = 0,05 mm). On calcule λ = i × b / D et son incertitude, de deux façons.

  1. Compléter les lignes b_sim, D_sim et lam_sim, puis exécuter. Décrire l'histogramme.
  2. Exécuter plusieurs fois. L'incertitude obtenue change-t-elle beaucoup ?
  3. Compléter la ligne u_formule avec la formule du rappel, et comparer les deux incertitudes. Écrire le résultat.
  1. b_sim et D_sim s'écrivent comme i_sim : loi normale, centrée sur la valeur mesurée, d'écart-type son incertitude-type.
  2. lam_sim se calcule comme λ, avec les tableaux simulés.
  3. La formule : lam * np.sqrt((u_i / i) ** 2 + (u_b / b) ** 2 + (u_D / D) ** 2).
Voir une solution
b_sim = np.random.normal(b, u_b, N)
D_sim = np.random.normal(D, u_D, N)
lam_sim = i_sim * b_sim / D_sim
...
u_formule = lam * np.sqrt((u_i / i) ** 2 + (u_b / b) ** 2 + (u_D / D) ** 2)

L'histogramme des 100 000 valeurs simulées est en cloche, centré sur λ = 1,10 × 10⁻⁶ m. D'une exécution à l'autre, u(λ) ne change que dans le troisième chiffre : 3,5 × 10⁻⁸ m, la valeur que donne la formule. On écrit λ = (1,10 ± 0,04) µm. La simulation n'a demandé aucune formule d'incertitude : c'est son intérêt quand la relation devient compliquée.

Bon à savoir

Dans les sujets d'ECE n° 1 et 78 (banque 2026), chaque grandeur est simulée selon ce qu'on sait d'elle : loi normale quand on connaît son incertitude-type, loi uniforme quand on connaît une tolérance « ± » de fabricant (fiole, pipette, fentes). Le sujet 22 fait le même calcul avec une boucle for, un tirage à la fois : plus lent, mais le principe est identique.

Projet 5 — La vitesse d'une voiture, par effet Doppler

Au TP5, une petite voiture portant un émetteur d'ultrasons de 40 000 Hz roule vers un récepteur. Le décalage Doppler a été mesuré plusieurs fois à deux endroits du parcours, en changeant le seuil de déclenchement de l'acquisition : 150 mV, puis 250 mV. La voiture a-t-elle la même vitesse aux deux endroits ?

TP5 — Ondes sonores et effet Doppler
Rappel de cours — Effet Doppler et incertitudes

Pour un émetteur qui s'approche d'un récepteur à une vitesse v faible devant c :

Δf ≈ fE × vc donc v = c × ΔffE et u(v) = c × u(Δf)fE

Comparer deux mesures

La différence v1 − v2 a pour incertitude-type √(u(v1)² + u(v2)²). On la compare à 0 par un z-score :

z = |v1 − v2|√(u(v1)² + u(v2)²)

Si z < 2, les deux vitesses sont compatibles ; sinon, elles diffèrent.

8.1 Deux séries, deux vitesses

Mesures du TP5 (corrigé) : neuf passages au seuil de 150 mV, six au seuil de 250 mV. Ultrasons dans l'air : c = 340 m·s⁻¹.

  1. Compléter v1 et u_v1 pour le seuil de 150 mV, puis exécuter.
  2. Compléter v2 et u_v2 pour le seuil de 250 mV, sur le même modèle.
  3. Compléter la condition. La vitesse est-elle la même aux deux endroits ? Que fait la voiture ?
  1. Le décalage Doppler moyen est np.mean(df_150) : on le place dans la formule du rappel.
  2. u_df1 est déjà calculée : u_v1 = c * u_df1 / f_E.
  3. Les vitesses sont compatibles si z < 2.
Voir une solution
v1 = c * np.mean(df_150) / f_E
u_v1 = c * u_df1 / f_E
...
v2 = c * np.mean(df_250) / f_E
u_v2 = c * u_df2 / f_E
...
if z < 2:

Seuil 150 mV : v = (2,96 ± 0,06) m·s⁻¹ ; seuil 250 mV : v = (3,32 ± 0,03) m·s⁻¹. L'écart entre les deux vitesses, 0,37 m·s⁻¹, vaut près de six fois son incertitude : z ≈ 5,7. Les vitesses ne sont pas compatibles : la voiture accélère entre les deux endroits du parcours. Le programme répond à la question 9 du TP5 en une exécution.

Projet 6 — Le sérum physiologique, par conductimétrie

Au TP4, on a dosé le chlorure de sodium d'un sérum physiologique par étalonnage. Ce projet reprend toute la chaîne de l'exploitation : droite d'étalonnage, concentration du sérum dilué, dilution, concentration en masse, incertitude et comparaison à l'étiquette, qui annonce 9,0 g·L⁻¹.

Rappel de cours — Dosage par étalonnage

Loi de Kohlrausch

Pour une solution diluée d'un seul soluté ionique, σ = k × c : une concentration inconnue se calcule par c = σk.

Dilution et concentration en masse

Une solution diluée F fois est F fois moins concentrée : cmère = F × cfille. La concentration en masse vaut t = c × M, avec c en mol·L⁻¹ et M en g·mol⁻¹.

9.1 Toute l'exploitation, en un programme

TP4 — Dosage par conductimétrie

Mesures du TP4 (corrigé). Le sérum a été dilué 20 fois avant la mesure : σ = 0,869 mS·cm⁻¹. On prend une incertitude-type de 5 % sur la concentration en masse du sérum.

  1. Compléter c_dil, la concentration du sérum dilué, puis exécuter : le point se place sur la droite.
  2. Compléter c_serum et t_serum.
  3. Compléter z, puis écrire les lignes qui concluent, comme à l'exercice 1.2. Le sérum respecte-t-il l'étiquette ?
  1. c_dil = sigma_dil / k : la concentration est en mmol/L, comme celles de la gamme.
  2. Le sérum est 20 fois plus concentré que la solution diluée.
  3. t = c × M demande c en mol/L : 1 mmol/L = 10⁻³ mol/L.
Voir une solution
c_dil = sigma_dil / k
c_serum = F * c_dil
t_serum = c_serum * 1e-3 * M
...
z = abs(t_serum - t_ref) / u_t
print('z =', round(z, 2))
if z < 1:
    print('valeurs très compatibles')
elif z < 2:
    print('valeurs compatibles')
else:
    print('valeurs non compatibles')

k = 0,1172 mS·cm⁻¹ par mmol·L⁻¹ ; cdil = 7,42 mmol·L⁻¹ ; c = 148 mmol·L⁻¹ ; t = (8,7 ± 0,5) g·L⁻¹. z ≈ 0,74 < 1 : la mesure est très compatible avec l'étiquette. L'oubli du 1e-3 donnerait 8 678 g·L⁻¹, plus de huit kilogrammes de sel par litre : un résultat absurde, que Python affiche sans broncher.

Le jour de l'épreuve

Vous avez mené six situations d'ECE complètes. Cette dernière étape rassemble la méthode, et un dernier outil : savoir lire un affichage que vous n'aurez pas écrit.

Le jour de l'épreuve, Python n'occupe qu'une partie du sujet. Le programme est fourni, presque entièrement écrit et commenté : on ne vous demande jamais d'écrire un programme entier.

Vous aurez à saisir vos mesures dans une liste ou un np.array, et parfois à compléter une formule, une conversion d'unités, un titre ou le nom d'un axe.

Il faut ensuite exécuter, puis exploiter : lire une valeur, comparer des mesures à un modèle, écrire un résultat avec son incertitude, conclure à l'aide d'un z-score.

Les fonctions utiles sont rappelées dans le sujet : rien n'est à connaître par cœur. Il faut en revanche savoir lire un programme : repérer ce qui est à compléter, et comprendre ce que calcule chaque ligne.

Les points se perdent sur une virgule décimale, une mesure oubliée dans une liste, des unités mélangées, un graphique tracé mais pas exploité, ou une conclusion sans justification.

À retenir — la méthode

  1. Lire tout le programme avant de toucher à quoi que ce soit : repérer les lignes à compléter et les unités notées en commentaire.
  2. Saisir les mesures : point décimal, virgules entre les valeurs, autant de valeurs dans chaque liste.
  3. Exécuter tout de suite, et lire le message d'erreur s'il y en a un : la ligne, puis le type d'erreur.
  4. Critiquer le résultat : ordre de grandeur, unité. Python ne signale jamais un résultat absurde.
  5. Exploiter par écrit : le résultat avec son incertitude et ses chiffres significatifs, puis une conclusion justifiée.

À retenir — lire un affichage formaté

  • Plusieurs sujets affichent leurs résultats avec f"…" : dans ce texte, chaque {…} est remplacé par sa valeur.
  • {x:.2f} affiche x avec 2 chiffres après la virgule ; {x:.0f}, arrondi à l'unité ; {x:.1e}, en écriture scientifique avec 1 chiffre après la virgule.
lam = 6.5286e-7
print(f"λ = {lam * 1e9:.0f} nm")     # affiche : λ = 653 nm
print(f"λ = {lam:.2e} m")            # affiche : λ = 6.53e-07 m

10.1 Les réflexes de l'épreuve

Pour chaque situation, choisir la bonne réponse. Les questions sur Python se vérifient dans l'éditeur.

Le bon réflexe

Le sujet indique a = np.array([ , , , , ]) # en µm. Vous avez mesuré 50, 100, 200, 280 et 400 µm. Quelle saisie est correcte ?

Il faut convertir ces largeurs en mètres. Quelle ligne convient ?

Que vaut f"u = {u:.1e} m", avec u = 2.948e-9 ?

Le programme affiche λ moyenne = 652.9 nm u = 2.9 nm. Comment écrire le résultat ?

Le programme affiche z = 2.4. Quelle conclusion écrire ?

Bilan du niveau 2

Ce que je sais faire

  • Comparer deux valeurs et conclure avec if, elif et else ; calculer un z-score avec abs.
  • Répéter un calcul pour chaque mesure avec for, range, et construire une liste avec append.
  • Extraire une partie d'une série avec une tranche : x[:5], x[-1].
  • Simuler des mesures avec np.random.normal et np.random.uniform ; évaluer une incertitude par Monte-Carlo.
  • Représenter la somme de deux signaux synchrones, en faisant varier le déphasage.
  • Tracer un diagramme de distribution ; calculer un taux d'avancement final.
  • Tester un modèle, comme L en fonction de 1/a ou de 1/a², et en tirer une grandeur.
  • Mener une exploitation complète : mesures, calcul, incertitude, comparaison, conclusion.

La partie Python de l'ECE n'a plus de secret pour vous. Le niveau 3 apprend à écrire seul de petits programmes complets, sur tout le programme de terminale.