PID Control of a Second Order System

Preparations

Here we import all necessary libraries.

Hide code cell source
    from IPython.core.display import HTML
    import numpy as np
    
    import matplotlib.pyplot as plt
    plt.rcParams.update({
        "text.usetex": True,
        "font.family": "Helvetica",
        "font.size": 10,
    })
    
    from sympy import *
    from sympy.plotting import plot
    
    from mathprint import *

These are some variables that we are going to use:

\(t, s, \tau, \omega, \omega_n, \zeta\)

from sympy.physics.control.lti import TransferFunction
Kp, Ki, Kd = symbols('K_p K_i K_d', positive=True)

t       = symbols('t', positive=True)
s       = symbols('s', complex=True)
tau     = symbols('tau', positive=True)

omega   = symbols("omega", positive=True)
omega_n = symbols('omega_n', positive=True)
zeta    = symbols('zeta', positive=True)

Let us define some helper functions.

def laplace(f):
    F = laplace_transform(f, t, s, noconds=True)
    return F

def ilaplace(F):
    f = inverse_laplace_transform(F, s, t)
    return f

def frac_to_tf(frac):
    return TransferFunction(fraction(frac)[0], fraction(frac)[1], s)

System and the control equations

The diagram above corresponds to a unity-feedback loop with

\[ G(s)=K_p+\frac{K_i}{s}+K_d \]

and plant

\[ H(s)=\frac{1}{s^2 + 2 \zeta \omega_n s +\omega_n^2}. \]

Thus, the closed-loop transfer function is

\[ \boxed{\frac{C(s)}{R(s)} = \frac{K_d s^2+K_p s+K_i}{s^2+\left(K_d+2 \omega_n\right) s^2+\left(K_p+\omega_n^2\right) s+K_i}} \]

After this, we will compute \(c(t)\), \(c'(t)\), \(c(0)\), \(c'(0)\), and \(c(\infty)\) where \(c(t)\) is the inverse Laplace of \(C(s)\).

