explainer
Multivariable control: manage coupling between outputs
Move one output without disturbing another. Compare independent feedback with matrix decoupling, then test model mismatch and large actuator commands.
What you will learn
- Read how each input affects both outputs of a coupled system.
- Compare independent proportional feedback with a matrix decoupler.
- Calculate actuator commands that cancel a known interaction.
- Explain how model mismatch restores cross-output motion.
- Connect nearly dependent actuator directions to conditioning and command size.
Before you start
Multivariable control coordinates several inputs and outputs when their effects interact. A system with multiple inputs and multiple outputs is often called MIMO. Moving one output can disturb another, even when that second output already sits at its target.
Here two actuators each move two position coordinates. You will compare separate feedback loops with a controller that cancels the known coupling. Then you will change the model and inspect the commands that cancellation requires.
One command can move two outputs
A single-input, single-output loop, or SISO loop, pairs one command with one measured quantity. For a coupled plant, that pairing leaves out the command's effect on the other quantity.
Imagine two ideal actuators that move a platform along different fixed directions. A positive command to actuator 1 moves both coordinates. Actuator 2 can counter the unwanted motion, but its correction also affects coordinate 1.
Independent loops can still stabilize such a plant. Their interaction changes the response, so tuning one loop while ignoring the other can miss a large excursion or a slow mode. The example below makes that distinction explicit.
Define the two-input plant
Let p = [p₁, p₂]ᵀ be position and u = [u₁, u₂]ᵀ the actuator commands. The measured outputs are both positions, y = p. Positions, commands, and time use fixed dimensionless normalizations throughout:
ṗ = B(c)u
B(c) = [[1, c], [c, 1]]
ṗ₁ = u₁ + c u₂
ṗ₂ = c u₁ + u₂
Each column of B gives one actuator's velocity direction. At c = 0.6, command [1, 0] produces velocity [1, 0.6]. Both outputs move.
The initial position is [0, 0]. At t = 0, request the constant target r = [1, 0]: move the first output to 1 while keeping the second at zero. Define the tracking error e = r − p.
This is an ideal kinematic model with no inertia, delay, noise, or actuator limits. Inputs can take either sign. In the state-space notation, A = 0, the input matrix is B(c), C = I, and D = 0.
Close two independent loops
Give each output its own proportional gain:
K = diag(k₁, k₂)
u = Ke
u₁ = k₁(1 − p₁), u₂ = −k₂p₂
With k₁ = k₂ = 1, the initial error is [1, 0], so the initial command is [1, 0]. The initial velocity is [1, 0.6]. Output 2 starts moving even though its requested change is zero.
As p₂ rises, its loop requests a negative u₂. That pushes p₂ back, while the same command also slows p₁. Both gains now affect the coupled response.
For c = 0.6 and unit gains, the exact outputs are:
p₁(t) = 1 − ½[exp(−0.4t) + exp(−1.6t)]
p₂(t) = ½[exp(−0.4t) − exp(−1.6t)]
The two error modes decay at rates 0.4 and 1.6. Both outputs reach their targets as time goes to infinity, but output 2 takes a detour. At t = 1, p₁ ≈ 0.563892 and p₂ ≈ 0.234212.
Cancel the known interaction
First choose a desired output velocity v = Ke. Then solve B(c)u = v for the actuator commands. When the design model matches the plant and B is invertible:
u = B(c)⁻¹Ke
B(c)⁻¹ = [[1, −c], [−c, 1]] / (1 − c²)
ṗ = Ke
Now each output follows its own first-order error equation. With the same target and unit gains, p₁ = 1 − exp(−t) and p₂ = 0. The first output reaches about 0.632121 at t = 1.
At the initial state and c = 0.6, the inverse requests u = [1.5625, −0.9375]. Multiplying by B verifies the intended velocity:
ṗ₁ = 1.5625 + 0.6(−0.9375) = 1
ṗ₂ = 0.6(1.5625) − 0.9375 = 0
The negative second command cancels the unwanted motion immediately. The controller remains a feedback law: it recomputes both commands from the current measured position.
This constant inverse is a static decoupler. MathWorks' two-loop decoupling example uses a static matrix with PI controllers for a different coupled plant. General MIMO dynamics can need more than one constant matrix, especially when channels have different delays or frequency responses.
Compare the two controllers
Start with the matched model and unit gains. Inspect time zero to compare commands, then move the time slider to watch both outputs. The first plot tracks the requested move; the second shows the motion you wanted to avoid.
Try these changes:
- Raise only k₂ from 1 to 2. In the independent controller, that changes both output histories. In the matched decoupled controller, p₂ already stays at zero, so this particular move does not use its gain.
- Select the model-mismatch preset. The inverse still uses c = 0.6, while the plant uses c = 0.8.
- Select the Nearly singular preset. The model matches again, but c = 0.95 makes the required commands much larger.
The curves sample exact continuous-time responses every 0.05 normalized time units. Commands shown at an inspected time are instantaneous feedback values, not commands held between samples. Reported peaks are maxima over the displayed samples; final error is ‖r − p(8)‖, not an infinite-time error.
Change the plant without changing the inverse
Let B̂ be the matrix used to design the controller. The actual output dynamics become:
ṗ = BactualB̂⁻¹Ke
In the mismatch preset, ĉ = 0.6 and c_actual = 0.8. Their product is:
BactualB̂⁻¹ = [[0.8125, 0.3125], [0.3125, 0.8125]]
With unit gains, the initial commands still equal [1.5625, −0.9375]. The actual initial velocity becomes [0.8125, 0.3125]. Output 2 moves because the two cross-effects no longer cancel.
The error modes now decay at rates 0.5 and 1.125, so this mismatched example still converges. It loses exact decoupling. These numbers establish neither instability nor a guarantee for arbitrary model errors; they describe this specified pair of matrices.
Ask what the cancellation costs
As c approaches 1, the two actuator directions become nearly parallel. Moving along the difference direction [1, −1] becomes difficult, since:
B(c)[1, −1]ᵀ = (1 − c)[1, −1]ᵀ
At c = 0.95, the inverse multiplies that direction by 20. For the initial error [1, 0] and unit gains, it requests approximately [10.256410, −9.743590]. Those large opposing commands still produce [1, 0] in the exact model.
The matrix's 2-norm condition number compares its strongest and weakest directions. For this symmetric matrix with 0 ≤ c < 1, its singular values are 1 + c and 1 − c:
κ₂(B) = (1 + c) / (1 − c)
κ₂(B(0.6)) = 4
κ₂(B(0.95)) = 39
Stanford's SVD notes connect condition number to sensitivity in solving linear equations. These values use the declared normalized coordinates; changing units or scaling can change a matrix's condition number.
The lab deliberately applies the full requested commands. If each actuator were limited to ±2, clipping the initial near-singular commands to [2, −2] would produce [0.1, −0.1], not the desired [1, 0]. This calculation checks only the initial velocity; the lab does not simulate a saturated rollout.
At c = 1, B has rank one and no inverse. Starting from zero, p₁ − p₂ stays zero under every command, so the target [1, 0] is unreachable. The controllability lesson explains why mathematical reachability and practical input requirements are separate questions.
Check convergence separately from interaction
For the matched decoupled controller, ė = −Ke. Choose V = ½eᵀe. Then:
V̇ = −k₁e₁² − k₂e₂²
Positive gains make this strictly negative for every nonzero error. Since V is positive definite and radially unbounded, the ideal closed-loop equilibrium is globally asymptotically stable. The Lyapunov lesson develops that proof pattern.
Both controllers converge for every preset and gain offered here. One way to check all those cases is to write ė = −GKe. For independent feedback, G = B_actual. For decoupled feedback, G = B_actual B̂⁻¹. In this particular family, each G is symmetric positive definite: its eigenvalues are 1 ± c_actual, or (1 ± c_actual)/(1 ± ĉ), respectively.
The function V = ½eᵀKe then has derivative −eᵀKGKe < 0 away from zero. It proves convergence even when the gains differ. Cross-output excursion and large commands can still make a convergent response unsuitable for a task.
Exact cancellation is one design choice. LQR offers a way to trade state error against control effort through an explicit objective. Delays, saturation, uncertain dynamics, and unequal channel behavior require analysis beyond this constant-matrix example.
Reproduce the responses in Python
Download the standalone Python example. Save it as mimo.py and run these commands in that folder:
python3 mimo.py --check
python3 mimo.py
python3 mimo.py --preset mismatch
python3 mimo.py --preset near-singular
It uses the Python standard library. The check command verifies the inverse, the exact responses, and the coupled equations. Running without options reports the matched preset; the other commands select model mismatch and nearly singular inputs. All three use k₁ = k₂ = 1 by default. Add --k1 2 --k2 1 to reproduce the first practice exercise.
For either controller, call its error-to-input matrix F, so u = Fe. With a constant target, the exact response follows:
M = BactualF
e(t) = exp(−Mt)e(0)
p(t) = r − e(t), u(t) = Fe(t)
Here exp is the matrix exponential, not an element-by-element exponential. The implementation evaluates the two eigenmodes and handles equal rates. Numerical comparisons verify the code; the algebra above establishes the stated convergence and decoupling claims.
Test gain changes and a singular limit
Double k₁ while leaving k₂ = 1. For c = 0.6 and p = [0, 0], calculate each controller's initial command and velocity. Which output moves despite a zero target?
Check the commands and initial motion
Independent feedback requests [2, 0], which gives velocity [2, 1.2]. Matched decoupling requests [3.125, −1.875], which gives [2, 0]. Its first error decays at rate 2; the independent controller's rates belong to the full coupled matrix B diag(2, 1).
Set c = 1 on paper. Could a pseudoinverse make the desired initial velocity [1, 0] exact? What does the least-squares input produce?
Check the unreachable direction
Both columns of B are [1, 1]ᵀ, so every possible velocity has equal coordinates. The minimum-norm least-squares command is [0.25, 0.25], producing [0.5, 0.5]. A pseudoinverse gives a best fit under that objective; it cannot create an actuator direction that the model lacks. The target position [1, 0] is also unreachable from zero.
Sources and further study
- MathWorks: Decoupling Controller for a Distillation Column, for a static decoupler combined with feedback loops on a coupled process.
- Stephen Boyd and Sanjay Lall, EE263: Singular value decomposition, for directional gains, inverses, and condition numbers.
To examine actuator directions through matrix rank, continue with controllability and observability. For the least-squares construction in the final exercise, use the pseudoinverse lesson.