Python Cheatsheet
TIP
Ce guide de référence présente les fonctions Python essentielles pour l'analyse des systèmes SLIT (Systèmes Linéaires Invariants dans le Temps). Il utilise principalement les bibliothèques scipy.signal et matplotlib.
Installation et Imports
Bibliothèques requises
pip install numpy scipy matplotlibImports standards
import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import lti
import scipy.signal as sigCréation de Fonctions de Transfert
Forme polynomiale [ba]
La fonction de transfert est définie par les coefficients des polynômes du numérateur et du dénominateur :
from scipy.signal import lti
# Coefficients par ordre décroissant de s
num = [b_m, ..., b1, b0] # Numérateur
den = [a_n, ..., a1, a0] # Dénominateur
H = lti(num, den)Exemple : Filtre RC passe-bas
from scipy.signal import lti
tau = 1e-3 # Constante de temps en secondes
H = lti([1], [tau, 1])Exemple : Système du second ordre
from scipy.signal import lti
K = 1 # Gain statique
omega0 = 1000 # Pulsation propre [rad/s]
m = 0.5 # Coefficient d'amortissement
num = [K * omega0**2]
den = [1, 2*m*omega0, omega0**2]
H = lti(num, den)Forme pôles-zéros-gain [zpk]
La fonction de transfert est définie par ses zéros, pôles et gain :
from scipy.signal import lti
zeros = [z1, z2, ...] # Liste des zéros
poles = [p1, p2, ...] # Liste des pôles
gain = K # Gain
H = lti(zeros, poles, gain)Exemple
from scipy.signal import lti
zeros = [] # Pas de zéros
poles = [-100, -500+500j, -500-500j] # 3 pôles
gain = 1e8
H = lti(zeros, poles, gain)
# Accès aux propriétés
print(f"Pôles: {H.poles}")
print(f"Zéros: {H.zeros}")Analyse Temporelle
Réponse indicielle
La réponse indicielle correspond à la sortie du système lorsque l'entrée est un échelon unitaire.
from scipy.signal import lti
import matplotlib.pyplot as plt
H = lti([1], [1e-3, 1]) # Exemple: premier ordre
# Calcul de la réponse (t et y sont générés automatiquement)
t, y = H.step()
# Avec un vecteur temps personnalisé
import numpy as np
t_custom = np.linspace(0, 5e-3, 1000)
t, y = H.step(T=t_custom)
# Tracé
plt.figure()
plt.plot(t, y)
plt.xlabel('Temps [s]')
plt.ylabel('Amplitude')
plt.title('Réponse indicielle')
plt.grid()
plt.show()Réponse impulsionnelle
La réponse impulsionnelle correspond à la sortie du système lorsque l'entrée est une impulsion de Dirac.
t, y = H.impulse()
plt.figure()
plt.plot(t, y)
plt.xlabel('Temps [s]')
plt.ylabel('Amplitude')
plt.title('Réponse impulsionnelle')
plt.grid()
plt.show()Analyse Fréquentielle
Réponse fréquentielle
La réponse fréquentielle
from scipy.signal import lti
import numpy as np
H = lti([1], [1e-3, 1])
# Calcul (w et Hjw sont générés automatiquement)
w, Hjw = H.freqresp()
# Avec un vecteur de pulsations personnalisé
w_custom = np.logspace(1, 6, 500) # de 10 à 1e6 rad/s
w, Hjw = H.freqresp(w=w_custom)
# Extraction du module et de l'argument
H_module = np.abs(Hjw)
H_phase_deg = np.angle(Hjw) * 180 / np.pi
H_module_dB = 20 * np.log10(H_module)Diagramme de Bode
from scipy.signal import lti
import matplotlib.pyplot as plt
import numpy as np
H = lti([1], [1e-3, 1])
w, Hjw = H.freqresp()
H_module = np.abs(Hjw)
H_phase = np.angle(Hjw) * 180 / np.pi
fig, axs = plt.subplots(2, 1, figsize=(8, 6), sharex=True)
# Module
axs[0].loglog(w, H_module)
axs[0].set_ylabel('Module $|H(j\\omega)|$')
axs[0].set_title('Diagramme de Bode')
axs[0].grid(which='both')
# Phase
axs[1].semilogx(w, H_phase)
axs[1].set_xlabel('Pulsation $\\omega$ [rad/s]')
axs[1].set_ylabel('Phase [deg]')
axs[1].grid(which='both')
plt.tight_layout()
plt.show()TIP
Pour afficher le module en dB, remplacer loglog par semilogx et tracer 20*np.log10(H_module).
Diagramme des pôles et zéros
import matplotlib.pyplot as plt
H = lti([1], [1e-3, 1])
# Récupération des pôles et zéros
poles = H.poles
zeros = H.zeros
# Tracé
plt.figure()
plt.plot(poles.real, poles.imag, 'rx', markersize=10, label='Pôles')
if len(zeros) > 0:
plt.plot(zeros.real, zeros.imag, 'bo', markersize=8, label='Zéros')
plt.axhline(y=0, color='k', linewidth=0.5)
plt.axvline(x=0, color='k', linewidth=0.5)
plt.xlabel('Partie réelle')
plt.ylabel('Partie imaginaire')
plt.title('Diagramme des pôles et zéros')
plt.legend()
plt.grid()
plt.axis('equal')
plt.show()Fonctions Utilitaires
Conversion dB / linéaire
def dB_to_lin(x_dB):
"""Convertit une valeur en dB vers une valeur linéaire."""
return 10**(x_dB / 20)
def lin_to_dB(x_lin):
"""Convertit une valeur linéaire vers une valeur en dB."""
return 20 * np.log10(x_lin)Exemple
# -3 dB correspond à 1/sqrt(2) ≈ 0.707
print(f"-3 dB = {dB_to_lin(-3):.3f}") # Affiche: -3 dB = 0.708
# 0.1 correspond à -20 dB
print(f"0.1 = {lin_to_dB(0.1):.1f} dB") # Affiche: 0.1 = -20.0 dBMise en série de fonctions de transfert
Lorsque deux systèmes sont en série, la fonction de transfert globale est le produit des fonctions de transfert individuelles :
import numpy as np
import scipy.signal as sig
def series(H_list):
"""
Combine plusieurs systèmes LTI en série.
Parameters
----------
H_list : list
Liste d'objets scipy.signal.lti
Returns
-------
scipy.signal.lti
Système résultant de la mise en série
"""
num = [1]
den = [1]
for H in H_list:
num = np.polymul(num, H.num)
den = np.polymul(den, H.den)
return sig.lti(num, den)Exemple
from scipy.signal import lti
# Deux filtres RC en série
H1 = lti([1], [1e-3, 1])
H2 = lti([1], [1e-4, 1])
H_total = series([H1, H2])
print(f"Pôles du système en série: {H_total.poles}")Synthèse de Filtres Analogiques
Filtres standards
import scipy.signal as sig
# Paramètres communs
N = 3 # Ordre du filtre
Wn = 1000 # Pulsation de coupure [rad/s]
# Butterworth (réponse maximalement plate)
b, a = sig.butter(N, Wn, btype='low', analog=True)
# Chebyshev Type I (ondulations en bande passante)
rp = 1 # Ondulation max en bande passante [dB]
b, a = sig.cheby1(N, rp, Wn, btype='low', analog=True)
# Chebyshev Type II (ondulations en bande atténuée)
rs = 40 # Atténuation min en bande atténuée [dB]
b, a = sig.cheby2(N, rs, Wn, btype='low', analog=True)
# Elliptique / Cauer (ondulations dans les deux bandes)
b, a = sig.ellip(N, rp, rs, Wn, btype='low', analog=True)
# Bessel (phase linéaire)
b, a = sig.bessel(N, Wn, btype='low', analog=True, norm='mag')WARNING
N'oubliez pas analog=True pour les filtres analogiques. Par défaut, scipy génère des filtres numériques.
Types de filtres
Le paramètre btype permet de spécifier le type de filtre :
btype | Type | Pulsation(s) |
|---|---|---|
'low' | Passe-bas | |
'high' | Passe-haut | |
'band' | Passe-bande | |
'stop' | Coupe-bande |
Exemple : Filtre passe-bande
import scipy.signal as sig
N = 2
Wn = [800, 1200] # Bande passante entre 800 et 1200 rad/s
b, a = sig.butter(N, Wn, btype='band', analog=True)
H = sig.lti(b, a)Format de sortie
Le paramètre output permet de choisir le format de sortie :
import scipy.signal as sig
N, Wn = 3, 1000
# Coefficients polynomiaux (par défaut)
b, a = sig.butter(N, Wn, analog=True, output='ba')
# Pôles, zéros, gain
z, p, k = sig.butter(N, Wn, analog=True, output='zpk')
# Sections du second ordre
sos = sig.butter(N, Wn, analog=True, output='sos')Gabarit de Filtre
Tracé du gabarit
import matplotlib.pyplot as plt
def plot_gabarit(ax, fc, Tc, fs, Ts):
"""
Trace le gabarit d'un filtre passe-bas.
Parameters
----------
ax : matplotlib.axes
Axes sur lesquels tracer
fc : float
Fréquence de coupure
Tc : float
Tolérance en bande passante (valeur linéaire)
fs : float
Fréquence de début de bande atténuée
Ts : float
Atténuation en bande atténuée (valeur linéaire)
"""
xmin, xmax = ax.get_xlim()
ymin, ymax = ax.get_ylim()
# Zone interdite bande passante
bp = [[xmin, Tc], [fc, Tc], [fc, ymin], [xmin, ymin]]
# Zone interdite bande atténuée
ba = [[xmin, ymax], [xmin, 1], [fs, 1], [fs, Ts],
[xmax, Ts], [xmax, ymax]]
options = {"fill": False, "closed": True, "color": 'b', "hatch": "//"}
ax.add_patch(plt.Polygon(bp, **options))
ax.add_patch(plt.Polygon(ba, **options))Exemple complet
import scipy.signal as sig
import matplotlib.pyplot as plt
import numpy as np
# Spécifications du filtre
fc = 1000 # Fréquence de coupure [rad/s]
Tc = 0.9 # Module min en bande passante
fs = 3000 # Début bande atténuée [rad/s]
Ts = 0.1 # Module max en bande atténuée
# Synthèse d'un filtre Butterworth
N = 4
b, a = sig.butter(N, fc, btype='low', analog=True)
H = sig.lti(b, a)
w, Hjw = H.freqresp()
# Tracé
fig, ax = plt.subplots()
ax.set_xlim([100, 10000])
ax.set_ylim([0.01, 2])
ax.loglog(w, np.abs(Hjw), 'b-', linewidth=2, label=f'Butterworth N={N}')
plot_gabarit(ax, fc, Tc, fs, Ts)
ax.set_xlabel('Pulsation [rad/s]')
ax.set_ylabel('Module')
ax.legend()
ax.grid(which='both')
plt.show()Récapitulatif des Méthodes
| Méthode | Description | Retour |
|---|---|---|
H.step(T=None) | Réponse indicielle | t, y |
H.impulse(T=None) | Réponse impulsionnelle | t, y |
H.freqresp(w=None) | Réponse fréquentielle | w, H(jw) |
H.poles | Pôles du système | array |
H.zeros | Zéros du système | array |
