Skip to content

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

bash
pip install numpy scipy matplotlib

Imports standards

python
import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import lti
import scipy.signal as sig

Cré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 :

H(s)=bmsm++b1s+b0ansn++a1s+a0
python
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

H(s)=1τs+1
python
from scipy.signal import lti

tau = 1e-3  # Constante de temps en secondes
H = lti([1], [tau, 1])

Exemple : Système du second ordre

H(s)=Kω02s2+2mω0s+ω02
python
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 :

H(s)=K(sz1)(sz2)(sp1)(sp2)
python
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

python
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.

python
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.

python
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 H(jω) s'obtient en évaluant la fonction de transfert pour s=jω.

python
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

python
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

python
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

python
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

python
# -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 dB

Mise 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 : H(s)=H1(s)×H2(s).

python
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

python
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

python
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 :

btypeTypePulsation(s)
'low'Passe-basωc
'high'Passe-hautωc
'band'Passe-bande[ω1,ω2]
'stop'Coupe-bande[ω1,ω2]

Exemple : Filtre passe-bande

python
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 :

python
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

python
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

python
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éthodeDescriptionRetour
H.step(T=None)Réponse indiciellet, y
H.impulse(T=None)Réponse impulsionnellet, y
H.freqresp(w=None)Réponse fréquentiellew, H(jw)
H.polesPôles du systèmearray
H.zerosZéros du systèmearray

Références