Cours:Elen4 TNS TP Implementations : Différence entre versions
| (12 révisions intermédiaires par le même utilisateur non affichées) | |||
| Ligne 23 : | Ligne 23 : | ||
Il s'agit de traiter le signal '''après''' son acquisition. | Il s'agit de traiter le signal '''après''' son acquisition. | ||
| − | Dans ''' | + | Dans '''Python''', Vous travaillerez avec le signal ''X<sub>1</sub>'' créé par le code suivant : |
| − | <source lang= | + | <source lang=python> |
| − | N = 1 | + | N = np.arange(1, 201) |
| − | X1 = sin(N/10) + randn( | + | X1 = np.sin(N / 10) + np.random.randn(len(N)) / 3 |
</source> | </source> | ||
===== Avec <code>filter</code> ===== | ===== Avec <code>filter</code> ===== | ||
| − | Il est évidemment possible de demander à | + | Il est évidemment possible de demander à Python de réaliser directement le filtrage, en utilisant la fonction <code>y = scipy.signal.lfilter(b,a,x)</code> qui traite le signal <code>x</code> avec le filtre défini par ses coefficients de sa fonction de transfert (<code>b</code> pour numérateur et <code>a</code> pour le dénominateur). |
| − | Voir la documentation (https:// | + | Voir la documentation (https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.lfilter.html#scipy.signal.lfilter) pour le détail. |
Cependant, pour éviter l'effet "boite noire", nous allons voir comment implémenter nous même un filtre. | Cependant, pour éviter l'effet "boite noire", nous allons voir comment implémenter nous même un filtre. | ||
| Ligne 38 : | Ligne 38 : | ||
===== Avec le produit de convolution ===== | ===== Avec le produit de convolution ===== | ||
| − | Avec le produit de convolution, Il s'agit d'une implémentation hors-ligne dans le domaine temporel. On nommera '' | + | Avec le produit de convolution, Il s'agit d'une implémentation hors-ligne dans le domaine temporel. On nommera ''Y<sub>c</sub>'' le signal de sortie obtenue avec cette implémentation. |
| − | a) Appliquez à '' | + | a) Appliquez à ''X<sub>1</sub>'' le filtre RIF dont la fonction de transfert est ''H(z)'' |
| − | par un produit de convolution (fonction <code> | + | par un produit de convolution (fonction <code>scipy.signal.convolve()</code>) avec la réponse impusionnelle ''h'' du filtre : |
<center> | <center> | ||
| − | + | Y<sub>c</sub> = X<sub>1</sub> ∗ h. | |
</center> | </center> | ||
| − | b) Tracer le graphe de l'entrée '' | + | b) Tracer le graphe de l'entrée ''X<sub>1</sub>'' et de la sortie ''Y<sub>c</sub>'' obtenue : |
| − | < | ||
| − | |||
| − | |||
| − | |||
| − | </ | ||
===== Avec la réponse fréquentielle ===== | ===== Avec la réponse fréquentielle ===== | ||
| − | Avec la réponse fréquentielle, il s'agit d'une implémentation hors-ligne dans le domaine fréquentiel. On nommera '' | + | Avec la réponse fréquentielle, il s'agit d'une implémentation hors-ligne dans le domaine fréquentiel. On nommera ''Y<sub>f''</sub> le signal de sortie obtenue avec cette implémentation. |
| + | |||
| + | a) En exploitant le théorème de la convolution (le produit de convolution se transforme en produit simple fréquences à fréquences), filtrer le signal ''X<sub>1</sub>''. Voir les documentations de : | ||
| + | * [https://numpy.org/doc/stable/reference/generated/numpy.fft.fft.html <code>numpy.fft.fft</code>] | ||
| + | * et [https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.fftconvolve.html#scipy.signal.fftconvolve <code>scipy.signal.fftconvolve</code>] pour valider votre implémentation. | ||
| − | |||
<center> | <center> | ||
| Ligne 65 : | Ligne 63 : | ||
</center> | </center> | ||
| − | b) Tracer le spectre d’amplitude de '' | + | b) Tracer le spectre d’amplitude de ''X<sub>1</sub>'', la réponse fréquentielle de ''H'' et le spectre d’amplitude de la sortie ''Y<sub>f</sub>''. |
===== Comparaison des implémentations ===== | ===== Comparaison des implémentations ===== | ||
| Ligne 71 : | Ligne 69 : | ||
Vérifier que le filtrage dans le domaine fréquentiel fourni une sortie identique à celle obtenue avec le produit de convolution. Vous pourrez faire | Vérifier que le filtrage dans le domaine fréquentiel fourni une sortie identique à celle obtenue avec le produit de convolution. Vous pourrez faire | ||
| − | a) une vérification graphique en affichant les signaux '' | + | a) une vérification graphique en affichant les signaux ''Y<sub>c</sub>'' et ''Y<sub>f</sub>'' |
| − | b) ainsi qu'une vérification quantifiée en calculant une norme entre les deux signaux '' | + | b) ainsi qu'une vérification quantifiée en calculant une norme entre les deux signaux ''Y''. |
| − | |||
=== Implémentation en ligne === | === Implémentation en ligne === | ||
| Ligne 82 : | Ligne 79 : | ||
===== Avec un bloc <code>FIR filter</code> ===== | ===== Avec un bloc <code>FIR filter</code> ===== | ||
| − | Comme pour | + | Comme pour Python, il est possible d'utiliser un bloc implémentant directement un filtre FIR (''Finite Impulse Response''), il s'agit du bloc <code>Frequency Xlating FIR filter</code>. |
Vous pourrez consulter la page [https://wiki.gnuradio.org/index.php/Designing_Filter_Taps Designing Filter Taps], en particulier la section ''Entering Filter Taps Manually''. | Vous pourrez consulter la page [https://wiki.gnuradio.org/index.php/Designing_Filter_Taps Designing Filter Taps], en particulier la section ''Entering Filter Taps Manually''. | ||
| Ligne 91 : | Ligne 88 : | ||
b) Donner le schéma-bloc équivalent à cette équation aux différences. | b) Donner le schéma-bloc équivalent à cette équation aux différences. | ||
| − | |||
c) Dans GnuRadio, produire un schéma qui implémente ce filtre. | c) Dans GnuRadio, produire un schéma qui implémente ce filtre. | ||
| Ligne 97 : | Ligne 93 : | ||
* Le bruit sera obtenu par un bloc <code>Noise Source</code> | * Le bruit sera obtenu par un bloc <code>Noise Source</code> | ||
* Vous implémenterez le système à l'aide de <code>Add</code> pour les additionneurs, de <code>Delay</code> pour les retards et de <code>Multiply Const</code> pour les gains | * Vous implémenterez le système à l'aide de <code>Add</code> pour les additionneurs, de <code>Delay</code> pour les retards et de <code>Multiply Const</code> pour les gains | ||
| − | * Vous afficherez les graphes de ''x<sub>1</sub>'' et de la sortie ''y'' avec 200 points (comme pour les implémentations dans | + | * Vous afficherez les graphes de ''x<sub>1</sub>'' et de la sortie ''y'' avec 200 points (comme pour les implémentations dans Python) |
| − | c) Afin de comparer l'implémentation GnuRadio aux implémentation | + | c) Afin de comparer l'implémentation GnuRadio aux implémentation Python, il est nécessaire de travailler sur le même signal : |
| − | * Dans | + | * Dans Python : écrire les valeurs du signal <code>X1</code> dans un fichier : |
| − | <source lang= | + | <source lang=python> |
| − | + | with open("x.raw", "wb") as f: | |
| − | + | X1.tofile(f) | |
| − | |||
</source> | </source> | ||
* Dans Gnuradio : utiliser les valeurs du fichier <code>x.raw</code> à l'aide d'un bloc <code>File Source</code> (attention à bien préciser une longueur de 200, des valeurs en 'float' et une non-répétition de la lecture). | * Dans Gnuradio : utiliser les valeurs du fichier <code>x.raw</code> à l'aide d'un bloc <code>File Source</code> (attention à bien préciser une longueur de 200, des valeurs en 'float' et une non-répétition de la lecture). | ||
| − | * Vous pourrez ensuite utiliser un bloc <code>File Sink</code> ([https://wiki.gnuradio.org/index.php?title=File_Sink File Sink]) pour écrire les valeurs de ''y'' dans un fichier, pour les relire dans | + | * Vous pourrez ensuite utiliser un bloc <code>File Sink</code> ([https://wiki.gnuradio.org/index.php?title=File_Sink File Sink]) pour écrire les valeurs de ''y'' dans un fichier, pour les relire dans Python afin de les comparer aux résultats précédents. Pour la lecture dans Python : |
| + | <source lang=python> | ||
| + | with open("data.bin", "rb") as f: | ||
| + | y = np.fromfile(f, dtype=np.float64) | ||
| + | </source> | ||
| + | |||
| + | Notes : | ||
| + | * attention au type des données dans les tableaux numpy et des signaux dans gnuradio (https://wiki.gnuradio.org/index.php?title=Signal_Data_Types). Au besoin convertir (dans Python) : <code>X1 = X1.astype(np.float32)</code> | ||
===== En écrivant du code ===== | ===== En écrivant du code ===== | ||
Version actuelle datée du 17 mai 2026 à 08:12
TP3 : Implémentation des filtres numériques
Le travail de ce TP va consister à filtrer des signaux numériques avec divers filtres RIF, en exploitant trois implémentations différentes à partir du produit de convolution, de la réponse fréquentielle et de l'équation aux différences.
L'objectif est de filtrer le signal
x1(n) = sin(n/10) + b(n)
b(t) étant du bruit gaussien.
Le filtre sera défini par sa fonction de transfert
| H(z) = |
1 + 2z-1 + z-2 |
| | |
|
4 |
Sommaire
Implémentation hors-ligne
Il s'agit de traiter le signal après son acquisition.
Dans Python, Vous travaillerez avec le signal X1 créé par le code suivant :
N = np.arange(1, 201)
X1 = np.sin(N / 10) + np.random.randn(len(N)) / 3
Avec filter
Il est évidemment possible de demander à Python de réaliser directement le filtrage, en utilisant la fonction y = scipy.signal.lfilter(b,a,x) qui traite le signal x avec le filtre défini par ses coefficients de sa fonction de transfert (b pour numérateur et a pour le dénominateur).
Voir la documentation (https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.lfilter.html#scipy.signal.lfilter) pour le détail.
Cependant, pour éviter l'effet "boite noire", nous allons voir comment implémenter nous même un filtre.
Avec le produit de convolution
Avec le produit de convolution, Il s'agit d'une implémentation hors-ligne dans le domaine temporel. On nommera Yc le signal de sortie obtenue avec cette implémentation.
a) Appliquez à X1 le filtre RIF dont la fonction de transfert est H(z)
par un produit de convolution (fonction scipy.signal.convolve()) avec la réponse impusionnelle h du filtre :
Yc = X1 ∗ h.
b) Tracer le graphe de l'entrée X1 et de la sortie Yc obtenue :
Avec la réponse fréquentielle
Avec la réponse fréquentielle, il s'agit d'une implémentation hors-ligne dans le domaine fréquentiel. On nommera Yf le signal de sortie obtenue avec cette implémentation.
a) En exploitant le théorème de la convolution (le produit de convolution se transforme en produit simple fréquences à fréquences), filtrer le signal X1. Voir les documentations de :
-
numpy.fft.fft - et
scipy.signal.fftconvolvepour valider votre implémentation.
Fig : principe du filtrage dans le domaine fréquentiel.
b) Tracer le spectre d’amplitude de X1, la réponse fréquentielle de H et le spectre d’amplitude de la sortie Yf.
Comparaison des implémentations
Vérifier que le filtrage dans le domaine fréquentiel fourni une sortie identique à celle obtenue avec le produit de convolution. Vous pourrez faire
a) une vérification graphique en affichant les signaux Yc et Yf
b) ainsi qu'une vérification quantifiée en calculant une norme entre les deux signaux Y.
Implémentation en ligne
Une implémentation en ligne permet de traiter le signal pendant ou au cours de son acquisition. Il s'agit de calculer à la volée les valeurs du signal de sortie. Il faut pour cela s'appuyer sur l'équation au différence, qui permet d'exprimer y(n).
Avec un bloc FIR filter
Comme pour Python, il est possible d'utiliser un bloc implémentant directement un filtre FIR (Finite Impulse Response), il s'agit du bloc Frequency Xlating FIR filter.
Vous pourrez consulter la page Designing Filter Taps, en particulier la section Entering Filter Taps Manually.
À partir du schéma-bloc
a) Établir l'équation aux différence du filtre H
b) Donner le schéma-bloc équivalent à cette équation aux différences.
c) Dans GnuRadio, produire un schéma qui implémente ce filtre.
- La source sera un bloc
Signal Sourcesinus. La fréquence du sinus sera obtenue à partir de la fréquence d'échantillonnagesamp_rateet de la définition x(n)=sin(n/10). On rappelle que sin(wt) est un sinus de pulsation w. - Le bruit sera obtenu par un bloc
Noise Source - Vous implémenterez le système à l'aide de
Addpour les additionneurs, deDelaypour les retards et deMultiply Constpour les gains - Vous afficherez les graphes de x1 et de la sortie y avec 200 points (comme pour les implémentations dans Python)
c) Afin de comparer l'implémentation GnuRadio aux implémentation Python, il est nécessaire de travailler sur le même signal :
- Dans Python : écrire les valeurs du signal
X1dans un fichier :
with open("x.raw", "wb") as f:
X1.tofile(f)
- Dans Gnuradio : utiliser les valeurs du fichier
x.rawà l'aide d'un blocFile Source(attention à bien préciser une longueur de 200, des valeurs en 'float' et une non-répétition de la lecture). - Vous pourrez ensuite utiliser un bloc
File Sink(File Sink) pour écrire les valeurs de y dans un fichier, pour les relire dans Python afin de les comparer aux résultats précédents. Pour la lecture dans Python :
with open("data.bin", "rb") as f:
y = np.fromfile(f, dtype=np.float64)
Notes :
- attention au type des données dans les tableaux numpy et des signaux dans gnuradio (https://wiki.gnuradio.org/index.php?title=Signal_Data_Types). Au besoin convertir (dans Python) :
X1 = X1.astype(np.float32)
En écrivant du code
Dans ce cas, le travail consiste à calculer y(n) à partir de la valeur x(n) et de ses versions précédentes x(n-1) et x(n-2) qu'il est nécessaire de stocker.
Ceci sera mis en place dans un TP ultérieur (Implémentations temps-réel)
Comparaison
Discuter de l’intérêt de chacune des implémentations (convolution, en fréquence, et avec l’équation aux différences), en termes de complexité de calcul et contrainte d'utilisation (en ligne / hors ligne).