Un lien vers Google Colab qui peut faire tourner le notebook qui contient les exercices se trouve ici :
https://colab.research.google.com/github/nickcollins-craft/USMA1Q-Methodes-Numeriques/blob/main/
Plan du cours¶
| Jour | Sujet |
|---|---|
| 03 mars | Fondamentaux de la programmation en Python |
| 04 mars (matin) | Fonctions, listes approfondies, fichiers et graphiques |
| 04 mars (après-midi) | Calcul numérique avec NumPy |
| 11 mars (matin) | Tableaux en mémoire, matrices & précision numérique |
| 11 mars (après-midi) | Résolution des systèmes linéaires |
| 18 mars (matin) | Interpolation & recherche des racines |
| 18 mars (après-midi) | Résolution des systèmes non linéaires |
| 25 mars | Intégration numérique |
| 02 avril | Équations différentielles |
| 08 avril | Examen |
Plan de la séance (indicatif)¶
| Horaire | Sujet |
|---|---|
| 0:00 – 1:00 | Interpolation : linéaire, splines cubiques, dérivées |
| 1:00 – 1:50 | Interpolation pratique : extrapolation, lissage, 2D |
| 1:50 – 2:00 | ☕ Pause |
| 2:05 – 2:45 | Recherche des racines scalaires |
| 2:45 – 3:40 | Combiner interpolation et recherche des racines |
Motivation — pourquoi interpoler ?¶
Les données expérimentales sont discrètes : on mesure aux instants donnés, et pas pour tous les temps entre le début et le fin.
Mais les calculs nécessitent souvent une fonction continue :
| Problème | Ce dont on a besoin |
|---|---|
| Évaluer k(T) à une température intermédiaire | Interpolant continu |
| Calculer dT/dt sur une courbe de refroidissement | Dérivée du spline |
| Trouver la résistance limite à 0,2 % d'écart | Racine d'une équation |
| Cartographier la dureté sur toute une plaque | Interpolation 2D |
Idée centrale : on construit une fonction $f(x)$ qui passe exactement par les données mesurées, puis on l'évalue là où on en a besoin.
1 · Principaux outils d'interpolation¶
⚠️ Pourquoi pas un polynôme de degré élevé ?¶
Avec $n$ points, il existe un unique polynôme de degré $n-1$ passant exactement par tous. C'est une mauvaise idée en pratique :
import numpy as np
import matplotlib.pyplot as plt
# 10 points équidistants sur [-1, 1]
x_data = np.linspace(-1, 1, 10)
y_data = 1 / (1 + 25 * x_data**2) # fonction de Runge
coeffs = np.polyfit(x_data, y_data, deg=9) # polynôme de degré 9
x_fin = np.linspace(-1, 1, 300)
y_poly = np.polyval(coeffs, x_fin)
Le polynôme oscille très fortement aux extrémités (phénomène de Runge) même s'il passe par tous les points. C'est mathématiquement exact mais numériquement inutilisable.

Interpolation linéaire — np.interp()¶
Relie les points successifs par des segments droits.
x_new = np.linspace(x_data.min(), x_data.max(), 300)
y_lin = np.interp(x_new, x_data, y_data) # interp = interpoler
Propriétés :
- Continu mais non différentiable aux nœuds (angle)
- Très stable : ne peut pas osciller entre les nœuds
- Adapté pour des données bruitées ou des tables de propriétés
Limites :
- La dérivée est constante par morceaux (ordre 1 seulement)
- Mauvaise approximation si les données varient vite
Spline cubique — scipy.interpolate.CubicSpline¶
Relie les points par des morceaux cubiques avec continuité de la dérivée première et seconde.
from scipy.interpolate import CubicSpline
cs = CubicSpline(x_data, y_data) # cs = cubic spline
y_spl = cs(x_new) # évaluation
dy_spl = cs(x_new, nu=1) # dérivée première (nu = order)
d2y_spl = cs(x_new, nu=2) # dérivée seconde
integrale = cs.integrate(a, b) # intégrale sur [a, b]
Propriétés :
- Continu avec dérivée 1ère et 2ème continues → courbe lisse
- Haute précision pour des données lisses
- La dérivée est disponible gratuitement sans besoin de la definir nous même !
Conditions aux limites :
| Option | Signification |
|---|---|
bc_type='not-a-knot' (défaut) |
Les deux prémieres segments sont assumés d'être la même polynôme (on utilise quand on n'a pas de l'information sur les conditions aux limites) |
bc_type='periodic' |
Les fonctions sont assumées périodiques avec une période de x[-1] - x[0], et on doit avoir y[-1] == y[0] |
bc_type='natural' |
$f''=0$ aux extrémités |
bc_type='clamped' |
$f'=0$ aux extrémités |
Quel outil choisir ?¶
| Situation | Outil recommandé | Raison |
|---|---|---|
| Données bruitées | np.interp() |
ne sur-ajuste pas |
| Données de simulation propres | CubicSpline |
lisse, dérivée exacte |
| Besoin de la dérivée | CubicSpline |
dérivée analytique par morceaux |
| Besoin de l'intégrale | CubicSpline |
.integrate(a, b) |
| Table de propriétés matériaux | np.interp() |
simple et robuste |
Règle d'or : si vous ne connaissez pas la physique sous-jacente, préférez l'interpolation linéaire pour les données bruitées et les splines pour les données propres ou les résultats de simulation.

