Chapter 25: Multiloop and Cascade Control Structures (SISO Focus)

Lesson 3: Outer-Loop Design on Top of an Inner Loop

In this lesson we assume that an inner loop has already been designed and tuned (Lesson 2) and study how to place an outer loop around it. We derive the effective plant seen by the outer controller, analyze stability and performance using transfer functions and sensitivity functions, and illustrate a simple PI outer-loop design. Finally, we show how to simulate such cascade structures in Python, C++, Java, MATLAB/Simulink, and Wolfram Mathematica, with an eye toward robotic servo applications.

1. Conceptual Role of the Outer Loop

Consider a plant with transfer function \( G_p(s) \), an inner controller \( C_i(s) \), and an outer controller \( C_o(s) \). The inner loop is already closed and operates on a reference signal \( w(t) \) generated by the outer loop. The outer controller compares the process output \( y(t) \) to the outer reference \( r(t) \) and adjusts \( w(t) \).

The inner loop from \( w \) to \( y \) has a closed-loop transfer function

\[ G_{\mathrm{i,cl}}(s) = \frac{C_i(s) G_p(s)}{1 + C_i(s) G_p(s)}. \]

The outer loop sees the composite plant \( G_{\mathrm{i,cl}}(s) \). Intuitively:

  • The inner controller shapes the actuator dynamics to be fast and well-damped.
  • The outer controller then solves the main tracking or regulation task with a simpler, better-behaved effective plant.

A typical signal structure is:

flowchart TD
  R["Outer reference r(t)"] --> Eo["Outer error e_o(t) = r(t) - y(t)"]
  Eo --> Co["Outer controller Co(s)"]
  Co --> W["Inner reference w(t)"]
  W --> Gi["Inner closed loop Gi_cl(s)"]
  Gi --> Y["Output y(t)"]
  Y --> Eo
        

In robotic servo drives, the inner loop often controls a fast variable (e.g. motor current or velocity), while the outer loop controls a slower task variable (e.g. joint position). The math here is SISO, but the same idea appears in many mechatronic systems.

2. Closed-Loop Mathematics of the Outer Loop

We derive the closed-loop transfer from outer reference \( R(s) \) to output \( Y(s) \) when the inner loop is already closed. Using the structure in Section 1:

  • Outer error: \( e_o(t) = r(t) - y(t) \), so in Laplace domain \( E_o(s) = R(s) - Y(s) \).
  • Outer controller: \( W(s) = C_o(s) E_o(s) \).
  • Inner closed loop: \( Y(s) = G_{\mathrm{i,cl}}(s) W(s) \).

Substituting step by step:

\[ Y(s) = G_{\mathrm{i,cl}}(s) C_o(s) \bigl(R(s) - Y(s)\bigr). \]

Rearranging:

\[ Y(s) + G_{\mathrm{i,cl}}(s) C_o(s) Y(s) = G_{\mathrm{i,cl}}(s) C_o(s) R(s), \]

\[ Y(s) \bigl[1 + C_o(s) G_{\mathrm{i,cl}}(s)\bigr] = C_o(s) G_{\mathrm{i,cl}}(s) R(s). \]

Hence the outer closed-loop transfer function is

\[ T_{\mathrm{o}}(s) = \frac{Y(s)}{R(s)} = \frac{C_o(s) G_{\mathrm{i,cl}}(s)}{1 + C_o(s) G_{\mathrm{i,cl}}(s)}. \]

This has the same structure as a standard single-loop system with open-loop transfer \( L_o(s) = C_o(s) G_{\mathrm{i,cl}}(s) \).

The corresponding sensitivity function of the outer loop is

\[ S_{\mathrm{o}}(s) = \frac{1}{1 + C_o(s) G_{\mathrm{i,cl}}(s)}, \]

while the complementary sensitivity of the outer loop coincides with \( T_{\mathrm{o}}(s) \). These objects thus inherit all the interpretations from Chapter 22: tracking, disturbance rejection at various frequencies, and robustness margins, but now with \( G_{\mathrm{i,cl}}(s) \) as the plant.

If a disturbance \( d(t) \) enters the inner loop (for instance at the plant input), one can show that the total disturbance-to-output transfer typically factors as

