Chapter 20: Two-Degree-of-Freedom (2-DOF) Linear Controllers

Lesson 2: Set-Point Weighting in PID Controllers

In this lesson we study set-point weighting as a concrete realization of two-degree-of-freedom (2-DOF) PID control. We derive the closed-loop transfer functions for a general plant with 2-DOF PID, prove that set-point weights do not change the closed-loop characteristic polynomial, and show how they shape tracking transients (especially overshoot and derivative kick) without degrading disturbance rejection. Finally, we give multi-language implementations suitable for robotic servo loops.

1. Conceptual Overview of Set-Point Weighting

Consider a unity negative-feedback loop with reference (set-point) \( r(t) \), measured output \( y(t) \), and control signal \( u(t) \). In a standard (1-DOF) PID controller, all three terms (proportional, integral, derivative) act on the same error signal \( e(t) = r(t) - y(t) \).

In contrast, a set-point weighted PID controller allows the reference to enter the proportional and derivative channels with independent weights \( b \) and \( c \). A widely used continuous-time structure is

\[ \begin{aligned} u(t) &= K_p\bigl(b\,r(t)-y(t)\bigr) + K_i \int_0^t \bigl(r(\sigma)-y(\sigma)\bigr)\,d\sigma + K_d\frac{d}{dt}\bigl(c\,r(t)-y(t)\bigr), \end{aligned} \]

where \( K_p \), \( K_i \), \( K_d \) are the proportional, integral, and derivative gains, and \( b, c \in \mathbb{R} \) are the set-point weights.

  • The integral term still uses the unweighted error \( r(t)-y(t) \), which preserves zero steady-state error for step references when the loop is stable.
  • The proportional weight \( b \) reshapes the tracking transient (especially overshoot) without modifying the closed-loop poles.
  • The derivative weight \( c \) is typically chosen as \( c = 0 \) to eliminate derivative kick on reference steps.

This decoupling of reference tracking and disturbance rejection is precisely what makes the controller effectively 2-DOF.

2. Standard 1-DOF PID Closed-Loop Relations

Let the plant transfer function be

\[ P(s) = \frac{B(s)}{A(s)}, \]

where \( A(s) \) and \( B(s) \) are real-coefficient polynomials with no common factors. The standard parallel-form PID controller has transfer function

\[ C(s) = K_p + \frac{K_i}{s} + K_d s = \frac{K_d s^2 + K_p s + K_i}{s}. \]

We assume unity negative feedback, with a load disturbance \( d(t) \) entering additively at the plant input:

\[ \begin{aligned} U(s) &= C(s)\bigl(R(s)-Y(s)\bigr),\\ Y(s) &= P(s)\bigl(U(s)+D(s)\bigr), \end{aligned} \]

where \( R(s), Y(s), U(s), D(s) \) are Laplace transforms of \( r,y,u,d \). Eliminating \( U(s) \) gives

\[ \bigl(1 + P(s)C(s)\bigr)Y(s) = P(s)C(s)R(s) + P(s)D(s). \]

Hence the closed-loop transfer functions from reference and disturbance to output for the 1-DOF PID loop are

\[ \begin{aligned} G_{yr}^{1\text{DOF}}(s) &= \frac{Y(s)}{R(s)}\bigg\rvert_{D=0} = \frac{P(s)C(s)}{1 + P(s)C(s)},\\[4pt] G_{yd}^{1\text{DOF}}(s) &= \frac{Y(s)}{D(s)}\bigg\rvert_{R=0} = \frac{P(s)}{1 + P(s)C(s)}. \end{aligned} \]

The characteristic equation is \( 1 + P(s)C(s) = 0 \), and its roots are the closed-loop poles. In 1-DOF PID, adjusting reference tracking and disturbance rejection simultaneously requires retuning \( K_p, K_i, K_d \).

3. 2-DOF PID Structure with Set-Point Weights

In the 2-DOF structure, the controller uses three different pseudo-errors:

\[ \begin{aligned} e_p(t) &= b\,r(t) - y(t),\\ e_i(t) &= r(t) - y(t),\\ e_d(t) &= c\,r(t) - y(t), \end{aligned} \]

and the control law is

\[ u(t) = K_p e_p(t) + K_i \int_0^t e_i(\sigma)\,d\sigma + K_d \frac{d}{dt} e_d(t). \]

The corresponding block-structure can be summarized as follows:

