🖥️ Simulation de la propagation d’un paquet d’onde dans un plasma ★

Notebook Capytale de cet exercice : b8f7-11678470

On s’intéresse à la propagation d’un paquet d’onde 𝑠(𝑥,𝑡) dans un milieu pouvant être dispersif.

Le paquet d’onde est connu en 𝑥=0 :

𝑠(0,𝑡)=𝑓(𝑡,0,Δ𝑡)cos(𝜔𝑡)

où 𝑓(𝑡,0,Δ𝑡) est la fonction gaussienne centrée en 0 et d’extension temporelle Δ𝑡. La porteuse a pour fréquence 2⁠ ⁠Hz.

Pour déterminer comment le paquet d’onde se propage, on le décompose grâce au théorème de Fourier et on étudie la propagation de chaque signal monochromatique composant le paquet d’onde.

1/ Compléter le code ci-dessous pour définir s_x0 avec 𝑠(0,𝑡).

  import numpy as np

  Deltat = 0.4 # extension temporelle (s)
  t = np.linspace(-2,10,1000) # temps pour lesquels on calcule s (s)

  def gaussienne(x, mu, sig): # Définition d'une gaussienne de x. sig est l'écart-type et mu la position du centre.
      return 1. / (np.sqrt(2. * np.pi) * sig) * np.exp(-np.power((x - mu) / sig, 2.) / 2)

  s_x0 = ... # onde s en x=0
Corrigé
s_x0 = np.cos(2*np.pi*2*t)*gaussienne(t,0,Deltat) # onde s en x=0

2/ Tracer l’onde en 𝑥=0 en fonction de 𝑡.

Corrigé
import matplotlib.pyplot as plt

plt.figure(1)
plt.clf()
plt.plot(t,s_x0)
plt.xlabel("temps (s)")
plt.title("Signal en x=0")
plt.show()

La décomposition spectrale consiste à décomposer un signal comme une somme de signaux monochromatiques

𝑠(𝑥=0,𝑡)=∑𝑖𝐴𝑖𝑒𝑗𝜔𝑖𝑡

On peut calculer le spectre du paquet d’onde pour obtenir la liste des 𝐴𝑖 grâce à la fonction rfft.

3/ Calculer le spectre de 𝑠(𝑥=0,𝑡) et tracer |𝐴| en fonction de la fréquence en complétant le code ci-dessous.

from numpy.fft import rfft, irfft, rfftfreq

frequences = rfftfreq(len(t), t[1]-t[0]) # calcul des fréquences de la transformée de Fourier (Hz)
pulsations = ... # pulsations (rad/s)
spectre_x0 = ... # spectre de s(x=0,t) (c'est-à-dire liste des A_i)

plt.figure()
plt.clf()
plt.plot(...)
plt.xlabel(...)
plt.title("spectre de s en x=0")
plt.show()
Corrigé
from numpy.fft import rfft, irfft, rfftfreq

frequences = rfftfreq(len(t), t[1]-t[0]) # calcul des fréquences de la transformée de Fourier (Hz)
pulsations = 2*np.pi*frequences # pulsations (rad/s)
spectre_x0 = rfft(s_x0) # spectre de s(x=0,t) (c'est-à-dire liste des A_i)

plt.figure()
plt.clf()
plt.plot(frequences, np.abs(spectre_x0))
plt.xlabel("fréquence (Hz)")
plt.title("spectre de s en x=0")
plt.show()

4/ En faisant varier Deltat, quel est l’effet de l’extension temporelle du paquet d’onde sur son spectre ?

On utilisera Deltat = 0.4 dans toute la suite.

Corrigé
Plus l’extension temporelle du paquet d’onde est grande, plus son spectre est concentré autour de la pulsation centrale. Inversement, plus l’extension temporelle est petite, plus le spectre est large et contient des fréquences éloignées de la pulsation centrale.

5/ Si une OPPH s’écrit 𝐴𝑖𝑒𝑗𝜔𝑖𝑡 en 𝑥=0, comment s’écrit-elle après avoir parcouru une distance 𝑥 dans le milieu ?

Coup de pouce 1
Comment s’écrit de manière générale une OPPH ?
Corrigé

Après avoir parcouru une distance 𝑥 dans le milieu, l’onde monochromatique s’écrit

𝐴𝑖𝑒𝑗(𝜔𝑖𝑡−𝑘𝑖𝑥)=𝐴𝑖𝑒𝑗𝜔𝑖𝑡𝑒−𝑗𝑘𝑖𝑥

La fonction irfft permet de réaliser l’opération inverse à la transformée de Fourier : elle calcule le signal à partir de son spectre.

6/ Compléter le code ci-dessous.

j = 1j
c = 1