# ── Démonstration : interpolation de la conductivité thermique ──
import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import CubicSpline
# Données de conductivité thermique de l'acier 316L
data = np.loadtxt('conductivite_thermique.csv', delimiter=',', skiprows=1)
T_data = data[:, 0] # °C
k_data = data[:, 1] # W/(m·K)
# Grille fine pour l'évaluation
T_fin = np.linspace(T_data.min(), T_data.max(), 300)
# Interpolation linéaire
k_lin = np.interp(T_fin, T_data, k_data)
# Spline cubique
cs = CubicSpline(T_data, k_data)
k_spl = cs(T_fin)
dk_spl = cs(T_fin, nu=1) # dk/dT
print('k à 400 °C (linéaire) :', round(np.interp(400, T_data, k_data), 3), 'W/(m·K)')
print('k à 400 °C (spline) :', round(float(cs(400)), 3), 'W/(m·K)')
À vous de faire l'exercice 1 !¶
2 · Interpolation pratique¶
⚠️ Danger de l'extrapolation¶
Un spline (ou tout interpolant) peut diverger très rapidement hors de la plage de données :
T_extrap = np.linspace(0, 1100, 400) # dépasse les données (max = 900 °C)
k_extrap = cs(T_extrap) # Hors de [20, 900] : résultats sans justification !
Règle : ne jamais extrapoler sans vérifier que les prédictions sont plausibles.

Spline de lissage — make_smoothing_spline¶
Pour des données bruitées, on veut un spline qui passe près des points sans suivre le bruit :
from scipy.interpolate import make_smoothing_spline
spl_lisse = make_smoothing_spline(x_data, y_data, lam=0.5)
# lam : paramètre de lissage — grand = plus lisse, petit = suit les données
y_lisse = spl_lisse(x_new)

Interpolation 2D¶
Données sur une grille régulière : RegularGridInterpolator¶
from scipy.interpolate import RegularGridInterpolator
# x_grid, y_grid : vecteurs 1D des coordonnées de la grille
# Z : tableau 2D des valeurs Z[i, j] = f(x_grid[i], y_grid[j])
interp = RegularGridInterpolator((x_grid, y_grid), Z)
z_new = interp([[x_new, y_new]]) # évaluer en un nouveau point
Données éparses (nuage de points) : griddata¶
from scipy.interpolate import griddata
# points : tableau (N, 2) des coordonnées (x, y)
# values : tableau (N,) des valeurs mesurées
# xi : grille sur laquelle interpoler — créée avec np.meshgrid
# method : 'linear', 'cubic', 'nearest'
xi, yi = np.meshgrid(np.linspace(0, 100, 50), np.linspace(0, 80, 40))
zi = griddata(points, values, (xi, yi), method='cubic')
À vous de faire l'exercice 2 !¶
☕ Pause — 10 minutes¶
3 · Recherche des racines scalaires¶
Tout problème de seuil se reformule en « trouver $x$ tel que $f(x) = 0$ » :
Trois familles de méthodes :
- Encadrement (bracketing) — lent mais garanti
- Newton — rapide mais a besoin d'une dérivée et d'une bonne valeur de départ
- Hybride — fusion intelligente →
scipy.optimize.brentq()
Méthode de la bissection¶
Idée : si $f(a) < 0$ et $f(b) > 0$ pour une $f(x)$ continue, il y a une racine dans $[a, b]$. On évalue $f$ au milieu $c = (a+b)/2$ et on garde la moitié qui contient encore la racine.
def bisection(f, a, b, tol=1e-8, max_iter=100):
for i in range(max_iter):
c = (a + b) / 2
if abs(f(c)) < tol or (b - a) / 2 < tol:
return c, i + 1
if f(a) * f(c) < 0:
b = c
else:
a = c
return (a + b) / 2, max_iter
Convergence : linéaire — l'intervalle est divisé par 2 à chaque itération → $n$ itérations donnent une précision $|b-a| / 2^n$.
Avantage : garanti de converger si $f$ est continue et que la racine est encadrée.

