Bodeplot Sampling Resolution Adjustable?

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)
1 Like

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 :slight_smile:
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.

1 Like