flowchart TD
  R["Setpoint r(t)"] --> BP["Weight b for P"]
  R --> IERR["Error for I: r(t) - y(t)"]
  R --> CD["Weight c for D"]

  Y["Output y(t)"] --> SUM_P["Sum for P: b r(t) - y(t)"]
  BP --> SUM_P
  SUM_P --> P_TERM["Proportional term Kp (b r - y)"]

  Y --> SUM_I["Sum for I: r(t) - y(t)"]
  IERR --> SUM_I
  SUM_I --> I_TERM["Integral term Ki integral (r - y)"]

  Y --> SUM_D["Sum for D: c r(t) - y(t)"]
  CD --> SUM_D
  SUM_D --> D_TERM["Derivative term Kd d/dt (c r - y)"]

  P_TERM --> SUM_U["Sum of PID terms"]
  I_TERM --> SUM_U
  D_TERM --> SUM_U
  SUM_U --> U["Control signal u(t)"]
  U --> PLANT["Plant P(s)"]
  PLANT --> Y
        

In Laplace domain the control signal becomes

\[ \begin{aligned} U(s) &= K_p\bigl(bR(s)-Y(s)\bigr) + \frac{K_i}{s}\bigl(R(s)-Y(s)\bigr) + K_d s\bigl(cR(s)-Y(s)\bigr)\\[2pt] &= \underbrace{\Bigl(K_p b + \frac{K_i}{s} + K_d c s\Bigr)}_{F_r(s)}R(s) - \underbrace{\Bigl(K_p + \frac{K_i}{s} + K_d s\Bigr)}_{C(s)}Y(s). \end{aligned} \]

Notice that \( C(s) \) is the same PID transfer function as in the 1-DOF case. Only the reference path \( F_r(s) \) is modified by the weights \( b \) and \( c \).

4. Closed-Loop Transfer Functions and Invariance of Poles

The plant dynamics are still given by \( Y(s) = P(s)\bigl(U(s)+D(s)\bigr) \). Substituting the 2-DOF expression for \( U(s) \):

\[ \begin{aligned} Y(s) &= P(s)\Bigl(F_r(s)R(s) - C(s)Y(s) + D(s)\Bigr)\\ \bigl(1 + P(s)C(s)\bigr)Y(s) &= P(s)F_r(s)R(s) + P(s)D(s). \end{aligned} \]

Therefore the 2-DOF closed-loop transfer functions are

\[ \begin{aligned} G_{yr}(s) &= \frac{Y(s)}{R(s)}\bigg\rvert_{D=0} = \frac{P(s)F_r(s)}{1 + P(s)C(s)},\\[4pt] G_{yd}(s) &= \frac{Y(s)}{D(s)}\bigg\rvert_{R=0} = \frac{P(s)}{1 + P(s)C(s)}. \end{aligned} \]

Comparing with Section 2, observe that \( G_{yd}(s) \) is identical to the 1-DOF expression. The disturbance response is thus completely unaffected by the set-point weights \( b \) and \( c \).

To see more explicitly how \( b \) and \( c \) enter \( G_{yr}(s) \), write \( P(s) = B(s)/A(s) \) and \( C(s) = (K_d s^2 + K_p s + K_i)/s \), \( F_r(s) = (K_d c s^2 + K_p b s + K_i)/s \). Then

\[ \begin{aligned} 1 + P(s)C(s) &= 1 + \frac{B(s)}{A(s)}\frac{K_d s^2 + K_p s + K_i}{s}\\ &= \frac{sA(s) + B(s)\bigl(K_d s^2 + K_p s + K_i\bigr)}{sA(s)}. \end{aligned} \]

Thus the characteristic polynomial of the closed loop is

\[ \Phi_{\text{cl}}(s) = sA(s) + B(s)\bigl(K_d s^2 + K_p s + K_i\bigr), \]

which depends on \( K_p, K_i, K_d \) but not on \( b \) and \( c \). Consequently, set-point weights do not change the closed-loop poles.

For the reference-to-output map we obtain

\[ G_{yr}(s) = \frac{B(s)\bigl(K_d c s^2 + K_p b s + K_i\bigr)} {sA(s) + B(s)\bigl(K_d s^2 + K_p s + K_i\bigr)}, \]

while the disturbance-to-output map is

\[ G_{yd}(s) = \frac{sB(s)} {sA(s) + B(s)\bigl(K_d s^2 + K_p s + K_i\bigr)}. \]

