USMA1Q — Méthodes Numériques¶
Séance 8 — Intégration numérique I : fondamentaux et quadrature de Gauss¶
Conservatoire National des Arts et Métiers
25 Mars 2026
nicholas-anton.collins-craft@enpc.fr
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) | Systèmes d'équations non linéaires |
| 25 mars (matin) | Intégration numérique I |
| 25 mars (après-midi) | Intégration numérique II (Monte Carlo) |
| 02 avril | Équations différentielles |
| 08 avril | Examen |
Plan de la séance (indicatif)¶
| Horaire | Sujet |
|---|---|
| 0:00 – 0:50 | Quadrature de Newton-Cotes : trapèzes et Simpson |
| 0:50 – 1:40 | Quadrature de Gauss–Legendre |
| 1:40 – 1:50 | ☕ Pause |
| 1:50 – 2:45 | Intégration de données discrètes & intégrales cumulatives |
| 2:45 – 3:40 | Intégrales impropres et singularités |
| 3:40 – 3:45 | Récapitulatif |
Motivation — pourquoi intégrer numériquement ?¶
De nombreuses quantités physiques importantes sont des intégrales :
| Quantité | Intégrale |
|---|---|
| Variation d'enthalpie ΔH | \(\int_{T_1}^{T_2} C_p(T)\,\mathrm{d}T\) |
| Ténacité (énergie absorbée) | \(\int_0^{\varepsilon_f}\sigma(\varepsilon)\,\mathrm{d}\varepsilon\) |
| Rigidité d'un élément fini | \(\int_0^L EA\left(\frac{\mathrm{d}N}{\mathrm{d}x}\right)^2\mathrm{d}x\) |
| Chaleur latente (DSC) | \(\int_{T_1}^{T_2}\dot{q}(T)\,\mathrm{d}T\) |
Problème : $C_p(T)$, $\sigma(\varepsilon)$ ne sont souvent disponibles que sous forme de données tabelées, pas de fonctions analytiques. Il faut donc intégrer numériquement.
1 · Quadrature de Newton-Cotes¶
Idée : remplacer l'intégrande par une fonction simple (polynôme) sur chaque sous-intervalle, puis intégrer ce polynôme exactement.
Avec $N$ points espacés de $h = (b-a)/(N-1)$, on obtient la règle composite.
Règle des trapèzes (méthode des trapèzes)¶
On relie les points par des segments droits :
$$\int_a^b f(x)\,\mathrm{d}x \approx h\left[\frac{f(x_0)}{2} + f(x_1) + f(x_2) + \cdots + f(x_{N-2}) + \frac{f(x_{N-1})}{2}\right]$$
Erreur : $\mathcal{O}(h^2)$ — si on divise $h$ par 2, l'erreur est divisée par 4.
En Python : scipy.integrate.trapezoid(y, x) où trapezoid = trapèze (méthode des trapèzes).
⚠️ Le $y$ est donné en prémier à cette méthode, le $x$ (si on a) est donné deuxième.

