TP3 Intégration¶
Dans ce TP on va s'intéresser au calcul d'intégrales. On commencera par calculer une intégrale par la méthode des rectangles avant d'utiliser une fonction pré-programmée dans python.
1) La méthode des rectangles¶
Cette méthode consiste à approximer une intégrale en divisant l'intervalle d'intégration en petits sous-intervalles, puis en utilisant des rectangles pour estimer l'aire sous la courbe dans chaque sous-intervalle.
La formule de la méthode des rectangles (à gauche) pour approcher une intégrale avec une grille uniforme sur $[a,b]$ est donnée par :
$$ \int_a^b f(t) \, dt \approx \frac{b-a}{n}\sum_{j=0}^{n-1} f(a_j)\qquad \text{avec}\quad a_j = a + j\frac{b-a}{n}\qquad j\in \{0,\dots,n\}. $$
import numpy as np
import matplotlib.pyplot as plt
a) Ecrire une fonction integrale
qui prend en argument le tableau f_grid
constituée de $(f(a_0),\dots,f(a_{n-1}))$, et les bornes a
et b
, puis renvoie la valeur approchée de l'intégrale par la méthode des rectangles.¶
Pour commencer, on pourra prendre $f(x) = \sin(x)$ ou $\cos(x)$ sur l'intervalle $[0,\pi]$ pour vérifier que son code fonctionne correctement (car on connait les valeurs exactes des intégrales).
En effet, on a $$ \int_0^\pi \sin(t) dt = [-\cos(t)]^\pi_0 = 2 \qquad\text{et}\qquad \int_0^\pi \cos(t) dt = [\sin(t)]^\pi_0 = 0. $$
def integrale(f_grid, a, b):
n = len(f_grid)
return sum(f_grid) * (b-a)/n
a, b = 0, np.pi # défini les bornes de l'intervalle
n = 100 # nombre de point de discrétisation de $f$
a_grid = np.arange(a, b, (b-a)/n) # grille de point a_j
# np.arange(point de départ, point d'arrivé, pas entre les points)
f = lambda x: np.sin(x) # définition de la fonction f à intégrer
# équivalent à
# def f(x):
# return np.sin(x)
f_grid = f(a_grid) # évaluation de f sur la grille de point
integrale(f_grid, a, b) # évaluation de l'intégrale
np.float64(1.9998355038874436)
# comme précédement avec la fonction cos
f = lambda x: np.cos(x)
f_grid = f(a_grid)
integrale(f_grid, a, b)
np.float64(0.0314159265358977)
b) Illustrer en fonction $n$ la convergence de la méthode des rectangles vers la valeur de l'intégrale.¶
On pourra prendre $f(x) = \sin(x)$ ou $\cos(x)$ sur l'intervalle $[0,\pi]$.
n_grid = range(10, 300, 5) # grille de n pour évaluer l'erreur d'approximation
errors = [] # liste enregistrant les erreurs pour les différents n
f = lambda x: np.sin(x) # on définit la fonction à intégrer
true_int = 2 # vraie valeur de l'intégrale
for n in n_grid: # pour chaque n
a_grid = np.arange(a, b, (b-a)/n) # on crée une grille
f_grid = f(a_grid) # on évalue la fonction sur la grille
err = np.abs(integrale(f_grid, a, b) - true_int) # on calcul l'erreur d'approximation de l'intégrale
errors.append(err) # on enregistre l'erreur dans la liste
plt.plot(n_grid, errors)
[<matplotlib.lines.Line2D at 0x7849dd4e97c0>]
Comme attendu, l'erreur d'approximation décroit quand $n$ augment, c'est à dire au fur et à mesure qu'on raffine la grille de point sur laquelle on évalue $f$.
2) La fonction quad
de scipy.integrate
.¶
Cette fonction permet de calculer l'intégrale d'une fonction $f$ sur un intervalle donné $[a,b]$. Elle utilise des techniques d'intégration numérique bien plus avancée que la simple méthode des rectangles.
Pour utiliser cette fonction on procède de la façon suivante pour une fonction $f$ sur l'intervalle $[0,1]$:
from scipy.integrate import quad # on importe la fonction permettant le calcul d'intégrale
# Définir la fonction à intégrer
f = lambda x: x**2
# Calculer l'intégrale de f(x) entre 0 et 1
result, error = quad(f, 0, 1)
result, error
# result contient une valeur approchée de l'intégrale, et
# error une estimation de l'erreur d'approximation
(0.33333333333333337, 3.700743415417189e-15)
a) Reproduire les résultats de la question 1-a avec la fonction quad
.¶
f = lambda x: np.sin(x) # fonction à intégrer
a, b = 0, np.pi # borne de l'intervalle
result, error = quad(f, a, b) # évalution de la fonction quad
result # contient la valeur approchée de l'intégrale
# error contient une estimation de l'erreur d'approximation
2.0
# même chose pour la fonction cos
f = lambda x: np.cos(x)
a, b = 0, np.pi
result, error = quad(f, a, b)
result
4.9225526349740854e-17
b) Illustrer numériquement la fonction porte.¶
$$ \Pi(t) = \begin{cases} 1 & \text{ si } |t| \leq T/2 \\ 0 & \text{ sinon.} \end{cases} $$
pour $T=4$.
T = 4
Pi = lambda t: 1.*(np.abs(t) < T/2) # définit la fonction porte
t = np.linspace(-2*T, 2*T, 200) # grille de temps pour illustrer la fonction
plt.plot(t,Pi(t))
[<matplotlib.lines.Line2D at 0x7849dd3597f0>]
c) Calculer numériquement sa transformée de Fourier $\mathcal{F}(\Pi)$ (on séparera partie réelle et imaginaire pour l'intégration). Comparer avec sa formule théorique.¶
def T_Fourier(f, s):
f_re_tmp = lambda t: f(t) * np.cos(2*np.pi*s*t)
# définit la partie réelle à intégrer dans la transformée de Fourier
tf_re, _ = quad(f_re_tmp, -10, 10)
# évalue la partie réelle de la transformée de Fourier
# on calcul l'intégrale sur un intervalle suffisament grand
# (même si pour cette exemple ca n'a pas vraiment de sens...)
f_im_tmp = lambda t: f(t) * np.sin(-2*np.pi*s*t)
# définit la partie réelle à intégrer dans la transformée de Fourier
tf_im, _ = quad(f_im_tmp, -10, 10)
# évalue la partie réelle de la transformée de Fourier
return np.array([tf_re, tf_im])
# on ranvoie un tableau numpy contenant
# la partie réelle et la partie imaginaire
# de la transformée de Fourier
freq = np.linspace(-4, 4, 100) # grille de fréquence
TF = np.array([T_Fourier(Pi,s) for s in freq])
# créer un tableau numpy contenant la valeur
# de la transformée de Fourier pour chaque $s$
TF_theorie = T*np.sinc(freq*T)
# Formule théorique de la transformée de Fourier pour la comparaison
/tmp/ipykernel_8010/3583195404.py:6: IntegrationWarning: The integral is probably divergent, or slowly convergent. tf_re, _ = quad(f_re_tmp, -10, 10)
TF
array([[ 7.90117197e-15, 0.00000000e+00], [-6.90132074e-02, 0.00000000e+00], [-7.43030631e-02, 0.00000000e+00], [-8.05234020e-03, 0.00000000e+00], [ 6.88917232e-02, 0.00000000e+00], [ 8.26896107e-02, 0.00000000e+00], [ 1.71373956e-02, 0.00000000e+00], [-6.80851545e-02, 0.00000000e+00], [-9.14856876e-02, 0.00000000e+00], [-2.74016900e-02, 0.00000000e+00], [ 6.64926497e-02, 0.00000000e+00], [ 1.00759514e-01, 0.00000000e+00], [ 3.90402652e-02, 0.00000000e+00], [-6.39867023e-02, 0.00000000e+00], [-1.10611142e-01, 0.00000000e+00], [-5.23186419e-02, 0.00000000e+00], [ 6.04005620e-02, 0.00000000e+00], [ 1.21187354e-01, 0.00000000e+00], [ 6.76073031e-02, 0.00000000e+00], [-5.55081516e-02, 0.00000000e+00], [-1.32705560e-01, 0.00000000e+00], [-8.54379190e-02, 0.00000000e+00], [ 4.89907768e-02, 0.00000000e+00], [ 1.45493807e-01, 0.00000000e+00], [ 1.06599207e-01, 0.00000000e+00], [-4.03793155e-02, 0.00000000e+00], [-1.60061317e-01, 0.00000000e+00], [-1.32309409e-01, 0.00000000e+00], [ 2.89479490e-02, 0.00000000e+00], [ 1.77230820e-01, 0.00000000e+00], [ 1.64547886e-01, 0.00000000e+00], [-1.35044433e-02, 0.00000000e+00], [-1.98406833e-01, 0.00000000e+00], [-2.06748336e-01, 0.00000000e+00], [-8.06316270e-03, 0.00000000e+00], [ 2.26176779e-01, 0.00000000e+00], [ 2.65416119e-01, 0.00000000e+00], [ 3.98926732e-02, 0.00000000e+00], [-2.65852763e-01, 0.00000000e+00], [-3.54517943e-01, 0.00000000e+00], [-9.13496716e-02, 0.00000000e+00], [ 3.30277977e-01, 0.00000000e+00], [ 5.10406429e-01, 0.00000000e+00], [ 1.89096341e-01, 0.00000000e+00], [-4.60362714e-01, 0.00000000e+00], [-8.66442364e-01, 0.00000000e+00], [-4.51228398e-01, 0.00000000e+00], [ 8.93478766e-01, 0.00000000e+00], [ 2.62308213e+00, 0.00000000e+00], [ 3.83034039e+00, 0.00000000e+00], [ 3.83034039e+00, 0.00000000e+00], [ 2.62308213e+00, 0.00000000e+00], [ 8.93478766e-01, 0.00000000e+00], [-4.51228398e-01, 0.00000000e+00], [-8.66442364e-01, 0.00000000e+00], [-4.60362714e-01, 0.00000000e+00], [ 1.89096341e-01, 0.00000000e+00], [ 5.10406429e-01, 0.00000000e+00], [ 3.30277977e-01, 0.00000000e+00], [-9.13496716e-02, 0.00000000e+00], [-3.54517943e-01, 0.00000000e+00], [-2.65852763e-01, 0.00000000e+00], [ 3.98926732e-02, 0.00000000e+00], [ 2.65416119e-01, 0.00000000e+00], [ 2.26176779e-01, 0.00000000e+00], [-8.06316270e-03, 0.00000000e+00], [-2.06748336e-01, 0.00000000e+00], [-1.98406833e-01, 0.00000000e+00], [-1.35044433e-02, 0.00000000e+00], [ 1.64547886e-01, 0.00000000e+00], [ 1.77230820e-01, 0.00000000e+00], [ 2.89479490e-02, 0.00000000e+00], [-1.32309409e-01, 0.00000000e+00], [-1.60061317e-01, 0.00000000e+00], [-4.03793155e-02, 0.00000000e+00], [ 1.06599207e-01, 0.00000000e+00], [ 1.45493807e-01, 0.00000000e+00], [ 4.89907768e-02, 0.00000000e+00], [-8.54379190e-02, 0.00000000e+00], [-1.32705560e-01, 0.00000000e+00], [-5.55081516e-02, 0.00000000e+00], [ 6.76073031e-02, 0.00000000e+00], [ 1.21187354e-01, 0.00000000e+00], [ 6.04005620e-02, 0.00000000e+00], [-5.23186419e-02, 0.00000000e+00], [-1.10611142e-01, 0.00000000e+00], [-6.39867023e-02, 0.00000000e+00], [ 3.90402652e-02, 0.00000000e+00], [ 1.00759514e-01, 0.00000000e+00], [ 6.64926497e-02, 0.00000000e+00], [-2.74016900e-02, 0.00000000e+00], [-9.14856876e-02, 0.00000000e+00], [-6.80851545e-02, 0.00000000e+00], [ 1.71373956e-02, 0.00000000e+00], [ 8.26896107e-02, 0.00000000e+00], [ 6.88917232e-02, 0.00000000e+00], [-8.05234020e-03, 0.00000000e+00], [-7.43030631e-02, 0.00000000e+00], [-6.90132074e-02, 0.00000000e+00], [ 7.90117197e-15, 0.00000000e+00]])
On voit que les parties imaginaires sont nulles, comme attendu.
plt.plot(freq, TF[:,0], label="calcul num")
plt.plot(freq, TF_theorie, label="théorie")
plt.legend()
<matplotlib.legend.Legend at 0x7849d32a8b60>
On ne voit pas la différence entre la formule théorique
d) Essauyer avec d'autres fonctions (comme celles du TD 3 de math 6 - Analyse)¶
On va faire exactement la même chose pour la fonction
$$ f(t) = \begin{cases} e^{-t}&\text{si }t>0 \\ 0&\text{si }t<=0 \end{cases} $$
illustrée ci-dessous, et dont on sait que la transformée de Fourier est (on l'a calculé en TD)
$$ \mathcal{F}f(s) = \frac{1}{1+2i \pi s}\qquad s\in \mathbb{R}. $$
f = lambda t: np.exp(-t)*(t>0)
t = np.linspace(-2, 10, 200)
plt.plot(t,f(t))
[<matplotlib.lines.Line2D at 0x7849d31649b0>]
# évaluation de la transformée de Fourier
freq = np.linspace(-4, 4, 200)
TF = np.array([T_Fourier(f,s) for s in freq])
TF_theorie = (1+2j*np.pi*freq)**(-1)
# Illsutration de la partie imaginaire
# dans la 1ère colonne de TF
plt.plot(freq, TF[:,0], label="calcul num")
plt.plot(freq, TF_theorie.real, label="théorie")
plt.legend()
<matplotlib.legend.Legend at 0x7849d3307350>
# Illsutration de la partie imaginaire
# dans la 1ère colonne de TF
plt.plot(freq, TF[:,1], label="calcul num")
plt.plot(freq, TF_theorie.imag, label="théorie")
plt.legend()
<matplotlib.legend.Legend at 0x7849d31908f0>