Hi
How can I adjust the sampling resolution of Bode plots? I am comparing the frequency responses of different filters, and some plots appear undersampled (see the blue curve in the illustration below).
Hi
How can I adjust the sampling resolution of Bode plots? I am comparing the frequency responses of different filters, and some plots appear undersampled (see the blue curve in the illustration below).
Can you share the code you used to create these plots?
Sure. I wrote the code in a Pluto.jl notebook. The relevant section has been copy pasted below. Among other packages, I used ControlSystemsBase.jl and DSP.jl. Just let me know if you prefer receiving the notebook.
# βββ‘ 468c4b00-6411-4563-8319-fa32063b8106
filterOrder = 3
# βββ‘ e92ecc87-b53f-45bd-afa6-89f41eacd5bd
filterCutoff = 38e3
# βββ‘ 71d17abf-93fe-4c5d-a94f-4939a0f06613
Ο_c = 2pi*filterCutoff
# βββ‘ ae4766ef-2dbe-42ab-a9ce-183eae7b160f
s = tf("s")
# βββ‘ cca9f01a-d0a2-4107-9def-01ce50809d49
md"""
## Strategy 1: Butterworth Filter
"""
# βββ‘ 99960c3e-fae8-4c34-963a-91638c95c6c7
butt = Butterworth(3)
# βββ‘ 78de9bc6-e8de-4322-88b3-b67349308960
begin
p1 = butt.p[1]
p2 = butt.p[2]
p3 = butt.p[3]
z1 = complex(0,1)
z2 = complex(0,-1)
z3 = complex(-1,0)
end;
# βββ‘ 101dd8b0-5a0c-4ac6-b219-58d14326284b
butterworthTF = ((s-z1)*(s-z2)*(s-z3))/((s-p1)*(s-p2)*(s-p3))
# βββ‘ 4a898312-5dc0-4154-855a-ccc1ad28695a
bodeplot(butterworthTF, hz=:true, minorgrid=:true)
# βββ‘ 8587a06e-b245-48b1-902a-3eb0f7268fe4
md"""
## Strategy 2: Chebyshev Filter
"""
# βββ‘ 86e11f3d-0988-49e0-8766-9918ee2f0b4e
cheb = Chebyshev1(3, 3)
# βββ‘ a9774b42-5387-4be5-a6bd-3ce303a33dae
begin
p11 = cheb.p[1]*x
p22 = cheb.p[2]*x
p33 = cheb.p[3]*x
z11 = complex(0,0.903)*x
z22 = complex(0,-0.903)*x
z33 = complex(-0.3,0)*x
end;
# βββ‘ 8a07713c-19d9-420a-8619-1e6e2a13b8b3
chebyshevTF = ((s-z11)*(s-z22)*(s-z33))/((s-p11)*(s-p22)*(s-p33))
# βββ‘ 0f350074-8a8b-4de9-8b49-7af5a9e261f8
bodeplot(chebyshevTF, hz=:true, minorgrid=:true)
# βββ‘ 9c6b27c6-47a6-44eb-85a0-6e65555afda1
@bind x Slider(1:0.01:2, show_value=:true) #Used to compensate frequency "skew"
# βββ‘ 872e4a02-8d18-45cc-8b6f-0df1f741f65d
bodeplot([chebyshevTF, butterworthTF], hz=:true, minorgrid=:true)
You may pass a frequency vector as the second argument together with adaptive=false
in order to turn of adaptive down sampling.
The result I get has a much higher resolution
This indicates to me that you are using an older version of ControlSystems that does not employ the adaptive sampling. If thatβs the case, you may either update CS to the latest version, or pass an explicit frequency vector as the second argument, like this
w = exp10.(LinRange(-2, 2, 2000))
bodeplot([chebyshevTF, butterworthTF], w, hz=true, minorgrid=true)
You may find it easier to create your transfer functions using the zpk
constructor
butterworthTF = zpk([z1, z2, z3], [p1, p2, p3], 1)
chebyshevTF = zpk([z11, z22, z33], [p11, p22, p33], 1)
you can also design the filters directly using the DSP.jl interface and just convert them to ControlSystemsBase.TransferFunction
using the tf
function like the example in the docs.
Thank you for your help! Adding an explicit frequency vector resolved the issue.
I have upgraded all packages and now have ControlSystemsBase v1.14.5. Could you provide examples of where adaptive=false
has an effect? I am having difficulties noticing any differences, and I want to understand it better.
Thank you for the hint. For clarity, I prefer the way via ControlSystemsBase.jl. That way, one can clearly see every root of the numerator and denominator.
At the same time, it is indeed easier using the zpk
constructor and less error prone due to fewer entries. Therefore, I consider switching to your suggested method.
That means that the adaptive sampling is working as intended
adaptive = true
tries to remove points from the frequency response in a way that does not impact the visual quality of the generated plot. It does this using RamerβDouglasβPeucker algorithm - Wikipedia
The motivation for using adaptive downsampling is that plots generated in HTML and SVG formats as well as plots inlined in Documenter builds otherwise tend to lead to poor interactive and rendering performance and large file sizes. If adaptive = false
, this downsampling is not performed and all the frequency points that are provided in the second argument are plotted.
The motivation for using adaptive downsampling rather than adaptive sampling from the beginning is that itβs generally much more efficient to compute the frequency response for a large array of frequency points once, than it is to compute several frequency responses for one point at the time.