\[ \frac{Y(s)}{D(s)} = G_{\mathrm{i,d}}(s)\, S_{\mathrm{o}}(s), \]

where \( G_{\mathrm{i,d}}(s) \) is the transfer from disturbance to output with the inner loop closed but the outer loop open. Thus a well-designed outer loop further attenuates the residual disturbances left by the inner loop.

3. Bandwidth Separation and Robustness Conditions

Let \( \omega_{\mathrm{c,i}} \) denote the crossover frequency of the inner loop open-loop transfer \( L_i(s) = C_i(s) G_p(s) \), and \( \omega_{\mathrm{c,o}} \) the crossover of the outer loop \( L_o(s) = C_o(s) G_{\mathrm{i,cl}}(s) \).

Heuristic separation rule. For approximate decoupling of the loops, a widely used guideline is

\[ \omega_{\mathrm{c,o}} \lesssim \frac{1}{3}\,\omega_{\mathrm{c,i}}. \]

Qualitatively:

  • For frequencies \( \omega \) in the main operating band of the outer loop, the inner loop is already close to its low-frequency closed-loop behavior (\( G_{\mathrm{i,cl}}(j\omega) \) nearly constant, good damping).
  • Around \( \omega_{\mathrm{c,i}} \), where the inner loop changes behavior and its phase margin is critical, the outer open-loop magnitude \( |L_o(j\omega)| \) is already small, so the outer loop does not significantly reduce inner-loop robustness.

More formally, suppose the inner loop is stable and has sensitivity \( S_i(s) = 1 / (1 + L_i(s)) \). If the outer loop is designed so that \( |L_o(j\omega)| \ll 1 \) for \( \omega \geq \omega_{\mathrm{c,i}} \), then the total loop gain seen by the plant near the inner crossover frequency is dominated by \( L_i(s) \), and the inner robustness margins are essentially preserved.

Therefore, the outer-loop design problem is:

  • Choose a controller \( C_o(s) \) achieving desired tracking and disturbance rejection for the slow dynamics of the process.
  • Ensure that \( \omega_{\mathrm{c,o}} \) and the associated gain/phase margins are compatible with the existing inner-loop dynamics and margins.

4. Example: PI Outer Loop Around a Fast Inner Loop

Consider a simple first-order plant

\[ G_p(s) = \frac{1}{s + 1}, \]

representing, e.g., a low-order approximation of a motor velocity loop. The inner loop uses proportional control \( C_i(s) = k_i \). Its closed-loop transfer from \( w(t) \) to \( y(t) \) is

\[ G_{\mathrm{i,cl}}(s) = \frac{k_i \frac{1}{s+1}}{1 + k_i \frac{1}{s+1}} = \frac{k_i}{s + 1 + k_i}. \]

Fix \( k_i = 9 \). Then

\[ G_{\mathrm{i,cl}}(s) = \frac{9}{s + 10}, \]

which has a time constant \( 0.1 \) and a bandwidth on the order of \( \omega_{\mathrm{c,i}} \approx 10 \,\mathrm{rad/s} \).

Now design a PI outer controller

\[ C_o(s) = k_p + \frac{k_I}{s} = \frac{k_p s + k_I}{s}. \]

The open-loop transfer of the outer loop is

\[ L_o(s) = C_o(s) G_{\mathrm{i,cl}}(s) = \frac{(k_p s + k_I) k_i}{s \bigl(s + 1 + k_i\bigr)}. \]

The outer closed-loop characteristic polynomial is obtained from \( 1 + L_o(s) = 0 \), i.e.,

\[ s \bigl(s + 1 + k_i\bigr) + k_i (k_p s + k_I) = 0. \]

Expanding and grouping in powers of \( s \),

\[ s^2 + (1 + k_i + k_i k_p) s + k_i k_I = 0. \]

This is a second-order polynomial of the form \( s^2 + a s + b \) with \( a = 1 + k_i + k_i k_p \) and \( b = k_i k_I \). For second-order systems, the Routh–Hurwitz criterion reduces to

\[ a > 0, \quad b > 0. \]