The numerator of \( G_{yr}(s) \) depends on \( b \) and \( c \), so the zeros of the tracking response can be shaped independently of the poles and of the disturbance response. This is the core mathematical advantage of set-point weighting.

5. Transient Response and Derivative Kick

5.1 Overshoot and Effective Closed-Loop Zero

Suppose the controller has already been tuned (for example using root locus or frequency-domain methods from previous chapters) to yield acceptable disturbance rejection and robustness. Changing \( b \) modifies only the numerator polynomial

\[ N_{yr}(s) = B(s)\bigl(K_d c s^2 + K_p b s + K_i\bigr), \]

thereby moving the closed-loop zeros and reshaping the step response. Typical choices satisfy \( 0 \leq b \leq 1 \), where

  • \( b = 1 \): reference and feedback are treated symmetrically in the proportional term (1-DOF behavior).
  • \( 0 < b < 1 \): softened proportional action on set-point changes, reducing overshoot for the same closed-loop poles.
  • \( b = 0 \): the proportional term reacts only to the measured output, while the integrator slowly drives the set-point change, often giving sluggish tracking.

Because the poles are unchanged, stability and disturbance rejection are preserved as long as the original tuning was acceptable.

5.2 Derivative Kick and the Choice of \( c \)

In a 1-DOF PID, the derivative term is \( K_d \frac{d}{dt}(r(t)-y(t)) \). For a step change in the reference, \( r(t) = r_0 H(t) \) (with \( H(t) \) the Heaviside step function), the derivative of the reference is \( \dot r(t) = r_0 \delta(t) \), where \( \delta(t) \) is the Dirac impulse. The derivative contribution to the control signal is therefore

\[ u_d(t) = K_d\bigl(\dot r(t) - \dot y(t)\bigr) = K_d r_0 \delta(t) - K_d \dot y(t). \]

The term \( K_d r_0 \delta(t) \) is an impulse of arbitrarily large amplitude when implemented approximately, causing a sharp spike in the actuator signal. This is the classical derivative kick.

For the set-point weighted PID, the derivative term is

\[ u_d(t) = K_d\frac{d}{dt}\bigl(c\,r(t)-y(t)\bigr) = K_d\bigl(c\,\dot r(t)-\dot y(t)\bigr). \]

For a step reference the impulse component becomes \( K_d c r_0 \delta(t) \). Choosing \( c = 0 \) removes this impulse entirely, so that the derivative term reacts only to changes in the measured output \( y(t) \). This is standard practice in industrial and robotic PID controllers.

In summary:

  • Tune \( K_p, K_i, K_d \) (for example as 1-DOF PID).
  • Choose \( c = 0 \) to avoid derivative kick.
  • Adjust \( b \) to balance overshoot and speed of tracking while leaving disturbance rejection unchanged.

6. Design Workflow and Practical Guidelines

A typical workflow, especially common in servo drives and robotic joint control, is:

flowchart TD
  S["Start with tuned 1-DOF PID (Kp, Ki, Kd)"] --> CHOOSE_B["Choose proportional weight b in [0, 1]"]
  CHOOSE_B --> SIM_SP["Simulate step response for reference changes"]
  SIM_SP --> CHECK_OS["Check overshoot and settling time"]
  CHECK_OS --> DEC_B["Decrease b if overshoot \nis too large"]
  CHECK_OS --> INC_B["Increase b if tracking \nis too slow"]
  DEC_B --> SIM_SP
  INC_B --> SIM_SP
  CHECK_OS --> FIX_B["Fix b when trade-off is acceptable"]
  FIX_B --> CHOOSE_C["Select derivative weight c"]
  CHOOSE_C --> SET_C0["Set c = 0 to avoid derivative kick"]
  SET_C0 --> IMPLEMENT["Implement in code or robotics middleware"]
        

Practical rules of thumb:

  • Keep the integral path unweighted. Using \( r(t)-y(t) \) in the integral term ensures that all steady-state accuracy results from earlier chapters remain valid.
  • Use \( c = 0 \) in most applications. Exceptions arise when reference trajectories are smooth and prefiltered, in which case a nonzero \( c \) can slightly improve tracking.
  • Typical \( b \) range. For well-tuned motion-control loops, values \( b \approx 0.4 \) to \( b \approx 1 \) are common, with smaller \( b \) used for overshoot-sensitive axes.

7. Python Implementation — 2-DOF PID in a Simple Servo Loop

