Synthèse d'un filtre passe-bande
Ce tutorial montre le process complet pour synthétiser un filtre d'ordre N à partir d'un cahier des charges. La méthodologie décrite ici est applicable à n'importe quel filtre.
Cahier des charges
- Type de filtre: passe-bande,
- Technique de synthèse: Butterworth,
- Bande passante :
rad/s, - Bande rejetée :
rad/s, - Atténuation maximale dans la bande passante:
dB, - Atténuation minimale dans la bande rejetée:
dB.
Code
Dans ce tutorial, nous utiliserons un fichier tools.py avec le code suivant :
import matplotlib.pyplot as plt
def plot_pzmap(ax, z, p):
ax.plot(p.real,p.imag,'x')
ax.plot(z.real,z.imag,'o')
ax.set_xlabel("Re (.)")
ax.set_ylabel("Im (.)")
ax.axis("equal")
ax.grid()
def plot_prototype(ax, type, wc, Tc, ws, Ts):
xmin, xmax = ax.get_xlim()
ymin, ymax = ax.get_ylim()
if type == "LP":
polygon_data1 = [[xmin,Tc], [wc,Tc], [wc,ymin], [xmin,ymin]]
polygon_data2 = [[xmin,ymax], [xmin,1], [ws,1], [ws,Ts], [xmax,Ts], [xmax,ymax], [xmin,ymax]]
if type == "BP":
polygon_data1 = [[wc[0], ymin], [wc[0],Tc], [wc[1],Tc], [wc[1],ymin], [wc[0], ymin]]
polygon_data2 = [[xmin,Ts], [ws[0],Ts], [ws[0],1], [ws[1],1], [ws[1],Ts], [xmax,Ts], [xmax,ymax], [xmin,ymax], [xmin,Ts]]
options = {"fill": False,"closed": True,"color": 'b',"hatch": "/"}
patch1 = plt.Polygon(polygon_data1,**options)
patch2 = plt.Polygon(polygon_data2,**options)
ax.add_patch(patch1)
ax.add_patch(patch2)
ax.set_xscale('log')
ax.set_yscale('log')
ax.set_xlabel("pulsation (rad/s)")
ax.set_ylabel("module")Détermination du Gabarit Normalisé
Dans un premier temps, nous allons revenir à la conception d'un filtre passe-bas normalisé (
Application Numérique
- Bande passante:
rad/s. - Pulsation centrale :
rad/s. - Valeur du module en
rad/s: , - Valeur du module en
rad/s: .
En utilisant la formule, nous obtenons :
Représentation du Gabarit
Code
import matplotlib.pyplot as plt
from tools import plot_prototype
fig, axs = plt.subplots(1, 2, figsize=(10, 4))
# Bandpass filter
ax0 = axs[0]
ax0.set_xlim([100, 10000])
ax0.set_ylim([0.001, 2])
ax0.set_title("filtre BP")
wc = [900, 1111]
ws = [500, 2000]
Tc = 0.707
Ts = 0.01
plot_prototype(ax0, "BP", wc, Tc, ws, Ts)
# Normalized Lowpass filter
ax1 = axs[1]
ax1.set_xlim([0.1, 100])
ax1.set_ylim([0.001, 2])
ax1.set_title("filtre LP normalisé")
wc_norm = 1
ws_norm = 7.11
plot_prototype(ax1, "LP", wc_norm, Tc, ws_norm, Ts)
fig.tight_layout()
plt.show()Courbes

Détermination de l'ordre
Il est possible de déterminer l'ordre du filtre passe-bas normalisé en utilisant le comportement asymptotique :
Synthèse du Filtre Normalisé
Pour synthétiser le filtre, nous allons utiliser la technique de synthèse de Butterworth. La fonction de transfert du filtre normalisé peut s'exprimer sous la forme factorisée suivante (zpk):
Il est possible d'obtenir les pôles
z,p,k = butter(3, 1, "low", analog=True, output="zpk")Nous obtenons les paramètres suivants:
- zéros:
, - pôles:
, - gain:
Dénormalisation du Filtre
Pour dénormaliser le filtre, nous allons opérer un mapping des pôles et zéros. Dans le cas d'un passe-bande, le mapping des pôles est donné par :
rad/s désigne la moitié de la bande passante, correspond aux pôles du filtre normalisé, correspond aux pôles du filtre dénormalisé.
Après dénormalisation, nous obtenons un filtre d'ordre
Application Numérique
Après dénormalisation, nous obtenons un filtre d'ordre 6 avec les paramètres suivants :
zéros: 3 zéros en 0 (filtre passe-bande d'ordre 6)
,
pôles: 3 paires de pôles complexes-conjugués
et , et et ,
gain
:

Vérification
Pour vérifier que le filtre dénormalisé respecte bien les contraintes du cahier des charges, une solution naturelle consiste à afficher la réponse fréquentielle du filtre dénormalisé.
Code
import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import lti, butter
from tools import plot_prototype
k2 = 9393931
z2 = [0.+0.j, 0.+0.j, 0.+0.j]
p2 = [ -47.943-911.374j, -105.5-994.369j, -47.943 +911.374j, -57.556+1094.106j, -105.5 +994.369j, -57.556-1094.106j]
H = lti(z2, p2, k2)
w, Hjw = H.freqresp()
fig = plt.figure()
w, Hjw = H.freqresp()
plt.loglog(w, np.abs(Hjw))
plt.xlabel("pulsation (rad/s)")
plt.ylabel("module")
ax = plt.gca()
wc = [900, 1111]
ws = [500, 2000]
Tc = 0.707
Ts = 0.01
ax.set_xlim([100, 10000])
ax.set_ylim([0.001, 2])
plot_prototype(ax, "BP", wc, Tc, ws, Ts)
fig.tight_layout()
plt.show()Résultat

