Chapter 22: Fundamentals of State-Feedback Control
Lesson 5: Practical Constraints and Limitations of State Feedback
State feedback can relocate the closed-loop modes of a controllable linear system, but the mathematical law \( u=-Kx+r \) is not implemented in an ideal algebraic universe. Real actuators saturate, sensors are noisy, sampling is finite, computation is delayed, and the plant model is uncertain. This lesson studies these effects using Lyapunov estimates, input bounds, eigenvalue sensitivity, and simulation.
1. Conceptual Overview: From Ideal Feedback to Real Implementation
In the previous lessons of this chapter, state feedback was introduced through the ideal continuous-time law \( u(t)=-Kx(t)+r(t) \), which gives the nominal closed-loop model
\[ \dot{x}(t)=(A-BK)x(t)+Br(t), \qquad y(t)=Cx(t)+Du(t). \]
If the pair \( (A,B) \) is controllable, the designer can assign the eigenvalues of \( A-BK \). However, pole placement alone does not certify that the implemented system will behave as predicted. A practical implementation usually has the form
\[ \begin{aligned} \hat{x}(t) &= x(t)+n(t),\\ v(t) &= -K\hat{x}(t)+r(t),\\ u(t) &= \operatorname{sat}_{\mathcal{U}} \left(\operatorname{rate}_{\dot{u}_{\max}}(v(t))\right),\\ \dot{x}(t) &= Ax(t)+Bu(t)+d(t)+\Delta A\,x(t)+\Delta B\,u(t), \end{aligned} \]
where \( n(t) \) is measurement noise, \( d(t) \) is an external disturbance, \( \mathcal{U} \) is the admissible actuator set, and \( \Delta A,\Delta B \) represent modeling uncertainty. Thus, practical state feedback is a constrained and uncertain nonlinear feedback loop, even if the nominal plant is linear.
flowchart TD
R["reference r"] --> SUM["compute v = -K xhat + r"]
X["true state x"] --> N["sensor noise and reconstruction"]
N --> XHAT["measured/estimated state xhat"]
XHAT --> SUM
SUM --> SAT["amplitude saturation"]
SAT --> RATE["rate limit and actuator bandwidth"]
RATE --> U["implemented input u"]
U --> PLANT["plant: A,B plus uncertainty and disturbance"]
PLANT --> X
PLANT --> Y["output y"]
2. Input Saturation and Loss of Global Linearity
Suppose the commanded input is \( v=-Kx \), but the actuator can only apply bounded control \( u\in[-u_{\max},u_{\max}] \) in the scalar-input case. The implemented law is
\[ u=\operatorname{sat}(v)= \begin{cases} u_{\max}, & v > u_{\max},\\ v, & -u_{\max} \leq v \leq u_{\max},\\ -u_{\max}, & v < -u_{\max}. \end{cases} \]
Hence the actual closed-loop dynamics are
\[ \dot{x}=Ax+B\operatorname{sat}(-Kx) =(A-BK)x+B\phi(-Kx), \]
where \( \phi(v)=\operatorname{sat}(v)-v \) is the saturation error. Since \( \phi(v)=0 \) only when the command lies inside the actuator range, the linear closed-loop matrix \( A-BK \) describes only the unsaturated region of the state space.
For multi-input systems with componentwise bounds \( |u_i|\leq u_{i,\max} \), the safe unsaturated set is
\[ \mathcal{S}_K= \left\{x\in\mathbb{R}^n: |k_i x|\leq u_{i,\max},\; i=1,\dots,m \right\}, \]
where \( k_i \) is the \( i \)-th row of \( K \). Inside \( \mathcal{S}_K \), the controller behaves exactly as the linear design predicts. Outside it, the closed-loop response may become slower, oscillatory, or even unstable for plants whose open-loop dynamics cannot be stabilized by the saturated input authority.
3. Lyapunov Estimate of the No-Saturation Region
Let \( A_c=A-BK \) be Hurwitz and choose \( Q=Q^T>0 \). The Lyapunov equation
\[ A_c^T P+PA_c=-Q,\qquad P=P^T>0 \]
defines the quadratic Lyapunov function \( V(x)=x^TPx \). In the unsaturated region,
\[ \dot{V}=x^T(A_c^TP+PA_c)x=-x^TQx<0, \qquad x\neq 0. \]
To guarantee that saturation is inactive on the ellipsoid \( \mathcal{E}_\rho=\left\{x:x^TPx\leq \rho\right\} \), we need \( |k_i x|\leq u_{i,\max} \) for every \( x\in\mathcal{E}_\rho \). The maximum value of the linear functional \( |k_i x| \) over the ellipsoid is
\[ \max_{x^TPx\leq \rho}|k_i x| =\sqrt{\rho\,k_iP^{-1}k_i^T}. \]
Therefore a sufficient no-saturation condition is
\[ \rho \leq \min_i \frac{u_{i,\max}^2}{k_iP^{-1}k_i^T}. \]
This result is conservative but useful: it gives a certified ellipsoidal region in which the linear pole-placement design is guaranteed to be implemented exactly.
Proof of the ellipsoid formula. Set \( z=P^{1/2}x \), so \( x=P^{-1/2}z \) and \( \|z\|_2^2\leq \rho \). Then
\[ |k_i x|=|k_iP^{-1/2}z| \leq \|k_iP^{-1/2}\|_2\|z\|_2 \leq \sqrt{\rho\,k_iP^{-1}k_i^T}. \]
Equality is achieved when \( z \) is parallel to \( (k_iP^{-1/2})^T \), so the bound is exact for each row constraint.
4. Speed of Response Versus Control Effort
Moving the closed-loop poles farther into the left half-plane generally increases feedback gain and control effort. For a SISO controllable system in controllable canonical form, pole placement sets the closed-loop characteristic polynomial
\[ p_d(s)=s^n+\alpha_{n-1}s^{n-1}+\cdots+\alpha_1s+\alpha_0. \]
The feedback gain adjusts the coefficients of the open-loop polynomial to these desired values. If the desired poles are scaled as \( \lambda_i^{(d)}=\gamma\lambda_i^{(0)} \) with \( \gamma>1 \), the coefficients of \( p_d(s) \) typically grow as powers of \( \gamma \). Thus
\[ |u(0)|=|Kx(0)| \leq \|K\|_2\|x(0)\|_2, \]
and faster poles require larger admissible input magnitudes for the same initial condition. If the actuator saturates, the intended fast eigenvalues are not actually realized during the saturated portion of the transient. This is why pole placement must be checked against actuator limits before being accepted as an engineering design.
5. Rate Limits, Bandwidth, Sampling, and Delay
Amplitude saturation limits how large the input can be. Rate limits and bandwidth constraints limit how fast the input can change. A simple rate-limited command can be written as
\[ |\dot{u}(t)|\leq \dot{u}_{\max}. \]
In a digital controller with sample time \( h \), the exact zero-order-hold discretization of the plant is
\[ x_{k+1}=A_dx_k+B_du_k,\qquad A_d=e^{Ah},\qquad B_d=\int_0^h e^{A\sigma}B\,d\sigma. \]
A continuous-time gain \( K \) should not be used blindly in discrete implementation. The sampled closed-loop matrix is \( A_d-B_dK \), and stability requires
\[ \rho(A_d-B_dK)<1, \]
where \( \rho(\cdot) \) denotes spectral radius. A computation or communication delay of one sample changes the state update to an augmented system, for example
\[ \begin{bmatrix}x_{k+1}\\u_k\end{bmatrix} = \begin{bmatrix}A_d & B_d\\ -K & 0\end{bmatrix} \begin{bmatrix}x_k\\u_{k-1}\end{bmatrix}, \]
so the delay changes the characteristic roots. Aggressive gains that are stable in a continuous-time model can become poorly damped or unstable when sampling and delay are introduced.
6. Noise Amplification and State Availability
State feedback assumes that the controller has access to the state. In practice, the implemented signal may be \( \hat{x}=x+n \), where \( n \) is measurement noise or estimation error. The control becomes
\[ u=-K\hat{x}=-Kx-Kn. \]
If \( n \) has covariance \( \Sigma_n \), then the covariance of the noise-induced input component is
\[ \operatorname{Cov}(K n)=K\Sigma_nK^T. \]
Hence large feedback gains amplify measurement noise into actuator motion. This is one reason practical designs avoid unnecessarily fast pole placement: high-gain control improves nominal speed but may degrade actuator wear, energy consumption, acoustic/vibration behavior, and robustness to sensor errors.
7. Model Uncertainty and Eigenvalue Sensitivity
Let the true plant be \( \dot{x}=(A+\Delta A)x+(B+\Delta B)u \). Under the same feedback \( u=-Kx \), the true closed-loop matrix is
\[ A_{c,true}=A-BK+\Delta A-\Delta B K. \]
The term \( -\Delta B K \) shows that large gains amplify uncertainty in the input matrix. For a simple eigenvalue \( \lambda_i \) of \( A_c=A-BK \), with right and left eigenvectors \( v_i,w_i \), first-order perturbation theory gives
\[ \delta \lambda_i \approx \frac{w_i^T(\Delta A-\Delta B K)v_i}{w_i^Tv_i}. \]
This formula clarifies two practical issues. First, if the closed-loop eigenvectors are ill-conditioned, small matrix perturbations can produce large eigenvalue shifts. Second, if \( \|K\| \) is very large, uncertainty in actuator effectiveness \( \Delta B \) becomes especially important.
flowchart TD
START["Proposed K"] --> C1["Check controllability of assigned modes"]
C1 --> C2["Check unsaturated region for expected states"]
C2 --> C3["Check max input and max input rate"]
C3 --> C4["Check sampling, delay, and bandwidth"]
C4 --> C5["Check noise amplification by K"]
C5 --> C6["Check sensitivity to A and B uncertainty"]
C6 --> OK["Accept, redesign, or reduce pole aggressiveness"]
8. Fundamental Structural Limitations
Practical constraints are not merely numerical nuisances. Some limitations are structural:
Uncontrollable modes. If \( (A,B) \) is not controllable, some modes cannot be moved by any state feedback. In PBH form, a mode \( \lambda \) is uncontrollable if
\[ \operatorname{rank}\begin{bmatrix}\lambda I-A & B\end{bmatrix} <n. \]
Such a mode remains in the closed-loop spectrum for every \( K \). If it is unstable, no static state feedback using the given input matrix can stabilize the system.
Transmission zeros and tracking limits. Even with full state feedback, input-output behavior is constrained by the plant zeros. Nonminimum-phase zeros restrict achievable tracking speed and disturbance rejection. State feedback can change internal poles, but it does not remove the fundamental input-output limitations imposed by invariant zeros of a fixed plant and output selection.
Actuator placement and authority. A mathematically controllable system may be poorly conditioned. The controllability matrix can have full rank but very small singular values:
\[ \mathcal{C}= \begin{bmatrix}B & AB & \cdots & A^{n-1}B\end{bmatrix}, \qquad \sigma_{\min}(\mathcal{C})\approx 0. \]
Then the system is theoretically controllable but some state directions require very large input energy. In such cases, pole placement can be numerically possible but practically unreasonable.
9. Python Implementation: Saturation, Rate Limits, Noise, and Lyapunov Region
The following script simulates a double integrator with ideal and constrained state feedback. It also computes a Lyapunov ellipsoid radius that guarantees no actuator saturation.
Chapter22_Lesson5.py
"""
Chapter22_Lesson5.py
Practical constraints and limitations of state feedback:
- ideal full-state feedback
- actuator amplitude saturation
- actuator rate limiting
- measurement noise amplification through K
- Lyapunov ellipsoid estimate for the no-saturation region
Dependencies:
pip install numpy matplotlib
"""
import numpy as np
import matplotlib.pyplot as plt
def solve_continuous_lyapunov_by_kron(A: np.ndarray, Q: np.ndarray) -> np.ndarray:
"""
Solve A.T P + P A = -Q using vectorization:
vec(A.T P + P A) = (I kron A.T + A.T kron I) vec(P)
This avoids requiring scipy.
"""
n = A.shape[0]
M = np.kron(np.eye(n), A.T) + np.kron(A.T, np.eye(n))
p = np.linalg.solve(M, -Q.reshape(-1, order="F"))
return p.reshape((n, n), order="F")
def saturate(value: float, lower: float, upper: float) -> float:
return min(max(value, lower), upper)
def rate_limit(new_value: float, old_value: float, max_rate: float, dt: float) -> float:
step = max_rate * dt
return saturate(new_value, old_value - step, old_value + step)
def simulate(constrained: bool, noisy: bool):
# Double integrator: position and velocity.
A = np.array([[0.0, 1.0],
[0.0, 0.0]])
B = np.array([[0.0],
[1.0]])
# Pole placement for desired poles -2 and -3 gives K = [6, 5].
K = np.array([[6.0, 5.0]])
umax = 1.0
max_rate = 8.0
noise_std = np.array([0.02, 0.03])
dt = 0.001
tf = 6.0
t = np.arange(0.0, tf + dt, dt)
x = np.zeros((len(t), 2))
u = np.zeros(len(t))
x[0] = np.array([1.2, 0.0])
rng = np.random.default_rng(4)
for k in range(len(t) - 1):
x_meas = x[k].copy()
if noisy:
x_meas += rng.normal(0.0, noise_std)
u_cmd = float(-K @ x_meas)
if constrained:
u_sat = saturate(u_cmd, -umax, umax)
u[k] = rate_limit(u_sat, u[k - 1] if k > 0 else 0.0, max_rate, dt)
else:
u[k] = u_cmd
# Fourth-order Runge-Kutta for xdot = A x + B u, with u held constant.
def f(xv):
return A @ xv + (B[:, 0] * u[k])
k1 = f(x[k])
k2 = f(x[k] + 0.5 * dt * k1)
k3 = f(x[k] + 0.5 * dt * k2)
k4 = f(x[k] + dt * k3)
x[k + 1] = x[k] + (dt / 6.0) * (k1 + 2 * k2 + 2 * k3 + k4)
u[-1] = u[-2]
return t, x, u, A, B, K
def lyapunov_no_saturation_radius(A: np.ndarray, B: np.ndarray, K: np.ndarray, umax: float):
"""
For Acl = A - B K and Lyapunov ellipsoid E_rho = {x: x.T P x <= rho},
saturation is certainly inactive if
sqrt(rho * k P^{-1} k.T) <= umax.
Thus rho <= umax^2 / (k P^{-1} k.T).
"""
Acl = A - B @ K
Q = np.eye(A.shape[0])
P = solve_continuous_lyapunov_by_kron(Acl, Q)
Pinv = np.linalg.inv(P)
denom = float(K @ Pinv @ K.T)
rho_max = umax * umax / denom
return P, rho_max
if __name__ == "__main__":
t1, x_ideal, u_ideal, A, B, K = simulate(constrained=False, noisy=False)
t2, x_con, u_con, _, _, _ = simulate(constrained=True, noisy=False)
t3, x_noise, u_noise, _, _, _ = simulate(constrained=True, noisy=True)
P, rho = lyapunov_no_saturation_radius(A, B, K, umax=1.0)
print("K =", K)
print("Lyapunov P =")
print(P)
print("Guaranteed no-saturation ellipsoid radius rho <=", rho)
plt.figure()
plt.plot(t1, x_ideal[:, 0], label="ideal x1")
plt.plot(t2, x_con[:, 0], label="constrained x1")
plt.plot(t3, x_noise[:, 0], label="constrained+noise x1")
plt.xlabel("time [s]")
plt.ylabel("position state")
plt.grid(True)
plt.legend()
plt.tight_layout()
plt.figure()
plt.plot(t1, u_ideal, label="ideal u")
plt.plot(t2, u_con, label="saturated/rate-limited u")
plt.plot(t3, u_noise, label="saturated/rate-limited/noisy u")
plt.xlabel("time [s]")
plt.ylabel("control input")
plt.grid(True)
plt.legend()
plt.tight_layout()
plt.show()
10. C++ Implementation: From-Scratch Constrained State Feedback
This implementation avoids external numerical libraries. It writes a CSV file that can be plotted in Python, MATLAB, Excel, or another tool.
Chapter22_Lesson5.cpp
/*
Chapter22_Lesson5.cpp
From-scratch simulation of a saturated state-feedback controller for
the double-integrator system:
x1_dot = x2
x2_dot = u
u = sat(-K x)
Compile:
g++ -std=c++17 -O2 Chapter22_Lesson5.cpp -o Chapter22_Lesson5
Run:
./Chapter22_Lesson5
The program writes Chapter22_Lesson5_cpp_output.csv.
*/
#include <algorithm>
#include <array>
#include <cmath>
#include <fstream>
#include <iostream>
using State = std::array<double, 2>;
double saturate(double value, double lower, double upper) {
return std::min(std::max(value, lower), upper);
}
double rateLimit(double requested, double previous, double maxRate, double dt) {
const double step = maxRate * dt;
return saturate(requested, previous - step, previous + step);
}
State dynamics(const State& x, double u) {
return State{x[1], u};
}
State addScaled(const State& x, const State& dx, double scale) {
return State{x[0] + scale * dx[0], x[1] + scale * dx[1]};
}
int main() {
const double k1 = 6.0;
const double k2 = 5.0;
const double umax = 1.0;
const double maxRate = 8.0;
const double dt = 0.001;
const double tf = 6.0;
const int nSteps = static_cast<int>(tf / dt);
State x{1.2, 0.0};
double uPrev = 0.0;
std::ofstream file("Chapter22_Lesson5_cpp_output.csv");
file << "time,x1,x2,u_command,u_actual\n";
for (int i = 0; i <= nSteps; ++i) {
const double time = i * dt;
const double uCommand = -(k1 * x[0] + k2 * x[1]);
const double uSat = saturate(uCommand, -umax, umax);
const double u = rateLimit(uSat, uPrev, maxRate, dt);
uPrev = u;
file << time << "," << x[0] << "," << x[1] << ","
<< uCommand << "," << u << "\n";
// Fourth-order Runge-Kutta with held input u.
State q1 = dynamics(x, u);
State q2 = dynamics(addScaled(x, q1, 0.5 * dt), u);
State q3 = dynamics(addScaled(x, q2, 0.5 * dt), u);
State q4 = dynamics(addScaled(x, q3, dt), u);
x[0] += (dt / 6.0) * (q1[0] + 2.0 * q2[0] + 2.0 * q3[0] + q4[0]);
x[1] += (dt / 6.0) * (q1[1] + 2.0 * q2[1] + 2.0 * q3[1] + q4[1]);
}
std::cout << "Finished. CSV written to Chapter22_Lesson5_cpp_output.csv\n";
return 0;
}
11. Java Implementation: Saturated Feedback with CSV Output
Chapter22_Lesson5.java
/*
Chapter22_Lesson5.java
From-scratch Java simulation of practical state-feedback limitations:
amplitude saturation and actuator rate limiting.
Compile:
javac Chapter22_Lesson5.java
Run:
java Chapter22_Lesson5
The program writes Chapter22_Lesson5_java_output.csv.
*/
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
public class Chapter22_Lesson5 {
static double saturate(double value, double lower, double upper) {
return Math.min(Math.max(value, lower), upper);
}
static double rateLimit(double requested, double previous, double maxRate, double dt) {
double step = maxRate * dt;
return saturate(requested, previous - step, previous + step);
}
static double[] dynamics(double[] x, double u) {
return new double[] {x[1], u};
}
static double[] addScaled(double[] x, double[] dx, double scale) {
return new double[] {x[0] + scale * dx[0], x[1] + scale * dx[1]};
}
public static void main(String[] args) throws IOException {
double k1 = 6.0;
double k2 = 5.0;
double umax = 1.0;
double maxRate = 8.0;
double dt = 0.001;
double tf = 6.0;
int nSteps = (int) Math.round(tf / dt);
double[] x = new double[] {1.2, 0.0};
double uPrev = 0.0;
try (PrintWriter file = new PrintWriter(new FileWriter("Chapter22_Lesson5_java_output.csv"))) {
file.println("time,x1,x2,u_command,u_actual");
for (int i = 0; i <= nSteps; i++) {
double time = i * dt;
double uCommand = -(k1 * x[0] + k2 * x[1]);
double uSat = saturate(uCommand, -umax, umax);
double u = rateLimit(uSat, uPrev, maxRate, dt);
uPrev = u;
file.printf("%.8f,%.12f,%.12f,%.12f,%.12f%n",
time, x[0], x[1], uCommand, u);
double[] q1 = dynamics(x, u);
double[] q2 = dynamics(addScaled(x, q1, 0.5 * dt), u);
double[] q3 = dynamics(addScaled(x, q2, 0.5 * dt), u);
double[] q4 = dynamics(addScaled(x, q3, dt), u);
x[0] += (dt / 6.0) * (q1[0] + 2.0 * q2[0] + 2.0 * q3[0] + q4[0]);
x[1] += (dt / 6.0) * (q1[1] + 2.0 * q2[1] + 2.0 * q3[1] + q4[1]);
}
}
System.out.println("Finished. CSV written to Chapter22_Lesson5_java_output.csv");
}
}
12. MATLAB/Simulink Implementation
The MATLAB script simulates the same constrained controller and, if Simulink is installed, creates a minimal Simulink model with a state-space plant, feedback gain, saturation block, and scope.
Chapter22_Lesson5.m
% Chapter22_Lesson5.m
%
% Practical constraints and limitations of state feedback:
% simulation of ideal, saturated, rate-limited, and noisy state feedback.
%
% Optional Simulink note:
% The final section creates a minimal Simulink model if Simulink is installed.
clear; clc; close all;
A = [0 1; 0 0];
B = [0; 1];
K = [6 5]; % desired continuous poles -2 and -3 for double integrator
umax = 1.0;
maxRate = 8.0;
dt = 0.001;
tf = 6.0;
t = 0:dt:tf;
x0 = [1.2; 0.0];
[xIdeal, uIdeal] = simulateCase(A, B, K, umax, maxRate, dt, t, x0, false, false);
[xCon, uCon] = simulateCase(A, B, K, umax, maxRate, dt, t, x0, true, false);
[xNoise, uNoise] = simulateCase(A, B, K, umax, maxRate, dt, t, x0, true, true);
Acl = A - B*K;
Q = eye(2);
P = lyap(Acl', Q);
rhoMax = umax^2 / (K * inv(P) * K');
disp('Lyapunov matrix P:');
disp(P);
disp('Guaranteed no-saturation ellipsoid radius rho <= ');
disp(rhoMax);
figure;
plot(t, xIdeal(1,:), 'DisplayName', 'ideal x1'); hold on;
plot(t, xCon(1,:), 'DisplayName', 'constrained x1');
plot(t, xNoise(1,:), 'DisplayName', 'constrained + noise x1');
grid on; xlabel('time [s]'); ylabel('position state');
legend('Location', 'best');
figure;
plot(t, uIdeal, 'DisplayName', 'ideal u'); hold on;
plot(t, uCon, 'DisplayName', 'saturated/rate-limited u');
plot(t, uNoise, 'DisplayName', 'saturated/rate-limited/noisy u');
grid on; xlabel('time [s]'); ylabel('control input');
legend('Location', 'best');
% Optional: create a minimal Simulink model with State-Space, Gain, Saturation,
% and Scope blocks. This section is skipped if Simulink is unavailable.
if exist('simulink', 'file') == 4
modelName = 'Chapter22_Lesson5_Simulink';
new_system(modelName);
open_system(modelName);
add_block('simulink/Continuous/State-Space', [modelName '/Plant']);
set_param([modelName '/Plant'], 'A', mat2str(A), 'B', mat2str(B), ...
'C', mat2str(eye(2)), 'D', mat2str([0;0]));
add_block('simulink/Math Operations/Gain', [modelName '/StateFeedbackGain']);
set_param([modelName '/StateFeedbackGain'], 'Gain', mat2str(-K), ...
'Multiplication', 'Matrix(K*u)');
add_block('simulink/Discontinuities/Saturation', [modelName '/Saturation']);
set_param([modelName '/Saturation'], 'UpperLimit', num2str(umax), ...
'LowerLimit', num2str(-umax));
add_block('simulink/Sinks/Scope', [modelName '/Scope']);
save_system(modelName);
disp(['Created optional Simulink model: ' modelName '.slx']);
end
function [x, u] = simulateCase(A, B, K, umax, maxRate, dt, t, x0, constrained, noisy)
x = zeros(2, numel(t));
u = zeros(1, numel(t));
x(:,1) = x0;
rng(4);
for k = 1:(numel(t)-1)
xMeas = x(:,k);
if noisy
xMeas = xMeas + [0.02; 0.03] .* randn(2,1);
end
uCmd = -K * xMeas;
if constrained
uSat = min(max(uCmd, -umax), umax);
if k == 1
uPrev = 0;
else
uPrev = u(k-1);
end
step = maxRate * dt;
u(k) = min(max(uSat, uPrev - step), uPrev + step);
else
u(k) = uCmd;
end
f = @(xx) A*xx + B*u(k);
q1 = f(x(:,k));
q2 = f(x(:,k) + 0.5*dt*q1);
q3 = f(x(:,k) + 0.5*dt*q2);
q4 = f(x(:,k) + dt*q3);
x(:,k+1) = x(:,k) + (dt/6)*(q1 + 2*q2 + 2*q3 + q4);
end
u(end) = u(end-1);
end
13. Wolfram Mathematica Implementation
The following notebook expression can be saved as Chapter22_Lesson5.nb. It simulates ideal and constrained state feedback and plots the first state.
Chapter22_Lesson5.nb
Notebook[{
Cell["Chapter22_Lesson5.nb", "Title"],
Cell["Practical Constraints and Limitations of State Feedback", "Subtitle"],
Cell[BoxData[
RowBox[{
RowBox[{"A", "=", "{{0,1},{0,0}}"}], ";",
RowBox[{"B", "=", "{{0},{1}}"}], ";",
RowBox[{"K", "=", "{{6,5}}"}], ";",
RowBox[{"umax", "=", "1.0"}], ";",
RowBox[{"maxRate", "=", "8.0"}], ";",
RowBox[{"dt", "=", "0.001"}], ";",
RowBox[{"tf", "=", "6.0"}], ";"
}]], "Input"],
Cell[BoxData[
RowBox[{
RowBox[{"sat", "[", "u_", "]"}], ":=",
RowBox[{"Clip", "[", RowBox[{"u", ",", RowBox[{"{", RowBox[{"-umax", ",", "umax"}], "}"}]}], "]"}]
}]], "Input"],
Cell[BoxData[
RowBox[{
RowBox[{"rateLimit", "[", RowBox[{"u_", ",", "uprev_"}], "]"}], ":=",
RowBox[{"Clip", "[",
RowBox[{"u", ",", RowBox[{"{",
RowBox[{RowBox[{"uprev", "-", RowBox[{"maxRate", " ", "dt"}]}], ",",
RowBox[{"uprev", "+", RowBox[{"maxRate", " ", "dt"}]}]}], "}"}]}], "]"}]
}]], "Input"],
Cell[BoxData[
RowBox[{
RowBox[{"simulate", "[", "constrained_", "]"}], ":=",
RowBox[{"Module", "[",
RowBox[{
RowBox[{"{", RowBox[{"n", ",", "x", ",", "u", ",", "ucmd", ",", "k"}], "}"}], ",",
RowBox[{
RowBox[{"n", "=", RowBox[{"Round", "[", RowBox[{"tf", "/", "dt"}], "]"}]}], ";",
RowBox[{"x", "=", RowBox[{"ConstantArray", "[", RowBox[{"{", RowBox[{"0.", ",", "0."}], "}", ",", RowBox[{"n", "+", "1"}]}], "]"}]}], ";",
RowBox[{"u", "=", RowBox[{"ConstantArray", "[", RowBox[{"0.", ",", RowBox[{"n", "+", "1"}]}], "]"}]}], ";",
RowBox[{RowBox[{"x", "[", RowBox[{"[", "1", "]"}], "]"}], "=", RowBox[{"{", RowBox[{"1.2", ",", "0."}], "}"}]}], ";",
RowBox[{"For", "[",
RowBox[{
RowBox[{"k", "=", "1"}], ",", RowBox[{"k", "<=", "n"}], ",", RowBox[{"k", "++"}], ",",
RowBox[{
RowBox[{"ucmd", "=", RowBox[{"-", RowBox[{"First", "[", RowBox[{"K", ".", RowBox[{"x", "[", RowBox[{"[", "k", "]"}], "]"}]}], "]"}]}]}], ";",
RowBox[{RowBox[{"u", "[", RowBox[{"[", "k", "]"}], "]"}], "=",
RowBox[{"If", "[", RowBox[{"constrained", ",",
RowBox[{"rateLimit", "[", RowBox[{RowBox[{"sat", "[", "ucmd", "]"}], ",", RowBox[{"If", "[", RowBox[{RowBox[{"k", "==", "1"}], ",", "0.", ",", RowBox[{"u", "[", RowBox[{"[", RowBox[{"k", "-", "1"}], "]"}], "]"}]}], "]"}]}], "]"}], ",", "ucmd"}], "]"}]}], ";",
RowBox[{RowBox[{"x", "[", RowBox[{"[", RowBox[{"k", "+", "1"}], "]"}], "]"}], "=",
RowBox[{RowBox[{"x", "[", RowBox[{"[", "k", "]"}], "]"}], "+",
RowBox[{"dt", RowBox[{"(", RowBox[{RowBox[{"A", ".", RowBox[{"x", "[", RowBox[{"[", "k", "]"}], "]"}]}], "+", RowBox[{"Flatten", "[", RowBox[{"B", " ", RowBox[{"u", "[", RowBox[{"[", "k", "]"}], "]"}]}], "]"}]}], ")"}]}]}]}]}]}], "]"}], ";",
RowBox[{"{", RowBox[{"x", ",", "u"}], "}"}]
}]
}], "]"}]
}]], "Input"],
Cell[BoxData[
RowBox[{
RowBox[{"ideal", "=", RowBox[{"simulate", "[", "False", "]"}]}], ";",
RowBox[{"constrained", "=", RowBox[{"simulate", "[", "True", "]"}]}], ";",
RowBox[{"ListLinePlot", "[",
RowBox[{
RowBox[{"{",
RowBox[{RowBox[{"ideal", "[", RowBox[{"[", RowBox[{"1", ",", "All", ",", "1"}], "]"}], "]"}], ",",
RowBox[{"constrained", "[", RowBox[{"[", RowBox[{"1", ",", "All", ",", "1"}], "]"}], "]"}]}], "}"}], ",",
RowBox[{"PlotLegends", "->", RowBox[{"{", RowBox[{"\"ideal x1\"", ",", "\"constrained x1\""}], "}"}]}]}], "]"}]
}]], "Input"]
}]
14. Problems and Solutions
Problem 1 (No-Saturation Ellipsoid): Consider a stable nominal closed-loop matrix \( A_c=A-BK \). Let \( P=P^T>0 \) solve \( A_c^TP+PA_c=-Q \) with \( Q=Q^T>0 \). For scalar input \( u=-Kx \) and limit \( |u|\leq u_{\max} \), derive a sufficient condition on \( \rho \) such that no saturation occurs in \( \mathcal{E}_\rho=\left\{x:x^TPx\leq\rho\right\} \).
Solution:
\[ \max_{x^TPx\leq\rho}|Kx| =\sqrt{\rho KP^{-1}K^T}. \]
Therefore saturation is inactive throughout the ellipsoid if
\[ \sqrt{\rho KP^{-1}K^T}\leq u_{\max} \quad\Longleftrightarrow\quad \rho\leq\frac{u_{\max}^2}{KP^{-1}K^T}. \]
Problem 2 (Noise-Induced Input Variance): Suppose \( \hat{x}=x+n \), \( E[n]=0 \), and \( E[nn^T]=\Sigma_n \). Show that the input noise covariance is \( K\Sigma_nK^T \).
Solution: The noise-only input term is \( u_n=-Kn \). Since \( E[u_n]=0 \),
\[ E[u_nu_n^T] = E[(-Kn)(-Kn)^T] = K E[nn^T] K^T = K\Sigma_nK^T. \]
Thus increasing \( K \) usually increases the actuator variance caused by sensor noise.
Problem 3 (Uncertainty Amplification by Input-Matrix Error): The true input matrix is \( B+\Delta B \). Under \( u=-Kx \), derive the true closed-loop matrix and identify the term that becomes large when \( K \) is large.
Solution:
\[ \dot{x}=Ax+(B+\Delta B)(-Kx) = (A-BK-\Delta BK)x. \]
If the nominal model also has \( \Delta A \), then \( A_{c,true}=A-BK+\Delta A-\Delta BK \). The uncertainty term \( -\Delta BK \) is directly magnified by the feedback gain.
Problem 4 (Discrete-Time Stability Check): A continuous-time controller is implemented with zero-order hold and sample period \( h \). Write the exact discrete-time plant matrices and the stability condition for the implemented closed-loop system.
Solution:
\[ A_d=e^{Ah},\qquad B_d=\int_0^h e^{A\sigma}B\,d\sigma,\qquad x_{k+1}=(A_d-B_dK)x_k. \]
The discrete-time implementation is asymptotically stable if and only if
\[ \rho(A_d-B_dK)<1. \]
Problem 5 (Why Faster Poles May Be Impractical): Explain mathematically why placing closed-loop poles very far to the left may violate actuator constraints.
Solution: For a given initial condition, the initial commanded input is \( u(0)=-Kx(0) \), so
\[ |u(0)|\leq \|K\|_2\|x(0)\|_2. \]
Faster assigned poles usually require larger polynomial coefficients and therefore larger gain entries. As \( \|K\|_2 \) increases, the set of initial states satisfying \( |Kx(0)|\leq u_{\max} \) shrinks. If saturation occurs, the intended matrix \( A-BK \) no longer describes the actual transient.
15. Summary
State feedback is powerful because it reshapes the internal modes of a controllable system. Its practical limitations arise because the implemented loop contains saturation, rate limits, finite sampling, delays, noise, unmodeled dynamics, and uncertainty. A responsible design therefore checks not only the eigenvalues of \( A-BK \), but also input magnitude, input rate, region of attraction, noise amplification, discrete-time stability, sensitivity, and structural limits such as uncontrollable modes and nonminimum-phase zeros.
16. References
- Kalman, R.E. (1960). On the general theory of control systems. Proceedings of the First International Congress on Automatic Control, 481–492.
- Wonham, W.M. (1967). On pole assignment in multi-input controllable linear systems. IEEE Transactions on Automatic Control, 12(6), 660–665.
- Kalman, R.E. (1963). Mathematical description of linear dynamical systems. Journal of the Society for Industrial and Applied Mathematics, Series A: Control, 1(2), 152–192.
- Brockett, R.W. (1983). Asymptotic stability and feedback stabilization. Differential Geometric Control Theory, 181–191.
- Sontag, E.D. (1984). An algebraic approach to bounded controllability of linear systems. International Journal of Control, 39(1), 181–188.
- Lin, Z., & Saberi, A. (1993). Semi-global exponential stabilization of linear systems subject to input saturation via linear feedbacks. Systems & Control Letters, 21(3), 225–239.
- Teel, A.R. (1992). Global stabilization and restricted tracking for multiple integrators with bounded controls. Systems & Control Letters, 18(3), 165–171.
- Doyle, J.C., & Stein, G. (1981). Multivariable feedback design: Concepts for a classical/modern synthesis. IEEE Transactions on Automatic Control, 26(1), 4–16.
- Zames, G. (1966). On the input-output stability of time-varying nonlinear feedback systems. IEEE Transactions on Automatic Control, 11(2), 228–238.
- Francis, B.A., & Wonham, W.M. (1976). The internal model principle of control theory. Automatica, 12(5), 457–465.