With \( k_i > 0 \), any \( k_p > -\frac{1 + k_i}{k_i} \) and \( k_I > 0 \) yield a stable outer loop. For practical positive gains \( k_p > 0 \), \( k_I > 0 \) the system is thus stable.

As a concrete choice, take

  • \( k_i = 9 \) (inner loop),
  • \( k_p = 0.5 \), \( k_I = 1.0 \) (outer PI).

Then

\[ a = 1 + 9 + 9 \cdot 0.5 = 14.5, \quad b = 9 \cdot 1.0 = 9. \]

The corresponding natural frequency and damping ratio are

\[ \omega_n = \sqrt{b} = 3, \quad \zeta = \frac{a}{2 \omega_n} = \frac{14.5}{6} \approx 2.42, \]

so the outer loop is highly overdamped with a dominant bandwidth on the order of \( \omega_{\mathrm{c,o}} \approx 3 \,\mathrm{rad/s} \), well below the inner loop bandwidth of about \( 10 \,\mathrm{rad/s} \). This satisfies the approximate separation rule and provides a slow, non-oscillatory response.

In practice, one would adjust \( k_p \) and \( k_I \) to achieve a preferred trade-off between rise time and overshoot, but the key point is that the outer-loop design can be analyzed using familiar second-order polynomial tools, treating the inner loop as a fixed fast subsystem.

5. Software Lab: Simulating the Outer Loop on Top of an Inner Loop

We now implement the example of Section 4 in several environments. Such simulations are directly relevant to robot joint control: the inner loop represents a fast current or velocity loop implemented in drive electronics, while the outer loop may be implemented in a higher-level controller (e.g., on a robot controller PC using ROS).

5.1 Python (with python-control)

The python-control package provides transfer-function and time-domain simulation tools. The code below constructs the inner closed loop and designs the outer PI controller as in Section 4.


import numpy as np
import matplotlib.pyplot as plt

# pip install control
import control as ct

# Plant and inner loop
s = ct.TransferFunction.s
Gp = 1 / (s + 1)     # G_p(s) = 1 / (s + 1)
k_i = 9.0
Ci = k_i
Gi_cl = ct.feedback(Ci * Gp, 1)  # inner closed loop G_i,cl(s)

# Outer PI controller
k_p = 0.5
k_I = 1.0
Co = k_p + k_I / s

# Outer closed loop T_o(s) from r to y
L_outer = Co * Gi_cl
T_outer = ct.feedback(L_outer, 1)

# Step response
t = np.linspace(0, 5, 1000)
t_out, y_out = ct.step_response(T_outer, T=t)

plt.figure()
plt.plot(t_out, y_out)
plt.xlabel("t [s]")
plt.ylabel("y(t)")
plt.title("Outer-loop step response with inner loop closed")
plt.grid(True)
plt.show()

# Frequency response to inspect bandwidth separation
w = np.logspace(-2, 2, 300)
mag_i, phase_i, w_i = ct.bode(Ci * Gp, w, Plot=False)
mag_o, phase_o, w_o = ct.bode(L_outer, w, Plot=False)

# Rough estimate of crossover frequencies
def crossover(w_vals, mag_vals):
    idx = np.argmin(np.abs(mag_vals - 1.0))
    return w_vals[idx]

w_ci = crossover(w_i, mag_i)
w_co = crossover(w_o, mag_o)
print("Inner-loop crossover ~", w_ci, "rad/s")
print("Outer-loop crossover ~", w_co, "rad/s")
      

In a robotic setup with ROS, the inner loop would run on the drive hardware, while the outer loop would run as a node computing \( w(t) \) from joint position error and sending it as a velocity or torque reference over a field bus.

5.2 C++ (Discrete-Time Simulation, ROS-Style Loop)

In C++, outer-loop control is often embedded in a real-time loop (for instance within ros_control or ros2_control). Below is a bare-bones Euler integration of the same cascade structure:


#include <iostream>
#include <vector>