def rd(omega): # relation de dispersion : calcule k(omega) et le renvoie
    c = 1 # célérité
    ##########################
    # D'Alembert
    # return ...
    ##########################
    # Plasma
    omega_p = 2*np.pi # pulsation plasma
    if omega > omega_p:
        return ...
    else:
        return 0 # pour des raisons de stabilité dépassant le programme, on laisse 0 pour ce cas-ci
    #########################

x = 3 # position où calculer l'onde
k = np.array(...) # nombres d'onde calculés grâce à la relation de dispersion
spectre_x = ... # spectre de s en x
s_x = ... # calcul de s(x,t) à l'abscisse x
Corrigé
j = 1j

c = 1

def rd(omega): # relation de dispersion : calcule k(omega) et le renvoie
    c = 1 # célérité
    ##########################
    # D'Alembert
    # return omega/c
    ##########################
    # Plasma
    omega_p = 2*np.pi # pulsation plasma
    if omega > omega_p:
        return omega/c*np.sqrt(1-omega_p**2/omega**2)
    else:
        return 0 # pour des raisons de stabilité dépassant le programme, on laisse 0 pour ce cas-ci
    #########################

x = 3 # position où calculer l'onde
k = np.array([rd(omega) for omega in pulsations]) # nombres d'onde calculés grâce à la relation de dispersion
spectre_x = spectre_x0 * np.exp(-j*k*x) # spectre de s en x
s_x = irfft(spectre_x) # calcul de s(x,t) à l'abscisse x

7/ Tracer l’onde après propagation sur une longueur 𝑥=3 m pour une onde vérifiant l’équation de d’Alembert puis dans un plasma. Vérifier l’existence d’un étalement du paquet d’onde pour l’onde dans un plasma. Est-ce que les hautes fréquences ou les basses fréquences se propagent plus vite ?

Corrigé
plt.figure(3)
plt.clf()
plt.plot(t,s_x)
plt.xlabel("temps (s)")
plt.title(f"Signal en x={x} m")
plt.show()

Le paquet d’onde est plus large en 𝑥 qu’en 𝑥=0.

On observe que les hautes fréquences arrivent plus vite que les basses fréquences : à une abscisse fixée, elles sont là plus tôt. C’est bien ce qu’annonce la vitesse de groupe 𝑣𝑔=𝑐1−𝜔𝑝2𝜔2, qui croît avec 𝜔.

On souhaite maintenant visualiser la propagation de l’onde en traçant 𝑠(𝑥,𝑡) en fonction de 𝑥 à 𝑡 fixé. Pour cela, il faut calculer 𝑠 pour un grand nombre de 𝑥 en utilisant la même méthode que précédemment.

8/ Compléter le code ci-dessous puis tracer 𝑠(𝑥,𝑡) en fonction de 𝑥 pour différents temps de sorte à visualiser la propagation de l’onde. Quelles fréquences sont plus rapides (hautes ou basses) ? Est-ce cohérent avec votre réponse précédente ?

x = np.linspace(-3,6,1000) # abscisses auxquelles l'onde sera calculée

s = np.zeros((len(x),len(t))) # s est un array à 2 dimensions dont les lignes correspondent à une position et les colonnes à un instant

for i in range(len(x)):
    s[i,:] = ...
    
    
plt.figure(4)
plt.clf()
i = 500 # à changer pour changer l'instant auquel l'onde est tracée
plt.plot(x,s[:,i])
plt.xlabel(...)
plt.title(f"signal à t={t[i]} s")
plt.show()
Corrigé
x = np.linspace(-3,6,1000) # abscisses auxquelles l'onde sera calculée

s = np.zeros((len(x),len(t))) # s est un array à 2 dimensions dont les lignes correspondent à une position et les colonnes à un instant

for i in range(len(x)):
    s[i,:] = irfft(spectre_x0 * np.exp(-j*k*x[i]))
    
    
plt.figure(4)
plt.clf()
i = 500 # à changer pour changer l'instant auquel l'onde est tracée
plt.plot(x,s[:,i])
plt.xlabel("position (m)")
plt.title(f"signal à t={t[i]} s")
plt.show()

On remarque qu’à 𝑡 fixé, les hautes fréquences sont à une abscisse plus grande : elles se sont propagées plus vite que les basses fréquences, ce qui confirme la réponse précédente.

Afin de visualiser la propagation de l’onde d’une façon plus commode, on peut animer l’évolution de l’onde.

import matplotlib.animation as animation

fig = plt.figure(5) # initialise la figure
plt.clf()
line, = plt.plot(x, s[:,0])

def animate(i):
    line.set_data(x, s[:,i])
    return line,

ani = animation.FuncAnimation(fig, animate, frames=1000, interval=10, blit=True, repeat=False)
plt.show()