We implement a discrete-time 2-DOF PID controlling a first-order plant often used as a simplified model of a velocity servo in robotics: \( \dot y(t) = -\frac{1}{T}y(t) + \frac{1}{T}u(t) \). The code uses only numpy and matplotlib, but in practice one would often combine this structure with the python-control library or robotics frameworks (for example ros_control) for analysis and deployment.


import numpy as np
import matplotlib.pyplot as plt

# First-order plant: dy/dt = -(1/T)*y + (1/T)*u
T = 0.5

# PID gains (already tuned as 1-DOF)
Kp = 2.0
Ki = 5.0
Kd = 0.1

# Set-point weights
b = 0.6   # proportional weight
c = 0.0   # derivative weight (no derivative kick)

# Simulation settings
dt = 0.001
t_final = 5.0
n_steps = int(t_final / dt)

t = np.linspace(0.0, t_final, n_steps)
y = np.zeros(n_steps)
u = np.zeros(n_steps)
r = np.ones(n_steps)  # unit step reference

# States for integral and derivative action
xi = 0.0
e_d_prev = 0.0

for k in range(n_steps - 1):
    # Current signals
    rk = r[k]
    yk = y[k]

    # 2-DOF pseudo-errors
    e_p = b * rk - yk           # proportional pseudo-error
    e_i = rk - yk               # integral error (unweighted)
    e_d = c * rk - yk           # derivative pseudo-error

    # Integrator update (rectangle rule)
    xi = xi + e_i * dt

    # Derivative of e_d, with simple backward difference
    de_d = (e_d - e_d_prev) / dt
    e_d_prev = e_d

    # Control signal
    uk = Kp * e_p + Ki * xi + Kd * de_d
    u[k] = uk

    # Plant integration (forward Euler)
    dy = (-(1.0 / T) * yk + (1.0 / T) * uk) * dt
    y[k + 1] = yk + dy

# Plot results
plt.figure()
plt.plot(t, r, label="reference r")
plt.plot(t, y, label="output y")
plt.xlabel("time [s]")
plt.ylabel("signals")
plt.legend()
plt.title("2-DOF PID with set-point weighting (Python)")
plt.grid(True)
plt.show()
      

The same structure can be embedded into a robotic joint controller running in a real-time loop (for example in a ROS node) by replacing the simple plant integration with sensor reading and actuator command calls.

8. C++ Implementation — Embedded 2-DOF PID

C++ is widely used in embedded and robotic control (for example via ros_control and control_toolbox in ROS). Below is a minimal discrete-time 2-DOF PID loop suitable for integration into a real-time control thread. The plant update is left abstract; in a robot you would replace it by reading sensors and writing actuators.


#include <cmath>

struct TwoDofPid {
    double Kp;
    double Ki;
    double Kd;
    double b;   // proportional weight
    double c;   // derivative weight

    double xi;        // integrator state
    double e_d_prev;  // previous derivative pseudo-error

    TwoDofPid(double Kp_, double Ki_, double Kd_,
              double b_, double c_)
        : Kp(Kp_), Ki(Ki_), Kd(Kd_),
          b(b_), c(c_), xi(0.0), e_d_prev(0.0) {}

    double step(double r, double y, double dt) {
        // 2-DOF pseudo-errors
        double e_p = b * r - y;
        double e_i = r - y;
        double e_d = c * r - y;

        // Integrator
        xi = xi + e_i * dt;

        // Derivative
        double de_d = (e_d - e_d_prev) / dt;
        e_d_prev = e_d;

        // Control output
        double u = Kp * e_p + Ki * xi + Kd * de_d;
        return u;
    }
};

int main() {
    // Example: use the controller in a simple loop
    TwoDofPid pid(2.0, 5.0, 0.1, 0.6, 0.0);
    const double dt = 0.001;
    const int n_steps = 5000;

    double y = 0.0;
    double u = 0.0;
    double r = 1.0;  // unit step

    for (int k = 0; k != n_steps; ++k) {
        u = pid.step(r, y, dt);

        // Replace this simple plant with your robotic actuator model:
        // Example first-order plant: dy/dt = -(1/T)*y + (1/T)*u
        double T = 0.5;
        double dy = (-(1.0 / T) * y + (1.0 / T) * u) * dt;
        y = y + dy;
    }

    return 0;
}
      

In ROS-based robotic systems, the logic inside step is often placed inside a controller object used by ros_control, with r coming from trajectory commands and y from joint encoders.