int main() {
    // Continuous-time model: x_dot = -x + u, y = x
    // Inner loop: u = k_i * (w - y)
    // Outer loop: w = k_p * e_o + z,  z_dot = k_I * e_o (PI integrator)
    double k_i = 9.0;
    double k_p = 0.5;
    double k_I = 1.0;

    double h = 1e-3;           // simulation step [s]
    double t_end = 5.0;
    int n_steps = static_cast<int>(t_end / h);

    double x = 0.0;            // plant state
    double z = 0.0;            // integral state of outer PI
    double y = 0.0;            // output
    double r = 1.0;            // step reference

    std::vector<double> t_hist, y_hist;
    t_hist.reserve(n_steps);
    y_hist.reserve(n_steps);

    for (int k = 0; k < n_steps; ++k) {
        double t = k * h;

        // Outer loop
        double e_outer = r - y;
        z += h * (k_I * e_outer);   // integrator
        double w = k_p * e_outer + z;

        // Inner loop (P)
        double u = k_i * (w - y);

        // Plant integration: x_dot = -x + u
        double x_dot = -x + u;
        x += h * x_dot;
        y = x;

        t_hist.push_back(t);
        y_hist.push_back(y);
    }

    // Print a few samples
    for (int i = 0; i < 10; ++i) {
        int idx = i * (n_steps / 10);
        std::cout << "t=" << t_hist[idx]
                  << "  y=" << y_hist[idx] << std::endl;
    }
    return 0;
}
      

In a robotics project, the loop body would run at a fixed sample time determined by the driver (e.g., 1 kHz), and the values \( r(t) \) and \( y(t) \) would be obtained from joint-space trajectories and sensors, respectively.

5.3 Java (Outer-Loop Simulation, Suitable for Embedded JVM Controllers)

Java is occasionally used in higher-level robot control stacks (or simulation tools). The following code performs the same discrete-time simulation using primitive arrays:


public class CascadeOuterLoopExample {
    public static void main(String[] args) {
        double k_i = 9.0;
        double k_p = 0.5;
        double k_I = 1.0;

        double h = 1e-3;
        double tEnd = 5.0;
        int nSteps = (int) (tEnd / h);

        double x = 0.0;   // plant state
        double z = 0.0;   // PI integrator
        double y = 0.0;   // output
        double r = 1.0;   // step reference

        double[] tHist = new double[nSteps];
        double[] yHist = new double[nSteps];

        for (int k = 0; k < nSteps; ++k) {
            double t = k * h;

            double eOuter = r - y;
            z += h * (k_I * eOuter);
            double w = k_p * eOuter + z;

            double u = k_i * (w - y);  // inner P loop

            double xDot = -x + u;
            x += h * xDot;
            y = x;

            tHist[k] = t;
            yHist[k] = y;
        }

        for (int i = 0; i < 10; ++i) {
            int idx = i * (nSteps / 10);
            System.out.println("t=" + tHist[idx] + "  y=" + yHist[idx]);
        }
    }
}
      

Libraries such as Apache Commons Math provide ODE solvers and matrix tools that can replace the simple Euler integration shown above for more accurate simulations.

5.4 MATLAB/Simulink

MATLAB Control System Toolbox allows a compact representation of the cascade structure:


% Plant and inner loop
s = tf('s');
Gp = 1 / (s + 1);
k_i = 9;
Ci = k_i;
Gi_cl = feedback(Ci * Gp, 1);    % inner closed loop

% Outer PI loop
k_p = 0.5;
k_I = 1.0;
Co = k_p + k_I / s;

L_outer = Co * Gi_cl;
T_outer = feedback(L_outer, 1);

figure;
step(T_outer);
title('Outer-loop step response with inner loop closed');
grid on;
      

A corresponding Simulink model can be built with:

  • A plant block implementing \( G_p(s) \).
  • An inner P controller in feedback around the plant.
  • An outer PI controller that feeds its output into the inner loop reference.

This is essentially the standard cascade control demo often used for motor drive and servo drive examples.

5.5 Wolfram Mathematica

In Mathematica, one can work symbolically with transfer functions:


s = LaplaceTransformVariable;

(* Plant and inner loop *)
Gp = TransferFunctionModel[1/(s + 1), s];
kI = 9;
Ci = kI;
GiCl = FeedbackConnect[Ci*Gp, 1];

(* Outer PI controller *)
kP = 0.5;
kInt = 1.0;
Co = TransferFunctionModel[(kP*s + kInt)/s, s];