Méthode de Newton–Raphson¶
Idée : à chaque étape, remplacer $f$ par sa tangente et trouver la racine de cette droite.
$$x_{n+1} = x_n - \frac{f(x_n)}{f'(x_n)}$$
def newton(f, df, x0, tol=1e-8, max_iter=50):
x = x0
for i in range(max_iter):
fx = f(x)
if abs(fx) < tol:
return x, i + 1
x = x - fx / df(x)
return x, max_iter
Convergence : quadratique près de la racine — le nombre de chiffres corrects double à chaque itération.
Inconvénients :
- Nécessite $f'(x)$ (souvent calculé séparément ou approximé numériquement)
- Peut diverger si le point de départ est trop loin ou si $f'(x) \approx 0$

Méthode de la sécante & quadratique inverse¶
Méthode de la sécante (secant method)¶
Approxime $f'(x_n)$ par la pente de la droite reliant les deux derniers points : $$x_{n+1} = x_n - f(x_n) \cdot \frac{x_n - x_{n-1}}{f(x_n) - f(x_{n-1})}$$
- Pas besoin de $f'$ explicitement
- Convergence super-linéaire ($\approx x^{1.618}$), plus rapide que la bissection, plus robuste que Newton
- Nécessite deux points de départ $x_0$ et $x_1$
Interpolation quadratique inverse (inverse quadratic interpolation)¶
Approche une racine via un polynôme quadratique évalué en 3 points $(x_{n-2}, x_{n-1}, x_n)$ puis extrapole à $y = 0$.
- Convergence encore plus rapide que la méthode de la sécante
- Peut devenir instable si les trois points sont mal placés

scipy.optimize.brentq() — la méthode hybride¶
L'algorithme de Brent (Brent's method) combine intelligemment :
- Bissection — pour garantir la convergence
- Sécante — pour accélérer
- Interpolation quadratique inverse — pour accélérer encore plus
Il n'utilise la bissection que quand les autres méthodes seraient dangereuses.
from scipy.optimize import brentq
def f(x):
return x**3 - 2*x - 5
racine = brentq(f, a=2, b=3) # encadrement : f(2) < 0, f(3) > 0
print('racine =', racine)
C'est la méthode à utiliser en pratique pour les problèmes scalaires — rapide, robuste, et ne demande qu'un encadrement.
À vous de faire les exercices 3.1 et 3.2 !¶
4 · Combiner interpolation et recherche des racines¶
Le problème pratique¶
En pratique, on n'a pas une formule analytique — on a des données :
temps | température
-------|------------
0 s | 1090 °C
6 s | 1087.7 °C
...
Stratégie :
- Interpoler les données avec un spline cubique → $T(t)$
- Calculer $dT/dt = T'(t)$ via
cs(t, nu=1) - Calculer $d^2T/dt^2 = T''(t)$ via
cs(t, nu=2) - Balayer $T''(t)$ pour détecter les changements de signe → encadrements
- Appliquer
brentqsur chaque encadrement → temps exacts - Les températures correspondantes sont les temperatures de transformation
Trouver plusieurs racines¶
Pour une fonction qui possède plusieurs racines, il faut :
- Scanner $f(x)$ sur une grille grossière et chercher les changements de signe
- Pour chaque paire $(x_i, x_{i+1})$ où $f(x_i) \cdot f(x_{i+1}) < 0$ → encadrement
- Affiner chaque encadrement avec
brentq
from scipy.optimize import brentq
def trouver_racines(f, t_scan):
"""Trouve toutes les racines de f sur la grille t_scan."""
f_vals = f(t_scan)
racines = []
for i in range(len(t_scan) - 1):
if f_vals[i] * f_vals[i + 1] < 0: # changement de signe
r = brentq(f, t_scan[i], t_scan[i + 1])
racines.append(r)
return racines
À vous de faire l'exercice 4 !¶
Points clés de la séance¶
| Concept | Ce qu'il faut retenir |
|---|---|
np.interp() |
Interpolation linéaire rapide — robuste pour données bruitées |
CubicSpline |
Spline cubique lisse — dérivées et intégrales gratuits via nu= |
| Phénomène de Runge | Ne jamais ajuster un polynôme de degré élevé sur beaucoup de points |
| Extrapolation | Toujours dangereuse — rester dans la plage des données |
griddata |
Interpolation 2D sur nuage de points éparses |
| Bissection | Lente mais garantie — nécessite un encadrement |
| Newton–Raphson | Rapide (quadratique) mais nécessite $f'$ et un bon point de départ |
brentq |
Méthode hybride recommandée — from scipy.optimize import brentq |
| Stratégie combinée | Données → spline → résidu → brentq |
| Plusieurs racines | Scanner les changements de signe, puis encadrer chacun |