Skip to content

Commit c16d5e3

Browse files
committed
Fixed Bode phase-gain relation
1 parent 2d7e70e commit c16d5e3

2 files changed

Lines changed: 113 additions & 29 deletions

File tree

BlockA/SysReg_crashcourse_TimeDomain_BlockA_03_ControlSynthesis.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@
2828
# 1. the Dirac-delta impulse signal
2929
# 2. and the (Heaviside) step signal.
3030
#
31-
# The impulse signal is primarily used to see the transient behaviour of the system and the step functions shows the transient and steady state behaviour. Look at these plots to see! We're even able to seperate the transient from the steady state for the step!
31+
# The impulse signal is primarily used to see the transient behaviour of the system and the step functions shows the transient and steady state behaviour. Look at these plots to see! We're even able to
32+
# seperate the transient from the steady state for the step!
3233

3334
# %%
3435
# Create random system

BlockB/SysReg_crashcourse_FreqDomain_BlockB_04_SystemAnalysis.py

Lines changed: 111 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -116,48 +116,131 @@
116116
display(fig, fig2)
117117

118118
# %% [markdown]
119-
#
120119
# ## Minimum Phase Systems
121-
# Bode has one last curve-ball for you lovely people, he has a relation named after him that couples the phase and gain of TFs for so-called "Minimum Phase Systems" (MPS). We'll look into that more in a bit,
122-
# first Bode's relation. Be warned, it's not pretty at first sight:
123-
#
124-
# TODO: I'm confused man, the stuff in the slides doesn't make sense to me...
125-
#
126-
# Very briefly, a system is minimum phase iff:
127-
# - There are no RHP zeros *and*
128-
# - There are no time delays.
120+
# Minimum phase systems (MPS) are systems where the phase is the absolute minimum possible value for any given magnitude. Defined the other way around: MPS are systems without phase addition from factors not
121+
# contributing to the magnitude. These factors are only time-delays and RHP zeros. Lets look at the difference between a LHP and RHP zero:
122+
# %%
123+
OM = np.logspace(-3, 3, 700)
124+
S = OM*1j
125+
126+
TFs = [.2*(S + 5.),
127+
.2*(S - 5.),
128+
5. / (S + 5.),
129+
]
130+
131+
fig, ax = plt.subplots(2,1, sharex=True)
132+
for tf, name, ls in zip(TFs, ["LHP zero", "RHP zero", "RHP pole"], ["-", "--", "-"]):
133+
T1 = np.log(np.abs(tf))
134+
PH1 = np.gradient(T1, np.log(OM))
135+
ax[0].loglog(OM, np.abs(tf), ls)
136+
ax[1].semilogx(OM, np.angle(tf, deg=True), label=name)
137+
138+
139+
ax[0].set(title="Bode plot", ylabel = "$|G(s)|$")
140+
ax[1].set(xlim=[OM[0], OM[-1]], xlabel = r"$\omega$", ylabel = r"$\angle G(s)$ / ${}^\circ$")
141+
ax[1].yaxis.set_major_locator(MultipleLocator(90))
142+
ax[1].legend()
143+
display(fig)
144+
145+
# %% [markdown]
146+
# This demonstrates the main troubles with RHP zeros: they cause a lot of phase loss, causing stability and performance limitations. One of these limitations is for example demonstrated through the
147+
# [root locus](https://en.wikipedia.org/wiki/Root_locus_analysis) (which is a very cool topic). In a very limited statement, the root locus says that closed-loop poles move towards zeros for increasingly higher
148+
# gain feedback. If there is a RHP zero, that means that for high gains at some point a closed loop pole will move to the RHP, destabilising the feedback system. Therefore, there is a limit to the feedback gain
149+
# you can set. You've seen before too that time delays incur a huge phase loss.
129150