Louter = SeriesConnect[Co, GiCl];
Tout = FeedbackConnect[Louter, 1];

(* Step response *)
resp = OutputResponse[Tout, UnitStep[t], {t, 0, 5}];
Plot[resp, {t, 0, 5}, AxesLabel -> {"t", "y(t)"},
     PlotLabel -> "Outer-loop step response"];
      

The symbolic environment is particularly convenient for verifying formulae such as the characteristic polynomial derived in Section 4.

6. Design Workflow for an Outer Loop on a Closed Inner Loop

A practical design workflow that respects the mathematics developed above can be summarized as:

flowchart TD
  A["Design and tune inner loop for speed and robustness"] --> B["Identify or approximate Gi_cl(s)"]
  B --> C["Specify outer-loop objectives (tracking, disturbance rejection)"]
  C --> D["Design Co(s) as if Gi_cl(s) were the plant"]
  D --> E["Check bandwidth separation and margins of both loops"]
  E --> F["Iterate inner / outer tuning until specifications are met"]
        

In robotics, one typically freezes the inner loop at the drive level and iterates mainly on the outer loop gains, while ensuring that the new outer loop does not reduce the inner-loop robustness below acceptable margins (e.g. gain and phase margins from Chapters 17–18).

7. Problems and Solutions

Problem 1 (Closed-Loop Derivation): Consider the cascade structure of Sections 1–2, with inner closed-loop transfer \( G_{\mathrm{i,cl}}(s) \) and outer controller \( C_o(s) \). Derive the outer closed-loop transfer \( T_{\mathrm{o}}(s) = Y(s) / R(s) \).

Solution: From the block diagram we have

\[ E_o(s) = R(s) - Y(s), \quad W(s) = C_o(s) E_o(s), \quad Y(s) = G_{\mathrm{i,cl}}(s) W(s). \]

Substituting \( W(s) = C_o(s) (R(s) - Y(s)) \) into the last equation gives

\[ Y(s) = G_{\mathrm{i,cl}}(s) C_o(s) \bigl(R(s) - Y(s)\bigr). \]

Rearrangement yields

\[ Y(s)\bigl[1 + C_o(s) G_{\mathrm{i,cl}}(s)\bigr] = C_o(s) G_{\mathrm{i,cl}}(s) R(s), \]

hence

\[ \frac{Y(s)}{R(s)} = \frac{C_o(s) G_{\mathrm{i,cl}}(s)}{1 + C_o(s) G_{\mathrm{i,cl}}(s)} = T_{\mathrm{o}}(s). \]

Problem 2 (Stability with Outer P Control): Assume the inner loop is closed and has stable transfer \( G_{\mathrm{i,cl}}(s) = \dfrac{b}{s + a} \) with \( a > 0 \) and \( b > 0 \). The outer controller is proportional: \( C_o(s) = k_p \). (a) Find the outer closed-loop transfer \( T_{\mathrm{o}}(s) \). (b) Show that the overall system is stable if and only if \( a + b k_p > 0 \). (c) Interpret this condition for \( k_p > 0 \).

Solution:

(a) Using the formula from Problem 1,

\[ T_{\mathrm{o}}(s) = \frac{k_p \frac{b}{s + a}}{1 + k_p \frac{b}{s + a}} = \frac{k_p b}{s + a + k_p b}. \]

(b) The characteristic polynomial is \( s + a + b k_p \). For a first-order system, the pole is at \( s = -a - b k_p \). Stability requires the pole to lie in the open left half-plane, i.e.

\[ -a - b k_p < 0 \quad \Longleftrightarrow \quad a + b k_p > 0. \]

(c) With \( a > 0 \), \( b > 0 \), any positive gain \( k_p > 0 \) satisfies this condition. Thus proportional outer control on top of a stable first-order inner loop cannot destabilize the system for positive gain, although large positive gains will shift the pole further left and may lead to actuator saturation in practice.

Problem 3 (Characteristic Polynomial with Outer PI): For the plant and controllers in Section 4, with \( G_p(s) = 1/(s + 1) \), \( C_i(s) = k_i \), and \( C_o(s) = k_p + k_I/s \), derive the outer closed-loop characteristic polynomial in terms of \( k_i, k_p, k_I \) and verify that it matches