import numpy as np
from scipy.integrate import trapezoid
# Exemple : sin(x) sur [0, π] — valeur exacte = 2
N = 10
x = np.linspace(0, np.pi, N)
y = np.sin(x)
resultat = trapezoid(y, x)
print("N =", N, " résultat =", round(resultat, 8), " erreur =", round(abs(resultat - 2.0), 4))
# Affichage plus lisible :
print("N = %d résultat = %.8f erreur = %.2e" % (N, resultat, abs(resultat - 2.0)))
N = 10 résultat = 1.97965081 erreur = 0.0203 N = 10 résultat = 1.97965081 erreur = 2.03e-02
Règle de Simpson (méthode de Simpson)¶
On relie les points par des paraboles :
$$\int_a^b f(x)\,\mathrm{d}x \approx \frac{h}{3}\bigl[f(x_0) + 4f(x_1) + 2f(x_2) + 4f(x_3) + \cdots + 4f(x_{N-2}) + f(x_{N-1})\bigr]$$
Nécessite un nombre impair de points (nombre pair d'intervalles).
Erreur : $\mathcal{O}(h^4)$ — deux ordres meilleurs que les trapèzes pour une même régularité !
En Python : scipy.integrate.simpson(y, x) où simpson = Simpson
⚠️ Le $y$ est donné en prémier à cette méthode, le $x$ (si on a) est donné deuxième.

from scipy.integrate import trapezoid, simpson
exact = 2.0 # valeur exacte de sin(x) sur [0, π]
print("N | erreur trapèzes | erreur Simpson")
print("-----|-----------------|---------------")
for N in [5, 11, 21, 51, 101, 201]:
x = np.linspace(0, np.pi, N)
y = np.sin(x)
err_trap = abs(trapezoid(y, x) - exact)
err_simp = abs(simpson(y, x) - exact)
print("%4d | %.3e | %.3e" % (N, err_trap, err_simp))
N | erreur trapèzes | erreur Simpson -----|-----------------|--------------- 5 | 1.039e-01 | 4.560e-03 11 | 1.648e-02 | 1.095e-04 21 | 4.114e-03 | 6.784e-06 51 | 6.580e-04 | 1.733e-07 101 | 1.645e-04 | 1.082e-08 201 | 4.112e-05 | 6.765e-10
Convergence : erreur en fonction de $h$¶
Sur un graphique log-log, l'erreur décroit en droite avec la pente :
- Trapèzes : pente $-2$ (erreur $\propto h^2$)
- Simpson : pente $-4$ (erreur $\propto h^4$)

À vous de faire les exercices 1.1 et 1.2 !¶
2 · Quadrature de Gauss–Legendre¶
Idée : au lieu d'imposer des points équirépartis, on choisit à la fois les nœuds $x_i$ et les poids $w_i$ de façon optimale.
$$\int_{-1}^{1} f(t)\,\mathrm{d}t \approx \sum_{i=1}^{n} w_i f(t_i)$$
Propriété remarquable : une quadrature de Gauss à $n$ points intègre exactement tout polynôme de degré $\leq 2n-1$.
La méthode des trapèzes composite à $n$ points n'intègre exactement que les polynômes de degré 1. Simpson n'intègre exactement que de degré 3.

Nœuds et poids de Gauss–Legendre¶
Les nœuds $t_i \in [-1, 1]$ sont les racines des polynômes de Legendre.
En Python : np.polynomial.legendre.leggauss(n).
t, w = np.polynomial.legendre.leggauss(n)
Changement de variable pour passer de $[-1, 1]$ à $[a, b]$ :
$$x = \frac{b-a}{2}\,t + \frac{a+b}{2}, \qquad \mathrm{d}x = \frac{b-a}{2}\,\mathrm{d}t$$
donc :
$$\int_a^b f(x)\,\mathrm{d}x = \frac{b-a}{2} \int_{-1}^{1} f\!\left(\frac{b-a}{2}t + \frac{a+b}{2}\right) \mathrm{d}t \approx \frac{b-a}{2}\sum_{i=1}^{n} w_i\, f(x_i)$$
import numpy as np
# Nœuds et poids sur [-1, 1]
t3, w3 = np.polynomial.legendre.leggauss(3)
print("n=3 — poids :", w3)
print("Somme des poids :", sum(w3), " (doit être 2.0 — longueur de [-1,1])")
n=3 — poids : [0.55555556 0.88888889 0.55555556] Somme des poids : 2.0000000000000004 (doit être 2.0 — longueur de [-1,1])
def gauss_legendre(f, a, b, n):
# Intégrale de f sur [a, b] par quadrature de Gauss-Legendre à n points.
t, w = np.polynomial.legendre.leggauss(n)
# Changement de variable : [-1,1] → [a,b]
x = (b - a) / 2.0 * t + (a + b) / 2.0
return (b - a) / 2.0 * np.sum(w * f(x))
# Démonstration : intégrer sin(x) sur [0, π]
print("Gauss-Legendre (n=3) :", round(gauss_legendre(np.sin, 0, np.pi, 3), 10))
print("Gauss-Legendre (n=5) :", round(gauss_legendre(np.sin, 0, np.pi, 5), 10))
print("Valeur exacte : 2.0")
Gauss-Legendre (n=3) : 2.0013889136 Gauss-Legendre (n=5) : 2.0000001103 Valeur exacte : 2.0
scipy.integrate.quad — intégration adaptative¶
quad (abréviation de quadrature) utilise la quadrature de Gauss-Kronrod adaptative :
il raffine automatiquement là où la fonction varie rapidement.
from scipy.integrate import quad
valeur, erreur_estimee = quad(f, a, b)
- Renvoie deux valeurs : le résultat et une estimation de l'erreur
- Toujours vérifier que
erreur_estimeeest acceptable ! - Gère les limites infinies :
quad(f, 0, np.inf)
from scipy.integrate import quad
# Intégrer sin(x) sur [0, π]
valeur, erreur = quad(np.sin, 0, np.pi)
print("Résultat :", valeur)
print("Erreur estimée :", erreur) # doit être très petite
print("Erreur réelle :", abs(valeur - 2.0))
Résultat : 2.0 Erreur estimée : 2.220446049250313e-14 Erreur réelle : 0.0
Gauss en pratique : éléments finis¶
Dans la méthode des éléments finis (MEF), les matrices de rigidité sont calculées (en pratique) par quadrature de Gauss sur chaque élément.
Pour un élément de barre 1D de longueur $L$, avec module $E$ et section $A$ :
$$k_{11} = \int_0^L EA \left(\frac{\mathrm{d}N_1}{\mathrm{d}x}\right)^2 \mathrm{d}x$$
Avec des fonctions de forme linéaires $N_1(x) = 1 - x/L$, on a $\mathrm{d}N_1/\mathrm{d}x = -1/L$.
Donc $k_{11} = EA/L$ pour un élément fini linéaire.
Gauss et sous-intégration¶
Le nombre de points de Gauss requis dépend du degré des fonctions de forme : l'intégrande $k_{ij} = EA\,(\mathrm{d}N_i/\mathrm{d}x)(\mathrm{d}N_j/\mathrm{d}x)$ est de degré $2(p-1)$ si les fonctions de forme $N_i$ sont de degré $p$.
| Élément | Degré des $N_i$ | Degré de l'intégrande | Pts de Gauss min. |
|---|---|---|---|
| Linéaire (2 nœuds) | 1 | 0 (constant) | 1 |
| Quadratique (3 nœuds) | 2 | 2 | 2 |
| Cubique (4 nœuds) | 3 | 4 | 3 |
Sous-intégration : utiliser trop peu de points introduit des erreurs dans la matrice de rigidité, la rendant trop souple (parfois très utile dans le contexte d'un intégration dit "reduit").
import numpy as np
from numpy.polynomial.legendre import leggauss
# Exemple MEF 1D : terme k11 d'un élément quadratique (3 nœuds)
# N1(xi) = 0.5*xi*(xi-1) => dN1/dx = (2/L)*(xi - 0.5),
# k11 = ∫_{-1}^{1} EA*(dN1/dx)^2 * (L/2) dxi
E, A, L = 1.0, 1.0, 1.0
def integrande_k11(xi, E=1.0, A=1.0, L=1.0):
dN1_dx = (2.0 / L) * (xi - 0.5)
jac = L / 2.0
return E * A * dN1_dx**2 * jac
def gauss_integrate_1d(func, n, E=1.0, A=1.0, L=1.0):
xi, w = leggauss(n)
return np.sum(w * func(xi, E, A, L))
k11_exact = 7.0 * E * A / (3.0 * L)
for n in [1, 2, 3]:
k11_n = gauss_integrate_1d(integrande_k11, n, E, A, L)
rel_err = abs(k11_n - k11_exact) / abs(k11_exact)
print("n = %d -> k11 = %.10f erreur relative = %.3e" % (n, k11_n, rel_err))
n = 1 -> k11 = 1.0000000000 erreur relative = 5.714e-01 n = 2 -> k11 = 2.3333333333 erreur relative = 1.903e-16 n = 3 -> k11 = 2.3333333333 erreur relative = 0.000e+00
À vous de faire l'exercice 2 !¶
☕ Pause — 10 minutes¶
3 · Intégration de données discrètes¶
Situation courante : votre capteur enregistre des mesures à intervalles réguliers. Vous ne pouvez pas repositionner les points — vous êtes limités à Newton-Cotes, ou à interpoler d'abord, puis intégrer.
Trois stratégies :
| Stratégie | Outil | Quand l'utiliser |
|---|---|---|
| Directe | trapezoid(y, x) |
Données brutes, précision modérée |
| Spline puis intégration | cs.integrate(a, b) |
Données propres, besoin de précision |
Spline puis quad |
quad(cs, a, b) |
Idem, vérification indépendante |
Intégrale cumulative¶
scipy.integrate.cumulative_trapezoid(y, x) (= intégrale cumulative par les trapèzes)
permet de calculer non pas la valeur totale de l'intégrale, mais la valeur
en fonction de la borne supérieure :
$$F(x) = \int_a^x f(t)\,\mathrm{d}t$$
Très utile pour :
- Énergie absorbée en fonction de la déformation
- Déplacement à partir de la vitesse
- Enthalpy cumulée en fonction de la température
⚠️ Le $y$ est donné en prémier à cette méthode, le $x$ (si on a) est donné deuxième.

Comparaison des stratégies d'intégration¶
Pour des données bien résolues (pas $h$ petit), les trois méthodes donnent des résultats très proches. Les différences apparaissent pour des données grossières ou irrégulièrement espacées.
Règle pratique :
- Si les données sont denses et régulières →
trapezoidsuffit - Si les données sont éparses ou irrégulières → interpoler d'abord, puis intégrer
À vous de faire les exercice 3.1 et 3.2 !¶
4 · Intégrales impropres et singularités¶
Une intégrale est dite impropre si :
- Un (ou les deux) limite(s) d'intégration est infinie
- L'intégrande a une singularité (divergence) dans l'intervalle
scipy.integrate.quad gère ces cas :
from scipy.integrate import quad
# Limite infinie
quad(f, 0, np.inf) # ∫₀^∞ f(x) dx
# Limite doublement infinie
quad(f, -np.inf, np.inf) # ∫₋∞^∞ f(x) dx
La syntaxe est quad(nom_de_function, borne_inferieur, borne_superieur).
from scipy.integrate import quad
import numpy as np
# Exemple 1 : ∫₀^∞ e^(-x) dx = 1
def f_exp(x):
return np.exp(-x)
val, err = quad(f_exp, 0, np.inf)
print("∫₀^∞ e^(-x) dx =", val, " (exact : 1.0)")
# Exemple 2 : ∫₋∞^∞ e^(-x²) dx = √π ≈ 1.7725...
def gaussienne(x):
return np.exp(-x**2)
val2, err2 = quad(gaussienne, -np.inf, np.inf)
print("∫₋∞^∞ e^(-x²) dx =", round(val2, 6), " (exact : √π =", round(np.sqrt(np.pi), 6), ")")
∫₀^∞ e^(-x) dx = 1.0000000000000002 (exact : 1.0) ∫₋∞^∞ e^(-x²) dx = 1.772454 (exact : √π = 1.772454 )
Singularités intégrables¶
Certaines fonctions divergent en un point, mais leur intégrale est finie.
Exemple : $\int_0^1 x^{-1/2}\,\mathrm{d}x = [2\sqrt{x}]_0^1 = 2$
quad le gère automatiquement dans les cas modérés. Pour une singularité forte,
on peut indiquer son emplacement :
quad(f, 0, 1, points=[0.5]) # Signale une singularité en x=0.5
from scipy.integrate import quad
# Singularité en x=0 : f(x) = 1/sqrt(x)
def f_sing(x):
return 1.0 / np.sqrt(x)
val, err = quad(f_sing, 0, 1)
print("∫₀¹ x^(-1/2) dx =", round(val, 8), " (exact : 2.0)")
print("Erreur estimée =", err)
∫₀¹ x^(-1/2) dx = 2.0 (exact : 2.0) Erreur estimée = 5.773159728050814e-15

À vous de faire l'exercice 4 !¶
Points clés de la séance¶
| Concept | Ce qu'il faut retenir |
|---|---|
| Trapèzes | Erreur $\mathcal{O}(h^2)$ ; scipy.integrate.trapezoid(y, x) |
| Simpson | Erreur $\mathcal{O}(h^4)$ — bien meilleur pour les fonctions lisses ; scipy.integrate.simpson(y, x) |
| Gauss–Legendre | $n$ points intègrent exactement les polynômes de degré $2n-1$ ; acceder aux points et poids avec numpy.polynomial.legendre.leggauss(n) |
scipy.integrate.quad |
Gauss-Kronrod adaptatif ; renvoie (valeur, erreur_estimée) ; toujours vérifier l'erreur |
| Cumulative | scipy.integrate.cumulative_trapezoid(y, x, initial=0) — intégrale en fonction de la borne supérieure |
| Données discrètes | Interpoler d'abord (spline) puis intégrer si les données sont éparses |
| Impropre | scipy.integrate.quad(f, 0, np.inf) — quad gère les limites infinies et les singularités modérées |
| Vérification | Comparer au moins deux méthodes ; vérifier erreur_estimée de quad |