Chapter 11: PID Control Basics
Lesson 4: PID Structures (P, PI, PD, PID; Series vs Parallel Forms)
This lesson formalizes the mathematical structures of P, PI, PD, and PID controllers and compares the widely used parallel (non-interacting) and series (interacting) realizations. We work in the continuous-time (Laplace) domain, connect controller parameters to closed-loop pole locations, and prepare for practical tuning and implementation (treated in later lessons) with code examples in Python, C++, Java, MATLAB/Simulink, and Wolfram Mathematica.
1. Structural Overview of P, PI, PD, and PID Controllers
We consider a standard single-input single-output feedback loop with reference signal \( r(t) \), measured output \( y(t) \), and error \( e(t) = r(t) - y(t) \). The controller output \( u(t) \) is applied to the plant (process) with transfer function \( G(s) \).
The elementary control actions are:
-
Proportional (P) action:
\[ u_P(t) = K_P\,e(t) \]
-
Integral (I) action: accumulates past error
\[ u_I(t) = K_I\int_0^t e(\tau)\,\mathrm{d}\tau \]
-
Derivative (D) action: anticipates future error from
its slope
\[ u_D(t) = K_D\,\frac{\mathrm{d}}{\mathrm{d}t}e(t) \]
In the Laplace domain (zero initial conditions), \( U_P(s) = K_P E(s) \), \( U_I(s) = K_I \frac{1}{s} E(s) \), and \( U_D(s) = K_D s E(s) \). The corresponding transfer functions from \( E(s) \) to \( U(s) \) are:
\[ C_P(s) = K_P,\qquad C_I(s) = \frac{K_I}{s},\qquad C_D(s) = K_D s. \]
When combined, we obtain PI, PD, and PID structures. The feedback interconnection with a generic controller \( C(s) \) and plant \( G(s) \) (unity feedback) has closed-loop transfer function
\[ T(s) = \frac{Y(s)}{R(s)} = \frac{C(s)G(s)}{1 + C(s)G(s)}, \]
and characteristic equation \( 1 + C(s)G(s) = 0 \) that determines stability and transient behavior (via pole locations).
flowchart TD
R["r(t)"] --> E["e(t) = r(t) - y(t)"]
E --> C["Controller C(s): P / PI / PD / PID"]
C --> U["u(t)"]
U --> G["Plant G(s)"]
G --> Y["y(t)"]
Y -->|feedback| E
2. Ideal Parallel (Non-Interacting) PID Structure
The most common mathematical representation in software and many digital controllers is the parallel (non-interacting) form:
\[ u(t) = K_P e(t) + K_I \int_0^t e(\tau)\,\mathrm{d}\tau + K_D \frac{\mathrm{d}}{\mathrm{d}t} e(t). \]
The associated controller transfer function is
\[ C_{\text{par}}(s) = K_P + \frac{K_I}{s} + K_D s. \]
Each gain directly scales one term (proportional, integral, derivative) and does not affect the others algebraically. This is why the form is called non-interacting: tuning \( K_P \) does not modify the integral or derivative gains, and so on.
It is often convenient to parameterize in terms of time constants \( T_I \) (integral time) and \( T_D \) (derivative time) by writing
\[ C_{\text{par}}(s) = K_P\left(1 + \frac{1}{T_I s} + T_D s\right), \]
which simply corresponds to \( K_I = \frac{K_P}{T_I} \) and \( K_D = K_P T_D \).
Special cases are obtained by zeroing some gains:
- P: \( K_I = 0,\,K_D = 0 \) → \( C(s) = K_P \).
- PI: \( K_D = 0 \) → \( C(s) = K_P + \frac{K_I}{s} \).
- PD: \( K_I = 0 \) → \( C(s) = K_P + K_D s \).
In robotics-oriented software (e.g., Python libraries such as
simple_pid, C++ libraries in ROS
control_toolbox::Pid, and Java robotics frameworks),
parameters are usually specified as
\( (K_P, K_I, K_D) \)
in this parallel form.
3. Series (Interacting) PID Structure and Parameter Mapping
Classical analog industrial controllers and some textbooks use a series or interacting PID structure, based on cascade connection of PI and PD elements:
\[ C_{\text{ser}}(s) = K_c\left(1 + \frac{1}{T_I s}\right)\left(1 + T_D s\right), \]
where \( K_c \) is an overall gain, and \( T_I \), \( T_D \) are integral and derivative times. Expanding algebraically,
\[ \begin{aligned} C_{\text{ser}}(s) &= K_c\left(1 + T_D s + \frac{1}{T_I s} + \frac{T_D}{T_I}\right) \\ &= K_c T_D s \;+\; \frac{K_c}{T_I}\frac{1}{s} \;+\; K_c\left(1 + \frac{T_D}{T_I}\right). \end{aligned} \]
Comparing with the parallel form \( C_{\text{par}}(s) = K_P + \frac{K_I}{s} + K_D s \), we obtain the mapping
\[ K_D = K_c T_D,\qquad K_I = \frac{K_c}{T_I},\qquad K_P = K_c\left(1 + \frac{T_D}{T_I}\right). \]
Hence the three parallel parameters \( (K_P, K_I, K_D) \) can be represented in series form \( (K_c, T_I, T_D) \), but the relations are coupled. If we try to recover \( T_I \) from given parallel gains, we must solve the quadratic equation
\[ K_P T_I = K_I T_I^2 + K_D \quad\Longrightarrow\quad K_I T_I^2 - K_P T_I + K_D = 0. \]
Its solutions (when the discriminant is non-negative) are
\[ T_I = \frac{K_P \pm \sqrt{K_P^2 - 4K_I K_D}}{2K_I}. \]
Only positive real roots are meaningful for controller design. Once \( T_I \) is chosen, \( K_c = K_I T_I \) and \( T_D = \dfrac{K_D}{K_c} \).
The interacting nature of the series form means that adjusting \( T_I \) or \( T_D \) also changes the effective proportional action through the relation for \( K_P \). This explains why tuning rules specific to the series form do not transfer trivially to the parallel form and vice versa.
4. Closed-Loop Dynamics for a First-Order Plant
To understand how P, PI, PD, and PID structures change closed-loop order and poles, consider a first-order plant
\[ G(s) = \frac{K}{\tau s + 1},\quad K > 0,\; \tau > 0. \]
With unity feedback and controller \( C(s) \), the closed-loop characteristic equation is \( 1 + C(s)G(s) = 0 \).
4.1 P Control
For \( C(s) = K_P \),
\[ 1 + K_P \frac{K}{\tau s + 1} = 0 \;\Longrightarrow\; \tau s + 1 + K_P K = 0. \]
This yields a single real pole at \( s = -\dfrac{1 + K_P K}{\tau} \). Increasing \( K_P \) moves the pole further left, speeding the response but not eliminating steady-state error to a step input (as studied in the steady-state error chapter).
4.2 PI Control
For a PI controller in parallel form \( C(s) = K_P + \dfrac{K_I}{s} \), we get
\[ 1 + \left(K_P + \frac{K_I}{s}\right)\frac{K}{\tau s + 1} = 0. \]
Bring to a common denominator:
\[ 1 + \frac{K\left(K_P s + K_I\right)}{s(\tau s + 1)} = 0 \;\Longrightarrow\; s(\tau s + 1) + K(K_P s + K_I) = 0. \]
Expanding,
\[ \tau s^2 + s + K K_P s + K K_I = 0 \;\Longrightarrow\; \tau s^2 + (1 + K K_P)s + K K_I = 0. \]
The closed-loop system is now second order; the integral action introduces a pole at the origin and changes the characteristic polynomial. Choosing \( K_P, K_I \) thus determines the damping ratio and natural frequency of the closed-loop response (via mapping to the standard second-order form).
4.3 PD and PID Control
For PD, \( C(s) = K_P + K_D s \), the characteristic equation becomes
\[ 1 + \left(K_P + K_D s\right)\frac{K}{\tau s + 1} = 0 \;\Longrightarrow\; \tau s + 1 + K\left(K_P + K_D s\right) = 0. \]
Rearranging gives
\[ (\tau + K K_D) s + (1 + K K_P) = 0, \]
still a first-order system, but with modified effective time constant and gain. In practice, PD is often used with higher-order plants where the zero introduced by derivative action reshapes the dominant poles.
For full PID \( C(s) = K_P + \dfrac{K_I}{s} + K_D s \), the plant becomes second order (through the integral action) and the derivative term adds a zero; the characteristic polynomial is
\[ \tau s^2 + (1 + K K_P + K K_D s)s + K K_I = 0, \]
which, after collecting terms, remains second order but with coefficients depending on all three gains. The precise form depends on the algebraic arrangement, but the key point is that PID provides a flexible shaping of the closed-loop poles, combining the steady-state benefits of integral action with the transient shaping of derivative action.
5. Implementation-Oriented View and Algorithmic Flow
In embedded and robotic systems, control laws are implemented as real-time algorithms executed at sampling period \( T_s \). Integrals and derivatives are approximated by sums and finite differences. For a parallel PID, a common discrete-time approximation (using a backward difference for the derivative and a rectangular rule for the integral) is:
\[ \begin{aligned} e[k] &= r[k] - y[k], \\ I[k] &= I[k-1] + T_s\, e[k], \\ D[k] &= \frac{e[k] - e[k-1]}{T_s}, \\ u[k] &= K_P e[k] + K_I I[k] + K_D D[k]. \end{aligned} \]
In robotics libraries (e.g., ROS ros_control in C++,
Python-based control nodes, and Java-based robotics frameworks), such
discrete algorithms are embedded inside controller classes that
interface with sensor feedback and actuator commands.
flowchart TD
START["Start loop at each sampling instant"] --> READ["Read reference r[k] and measurement y[k]"]
READ --> ERR["Compute error e[k] = r[k] - y[k]"]
ERR --> INT["Update integral I[k] = I[k-1] + Ts * e[k] (apply anti-windup limits)"]
INT --> DER["Compute derivative D[k] = (e[k] - e[k-1]) / Ts"]
DER --> CTRL["Compute control u[k] = Kp * e[k] + Ki * I[k] + Kd * D[k]"]
CTRL --> SAT["Apply actuator limits and safety checks"]
SAT --> ACT["Send u[k] to actuator"]
ACT --> END["Wait until next sampling instant"]
The structural distinction between parallel and series forms persists in discrete-time implementations: in the series form, integral and derivative blocks are cascaded, while in the parallel form, all three terms are computed from the same error \( e[k] \) and summed.
6. Multi-Language Implementations (Robotics-Oriented)
We now illustrate simple parallel PID implementations in several languages. Each example is suitable as a building block in a robotic joint or wheel velocity controller. In practice, these classes would be wrapped inside frameworks such as ROS (C++/Python) or WPILib (Java), or connected to Simulink and Mathematica models.
6.1 Python (Parallel PID Class)
import math
from typing import Optional
class PIDController:
"""
Parallel PID controller for robotic actuators.
Parameters
----------
Kp, Ki, Kd : float
Proportional, integral, derivative gains.
dt : float
Sampling period (seconds).
u_min, u_max : Optional[float]
Optional actuator limits for saturation.
"""
def __init__(self, Kp: float, Ki: float, Kd: float,
dt: float,
u_min: Optional[float] = None,
u_max: Optional[float] = None):
self.Kp = Kp
self.Ki = Ki
self.Kd = Kd
self.dt = dt
self.u_min = u_min
self.u_max = u_max
self.integral = 0.0
self.e_prev = 0.0
self.first_call = True
def reset(self) -> None:
self.integral = 0.0
self.e_prev = 0.0
self.first_call = True
def update(self, r: float, y: float) -> float:
"""
Compute control u[k] given reference r and measurement y.
"""
e = r - y
# Integral update (forward Euler)
self.integral += e * self.dt
# Derivative term (backward difference)
if self.first_call:
d = 0.0
self.first_call = False
else:
d = (e - self.e_prev) / self.dt
u = self.Kp * e + self.Ki * self.integral + self.Kd * d
# Simple saturation and anti-windup
if self.u_min is not None and u < self.u_min:
u = self.u_min
# Optional: prevent further integral growth
# self.integral -= e * self.dt
if self.u_max is not None and u > self.u_max:
u = self.u_max
# Optional: prevent further integral growth
# self.integral -= e * self.dt
self.e_prev = e
return u
# Example usage inside a robotic joint control loop:
# pid = PIDController(Kp=10.0, Ki=5.0, Kd=0.2, dt=0.001, u_min=-12.0, u_max=12.0)
# while running:
# q_ref = desired_joint_angle()
# q_meas = read_encoder()
# u_cmd = pid.update(q_ref, q_meas)
# send_torque_command(u_cmd)
6.2 C++ (ROS/Robotics-Style PID Class)
#include <algorithm>
#include <cmath>
class PID {
public:
PID(double Kp, double Ki, double Kd, double dt,
double u_min = -1e9, double u_max = 1e9)
: Kp_(Kp), Ki_(Ki), Kd_(Kd),
dt_(dt), u_min_(u_min), u_max_(u_max),
integral_(0.0), e_prev_(0.0), first_call_(true) {}
void reset() {
integral_ = 0.0;
e_prev_ = 0.0;
first_call_ = true;
}
double update(double r, double y) {
double e = r - y;
// Integral term
integral_ += e * dt_;
// Derivative term
double d = 0.0;
if (!first_call_) {
d = (e - e_prev_) / dt_;
} else {
first_call_ = false;
}
double u = Kp_ * e + Ki_ * integral_ + Kd_ * d;
// Saturation
u = std::max(u_min_, std::min(u_max_, u));
e_prev_ = e;
return u;
}
private:
double Kp_, Ki_, Kd_;
double dt_;
double u_min_, u_max_;
double integral_;
double e_prev_;
bool first_call_;
};
/*
* In ROS, this PID class could be embedded inside a controller plugin,
* using the ros_control/controller_interface API. The structure here
* corresponds to the parallel form (Kp, Ki, Kd) used by many robotics
* libraries such as control_toolbox::Pid.
*/
6.3 Java (PID for Robot Joint Control)
public class PIDController {
private double Kp, Ki, Kd;
private double dt;
private double integral = 0.0;
private double prevError = 0.0;
private boolean firstCall = true;
private double uMin, uMax;
public PIDController(double Kp, double Ki, double Kd,
double dt, double uMin, double uMax) {
this.Kp = Kp;
this.Ki = Ki;
this.Kd = Kd;
this.dt = dt;
this.uMin = uMin;
this.uMax = uMax;
}
public void reset() {
integral = 0.0;
prevError = 0.0;
firstCall = true;
}
public double update(double r, double y) {
double e = r - y;
// Integral
integral += e * dt;
// Derivative
double d;
if (firstCall) {
d = 0.0;
firstCall = false;
} else {
d = (e - prevError) / dt;
}
double u = Kp * e + Ki * integral + Kd * d;
// Saturation
if (u < uMin) u = uMin;
if (u > uMax) u = uMax;
prevError = e;
return u;
}
}
/*
* In Java-based robotics (e.g., WPILib for FRC robots),
* a similar PIDController class is used to control wheel speeds,
* arm positions, etc., again relying on the parallel (Kp, Ki, Kd) structure.
*/
6.4 MATLAB/Simulink (Transfer Function and PID Object)
% First-order plant G(s) = K / (tau s + 1)
K = 2.0;
tau = 0.5;
s = tf('s');
G = K / (tau * s + 1);
% Parallel-form PID parameters
Kp = 8.0;
Ki = 5.0;
Kd = 0.1;
% MATLAB PID object (parallel structure)
C_pid = pid(Kp, Ki, Kd);
% Closed-loop transfer function with unity feedback
T = feedback(C_pid * G, 1);
figure;
step(T);
title('Step response with parallel PID controller');
% In Simulink, the same structure is realized by connecting:
% - a "PID Controller" block (set to Parallel form),
% - the plant G(s) implemented as a Transfer Fcn or State-Space block,
% - and a unity feedback loop with appropriate summation blocks.
6.5 Wolfram Mathematica (PID Transfer Function)
(* Parameters *)
K = 2.0;
tau = 0.5;
s = LaplaceTransformVariable;
(* First-order plant G(s) = K / (tau s + 1) *)
G[s_] := K/(tau*s + 1);
(* Parallel PID: C(s) = Kp + Ki/s + Kd s *)
Kp = 8.0;
Ki = 5.0;
Kd = 0.1;
C[s_] := Kp + Ki/s + Kd*s;
(* Closed-loop transfer function *)
T[s_] := (C[s]*G[s])/(1 + C[s]*G[s]);
(* Represent as TransferFunctionModel *)
tfModel = TransferFunctionModel[T[s], s];
(* Step response *)
ResponsePlot[
{tfModel},
{t, 0, 5},
PlotLabel -> "Step response with parallel PID",
Frame -> True
]
These implementations all embody the same underlying structure \( C_{\text{par}}(s) = K_P + \dfrac{K_I}{s} + K_D s \), even though each robotics framework wraps it in slightly different APIs. The mathematical equivalence across languages is crucial for systematic controller design and tuning.
7. Problems and Solutions
In this section we work through theoretical exercises that deepen understanding of PID structures and the relation between series and parallel forms.
Problem 1 (Mapping Series to Parallel PID Parameters): Starting from the series (interacting) form \( C_{\text{ser}}(s) = K_c\left(1 + \dfrac{1}{T_I s}\right)\left(1 + T_D s\right) \), derive explicit expressions for the equivalent parallel parameters \( K_P, K_I, K_D \) in \( C_{\text{par}}(s) = K_P + \dfrac{K_I}{s} + K_D s \).
Solution:
Expand the product:
\[ \begin{aligned} C_{\text{ser}}(s) &= K_c\left(1 + \frac{1}{T_I s}\right)\left(1 + T_D s\right) \\ &= K_c\left(1 + T_D s + \frac{1}{T_I s} + \frac{T_D}{T_I}\right). \end{aligned} \]
Grouping terms by powers of \( s \) gives
\[ C_{\text{ser}}(s) = K_c T_D s + \frac{K_c}{T_I} \frac{1}{s} + K_c\left(1 + \frac{T_D}{T_I}\right). \]
Comparing with \( C_{\text{par}}(s) = K_P + \dfrac{K_I}{s} + K_D s \), we identify
\[ K_D = K_c T_D,\quad K_I = \frac{K_c}{T_I},\quad K_P = K_c\left(1 + \frac{T_D}{T_I}\right). \]
Thus any choice of \( (K_c, T_I, T_D) \) generates corresponding parallel gains \( (K_P, K_I, K_D) \) via the above relations.
Problem 2 (Recovering Series Parameters from Parallel Ones): Suppose a PID controller is specified in parallel form with gains \( K_P, K_I, K_D > 0 \). Show that the integral time \( T_I \) in the equivalent series representation must satisfy a quadratic equation. Derive this equation explicitly.
Solution:
From the mapping in Problem 1 we have \( K_I = \dfrac{K_c}{T_I} \) and \( K_P = K_c\left(1 + \dfrac{T_D}{T_I}\right) \), \( K_D = K_c T_D \).
Eliminate \( K_c \) and \( T_D \). From \( K_I = \dfrac{K_c}{T_I} \) we get \( K_c = K_I T_I \). From \( K_D = K_c T_D \), \( T_D = \dfrac{K_D}{K_c} = \dfrac{K_D}{K_I T_I} \).
Substitute these into the expression for \( K_P \):
\[ K_P = K_c\left(1 + \frac{T_D}{T_I}\right) = K_I T_I\left(1 + \frac{K_D}{K_I T_I^2}\right) = K_I T_I + \frac{K_D}{T_I}. \]
Multiply through by \( T_I \) to obtain
\[ K_P T_I = K_I T_I^2 + K_D \quad\Longrightarrow\quad K_I T_I^2 - K_P T_I + K_D = 0. \]
Thus \( T_I \) must satisfy a quadratic equation in general. Positive real roots correspond to feasible series parameters.
Problem 3 (Order of Closed-Loop System with PI Control): Consider the first-order plant \( G(s) = \dfrac{K}{\tau s + 1} \) with a PI controller \( C(s) = K_P + \dfrac{K_I}{s} \) in a unity feedback loop. Prove that the closed-loop system is second order and write its characteristic polynomial explicitly.
Solution:
The characteristic equation is \( 1 + C(s)G(s) = 0 \), so
\[ 1 + \left(K_P + \frac{K_I}{s}\right)\frac{K}{\tau s + 1} = 0. \]
Find a common denominator:
\[ 1 + \frac{K(K_P s + K_I)}{s(\tau s + 1)} = 0 \;\Longrightarrow\; s(\tau s + 1) + K(K_P s + K_I) = 0. \]
Expand and collect terms:
\[ \tau s^2 + s + K K_P s + K K_I = 0 \;\Longrightarrow\; \tau s^2 + (1 + K K_P)s + K K_I = 0. \]
This is a second-degree polynomial in \( s \), so the closed-loop system is second order. The coefficients depend linearly on \( K_P \) and \( K_I \).
Problem 4 (Effect of PD Controller on First-Order Plant): For the same plant \( G(s) = \dfrac{K}{\tau s + 1} \), consider a PD controller \( C(s) = K_P + K_D s \). Show that the closed-loop system remains first order and compute its effective time constant.
Solution:
The characteristic equation is
\[ 1 + \left(K_P + K_D s\right)\frac{K}{\tau s + 1} = 0 \;\Longrightarrow\; \tau s + 1 + K(K_P + K_D s) = 0. \]
Collect the terms in \( s \):
\[ (\tau + K K_D)s + (1 + K K_P) = 0. \]
This is a first-order polynomial. The effective time constant \( \tau_{\text{eff}} \) of the closed-loop system is
\[ \tau_{\text{eff}} = \frac{\tau + K K_D}{1 + K K_P}. \]
Thus derivative action changes both numerator and denominator in a way that can speed up or slow down response depending on \( K_P \), \( K_D \), and plant parameters, but does not increase the order for this first-order plant.
Problem 5 (PI vs PID for Steady-State Error): For a unity-feedback system with plant \( G(s) = \dfrac{K}{\tau s + 1} \) and parallel PID controller \( C(s) = K_P + \dfrac{K_I}{s} + K_D s \), show that the presence of the integral term \( K_I > 0 \) guarantees zero steady-state error to a step input, while \( K_D \) has no effect on the steady-state error.
Solution:
For a unit step input \( R(s) = \dfrac{1}{s} \), the steady-state error is
\[ e_{\text{ss}} = \lim_{t \to \infty} e(t) = \lim_{s \to 0} s E(s), \]
where \( E(s) = \dfrac{R(s)}{1 + C(s)G(s)} \) for unity feedback. Hence
\[ e_{\text{ss}} = \lim_{s \to 0} \frac{s}{1 + C(s)G(s)}. \]
Substituting \( C(s) = K_P + \dfrac{K_I}{s} + K_D s \) and \( G(s) = \dfrac{K}{\tau s + 1} \), we examine the limit as \( s \to 0 \). The dominant term in \( C(s) \) is \( \dfrac{K_I}{s} \), so
\[ C(s)G(s) \approx \frac{K_I}{s}\cdot\frac{K}{1} = \frac{K K_I}{s} \quad\text{as } s \to 0. \]
Therefore,
\[ e_{\text{ss}} = \lim_{s \to 0} \frac{s}{1 + C(s)G(s)} \approx \lim_{s \to 0} \frac{s}{1 + \dfrac{K K_I}{s}} = \lim_{s \to 0} \frac{s^2}{s + K K_I} = 0. \]
The derivative term contributes a factor proportional to \( s \) in \( C(s) \), which vanishes as \( s \to 0 \) and hence does not alter the steady-state error. Thus \( K_I \) determines the ability to achieve zero steady-state error to a step, whereas \( K_D \) affects only transient behavior.
8. Summary
In this lesson we formalized the continuous-time structures of P, PI, PD, and PID controllers and distinguished between parallel (non-interacting) and series (interacting) forms. We derived precise mappings between series and parallel parameters and showed how P, PI, PD, and PID structures affect the order and characteristic polynomial of a first-order plant in unity feedback.
On the implementation side, we outlined a discretized algorithm for real-time PID control in robotic systems and demonstrated parallel PID implementations in Python, C++, Java, MATLAB/Simulink, and Mathematica. These constructions provide the structural foundation on which heuristic and systematic tuning methods (e.g., Ziegler–Nichols and modern optimization-based tuning) will be built in subsequent lessons.
9. References
- Ziegler, J.G., & Nichols, N.B. (1942). Optimum settings for automatic controllers. Transactions of the ASME, 64(11), 759–768.
- Åström, K.J., & Hägglund, T. (1984). Automatic tuning of simple regulators with specifications on phase and amplitude margins. Automatica, 20(5), 645–651.
- Ho, W.K., Ang, K.H., & Chong, G. (1995). PID control system analysis, design, and technology. IEEE Transactions on Control Systems Technology, 4(4), 559–566.
- Åström, K.J., & Hägglund, T. (1995). PID Controllers: Theory, Design, and Tuning. Research Triangle Park, NC: Instrument Society of America.
- Middleton, R.H., & Goodwin, G.C. (1990). Improved finite settling time response in digital control. IEEE Transactions on Automatic Control, 35(8), 1018–1021.
- Silva, G.J., Datta, A., & Bhattacharyya, S.P. (2002). New results on the synthesis of PID controllers. IEEE Transactions on Automatic Control, 47(2), 241–252.