\[ s^2 + (1 + k_i + k_i k_p) s + k_i k_I = 0. \]

Solution:

First compute the inner closed loop:

\[ G_{\mathrm{i,cl}}(s) = \frac{k_i \frac{1}{s + 1}}{1 + k_i \frac{1}{s + 1}} = \frac{k_i}{s + 1 + k_i}. \]

The outer open loop is

\[ L_o(s) = C_o(s) G_{\mathrm{i,cl}}(s) = \frac{k_p s + k_I}{s} \cdot \frac{k_i}{s + 1 + k_i} = \frac{(k_p s + k_I) k_i}{s (s + 1 + k_i)}. \]

The characteristic equation is \( 1 + L_o(s) = 0 \), or

\[ s (s + 1 + k_i) + k_i (k_p s + k_I) = 0. \]

Expanding:

\[ s^2 + (1 + k_i) s + k_i k_p s + k_i k_I = s^2 + (1 + k_i + k_i k_p) s + k_i k_I = 0, \]

which is precisely the expression stated.

Problem 4 (Bandwidth Separation Check): Suppose the inner loop has crossover frequency \( \omega_{\mathrm{c,i}} = 30 \,\mathrm{rad/s} \), and an outer design yields \( \omega_{\mathrm{c,o}} \approx 3 \,\mathrm{rad/s} \). (a) Compute the ratio \( \omega_{\mathrm{c,i}} / \omega_{\mathrm{c,o}} \). (b) Comment on whether this satisfies the heuristic separation rule \( \omega_{\mathrm{c,o}} \lesssim \omega_{\mathrm{c,i}}/3 \). (c) What qualitative behavior would you expect for the combined system?

Solution:

(a) The ratio is

\[ \frac{\omega_{\mathrm{c,i}}}{\omega_{\mathrm{c,o}}} = \frac{30}{3} = 10. \]

(b) The heuristic rule gives \( \omega_{\mathrm{c,i}}/3 = 10 \,\mathrm{rad/s} \). Since \( \omega_{\mathrm{c,o}} = 3 \,\mathrm{rad/s} \), we have \( \omega_{\mathrm{c,o}} \ll \omega_{\mathrm{c,i}}/3 \). Therefore the separation is stronger than required by the rule.

(c) The inner loop will be very fast compared with the outer loop, so the outer controller effectively sees a well-behaved, almost static gain around its crossover. The inner-loop robustness margins will not be significantly affected by the outer loop, and the overall response will typically be smooth and well damped, at the cost of a relatively slow outer-loop response.

8. Summary

In this lesson we formalized outer-loop design on top of a preexisting inner loop. The key idea is that the outer loop sees the inner closed loop as an effective plant \( G_{\mathrm{i,cl}}(s) \), and hence its design can be treated using the same transfer-function methods as a single-loop system. We derived the outer closed-loop transfer function and characteristic polynomial, highlighted the importance of bandwidth separation to preserve inner-loop robustness, and worked through a simple PI outer-loop example.

Through multi-language software implementations, we saw how such cascade structures can be simulated and implemented in practice, particularly in robotic servo systems where fast inner loops run on drive electronics and slower outer loops run on higher-level controllers. The next lessons will augment these multiloop structures with feedforward paths for improved disturbance rejection.

9. References

  1. Å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.
  2. Hovd, M., & Skogestad, S. (1994). Sequential design of decentralized controllers. Automatica, 30(10), 1601–1607. (Discusses multi-loop and cascade structures from a theoretical perspective.)
  3. Goodwin, G. C., Graebe, S. F., & Salgado, M. E. (2001). Control System Design. Prentice Hall. (Chapters on cascade and multiloop control.)
  4. Åström, K. J., & Murray, R. M. (2008). Feedback Systems: An Introduction for Scientists and Engineers. Princeton University Press. (See sections on multi-loop and hierarchical control.)
  5. Skogestad, S., & Postlethwaite, I. (2005). Multivariable Feedback Control: Analysis and Design. Wiley. (Although oriented to MIMO, provides rigorous analysis tools applicable to multiloop SISO.)