130151
# %% [markdown]
131-
# ### My Bode's Relation confusion
132-
# The relation is defined in the slides (of '24/'25) as
133-
# $$ \angle G(i\Omega) = \frac{1}{\pi}\int_{-\infty}^{\infty}\frac{\text{d}\log|G(i\omega)|}{\text{d}\log(\omega)}\;\log\left|\frac{\omega+\Omega}{\omega-\Omega}\right|
134-
# \frac{\text{d}\omega}{\omega}.$$
135-
# Now my issue is that the integral is from $-\infty$ onwards, but that $\log(x)$ is not defined for $x\leq0$, and there are many logarithms. Investigating
136-
# the three factors one by one:
152+
# <div style="text-align:center;background-color:orange;color:black;">Maybe this entire Bode block should be a seperate deep dive page...</div>
137153
#
138-
# $\frac{\text{d}\log|G(i\omega)|}{\text{d}\log(\omega)}$ is a derivative. As we've seen before, this is just the slope of the log-log graph for positive frequencies and for negative
154+
# ## Bodes phase-magnitude relation
155+
# Bode has one last curve-ball for you lovely people, he has a relation named after him that couples the phase and gain of TFs for so-called "Minimum Phase Systems" (MPS). We'll look into that more in a bit,
156+
# first Bode's relation. Be warned, it's not pretty at first sight: the relation is defined in Eq. 2.10 of Skogestad as
157+
# $$ \angle G(i\Omega) = \frac{1}{\pi}\int_{-\infty}^{\infty}\underbrace{\frac{\text{d}\log|G(i\omega)|}{\text{d}\log(\omega)}}_{N(\omega)}\;\log\left|\frac{\omega+\Omega}{\omega-\Omega}\right|
158+
# \frac{\text{d}\omega}{\omega} \approx 90^\circ N(\omega).$$
159+
# Now my issue with this is that the integral is from $-\infty$ onwards, but that $\log(x)$ is not defined for $x\leq0$, and there are many logarithms. Investigating
160+
# those three factors one by one:
161+
#
162+
# $\frac{\text{d}\log|G(i\omega)|}{\text{d}\log(\omega)}=N(\omega)$ is a derivative. As we've seen before, this is just the slope of the log-log graph for positive frequencies and for negative
139163
# frequencies it's the same but negative. I do have some issues with the notation of the denominator though.
140164
#
141165
# $\log\left|\frac{\omega+\Omega}{\omega-\Omega}\right|$ is a bit weirder, but logarithms of an absolute value, so we're good for negative values. Let's do some simplifications
142166
# $$ \log\left|\frac{\omega+\Omega}{\omega-\Omega}\right| = \log\frac{|\omega+\Omega|}{|\omega-\Omega|} = \log|\omega+\Omega| - \log|\omega-\Omega|.$$
143-
# Okay, so the function is not defined for $\omega = \Omega$.
167+
# Okay, so the function is not defined for $\omega = \pm\Omega$, because logarithms don't work for zero.
144168
#
145169
# Lastly, there is $\frac{1}{\omega}$, causing problems when $\omega=0$.
146170
#
147-
# ### So do better then
148-
# Yeah, I'll try. I'm at my parents at the moment and don't have my books, so we'll all have to make do with wikipedia.
171+
# Now also why in tarnation is that approximation true? That has exactly to do with the problems described just now. Let's have a gander at the function $\frac{1}{\omega}\log
172+
# \left|\frac{\omega+\Omega}{\omega-\Omega}\right|$. We plot it for some values of $\Omega$:
173+
#
174+
# %%
175+
W = [.8, 2., 20.3]
176+
f = lambda w, W0 : np.log(np.abs((w + W0) / (w - W0))) / w
177+
w = np.linspace(-max(W)-5, max(W)+5, 2000)
178+
179+
fig, ax = plt.subplots()
180+
[ax.plot(w, f(w, q)) for q in W]
181+
display(fig)
182+
183+
# %% [markdown]
184+
# Spiky plot, but what's happening at those discontinuities? So turns out that
185+
# $$\lim_{w\rightarrow\Omega} \frac{1}{\omega}\log\left|\frac{\omega+\Omega}{\omega-\Omega}\right| = \frac{1}{\Omega}\log|2\Omega| - \lim_{w\rightarrow\Omega}\frac{1}{\Omega}\log|\omega-\Omega| =\infty,$$
186+
# since $\log(0^+)=-\infty$.
187+
# Now for
188+
# $$\lim_{w\rightarrow-\Omega} \frac{1}{\omega}\log\left|\frac{\omega+\Omega}{\omega-\Omega}\right| = \frac{1}{\Omega}\log|-2\Omega| - \frac{1}{\Omega}\lim_{w\rightarrow-\Omega} \log|\omega+\Omega| =\infty.$$
189+
# Therefore, we have peaks up to infinity at $\omega=\pm\Omega$. The limit at $\omega=0$ is annoying and I don't want to do it, because
190+
# $$ \lim_{w\rightarrow0} \frac{1}{\omega}\log\left|\frac{\omega+\Omega}{\omega-\Omega}\right| = \frac00.$$
191+
# So we're going to do a proof by plot that $ \lim_{w\rightarrow0} \frac{1}{\omega}\log\left|\frac{\omega+\Omega}{\omega-\Omega}\right| = \frac{2}{\Omega}$ and you're going to believe me:
192+
#
193+
# %%
194+
W_ = np.linspace(0, W[-1], 300)
195+
196+
fig, ax = plt.subplots()
197+
ax.plot(W_, [(f(-1e-12, w) + f(1e-12, w)) / 2. for w in W_], 'r--')
198+
ax.plot(W_, 2./W_, 'k--')
199+
display(fig)
200+
201+
# %% [markdown]
202+
# *As you can see*, **obviously** $ \lim_{w\rightarrow0} \frac{1}{\omega}\log\left|\frac{\omega+\Omega}{\omega-\Omega}\right| = \frac{2}{\Omega}$. Now this explanation has gotten muddy, what you need
203+
# to realise about $\frac{1}{\omega}\log\left|\frac{\omega+\Omega}{\omega-\Omega}\right|$ for the next step is that it's infinte at $\pm\Omega$ and finite everywhere else.
149204
#
150-
# In [this paragraph](https://en.wikipedia.org/wiki/Minimum_phase#Relationship_of_magnitude_response_to_phase_response), they define the relation through the Hilbert transform,
151-
# $\mathcal{H}$. The relation is then
152-
# $$ \angle G(s) = -\mathcal{H}\{\log|G(s)|\}, $$
153-
# with the inverse
154-
# $$ \log|G(s)| = \log|G(i\infty)| + \mathcal{H}\{\angle G(s)\} .$$
155-
# Here, the Hilbert transform is defined in time-domain as
156-
# $$ \mathcal{H}\{x(t)\} = \frac{1}{\pi}\int_{-\infty}^{\infty} \frac{x(\tau)}{t-\tau}\text{d}\tau$$
157-
# [This page](https://en.wikipedia.org/wiki/Hilbert_transform#Relationship_with_the_Fourier_transform) also exists. Also see page 172 of Skogestad. This is a bigger time investment than I expected.
205+
# The next step is to realise that you can approximate this with a Dirac-delta impulse that we saw in block A with the impulse response. To define that impulse, $\delta(t)$, a bit more precisely:
206+
# $$\delta(t) = \infty \text{ for } t = 0,\; \delta(t) = 0 \text{ otherwise, and } \int_{-\infty}^\infty\delta(t)=1.$$
207+
# Now you're also going to believe me that $\int_{-\infty}^\infty \frac{1}{\omega}\log\left|\frac{\omega+\Omega}{\omega-\Omega}\right|\text{d}\omega = \frac{\pi^2}{2}$. Then the approximation is
208+
# $$ \frac{1}{\omega}\log\left|\frac{\omega+\Omega}{\omega-\Omega}\right| \approx \frac{\pi^2}{2} \delta(\omega - \Omega).$$
209+
# See Sec. 3 of [Bechhoefer 2024](https://arxiv.org/abs/1107.0071) (DOI:10.1119/1.3614039) on why this is one-sided.
158210
#
159-
# I give up (for now)
211+
# Finally connecting back to the phase-gain relation, we get
212+
# $$ \angle G(i\Omega) = \frac{1}{\pi}\int_{-\infty}^{\infty}N(\omega)\;\log\left|\frac{\omega+\Omega}{\omega-\Omega}\right|
213+
# \frac{\text{d}\omega}{\omega} \approx \frac{1}{\pi}\int_{-\infty}^{\infty}N(\omega)\frac{\pi^2}{2}\delta(\omega - \Omega) = \frac{\pi}{2}N(\Omega) = 90^\circ N(\Omega).$$
214+
# Tadaaa🎊
215+
#
216+
# Now lets see how good this approximation is:
217+
# %%
218+
OM = np.logspace(-3, 3, 700)
219+
S = OM*1j
220+
221+
TFs = [1. / (S + 5),
222+
1. / (S**2 + 2*0.5*1e-1*S + 1e-1**2),
223+
# (S + 3.) / ((S + 1e-1) * (S**2 + 2*.6*1e1*S + 1e1**2)),
224+
]
225+
226+
fig, ax = plt.subplots(2,1, sharex=True)
227+
for tf in TFs:
228+
T1 = np.log(np.abs(tf))
229+
PH1 = np.gradient(T1, np.log(OM))
230+
ax[0].loglog(OM, np.abs(tf), 'k')
231+
l1, = ax[1].semilogx(OM, np.angle(tf, deg=True), 'k', label="True phase")
232+
l2, = ax[1].semilogx(OM, 90 * PH1, 'k--', label="Approximation")
233+
234+
ax[1].set(xlim=[OM[0], OM[-1]], ylim=[-200,200])
235+
ax[1].legend(handles=[l1,l2])
236+
display(fig)
160237

238+
# %% [markdown]
239+
# Very mediocre around poles, to be honest.
240+
#
241+
# Just to summarise, a system is minimum phase iff:
242+
# - There are no RHP zeros *and*
243+
# - There are no time delays.
161244

162245
# %% [markdown]
163246
# <div style="text-align:center;background-color:tomato;">End of lecture "Frequency Domain Analysis"</div>

0 commit comments

Comments
 (0)