9. Java Implementation — 2-DOF PID for Mechatronic Systems

Java is used in several educational and industrial robotics platforms (for example FIRST Robotics with WPILib, or Java bindings to middleware such as ROS). The following code illustrates a 2-DOF PID loop in Java. The plant model is a simple first-order system, as before.


public class TwoDofPid {
    private double Kp;
    private double Ki;
    private double Kd;
    private double b;
    private double c;

    private double xi;       // integrator state
    private double eDPrev;   // previous derivative pseudo-error

    public TwoDofPid(double Kp, double Ki, double Kd,
                     double b, double c) {
        this.Kp = Kp;
        this.Ki = Ki;
        this.Kd = Kd;
        this.b = b;
        this.c = c;
        this.xi = 0.0;
        this.eDPrev = 0.0;
    }

    public double step(double r, double y, double dt) {
        double eP = b * r - y;
        double eI = r - y;
        double eD = c * r - y;

        xi = xi + eI * dt;

        double dED = (eD - eDPrev) / dt;
        eDPrev = eD;

        double u = Kp * eP + Ki * xi + Kd * dED;
        return u;
    }

    public static void main(String[] args) {
        TwoDofPid pid = new TwoDofPid(2.0, 5.0, 0.1, 0.6, 0.0);

        double dt = 0.001;
        int nSteps = 5000;

        double y = 0.0;
        double u = 0.0;
        double r = 1.0;
        double T = 0.5;

        for (int k = 0; k != nSteps; ++k) {
            u = pid.step(r, y, dt);

            // Simple plant model; replace with real actuator dynamics
            double dy = (-(1.0 / T) * y + (1.0 / T) * u) * dt;
            y = y + dy;
        }

        // In practice, log y and u or visualize them using a plotting library.
    }
}
      

In a robotics setting, this 2-DOF PID block can be integrated into higher-level frameworks that handle trajectory generation and communication with sensors and actuators.

10. MATLAB/Simulink Implementation with Robotics Context

MATLAB and Simulink are standard tools in control and robotics. The following script builds the closed-loop transfer functions \( G_{yr}(s) \) and \( G_{yd}(s) \) for a simple plant under 2-DOF PID control using the formulae derived earlier. The same structure can be represented in Simulink using blocks, and connected to articulated robot models via Robotics System Toolbox.


s = tf('s');

% Plant: simple velocity servo model
P = 1 / ((0.5 * s + 1) * s);  % type-1 plant

% PID gains from a previous 1-DOF design
Kp = 2.0;
Ki = 5.0;
Kd = 0.1;

% Set-point weights
b = 0.6;
c = 0.0;

% 1-DOF PID transfer function
C = Kp + Ki / s + Kd * s;

% Reference path transfer function F_r(s)
Fr = Kp * b + Ki / s + Kd * c * s;

% Closed-loop transfer functions using analytical formulas
Gyr = (P * Fr) / (1 + P * C);  % from r to y
Gyd = P / (1 + P * C);         % from d (load) to y

figure;
step(Gyr);
hold on;
step(Gyd);
grid on;
legend('G_{yr}(s)', 'G_{yd}(s)');
title('2-DOF PID: tracking vs disturbance response');

% In Simulink:
%  - Use separate summing blocks for b*r - y, r - y, and c*r - y.
%  - Implement Kp, Ki/s, Kd*s as gain, integrator, and derivative blocks.
%  - Connect plant P(s) using a Transfer Fcn block or a more detailed robot model.
      

When controlling robot joints, replace P with the transfer function derived from the joint dynamics (motor, gear, load inertia) and connect Gyr to reference trajectories generated by a motion planner.

11. Wolfram Mathematica Implementation

Mathematica provides symbolic and numeric tools for control analysis. The following snippet constructs the 2-DOF closed-loop transfer functions in symbolic form and evaluates step responses. The same framework can be interfaced with multibody robot models via SystemModeler.


(* Define symbolic variable *)
Clear[s];
Kp = 2.0; Ki = 5.0; Kd = 0.1;
b = 0.6;  c = 0.0;

(* Plant and controller *)
P[s_] := 1/((0.5 s + 1) s);
C[s_] := Kp + Ki/s + Kd s;
Fr[s_] := Kp b + Ki/s + Kd c s;

(* Closed-loop transfer functions *)
Gyr[s_] := (P[s] Fr[s])/(1 + P[s] C[s]);
Gyd[s_] := P[s]/(1 + P[s] C[s]);