From \(c(\infty)\), we can get the steady state output of the controlled system while \(c'(0)\) tells us the occurance of derivative kick in the controlled system (non-zero initial velocity).

H = 1 / (s**2+2*zeta*omega_n*s+omega_n**2)
G = Kp + Ki/s + Kd*s        # PID TF
Q = factor(G*H / (1 + G*H)) # CL TF
Q = collect(Q, [s**3, s**2, s])

print("First-order system:")
mprint("H(s)=", latex(H))

print("PID-control:")
mprint("G(s)= ", latex(G))

print("The resulting closed-loop system:")
mprint("Q(s)=", latex(Q))
First-order system:
\[\displaystyle H(s)=\frac{1}{\omega_{n}^{2} + 2 \omega_{n} s \zeta + s^{2}}\]
PID-control:
\[\displaystyle G(s)= K_{d} s + \frac{K_{i}}{s} + K_{p}\]
The resulting closed-loop system:
\[\displaystyle Q(s)=\frac{K_{d} s^{2} + K_{i} + K_{p} s}{K_{i} + s^{3} + s^{2} \left(K_{d} + 2 \omega_{n} \zeta\right) + s \left(K_{p} + \omega_{n}^{2}\right)}\]

At this point, we can tell that the equations are already complicated, thus, finding some equations for further analysis might not be feasible. What we are going to do next is steady state analysis for several combinations of controller terms.

Second-order system with P-control

Qp = simplify(Q.subs(([Kd, 0],
                      [Ki, 0])))

mprint("Q_P=", latex(Qp))
\[\displaystyle Q_P=\frac{K_{p}}{K_{p} + \omega_{n}^{2} + 2 \omega_{n} s \zeta + s^{2}}\]

For step response, we apply \(1/s\) as its input, perform an inverse Laplace operation to \(C(s)\) and obtain \(c(t)\) as the result. Finally, we compute the steady state-value for the output: \(c_{ss} = \lim_{t \to \infty} c(t)\).

cp = logcombine(ilaplace(Qp * 1/s))
cssp = simplify(limit(cp, t, 'oo'))
c0p  = limit(cp, t, 0)
cp_d  = simplify(diff(cp, t))
c0p_d  = limit(cp_d, t, 0)

mprint("c(t) = ", latex(cp))
mprint("c'(t) = ", latex(cp_d))
mprintb("c_{ss} = ", latex(cssp))
mprintb("c(0) = ", latex(c0p))
mprintb("c'(0) = ", latex(c0p_d))
\[\displaystyle c(t) = K_{p} \left(\frac{\left(- \frac{2 \omega_{n} \zeta}{K_{p} + \omega_{n}^{2}} + \frac{2 K_{p} \omega_{n} \zeta + 2 \omega_{n}^{3} \zeta}{2 \left(K_{p} + \omega_{n}^{2}\right)^{2}}\right) e^{- \frac{t \left(2 K_{p} \omega_{n} \zeta + 2 \omega_{n}^{3} \zeta\right)}{2 \left(K_{p} + \omega_{n}^{2}\right)}} \sin{\left(t \sqrt{K_{p} - \omega_{n}^{2} \zeta^{2} + \omega_{n}^{2}} \right)}}{\sqrt{K_{p} - \omega_{n}^{2} \zeta^{2} + \omega_{n}^{2}}} + \frac{1}{K_{p} + \omega_{n}^{2}} - \frac{e^{- \frac{t \left(2 K_{p} \omega_{n} \zeta + 2 \omega_{n}^{3} \zeta\right)}{2 \left(K_{p} + \omega_{n}^{2}\right)}} \cos{\left(t \sqrt{K_{p} - \omega_{n}^{2} \zeta^{2} + \omega_{n}^{2}} \right)}}{K_{p} + \omega_{n}^{2}}\right)\]
\[\displaystyle c'(t) = \frac{K_{p} e^{- \omega_{n} t \zeta} \sin{\left(t \sqrt{K_{p} - \omega_{n}^{2} \zeta^{2} + \omega_{n}^{2}} \right)}}{\sqrt{K_{p} - \omega_{n}^{2} \zeta^{2} + \omega_{n}^{2}}}\]
\[\displaystyle \boxed{c_{ss} = \frac{K_{p}}{K_{p} + \omega_{n}^{2}}}\]
\[\displaystyle \boxed{c(0) = 0}\]
\[\displaystyle \boxed{c'(0) = 0}\]

Our conclusions:

  • no derivative kick

  • smooth start

  • zero initial velocity

Next, we can write the steady state error as: \(e_{ss} = 1 - c_{ss}\)

mprintb("e_{ss}=", latex(simplify(1-cssp)))
\[\displaystyle \boxed{e_{ss}=\frac{\omega_{n}^{2}}{K_{p} + \omega_{n}^{2}}}\]

Next, let us try with some numerical valuses.

omega_n_ = 1
zeta_ = 1;
Kp_  = [1, 2, 4, 8, 20]
Hide code cell source
p = [plot(cp.subs(([zeta, zeta_], [omega_n, omega_n_], [Kp, Kp_[j]])), 
          (t, 0, 6), size=(5, 2.5), ylabel='$c(t)$', show=False, legend=True) 
     for j in range(len(Kp_))]

p1 = plot(1, (t, 0, 6), line_color='k', line_style=':', show=False) # unit-step
p1[0].label = "$c(t)=1$"
for j in range(len(p)):
    p[j][0].label = "$K_p=" + str(Kp_[j]) + "$"
    if j > 0:
        p[0].append(p[j][0])

p[0].append(p1[0])
p[0].show()
_images/3004743cd427419cfcbaa3b39c67a6a1db8f14630b824d2f5f8cce8f26a75759.png

As evidenced by the gap between the response and the black target line, P-control results in a permanent steady-state offset. The P-control cannot drive the error to zero.

Second-order system with PD-control

Closed-loop transfer function:

Qpd = simplify(Q.subs(Ki, 0))
mprint("Q_{PD}=", latex(Qpd))
\[\displaystyle Q_{PD}=\frac{K_{d} s + K_{p}}{K_{p} + \omega_{n}^{2} + s^{2} + s \left(K_{d} + 2 \omega_{n} \zeta\right)}\]

Next, we perform an inverse Laplace operation to \(C(s)\) and obtain \(c(t)\) as the result. Additionally, we will also compute the steady state-value for the output (\(c_{ss}\)).

A phenomenon that can be observed in a derivative control is the “kick” that happens when a step input is applied to the controlled system. Because of the kick, system output does not start from zero.

cpd    = logcombine(ilaplace(Qpd * 1/s))
cpd_d  = powsimp(factor((diff(cpd, t))))

csspd = limit(cpd, t, 'oo')
c0pd  = limit(cpd, t, 0)
c0pd_d  = limit(cpd_d, t, 0)

mprint("\\small c(t) = ", latex(cpd))
mprint("\\small c'(t) = ", latex(cpd_d))
mprintb("c_{ss} = ", latex(csspd))
mprintb("c(0) = ", latex(c0pd))
mprintb("c'(0) = ", latex(c0pd_d))
\[\displaystyle \small c(t) = \frac{K_{p}}{K_{p} + \omega_{n}^{2}} - \frac{K_{p} e^{- \frac{t \left(K_{d} K_{p} + K_{d} \omega_{n}^{2} + 2 K_{p} \omega_{n} \zeta + 2 \omega_{n}^{3} \zeta\right)}{2 \left(K_{p} + \omega_{n}^{2}\right)}} \cos{\left(\frac{t \sqrt{- K_{d}^{2} - 4 K_{d} \omega_{n} \zeta + 4 K_{p} - 4 \omega_{n}^{2} \zeta^{2} + 4 \omega_{n}^{2}}}{2} \right)}}{K_{p} + \omega_{n}^{2}} + \frac{2 \left(\frac{K_{p} \left(K_{d} K_{p} + K_{d} \omega_{n}^{2} + 2 K_{p} \omega_{n} \zeta + 2 \omega_{n}^{3} \zeta\right)}{2 \left(K_{p} + \omega_{n}^{2}\right)^{2}} + \frac{K_{d} \omega_{n}^{2} - 2 K_{p} \omega_{n} \zeta}{K_{p} + \omega_{n}^{2}}\right) e^{- \frac{t \left(K_{d} K_{p} + K_{d} \omega_{n}^{2} + 2 K_{p} \omega_{n} \zeta + 2 \omega_{n}^{3} \zeta\right)}{2 \left(K_{p} + \omega_{n}^{2}\right)}} \sin{\left(\frac{t \sqrt{- K_{d}^{2} - 4 K_{d} \omega_{n} \zeta + 4 K_{p} - 4 \omega_{n}^{2} \zeta^{2} + 4 \omega_{n}^{2}}}{2} \right)}}{\sqrt{- K_{d}^{2} - 4 K_{d} \omega_{n} \zeta + 4 K_{p} - 4 \omega_{n}^{2} \zeta^{2} + 4 \omega_{n}^{2}}}\]
\[\displaystyle \small c'(t) = \frac{\left(- K_{d}^{2} \sin{\left(\frac{t \sqrt{- K_{d}^{2} - 4 K_{d} \omega_{n} \zeta + 4 K_{p} - 4 \omega_{n}^{2} \zeta^{2} + 4 \omega_{n}^{2}}}{2} \right)} - 2 K_{d} \omega_{n} \zeta \sin{\left(\frac{t \sqrt{- K_{d}^{2} - 4 K_{d} \omega_{n} \zeta + 4 K_{p} - 4 \omega_{n}^{2} \zeta^{2} + 4 \omega_{n}^{2}}}{2} \right)} + K_{d} \sqrt{- K_{d}^{2} - 4 K_{d} \omega_{n} \zeta + 4 K_{p} - 4 \omega_{n}^{2} \zeta^{2} + 4 \omega_{n}^{2}} \cos{\left(\frac{t \sqrt{- K_{d}^{2} - 4 K_{d} \omega_{n} \zeta + 4 K_{p} - 4 \omega_{n}^{2} \zeta^{2} + 4 \omega_{n}^{2}}}{2} \right)} + 2 K_{p} \sin{\left(\frac{t \sqrt{- K_{d}^{2} - 4 K_{d} \omega_{n} \zeta + 4 K_{p} - 4 \omega_{n}^{2} \zeta^{2} + 4 \omega_{n}^{2}}}{2} \right)}\right) e^{- \frac{t \left(\frac{K_{d} K_{p}}{2} + \frac{K_{d} \omega_{n}^{2}}{2} + K_{p} \omega_{n} \zeta + \omega_{n}^{3} \zeta\right)}{K_{p} + \omega_{n}^{2}}}}{\sqrt{- K_{d}^{2} - 4 K_{d} \omega_{n} \zeta + 4 K_{p} - 4 \omega_{n}^{2} \zeta^{2} + 4 \omega_{n}^{2}}}\]
\[\displaystyle \boxed{c_{ss} = \frac{K_{p}}{K_{p} + \omega_{n}^{2}}}\]
\[\displaystyle \boxed{c(0) = 0}\]
\[\displaystyle \boxed{c'(0) = K_{d}}\]

Our conclusions:

  • derivative kick

  • non-smooth start

  • non-zero initial velocity

Next, we can write the steady state error as: \(e_{ss} = 1 - c_{ss}\)

mprintb("e_{ss}=", latex(simplify(1-csspd)))
\[\displaystyle \boxed{e_{ss}=\frac{\omega_{n}^{2}}{K_{p} + \omega_{n}^{2}}}\]
omega_n_ = 1
zeta_ = 1;
Kp_  = 20
Kd_  = [1, 2, 5]
Hide code cell source
p = [plot(cpd.subs(([zeta, zeta_], [omega_n, omega_n_], [Kp, Kp_], [Kd, Kd_[j]])), 
          (t, 0, 6), size=(5, 2.5), ylabel='$c(t)$', show=False, legend=True, axis_center=[0,0]) 
     for j in range(len(Kd_))]
p1 = plot(1, (t, 0, 6), line_color='k', line_style=':', show=False) # unit-step
p1[0].label = "$c(t)=1$"
for j in range(len(p)):
    p[j][0].label = "$K_d=" + str(Kd_[j]) + "$"
    if j > 0:
        p[0].append(p[j][0])

p[0].append(p1[0])
p[0].show()
_images/34075f6ab2dc8c04aab09e44299a222757c7b3f6d2c657d56b164b9b530284b0.png

Second-order system with PI-control

Let us write down the closed-loop transfer function of a PI-controlled second-order system:

Qpi = simplify(Q.subs(Kd, 0))
mprintb("Q_{PI} =", latex(Qpi))
\[\displaystyle \boxed{Q_{PI} =\frac{K_{i} + K_{p} s}{K_{i} + 2 \omega_{n} s^{2} \zeta + s^{3} + s \left(K_{p} + \omega_{n}^{2}\right)}}\]

At this point we can no longer afford performing Inverse Laplace operation with SymPy since it is now involving finding root of a third orde polynomials. In order to find the steady state ouput, we will use final value theorem.

Cpi = Qpi*1/s
csspi = limit(s * Cpi, s, 0) 
mprint("C(s) =", latex(Cpi))
mprintb("c_{ss} = c(\\infty) =", latex(csspi))
\[\displaystyle C(s) =\frac{K_{i} + K_{p} s}{s \left(K_{i} + 2 \omega_{n} s^{2} \zeta + s^{3} + s \left(K_{p} + \omega_{n}^{2}\right)\right)}\]
\[\displaystyle \boxed{c_{ss} = c(\infty) =1}\]

At steady state, the output is 1 which means PI controlled system does not have steady state error.

Next, we wll introduce \(-a_1\), \(-a_2\), and \(-a_3\) as the roots of: \(\left(K_i+2 \omega_n s^2 \zeta+s^3+s\left(K_p+\omega_n^2\right)\right)\)

\[C(s)=\frac{K_i+K_p s}{s\left(K_i+2 \omega_n s^2 \zeta+s^3+s\left(K_p+\omega_n^2\right)\right)} = \frac{K_i+K_p s}{s(s+a_1)(s+a_3)(s+a_2)} \]
a1, a2, a3 = symbols('a1 a2 a3', complex=True)
Cpi_fac = (Kp*s + Ki) / (s*(s + a1)*(s + a2)*(s + a3))

mprint("C(s) = ", latex(Cpi_fac))

Cpi_pf = apart(Cpi_fac, s)

print("\nPartial fraction form")
mprint("C(s) = ", latex(Cpi_pf))

cpi = logcombine(inverse_laplace_transform(Cpi_pf, s, t))

print("\nInverse Laplace")
mprintb("c(t) = ", latex(cpi))
\[\displaystyle C(s) = \frac{K_{i} + K_{p} s}{s \left(a_{1} + s\right) \left(a_{2} + s\right) \left(a_{3} + s\right)}\]
Partial fraction form
\[\displaystyle C(s) = \frac{K_{i}}{a_{1} a_{2} a_{3} s} + \frac{- K_{i} + K_{p} a_{3}}{a_{3} \left(a_{1} - a_{3}\right) \left(a_{2} - a_{3}\right) \left(a_{3} + s\right)} - \frac{- K_{i} + K_{p} a_{2}}{a_{2} \left(a_{1} - a_{2}\right) \left(a_{2} - a_{3}\right) \left(a_{2} + s\right)} + \frac{- K_{i} + K_{p} a_{1}}{a_{1} \left(a_{1} - a_{2}\right) \left(a_{1} - a_{3}\right) \left(a_{1} + s\right)}\]
Inverse Laplace
\[\displaystyle \boxed{c(t) = \frac{K_{i}}{a_{1} a_{2} a_{3}} + \frac{\left(- K_{i} + K_{p} a_{3}\right) e^{- a_{3} t}}{a_{3} \left(a_{1} - a_{3}\right) \left(a_{2} - a_{3}\right)} - \frac{\left(- K_{i} + K_{p} a_{2}\right) e^{- a_{2} t}}{a_{2} \left(a_{1} - a_{2}\right) \left(a_{2} - a_{3}\right)} + \frac{\left(- K_{i} + K_{p} a_{1}\right) e^{- a_{1} t}}{a_{1} \left(a_{1} - a_{2}\right) \left(a_{1} - a_{3}\right)}}\]

We can now compute the intial output \(c(0)\).

c0pi = simplify(cpi.subs(t, 0))
cpi_d = simplify(diff(cpi, t))
c0pi_d = limit(cpi_d, t, 0)

mprintb("c(0) = ", latex(c0pi))
mprint("c'(t) = ", latex(cpi_d))
mprintb("c'(0) = ", latex(c0pi_d))
\[\displaystyle \boxed{c(0) = 0}\]
\[\displaystyle c'(t) = \frac{\left(\left(- K_{i} + K_{p} a_{2}\right) \left(a_{1} - a_{3}\right) e^{t \left(a_{1} + a_{3}\right)} + \left(K_{i} - K_{p} a_{1}\right) \left(a_{2} - a_{3}\right) e^{t \left(a_{2} + a_{3}\right)} + \left(K_{i} - K_{p} a_{3}\right) \left(a_{1} - a_{2}\right) e^{t \left(a_{1} + a_{2}\right)}\right) e^{- t \left(a_{1} + a_{2} + a_{3}\right)}}{\left(a_{1} - a_{2}\right) \left(a_{1} - a_{3}\right) \left(a_{2} - a_{3}\right)}\]
\[\displaystyle \boxed{c'(0) = 0}\]

Our conclusions:

  • no derivative kick

  • smooth start

  • zero initial velocity

Next, we can write the steady state error as: \(e_{ss} = 1 - c_{ss}\)

In this case, we will need to first find \(a_1\), \(a_2\), and \(a_3\) (perhaps numerically). Then, we plug them into the later equation to find \(c(t)\). Let us take some arbitrary numerical values so we can plot the controlled system’s reponses.

tau_ = 1
Kp_ = 5
Ki_ = [0.5, 1, 2]
Kd_ = 0
omega_n_ = 1
zeta_ = 1

We must first calculate the denominator roots or \(-a_1\), \(-a_2\), and \(-a_3\) by finding 3rd-order polynomial roots for each \(K_i\).

Hide code cell source
ROOTS = []
for j in range(len(Ki_)):
    eq = Qpi.subs(([zeta, zeta_], [omega_n, omega_n_], [tau, tau_], [Kp, Kp_],[Ki, Ki_[j]]))
    root = solve(denom(eq),s)
    ROOTS.append([-root[k].evalf() for k in range(len(root))])
    mprint("K_i=", latex(Ki_[j]), "\\rightarrow", latex(ROOTS[j]))
\[\displaystyle K_i=0.5\rightarrow\left[ 0.085675271006571, \ 0.957162364496714 + 2.21806896151584 i, \ 0.957162364496714 - 2.21806896151584 i\right]\]
\[\displaystyle K_i=1\rightarrow\left[ 0.911953586623987 + 2.20162750845213 i, \ 0.911953586623987 - 2.20162750845213 i, \ 0.176092826752025\right]\]
\[\displaystyle K_i=2\rightarrow\left[ 0.814680840208074 + 2.17540599736557 i, \ 0.814680840208074 - 2.17540599736557 i, \ 0.370638319583852\right]\]

With \(a_1\), \(a_2\), and \(a_3\) found, we now have the complete \(c(t)\) responses for all \(K_i\). This, we can plot the responses.

Hide code cell source
p = [plot(cpi.subs(([zeta, zeta_], [omega_n, omega_n_], [tau, tau_], [Kp, Kp_], [Ki, Ki_[j]],
                    [a1, ROOTS[j][0]], [a2, ROOTS[j][1]], [a3, ROOTS[j][2]])), (t, 0, 25), size=(5, 3), ylabel='$c(t)$', show=False, legend=True) for j in range(len(Ki_))]

for j in range(len(p)):
    p[j][0].label = "$K_i=" + str(Ki_[j]) + "$"
    if j > 0:
        p[0].append(p[j][0])

q = plot(csspi.subs(Kp, Kp_), (t, 0, 25), line_color='k', show=False)
q[0].label = "$ c_{ss} (t) = " + latex(csspi.subs(Kp, Kp_)) + " $"
p[0].append(q[0])
p[0].show()
_images/f0df08854fe682fda0d17a4135ddc317d7a7bb414a7116f1d573cf6f38852f83.png

Second-order system with PID-control

This PID-control section is very similar to PI-control.

Qpid = Q
Cpid = Qpid * 1/s
mprint("Q_{PID}=", latex(Qpid))

csspid = limit(s * Cpid, s, 0) 
mprint("C(s) =", latex(Cpid))
mprintb("c_{ss} = c(\\infty) =", latex(csspid))
\[\displaystyle Q_{PID}=\frac{K_{d} s^{2} + K_{i} + K_{p} s}{K_{i} + s^{3} + s^{2} \left(K_{d} + 2 \omega_{n} \zeta\right) + s \left(K_{p} + \omega_{n}^{2}\right)}\]
\[\displaystyle C(s) =\frac{K_{d} s^{2} + K_{i} + K_{p} s}{s \left(K_{i} + s^{3} + s^{2} \left(K_{d} + 2 \omega_{n} \zeta\right) + s \left(K_{p} + \omega_{n}^{2}\right)\right)}\]
\[\displaystyle \boxed{c_{ss} = c(\infty) =1}\]
a1, a2, a3 = symbols('a1 a2 a3', complex=True)
Cpid_fac = (Kd*s**2 + Kp*s + Ki) / (s*(s + a1)*(s + a2)*(s + a3))

mprint("C(s) = ", latex(Cpid_fac))

Cpid_pf = apart(Cpid_fac, s)

print("\nPartial fraction form")
mprint("C(s) = ", latex(Cpid_pf))

cpid = logcombine(inverse_laplace_transform(Cpid_pf, s, t))

print("\nInverse Laplace")
mprintb("c(t) = ", latex(cpid))
\[\displaystyle C(s) = \frac{K_{d} s^{2} + K_{i} + K_{p} s}{s \left(a_{1} + s\right) \left(a_{2} + s\right) \left(a_{3} + s\right)}\]
Partial fraction form
\[\displaystyle C(s) = \frac{K_{i}}{a_{1} a_{2} a_{3} s} - \frac{K_{d} a_{3}^{2} + K_{i} - K_{p} a_{3}}{a_{3} \left(a_{1} - a_{3}\right) \left(a_{2} - a_{3}\right) \left(a_{3} + s\right)} + \frac{K_{d} a_{2}^{2} + K_{i} - K_{p} a_{2}}{a_{2} \left(a_{1} - a_{2}\right) \left(a_{2} - a_{3}\right) \left(a_{2} + s\right)} - \frac{K_{d} a_{1}^{2} + K_{i} - K_{p} a_{1}}{a_{1} \left(a_{1} - a_{2}\right) \left(a_{1} - a_{3}\right) \left(a_{1} + s\right)}\]
Inverse Laplace
\[\displaystyle \boxed{c(t) = \frac{K_{i}}{a_{1} a_{2} a_{3}} - \frac{\left(K_{d} a_{3}^{2} + K_{i} - K_{p} a_{3}\right) e^{- a_{3} t}}{a_{3} \left(a_{1} - a_{3}\right) \left(a_{2} - a_{3}\right)} + \frac{\left(K_{d} a_{2}^{2} + K_{i} - K_{p} a_{2}\right) e^{- a_{2} t}}{a_{2} \left(a_{1} - a_{2}\right) \left(a_{2} - a_{3}\right)} - \frac{\left(K_{d} a_{1}^{2} + K_{i} - K_{p} a_{1}\right) e^{- a_{1} t}}{a_{1} \left(a_{1} - a_{2}\right) \left(a_{1} - a_{3}\right)}}\]
c0pid = simplify(cpid.subs(t, 0))
cpid_d = simplify(diff(cpid, t))
c0pid_d = simplify(limit(cpid_d, t, 0))

mprintb("c(0) = ", latex(c0pid))
mprint("c'(t) = ", latex(cpid_d))
mprintb("c'(0) = ", latex(c0pid_d))
\[\displaystyle \boxed{c(0) = 0}\]
\[\displaystyle c'(t) = \frac{\left(\left(a_{1} - a_{2}\right) \left(K_{d} a_{3}^{2} + K_{i} - K_{p} a_{3}\right) e^{t \left(a_{1} + a_{2}\right)} + \left(a_{1} - a_{3}\right) \left(- K_{d} a_{2}^{2} - K_{i} + K_{p} a_{2}\right) e^{t \left(a_{1} + a_{3}\right)} + \left(a_{2} - a_{3}\right) \left(K_{d} a_{1}^{2} + K_{i} - K_{p} a_{1}\right) e^{t \left(a_{2} + a_{3}\right)}\right) e^{- t \left(a_{1} + a_{2} + a_{3}\right)}}{\left(a_{1} - a_{2}\right) \left(a_{1} - a_{3}\right) \left(a_{2} - a_{3}\right)}\]
\[\displaystyle \boxed{c'(0) = K_{d}}\]

Our conclusions:

  • derivative kick

  • non-smooth start

  • non-zero initial velocity

Next, we can write the steady state error as: \(e_{ss} = 1 - c_{ss}\)

mprintb("e_{ss}=", latex(simplify(1-csspid)))
\[\displaystyle \boxed{e_{ss}=0}\]

Summary

Initial and steady-state output for unit-step input

Hide code cell source
from pandas import DataFrame, set_option
from IPython.display import Markdown, display

def makelatex(args):
    return ["${}$".format(latex(a)) for a in args]

descs = ["P", 
         "PD",
         "PI",
         "PID"]

css_label = [cssp, csspd, csspi, csspid]
c_label   = [cp, cpd, cpi, cpid]
init      = [c0p, c0pd, c0pid, c0pid]
initd     = [c0p_d, c0pd_d, c0pi_d, c0pid_d]

dic = {''         : makelatex(descs), 
       '$c_{ss}$' : makelatex(css_label),
       '$c(0)$'   : makelatex(init),
       "$c'(0)$"  : makelatex(initd)}


df = DataFrame(dic)
Markdown(df.to_markdown(index=False))

\(c_{ss}\)

\(c(0)\)

\(c'(0)\)

\(\mathtt{\text{P}}\)

\(\frac{K_{p}}{K_{p} + \omega_{n}^{2}}\)

\(0\)

\(0\)

\(\mathtt{\text{PD}}\)

\(\frac{K_{p}}{K_{p} + \omega_{n}^{2}}\)

\(0\)

\(K_{d}\)

\(\mathtt{\text{PI}}\)

\(1\)

\(0\)

\(0\)

\(\mathtt{\text{PID}}\)

\(1\)

\(0\)

\(K_{d}\)