# why Type III systems has at least two gain margins?

I heard the following statement https://engineering.stackexchange.com/a/54322/40848

if we have a type III system, or one that has three or more low-frequency poles that we're closing around, then we have at least two gain margins: a low-frequency margin that defines the minimum gain for stability, and a high-frequency one that defines the maximum gain for stability.

Can anyone explain that or use an image to show that a type III system has two gain margins. I can't quite understand this thing, it seems too abstract.

• Are you familiar with root locus plots? If you are, then it might be easy to understand by drawing root locus plots for type 0,1,2,3 systems. Please also edit into the question a link to where this statement was seen so that the points covered there need not be repeated.
– AJN
Feb 24 at 2:10
• That's a good point. I'm just learning some new software, or I'd include one in my upcoming answer! Feb 24 at 2:54

Consider a plant with a transfer function equal to $$H(s) = \frac{250000}{s^2 \left(s^2 + 1000 s + 250000 \right)} \tag 1$$

For some good reason (when I've done this it's for low-frequency disturbance rejection) we want to wrap it with a full PID controller:

$$G(s) = 250 + 50 \frac{1}{s} + 25 \frac{s}{0.005 s + 1} \tag 2$$

The closed-loop response of this combination is So, all-in-all a nice closed-loop response, if your goal was a loop that closes at around 7Hz.

The open loop response is: Note that the phase plot crosses -180 degrees at two frequencies, and two gains: a little over 0.2Hz and a gain of +40dB, and around 30Hz and a gain of maybe -20dB.

What this tells you is that you don't just have a unidirectional gain margin. If your gain were to rise by 20dB, then your system would go unstable. But the story doesn't end there -- if your gain were to fall by 40dB, then your system would also go unstable. So -- you have two gain margins, both of which must be observed.

(Note that in real life these margins can be worse than this -- I just whipped something up on the fly -- margins of $$\pm$$ 6dB aren't unheard of).

As a test, I calculated the pole positions for the closed-loop system as given by (1) and (2), the system with the gain reduced by 43dB, and the system with the gain increased by 23dB. You can see that both of the cases where the gain margin is violated have unstable poles.

as designed 43dB down 23dB up
$$s = -520 \pm j85$$ $$s = -500 \pm j7.7$$ $$s = -603 \pm j225$$
$$s = -132$$ $$s = -200$$ $$s = -9.6$$
$$s = -16 \pm j9.0$$ $$s = 0.0016 \pm j1.33$$ $$s = 7.8 \pm j208$$
$$s = -0.20$$ $$s = -0.20$$ \$s = -0.20

For reference, here's the Python script I used to do this analysis:

#! /usr/bin/env python3

import control
import matplotlib.pyplot as plt
import numpy as np

omega_0 = 500
plant = control.TransferFunction(, [1, 0, 0]) * \
control.TransferFunction([omega_0 ** 2], [1, 2 * omega_0, omega_0 ** 2])
tau = 5e-3
k_i = 50
k_p = 250
k_d = 25

freq = np.geomspace(0.01, 100)
controller = k_p + k_i * control.TransferFunction(, [1, 0]) + \
k_d * control.TransferFunction([1, 0], [tau, 1])

print(f'{controller = }')
print(f'{plant = }')
open_loop = plant * controller
closed_loop = 1 / (1 + 1 / open_loop)

print(f'{control.poles(open_loop) = }')
print(f'{control.poles(closed_loop) = }')
print(f'{control.poles(1 / (1 + 1 / (0.007 * open_loop))) = }')
print(f'{control.poles(1 / (1 + 1 / (14 * open_loop))) = }')

mag, phase, _ = control.frequency_response(open_loop, omega=2 * np.pi * freq)

fig, ax = plt.subplots(nrows=2)
fig.suptitle('Open-loop Bode plot')
ax.semilogx(freq, 20 * np.log10(mag))
ax.grid(True)
ax.set_ylabel('mag, dB')
ax.semilogx(freq, np.unwrap(phase) * 180 / np.pi - 360)
ax.hlines(-180, freq, freq[-1], 'r')
ax.grid(True)
ax.set_ylabel('phase')
ax.set_xlabel('frequency, Hz')

mag, phase, _ = control.frequency_response(closed_loop, omega=2 * np.pi * freq)

fig, ax = plt.subplots(nrows=2)
fig.suptitle('Closed-loop Bode plot')
ax.semilogx(freq, 20 * np.log10(mag))
ax.grid(True)
ax.set_ylabel('mag, dB')
ax.semilogx(freq, np.unwrap(phase) * 180 / np.pi)
ax.grid(True)
ax.set_ylabel('phase')
ax.set_xlabel('frequency, Hz')

# plt.figure()
# control.root_locus(plant * controller, kvect=np.geomspace(0.01, 1))
plt.show()

• It is very excellent, I understand it. Thanks a lot!!!! Feb 24 at 4:06