Python Cheatsheet
TIP
Ce guide de référence rapide présente les fonctions Python essentielles pour l'analyse des systèmes SLIT. Il utilise principalement les bibliothèques scipy.signal et matplotlib.
General
dB 2 linear conversion
python
def dB_2_nat(V_dB):
"""
dB_2_nat
Convert dB value to natural value
"""
return 10**(V_dB/20)Usage
python
V_dB = -3
V_N = dB_2_nat(V_dB)
print(f"Natural Value: {V_N}")Combination of Transfer Functions
python
def series(H_list):
"""
Combine multiple LTI systems in series.
This function takes a list of LTI systems (scipy.signal.lti objects)
and returns a new LTI system that represents the series connection
of all the systems in the list.
Parameters:
H_list (list): A list of scipy.signal.lti objects.
Returns:
scipy.signal.lti: The resulting LTI system after combining all systems in series.
"""
num = [1] # Initial numerator
den = [1] # Initial denominator
# Loop through each LTI system in the list
for H_temp in H_list:
num = np.polymul(num, H_temp.num)
den = np.polymul(den, H_temp.den)
H = sig.lti(num, den)
return HPlotting
Pole and Zero Diagram
python
import matplotlib.pyplot as plt
# Assuming poles and zeros are numpy arrays
plt.plot(poles.real, poles.imag, "x", label="poles", markersize=10)
plt.plot(zeros.real, zeros.imag, "o", label="zeros", markersize=8)
plt.axhline(y=0, color='k', linewidth=0.5)
plt.axvline(x=0, color='k', linewidth=0.5)
plt.axis("equal")
plt.grid(True)
plt.xlabel("Real part")
plt.ylabel("Imaginary part")
plt.legend()
plt.title("Pole-Zero Diagram")Step Response
python
from scipy.signal import lti
import matplotlib.pyplot as plt
# Define transfer function
H = lti([b0], [a1, a0]) # Example: first order
# Compute step response
t, y = H.step()
# Plot
plt.plot(t, y)
plt.xlabel('Time [s]')
plt.ylabel('Amplitude')
plt.title('Step Response')
plt.grid()
plt.show()Bode Diagram
python
from scipy.signal import lti
import matplotlib.pyplot as plt
import numpy as np
# Define transfer function
H = lti([b0], [a1, a0])
# Compute frequency response
w, Hjw = H.freqresp()
H_modulus = np.abs(Hjw)
H_angle = (180/np.pi) * np.angle(Hjw)
# Plot magnitude
plt.subplot(211)
plt.loglog(w, H_modulus, label='Magnitude')
plt.ylabel('$|H(j\\omega)|$')
plt.title('Bode Diagram')
plt.grid(which='both')
plt.legend()
# Plot phase
plt.subplot(212)
plt.semilogx(w, H_angle, label='Phase')
plt.xlabel('$\\omega$ [rad/s]')
plt.ylabel('$\\arg(H(j\\omega))$ [deg]')
plt.grid(which='both')
plt.legend()
plt.tight_layout()
plt.show()Draw LP Prototype
python
import matplotlib.pyplot as plt
def plot_prototype(ax, xc, Tc, xs, Ts):
"""
plot_LP_prototype
Plot low-pass prototype filter specification
Parameters:
ax: matplotlib axis
xc: cutoff frequency
Tc: passband tolerance
xs: stopband frequency
Ts: stopband attenuation
"""
xmin, xmax = ax.get_xlim()
ymin, ymax = ax.get_ylim()
# Passband region
polygon_data1 = [[xmin, Tc], [xc, Tc], [xc, ymin], [xmin, ymin]]
# Stopband region
polygon_data2 = [[xmin, ymax], [xmin, 1], [xs, 1], [xs, Ts],
[xmax, Ts], [xmax, ymax], [xmin, ymax]]
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')Usage
python
# Specifications
fc, Tc = 1e3, 0.7 # Cutoff: 1kHz, tolerance: 0.7
fs, Ts = 1e4, 1e-4 # Stopband: 10kHz, attenuation: 0.0001
# Create figure
fig = plt.figure()
ax = fig.gca()
ax.set_xlim([1e2, 1e6])
ax.set_ylim([1e-5, 2])
# Plot prototype
plot_prototype(ax, fc, Tc, fs, Ts)
ax.set_xlabel("Frequency [Hz]")
ax.set_ylabel("Magnitude")
ax.set_title("Filter Specification (Gabarit)")
plt.show()Prototype and Frequency Response Superposition
python
import scipy.signal as sig
import matplotlib.pyplot as plt
import numpy as np
# Design Butterworth filter
N = 3 # Filter order
z, p, k = sig.butter(N, 1, btype='low', analog=True, output='zpk')
# Create LTI system
H = sig.lti(z, p, k)
# Compute frequency response
w, Hjw = H.freqresp()
# Plot
fig = plt.figure()
ax = fig.gca()
ax.loglog(w, np.abs(Hjw), label=f'Butterworth N={N}')
plot_prototype(ax, 1, 0.7, 5, 1e-4)
ax.set_xlabel("Normalized frequency")
ax.set_ylabel("Magnitude")
ax.legend()
plt.show()Common Transfer Function Creation
From Polynomial Coefficients [ba]
python
from scipy.signal import lti
# H(s) = (b1*s + b0) / (a2*s^2 + a1*s + a0)
num = [b1, b0]
den = [a2, a1, a0]
H = lti(num, den)From Zeros, Poles, and Gain [zpk]
python
from scipy.signal import lti
# Define zeros, poles, and gain
zeros = [-1, -2]
poles = [-0.5+1j, -0.5-1j]
gain = 2.0
H = lti(zeros, poles, gain)Standard Second Order Forms
python
import numpy as np
from scipy.signal import lti
# Low-pass
def second_order_LP(T0, omega0, m):
"""Second order low-pass filter"""
num = [T0 * omega0**2]
den = [1, 2*m*omega0, omega0**2]
return lti(num, den)
# Band-pass
def second_order_BP(Tm, omega0, m):
"""Second order band-pass filter"""
num = [2*m*Tm*omega0, 0]
den = [1, 2*m*omega0, omega0**2]
return lti(num, den)
# High-pass
def second_order_HP(Tinf, omega0, m):
"""Second order high-pass filter"""
num = [Tinf, 0, 0]
den = [1, 2*m*omega0, omega0**2]
return lti(num, den)Useful scipy.signal Functions
python
import scipy.signal as sig
# Filter design
sig.butter(N, Wn) # Butterworth filter
sig.cheby1(N, rp, Wn) # Chebyshev Type I
sig.cheby2(N, rs, Wn) # Chebyshev Type II
sig.ellip(N, rp, rs, Wn) # Elliptic (Cauer)
sig.bessel(N, Wn) # Bessel/Thomson
# System analysis
H.freqresp(w) # Frequency response
H.step() # Step response
H.impulse() # Impulse response
H.bode() # Bode plot
# System properties
H.poles # System poles
H.zeros # System zeros