Filtre FIR ( Finite Impulse Response )
Commençons par un exemple :
Le programme suivant permet de réaliser un filtre passe bas dont la fréquence de coupure est 2000Hz :
#define FILTER_ORDER 20
float fir(float new_ech)
{
float y = 0.0;
const float h[FILTER_ORDER]={-0.022508, 0.0082564, 0.037841, 0.034578, -0.0082991,
-0.058816, -0.06438, 0.0083248, 0.14181, 0.2714,
0.325,
0.2714, 0.14181, 0.0083248, -0.06438, -0.058816,
-0.0082991, 0.034578, 0.037841, 0.0082564, -0.022508
};
static float x[FILTER_ORDER];
x[FILTER_ORDER - 1] = new_ech;
for( int i = 0 ; i++ ; i < FILTER_ORDER )
{
y = y + h[i]*x[i];
}
// Vieillissement des Echantillons d'Entrée
for( i = 1 ; i++ ; i < FILTER_ORDER )
{
x[i] = x[i-1];
}
return y;
}
Il s’agit d’une opération de multiplication-accumulation ( somme discrète de produits entre coefficients et échantillons ).
Cela correspond à une convolution numérique.
La fréquence d’échantillonage est Fe=8kHz.
L’opération de filtrage est donc à considérer entre 0 et Fe/2 ( Fréquence de Shannon )
Il faut effectuer 21 calculs, l’ordre du filtre est N = 21
La caractéristique fréquentielle idéale du filtre serait donc :
Néanmoins la caractéristique fréquentielle réelle de ce filtre est :
Lien Equation de Récurrence / Transformée de Fourier
Tous les Te, un échantillon d’entrée x est prélevé, et l’opération suivante est effectuée :
autrement dit, à l’instant n, nous calculons l’échantillon de sortie y à partir des N échantillons d’entrée précédents et des coefficients du filtre h
Considérons le cas N=4 :
Passons de cette équation de récurrence à la transformée en z :
avec y(n) de la forme :
et
Rappelons la définition de la transformée en z :
s’agissant d’un filtre, nous nous intéressons au comportement de H en fonction de la fréquence.
Nous nous trouvons donc dans le cas particulier où
Ainsi, la Transformée de Fourier Discrète ( TFD ) de H est :
Revenons au cas idéal, pour lequel le nombre d’échantillons serait infini :
Soit la fréquence normalisée
Calcul de la Transformée de Fourier Discrète Inverse :
Considérons le filtre passe bas ideal :
- pour avec
- pour
La réponse impulsionnelle est donc
Réalisation du Filtre
Problème : cela correspond à une séquence infinie ( donc impossible à réaliser avec une boucle de calculs) .
Il faut donc tronquer n pour avoir une réponse finie ( on ne peut pas réaliser une multiplication-accumulation d’une infinité d’échantillons à chaque période ) .
Pour réaliser le filtre, nous allons multiplier par une fenêtre rectangle.
Cela aura bien sûr comme effet de dégrader l’effet du filtrage, mais c’est une condition nécéssaire pour le réaliser.
En effet La Transformée de fourier d’un produit de signaux temporels correspond à la convolution des tranformées de fourier de chacun des signaux.
avec :
- rect(n) = 1 si
- rect(n) = 0 si
Ex pour N=4:
ATTENTION : il s’agit bien ici d’une multiplication en temporel
Ainsi, dans le cas où N=21, nous retenons 21 coefficients de
Notons qu’en numérique la notion de causalité est relative, étant donné que l’on traite “N échantillons précédents mémorisés”
Influence de l’ordre du filtre
Bien évidemment, en augmentant l’ordre du filtre, les caractéristiques sont meilleures ( pente plus prononcée notamment ).
Attention toutefois, il faut pouvoir réaliser le calcul entre 2 acquisitions d’un échantillon d’entrée.
Influence du type de fenêtre
L’utilisation d’une fenêtre rectangulaire induit le phénomène de gibbs en fréquentiel, ce qui altère la caractéristique.
Il existe d’autres fenêtres pour des caractèristiques meilleures.
- Fenêtre Rectangulaire ( scipy : boxcar ) :
- Fenêtre de Hamming ( scipy : hamming ) :
- Fenêtre de Blackman ( scipy : blackman ) :
from scipy.signal import get_window
import matplotlib.pyplot as plt
N = 1000
r = get_window("boxcar", N+1, fftbins=False)
plt.plot(r, label="boxcar")
h = get_window("hamming", N+1, fftbins=False)
plt.plot(h, label="hamming")
b = get_window("blackman", N+1, fftbins=False)
plt.plot(b, label="blackman")
plt.grid()
plt.xlabel("$n$")
plt.xlim([0, N])
plt.legend()
plt.show()
Considérons un filtre FIR Passe Bas d’ ordre 128, de fréquence de coupure fc=5000Hz, à une fréquence d' échantillonnage fs=44100Hz.
from scipy import signal
import matplotlib.pyplot as plt
import numpy as np
from scipy.signal import freqz, get_window
N = 128
fc = 5000
fs = 44100
n_vect = np.arange(N+1) #0 1 2 3 ...100
# Fenêtre Idéale
# !! dans numpy, sinc(x)=sin(pi.x)(pi.x)
h_d =2*(fc/fs)*np.sinc((2*(fc/fs))*(n_vect-int((N+1)/2)))
# Fenêtre Rectangulaire
f, H = freqz(h_d, fs=fs)
h_dB = 20*np.log10(abs(H))
plt.subplot(211)
plt.plot(f,h_dB, label="rectangle")
h_Phase = np.unwrap(np.arctan2(np.imag(H),np.real(H)))
plt.subplot(212)
plt.plot(f,h_Phase, label="rectangle")
# Fenêtre de Hamming
w = get_window("hamming", N+1, fftbins=False)
h=w*h_d
f, H = freqz(h, fs=fs)
h_dB = 20*np.log10(abs(H))
plt.subplot(211)
plt.plot(f,h_dB, label="Hamming")
h_Phase = np.unwrap(np.arctan2(np.imag(H),np.real(H)))
plt.subplot(212)
plt.plot(f,h_Phase,label="Hamming" )
# Fenêtre de Blackman
w = get_window("blackman", N+1, fftbins=False)
h=w*h_d
f, H = freqz(h, fs=fs)
h_dB = 20*np.log10(abs(H))
plt.subplot(211)
plt.plot(f,h_dB, label="Blackman")
h_Phase = np.unwrap(np.arctan2(np.imag(H),np.real(H)))
plt.subplot(212)
plt.plot(f,h_Phase,label="Blackman" )
# MISE EN FORME DES TRACES
plt.subplot(211)
plt.ylabel("Module $H(e^{j\omega})\ en\ dB$")
plt.xlabel("Frequence [Hz]")
plt.xlim([0, fs/2])
plt.grid()
plt.legend()
plt.subplot(212)
plt.ylabel("Phase $H(e^{j\omega})\ en\ rad$")
plt.xlabel("Frequence [Hz]")
plt.xlim([0, fs/2])
plt.grid()
plt.legend()
plt.show()
#=========================================================
REMARQUE : Le Filtre FIR a une Phase Linéaire, ainsi le filtre fir ne provoque pas de distorsion de phase.