(* Convert to TransferFunctionModel for simulation *)
GyrTF = TransferFunctionModel[Gyr[s], s];
GydTF = TransferFunctionModel[Gyd[s], s];

(* Step responses *)
tmax = 5.0;
ResponsePlot[
  {
    {GyrTF, "tracking"},
    {GydTF, "disturbance"}
  },
  {0, tmax},
  PlotLegends -> Automatic,
  Frame -> True,
  FrameLabel -> {"time", "output"},
  GridLines -> Automatic
]
      

Symbolic access to \( G_{yr}(s) \) and \( G_{yd}(s) \) is particularly useful for theoretical analysis of pole-zero cancellations, sensitivity to parameter variations, and the effect of different values of \( b \) and \( c \).

12. Problems and Solutions

Problem 1 (Derivation of 2-DOF Closed-Loop Maps): Consider a plant \( P(s) \) and a 2-DOF PID controller as defined in this lesson, with set-point weights \( b \) and \( c \). Derive the closed-loop transfer functions \( G_{yr}(s) \) and \( G_{yd}(s) \) and show explicitly that the disturbance response does not depend on \( b \) and \( c \).

Solution: We start from

\[ \begin{aligned} U(s) &= K_p\bigl(bR(s)-Y(s)\bigr) + \frac{K_i}{s}\bigl(R(s)-Y(s)\bigr) + K_d s\bigl(cR(s)-Y(s)\bigr)\\ &= F_r(s)R(s) - C(s)Y(s), \end{aligned} \]

where \( F_r(s) = K_p b + \frac{K_i}{s} + K_d c s \) and \( C(s) = K_p + \frac{K_i}{s} + K_d s \). The plant with input disturbance satisfies \( Y(s) = P(s)\bigl(U(s)+D(s)\bigr) \), so

\[ Y(s) = P(s)\bigl(F_r(s)R(s) - C(s)Y(s) + D(s)\bigr). \]

Collecting terms in \( Y(s) \) gives

\[ \bigl(1 + P(s)C(s)\bigr)Y(s) = P(s)F_r(s)R(s) + P(s)D(s). \]

Setting \( D(s) = 0 \) yields \( G_{yr}(s) = \frac{P(s)F_r(s)}{1+P(s)C(s)} \), while setting \( R(s) = 0 \) yields \( G_{yd}(s) = \frac{P(s)}{1+P(s)C(s)} \). The disturbance response contains only \( P(s) \) and \( C(s) \), and is therefore independent of the weights \( b \) and \( c \).

Problem 2 (Characteristic Polynomial Independence): With \( P(s) = B(s)/A(s) \) and \( C(s) = \frac{K_d s^2 + K_p s + K_i}{s} \), show that the closed-loop characteristic polynomial does not depend on the weights \( b \) and \( c \) in the 2-DOF PID structure.

Solution: From Problem 1 the characteristic equation is \( 1 + P(s)C(s) = 0 \), independent of \( F_r(s) \). Substituting \( P(s) = B(s)/A(s) \) and \( C(s) = (K_d s^2 + K_p s + K_i)/s \):

\[ \begin{aligned} 1 + P(s)C(s) &= 1 + \frac{B(s)}{A(s)}\frac{K_d s^2 + K_p s + K_i}{s}\\ &= \frac{sA(s) + B(s)\bigl(K_d s^2 + K_p s + K_i\bigr)}{sA(s)}. \end{aligned} \]

The closed-loop characteristic polynomial is therefore \( \Phi_{\text{cl}}(s) = sA(s) + B(s)\bigl(K_d s^2 + K_p s + K_i\bigr) \), which depends on the plant and PID gains but not on \( b \) or \( c \). Thus the closed-loop poles are invariant under changes in the set-point weights.

Problem 3 (Derivative Kick with and without Weighting): For a standard 1-DOF PID with derivative term \( u_d(t) = K_d\frac{d}{dt}(r(t)-y(t)) \), consider a step change \( r(t) = r_0 H(t) \) at \( t=0 \). Assume \( y(t) \) is continuous at \( t=0 \). Show that the control signal contains an impulse, and compute its magnitude. Then repeat the calculation for the 2-DOF derivative term \( u_d(t) = K_d\frac{d}{dt}(c\,r(t)-y(t)) \) and show how the weight \( c \) affects the impulse.

