Frequency Response With Python
Frequency Response With Python
blog
Frequency Response
with Python
Hans-Petter Halvorsen
Free Textbook with lots of Practical Examples
https://www.halvorsen.blog/documents/programming/python/
Additional Python Resources
https://www.halvorsen.blog/documents/programming/python/
Contents
• Introduction to Frequency Response
• Python Examples:
2 different Python libraries will be used:
– SciPy (SciPy.Signal)
– The Python Control Systems Library
• Introduction to Filter Design and Stability
Analysis in Control Systems with Examples
It is recommended that you know about Transfer Functions. If not, take a closer look at my Tutorial “Transfer Functions with Python”
Frequency Response
• The frequency response of a system is a frequency dependent
function which expresses how a sinusoidal signal of a given frequency
on the system input is transferred through the system. Each
frequency component is a sinusoidal signal having certain amplitude
and a certain frequency.
• The frequency response is an important tool for analysis and design
of signal filters and for analysis and design of control systems.
• The frequency response can be found experimentally or from a
transfer function model.
• The frequency response of a system is defined as the steady-state
response of the system to a sinusoidal input signal. When the system
is in steady-state, it differs from the input signal only in
amplitude/gain (A) and phase lag (𝜙).
Frequency Response
Input Signal
Dynamic Output Signal
𝑢 𝑡 = 𝑈 % sin(𝜔𝑡) System 𝑦 𝑡 = 𝑈𝐴 % 𝑠𝑖𝑛(𝜔𝑡 + 𝜙)
Amplitude Frequency
Gain Phase Lag
T = 1 year
frequency 1 (year)
Dynamic System frequency 1 (year)
Inside Temperature
𝑈
𝑌 𝑡[𝑠]
Δ𝑡
𝑥 𝑑𝐵 = 20𝑙𝑜𝑔CD𝑥
Python Examples
Hans-Petter Halvorsen
Python Examples
2 different Python libraries will be
used:
• SciPy (SciPy.Signal)
–Included with Anaconda Distribution
• The Python Control Systems Library
–You must install it using PIP
https://www.halvorsen.blog
SciPy.signal
Hans-Petter Halvorsen
SciPy.signal
• The SciPy.signal contains Signal Processing functions
• SciPy is also included with the Anaconda distribution
• If you have installed Python using the Anaconda
distribution, you don’t need to install anything
• https://docs.scipy.org/doc/scipy/reference/signal.html
Basic Example import numpy as np
import scipy.signal as signal
import matplotlib.pyplot as plt
Transfer Function: 3
𝐻 𝑠 =
4𝑠 + 1 num = np.array([3])
den = np.array([4 , 1])
H = signal.TransferFunction(num, den)
Magnitude Plot print ('H(s) =', H)
plt.figure()
plt.semilogx(w, mag) # Magnitude Plot
plt.grid()
plt.figure()
plt.semilogx(w, phase) # Phase plot
plt.grid()
Phase Plot plt.show()
Modified
import numpy as np
import scipy.signal as signal
import matplotlib.pyplot as plt
# Bode Plot
w, mag, phase = signal.bode(H, w)
plt.figure()
plt.subplot (2, 1, 1)
plt.semilogx(w, mag) # Bode Magnitude Plot
plt.title("Bode Plot")
plt.grid(b=None, which='major', axis='both')
plt.grid(b=None, which='minor', axis='both')
plt.ylabel("Magnitude (dB)")
plt.subplot (2, 1, 2)
plt.semilogx(w, phase) # Bode Phase plot
plt.grid(b=None, which='major', axis='both')
plt.grid(b=None, which='minor', axis='both')
plt.ylabel("Phase (deg)")
plt.xlabel("Frequency (rad/sec)")
plt.show()
2.order System
import numpy as np
import scipy.signal as signal
import matplotlib.pyplot as plt
3 # Frequencies
𝐻 𝑠 = # w_start = 0.01
4𝑠 + 5𝑠 + 6 w_stop = 10
step = 0.01
N = int ((w_stop-w_start )/step) + 1
w = np.linspace (w_start , w_stop , N)
# Bode Plot
w, mag, phase = signal.bode(H, w)
plt.figure()
plt.subplot (2, 1, 1)
plt.semilogx(w, mag) # Bode Magnitude Plot
plt.title("Bode Plot")
plt.grid(b=None, which='major', axis='both')
plt.grid(b=None, which='minor', axis='both')
plt.ylabel("Magnitude (dB)")
plt.subplot (2, 1, 2)
plt.semilogx(w, phase) # Bode Phase plot
plt.grid(b=None, which='major', axis='both')
plt.grid(b=None, which='minor', axis='both')
plt.ylabel("Phase (deg)")
plt.xlabel("Frequency (rad/sec)")
plt.show()
Phase Plot and Transfer Functions
𝐾
Integrator: 𝐻 𝑠 = The phase goes to −90°
𝑠
𝐾
1.order System: 𝐻 𝑠 = The phase goes to −90°
𝑇𝑠 + 1
𝐾
2.order System: 𝐻 𝑠 = The phase goes to −180°
(𝑇$ 𝑠 + 1)(𝑇# 𝑠 + 1)
(3𝑠 + 1)(5𝑠 + 1)
den2 = np.array([5, 1])
den = np.convolve(den1, den2)
H = signal.TransferFunction(num, den)
print ('H(s) =', H)
# Frequencies
w_start = 0.01
w_stop = 10
step = 0.01
N = int ((w_stop-w_start )/step) + 1
w = np.linspace (w_start , w_stop , N)
# Bode Plot
w, mag, phase = signal.bode(H, w)
plt.figure()
plt.subplot (2, 1, 1)
plt.semilogx(w, mag) # Bode Magnitude Plot
plt.title("Bode Plot")
plt.grid(b=None, which='major', axis='both')
plt.grid(b=None, which='minor', axis='both')
plt.ylabel("Magnitude (dB)")
plt.subplot (2, 1, 2)
plt.semilogx(w, phase) # Bode Phase plot
plt.grid(b=None, which='major', axis='both')
plt.grid(b=None, which='minor', axis='both')
The phase goes to −90° (There are 1 zero and 2 poles) plt.ylabel("Phase (deg)")
plt.xlabel("Frequency (rad/sec)")
plt.show()
https://www.halvorsen.blog
Python Control
Systems Library
Hans-Petter Halvorsen
Python Control Systems Library
• The Python Control Systems Library (control) is a
Python package that implements basic operations
for analysis and design of feedback control systems.
• Existing MATLAB user? The functions and the
features are very similar to the MATLAB Control
Systems Toolbox.
• Python Control Systems Library Homepage:
https://pypi.org/project/control
• Python Control Systems Library Documentation:
https://python-control.readthedocs.io
Installation
The Python Control Systems Library
package may be installed using pip:
pip install control
pip list
Command Prompt - PIP
pip install control
num = np.array([3])
den = np.array([4 , 1])
H = control.tf(num , den)
print ('H(s) =', H)
control.bode_plot(H, dB=True)
control.bode_plot()
https://python-control.readthedocs.io
From “Scratch“
import numpy as np
import matplotlib.pyplot as plt
import control
num = np.array([3])
den = np.array([4 , 1])
H = control.tf(num , den)
Transfer Function print ('H(s) =', H)
# Frequencies
3 w_start = 0.01
𝐻 𝑠 = w_stop = 10
4𝑠 + 1
step = 0.01
N = int ((w_stop-w_start )/step) + 1
w = np.linspace (w_start , w_stop , N)
plt.subplot (2, 1, 1)
We make our own Bode plot using the plt.semilogx(w, mag_db)
plt.title("Bode Plot")
# Bode Magnitude Plot
control.bode(H, dB=True)
Default
https://www.halvorsen.blog
Filter Design
Hans-Petter Halvorsen
Lowpass Filter
The Transfer Function for a Low-pass filter is given by:
𝑦(𝑠) 1
𝐻 𝑠 = = Where 𝑇) is the Filter Time Constant
𝑢(𝑠) 𝑇S 𝑠 + 1
Why Lowpass Filter?
• In Measurement systems and Control Systems we typically need to deal with
noise
• Noise is something we typically don’t want
• Lowpass Filters are used to remove noise from the measured signals
• Noise is high-frequency signals
• A Lowpass Filter make sure the low frequencies pass and removes the high
frequencies (the noise)
Lowpass Filter
Below we see an Ideal Lowpass Filter:
1 1
𝐻 𝑠 = =
Amplitude Gain 𝑇! 𝑠 + 1 1
𝑠+1
𝜔"
0 𝑑𝐵 1
Where 𝜔* is the Bandwidth
(or the cut-off frequency) of
the Lowpass Filter
Frequency
0
Bandwidth 𝜔*
# Frequencies
w_start = 0.01
w_stop = 100
step = 0.01
N = int ((w_stop-w_start )/step) + 1
w = np.linspace (w_start , w_stop , N)
plt.figure()
plt.semilogx(w, mag)
plt.title("Lowpass Filter")
plt.grid(b=None, which='major', axis='both')
plt.grid(b=None, which='minor', axis='both')
plt.ylabel("Magnitude (dB)")
Bandwidth
1 1 Bandwidth (or the cut-off frequency)
𝐻 𝑠 = =
𝑇) 𝑠 + 1 1
𝑠+1
𝜔*
We set 𝜔* = 10 [rad/s] in this example
−3𝑑𝐵
0 0
𝜔* 𝜔+
Series
0 0 Parallel
𝜔+ 𝜔, 𝜔+ 𝜔,
High-pass Filter
import numpy as np
import scipy.signal as signal
import matplotlib.pyplot as plt
# Frequencies
w_start = 0.01
w_stop = 1000
step = 0.01
N = int ((w_stop-w_start )/step) + 1
w = np.linspace (w_start , w_stop , N)
plt.figure()
plt.semilogx(w, mag)
plt.title("Highpass Filter")
plt.grid(b=None, which='major', axis='both')
plt.grid(b=None, which='minor', axis='both')
plt.ylabel("Magnitude (dB)")
Band-pass Filter
import numpy as np
import control
import matplotlib.pyplot as plt
# Frequencies
w_start = 0.01
w_stop = 1000
step = 0.01
N = int ((w_stop-w_start )/step) + 1
w = np.linspace (w_start , w_stop , N)
# Convert to dB
mag_db = 20 * np.log10(mag)
plt.figure()
plt.semilogx(w, mag_db)
plt.title("Lowpass Filter")
plt.grid(b=None, which='major', axis='both')
plt.grid(b=None, which='minor', axis='both')
plt.ylabel("Magnitude (dB)")
Band-stop Filter
import numpy as np
import control
import matplotlib.pyplot as plt
# Frequencies
w_start = 0.01
w_stop = 1000
step = 0.01
N = int ((w_stop-w_start )/step) + 1
w = np.linspace (w_start , w_stop , N)
# Convert to dB
mag_db = 20 * np.log10(mag)
plt.figure()
plt.semilogx(w, mag_db)
plt.title("Lowpass Filter")
plt.grid(b=None, which='major', axis='both')
plt.grid(b=None, which='minor', axis='both')
plt.ylabel("Magnitude (dB)")
https://www.halvorsen.blog
Frequency Response
Stability Analysis of Control
Systems
Hans-Petter Halvorsen
Stability Analysis Example
Given the following 𝐾! (𝑇# 𝑠 + 1) 3
Control System: 𝐻" 𝑠 = 𝐻! 𝑠 =
𝑇# 𝑠 4𝑠 + 1
𝑟 𝑒 𝑢 𝑥
Controller Process
−
𝑦S
Filter Sensor
1 1
𝐻% 𝑠 = 𝐻$ 𝑠 =
𝑇% 𝑠 + 1 𝑇$ 𝑠 + 1
In Frequency Response Stability Analysis we use the Loop Transfer Function:
wc = 0.37 rad/s
𝜔$01 ≈ 0.77 𝑟𝑎𝑑/𝑠 w180 = 0.77 rad/s
Phase Margin (PM): φ ≈ 30° GM = 3.57
GM = 11.06 dB
𝜔$01 = 0.26𝑟𝑎𝑑/𝑠
As you see we have an Asymptotically Stable System PM = 30.09 deg
Kc = 1.43
The Critical Gain is 𝐾! = 𝐾" × Δ𝐾 = 1.43
Frequency Response Analysis
We have an Asymptotically Stable System when 𝐾/ < 𝐾0
𝜔0 < 𝜔123
https://www.halvorsen.blog/documents/programming/python/
Hans-Petter Halvorsen
University of South-Eastern Norway
www.usn.no
E-mail: [email protected]
Web: https://www.halvorsen.blog