Solution: For the 1-DOF derivative term,

\[ u_d(t) = K_d\bigl(\dot r(t) - \dot y(t)\bigr). \]

With \( r(t) = r_0 H(t) \), we have \( \dot r(t) = r_0 \delta(t) \). Since \( y(t) \) is continuous at \( t=0 \), \( \dot y(t) \) does not contain a Dirac impulse. Hence

\[ u_d(t) = K_d r_0 \delta(t) - K_d \dot y(t), \]

so the impulse magnitude at \( t = 0 \) is \( K_d r_0 \).

For the 2-DOF derivative term \( u_d(t) = K_d\frac{d}{dt}\bigl(c\,r(t)-y(t)\bigr) \) we obtain

\[ u_d(t) = K_d\bigl(c\,\dot r(t) - \dot y(t)\bigr) = K_d c r_0 \delta(t) - K_d \dot y(t). \]

Thus the derivative kick is scaled by \( c \). For \( c = 0 \) no impulse appears in \( u_d(t) \), which explains the standard industrial choice \( c = 0 \).

Problem 4 (Steady-State Error with Set-Point Weighting): Assume that the 2-DOF PID uses the unweighted error \( r(t)-y(t) \) in the integral path, as in this lesson. Let the plant be strictly proper and stable when closed with the tuned PID. Show, using the final value theorem, that the steady-state error to a unit step reference is zero, independently of \( b \) and \( c \).

Solution: Let \( e(t) = r(t)-y(t) \), and assume \( r(t) = H(t) \). From Chapter 8 we know that if the closed loop has at least one pole at the origin due to integral action and is internally stable, then the final value theorem yields

\[ e_{\text{ss}} = \lim_{t \rightarrow \infty} e(t) = \lim_{s \rightarrow 0} sE(s). \]

The integral term contributes \( K_i/s \) in \( C(s) \), so the loop is at least of type one with respect to reference tracking. The presence of \( b \) and \( c \) only modifies the numerator of the reference-to-output transfer function, not the factor \( K_i/s \) nor the characteristic polynomial. Hence the same argument as for standard PI or PID control applies: for a stable closed loop, the steady-state error to a step reference is zero. The values of \( b \) and \( c \) may change the transient but cannot change the limit value of \( e(t) \).

13. Summary

In this lesson we introduced set-point weighting as a key mechanism for realizing two-degree-of-freedom PID control. Starting from the standard 1-DOF PID structure, we derived the 2-DOF control law with proportional and derivative weights \( b \) and \( c \), and showed that:

  • The closed-loop characteristic polynomial \( \Phi_{\text{cl}}(s) \) is independent of \( b \) and \( c \), so stability and disturbance rejection remain unchanged when set-point weights are introduced.
  • The numerator of the tracking transfer function \( G_{yr}(s) \) depends on \( b \) and \( c \), allowing independent shaping of reference-tracking transients.
  • Choosing \( c = 0 \) eliminates derivative kick on step changes in the reference, which is crucial for actuator protection in robotics and mechatronics.
  • Practical implementations in Python, C++, Java, MATLAB/Simulink, and Mathematica are straightforward, and integrate naturally with robotics libraries such as ros_control, control_toolbox, WPILib, and Robotics System Toolbox.

In the next lesson, we will generalize these ideas by introducing explicit reference pre-filters, further refining the separation between tracking and disturbance-rejection objectives in 2-DOF designs.

14. References

  1. Åström, K. J., & Hägglund, T. (1995). PID Controllers: Theory, Design, and Tuning. ISA, Research Triangle Park, NC.
  2. Åström, K. J., & Hägglund, T. (2001). The future of PID control. Control Engineering Practice, 9(11), 1163–1175.
  3. Hang, C. C., Åström, K. J., & Ho, W. K. (1993). Refinements of the Ziegler–Nichols tuning formula. IEE Proceedings D (Control Theory and Applications), 140(4), 317–322.
  4. Ho, W. K., Hang, C. C., & Cao, L. S. (1995). Tuning of PID controllers based on gain and phase margin specifications. Automatica, 31(3), 497–502.
  5. Horowitz, I. M. (1963). Synthesis of feedback systems with small sensitivity to parameter variations. International Journal of Electronics, 15(5), 489–498.
  6. Shamsuzzoha, M., & Lee, M. (2008). Design of a two-degree-of-freedom PID controller with set-point weighting. Journal of Process Control, 18(5), 445–456.