Control Systems

State-Space Control

Two matrix equations replace the entire toolbox of classical transfer functions — and unlock every modern autopilot, robot, and predictive controller

State-space control models a dynamical system as ẋ = Ax + Bu, y = Cx + Du. The state vector x ∈ ℝⁿ captures every variable needed to predict the future. Stability is read off the eigenvalues of A. Controllability and observability — Kalman's two rank tests — decide whether the state can be steered and whether it can be seen. Built by Kalman, Bucy and Falb in the 1960s, state-space is the foundation of LQR, Kalman filtering, H∞ control, and model-predictive control — the algorithms running every aerospace autopilot, robot arm, and process plant on Earth.

  • Core formẋ = Ax + Bu, y = Cx + Du
  • Stability (continuous)Re λ(A) < 0
  • Stability (discrete)|λ(A_d)| < 1
  • Controllable iffrank [B AB … Aⁿ⁻¹B] = n
  • Observable iffrank [C; CA; … ; CAⁿ⁻¹] = n
  • Modern eraKalman, Bucy, Falb — 1960s

Interactive visualization

Press play, or step through manually. The visualization is yours to drive — try it before reading on.

Open visualization fullscreen ↗

Watch the 60-second explainer

A condensed visual walkthrough — narrated, captioned, under a minute.

Why we replaced transfer functions

Classical control — Bode plots, root locus, Nyquist diagrams, lead-lag compensators — is one of the great engineering achievements of the twentieth century. It dominated everything from steam-engine governors to early aircraft autopilots. But by the 1950s its limits were starting to bite. Classical control speaks the language of scalar transfer functions, G(s) = Y(s)/U(s), and that language has three structural weaknesses.

First, it is fundamentally single-input single-output. Real aircraft have elevators, ailerons, rudder, throttle and spoilers; real chemical plants have dozens of valves and heaters interacting through dozens of measurements. You can split a multivariable system into a grid of SISO loops, but the cross-couplings — what control engineers call interaction — wreck the design. Decouplers help. They never quite get you home.

Second, classical methods see the system only through its input-output behaviour. Internal state — the temperature inside the reactor, the angular momentum of a satellite, the bending moment in a wing — is invisible. If two different physical systems have the same transfer function, classical control cannot tell them apart. Sometimes that is fine. Sometimes the unobservable internal state is exactly the thing that kills you, like a hidden resonance or an unstable mode hiding behind a pole-zero cancellation.

Third, classical control offers no clean path to optimisation, constraints or estimation. It is a graphical, intuition-driven discipline. By the time the Apollo programme needed to land humans on the Moon, the field needed something more.

That something was state-space. Rudolf Kalman, Richard Bucy, Peter Falb and others reformulated control theory in the late 1950s and early 1960s. The new framework was matrix-valued from the start, exposed internal state explicitly, and reduced almost every classical question to a question of linear algebra. By 1970 it had taken over aerospace; by 1990 it had taken over robotics and high-end process control. The story of every modern controller — Kalman filters, LQR, H∞, MPC, modern adaptive and reinforcement-learning controllers — starts here.

The state-space form

A continuous-time linear time-invariant (LTI) system is written as two coupled matrix equations.

ẋ(t) = A x(t) + B u(t)        (state equation)
y(t) = C x(t) + D u(t)        (output equation)

The pieces are:

  • x ∈ ℝⁿ is the state vector. n is the order of the system. x carries every variable that you need to predict the system's future given the inputs going forward. For a mass on a spring, x = [position; velocity]. For a satellite attitude controller, x might include three quaternion components, three body rates, and three integrators. The choice of state is not unique — any invertible linear change of coordinates gives a valid alternative — but the dimension n is.
  • u ∈ ℝᵐ is the input or control, what you can manipulate: a voltage, a valve opening, a thrust command. m is the number of independent control channels.
  • y ∈ ℝᵖ is the output, what your sensors measure. p is the number of measurement channels.
  • A ∈ ℝⁿˣⁿ is the dynamics matrix. It says how x evolves on its own with u = 0.
  • B ∈ ℝⁿˣᵐ is the input matrix. It says how each component of u pushes on each component of x.
  • C ∈ ℝᵖˣⁿ is the output matrix. It picks linear combinations of states that become outputs.
  • D ∈ ℝᵖˣᵐ is the direct feedthrough. Usually D = 0 — in physical systems, applying an input takes time to propagate through state before reaching the output. D ≠ 0 mostly appears in algebraic models and embedded code.

For digital control you discretise. Sampling at period T, with a zero-order-hold on u, the equivalent discrete-time system is

x[k+1] = A_d x[k] + B_d u[k]
y[k]   = C x[k] + D u[k]

A_d = e^(AT)                       (matrix exponential)
B_d = ∫₀ᵀ e^(Aτ) dτ · B            (integral of matrix exponential)

Every continuous-time concept — stability, controllability, observability, pole placement, optimal control — has a discrete-time counterpart with the same flavour but slightly different formulas (eigenvalues on the unit circle, not the imaginary axis; Lyapunov equations in discrete form; and so on). Aerospace traditionally works continuous; embedded process control traditionally works discrete; modern toolboxes handle both.

A worked example: pendulum on a cart

The canonical state-space teaching example is a pendulum hinged on a wheeled cart, with a force u applied horizontally to the cart. Let p be the cart position, θ the pendulum angle from upright, M the cart mass, m the pendulum mass, ℓ the pendulum length, g gravity. Linearising about the upright equilibrium (θ ≈ 0, sin θ ≈ θ, cos θ ≈ 1), and picking the state x = [p; ṗ; θ; θ̇], the equations of motion give

         ⎡ 0   1        0         0 ⎤        ⎡   0    ⎤
A =      ⎢ 0   0   −mg/M         0 ⎥   B =  ⎢  1/M  ⎥
         ⎢ 0   0        0         1 ⎥        ⎢   0    ⎥
         ⎣ 0   0   (M+m)g/(Mℓ)   0 ⎦        ⎣ −1/(Mℓ)⎦

C = [ 1  0  0  0 ;  0  0  1  0 ]    (measure p and θ)
D = 0

The eigenvalues of A are 0, 0, ±√((M+m)g/(Mℓ)). Two integrators (for cart position and velocity drifting freely), and a real pair around ±√(g/ℓ_eff) — one of which is in the right half-plane. The pendulum is open-loop unstable, as expected. State-space gives you the instability as a 30-second linear algebra calculation; classical methods need a hand-drawn root locus and a careful pole-zero map.

With state feedback u = −Kx, the closed-loop dynamics become ẋ = (A − BK) x. Pick desired closed-loop poles (say, four poles at −2 ± 2j and −5, −5), call place(A, B, p) in MATLAB or control.place_poles(A, B, p) in Python, and out comes a 1×4 row vector K. The same problem in classical control would require a two-loop cascade with a careful loop-shaping argument that almost certainly fails the first time. With state-space it is mechanical.

Stability — eigenvalues of A

The unforced system ẋ = Ax has solution x(t) = e^(At) x(0). The matrix exponential e^(At) decomposes through A's eigenstructure: each eigenvalue λ contributes a term proportional to e^(λt) along its eigenvector. So the question of whether x(t) decays, grows, or oscillates is the question of where the eigenvalues of A sit in the complex plane.

Eigenvalue locationMode behaviourSystem
Re λ < 0 (left half plane)Decays exponentiallyStable
Re λ > 0 (right half plane)Grows exponentiallyUnstable
Re λ = 0, Im λ ≠ 0Pure oscillationMarginally stable
Re λ = 0 (simple)ConstantMarginally stable
Re λ = 0 (repeated)Polynomial growthUnstable

In discrete time the corresponding test is whether the eigenvalues of A_d lie inside the unit circle: |λ| < 1 stable, |λ| > 1 unstable. The mapping λ_c → λ_d = e^(λ_c T) maps the left half plane to the interior of the unit circle, so the two tests are equivalent under sampling.

One subtlety: the eigenvalues of A are exactly the poles of the transfer function G(s) = C(sI − A)⁻¹B + D. Classical and modern control agree on stability — they just talk about it differently. The advantage of the matrix view is that stability becomes a linear algebra calculation that works regardless of how big A is, while classical pole-by-pole analysis breaks down once the order exceeds three or four.

Controllability — can we steer the state?

A natural question: given the system, can we find some input signal u(t) that drives x from any starting point x₀ to any target x_f in finite time? Kalman gave the answer in 1960. Build the controllability matrix

W_c = [ B  |  AB  |  A²B  |  ...  |  Aⁿ⁻¹B ]    ∈ ℝⁿˣⁿᵐ

If rank(W_c) = n, the pair (A, B) is controllable, and we can move x anywhere we like. If rank(W_c) < n, there is a subspace of the state — the uncontrollable subspace — that no input can ever influence. Modes living in that subspace are stuck wherever they start. If any of them is also unstable, the system is fundamentally hopeless: no feedback gain K can stabilise it.

The construction is intuitive once you see it. B u is the only place where u enters the state. A B u is where u shows up at the next time step after being filtered through one round of dynamics. A² B u is two steps out, and so on. Cayley-Hamilton tells us we never need to go past Aⁿ⁻¹ — higher powers are linear combinations of lower ones. So Wc captures every direction in state space that the input can ever reach.

A handy refinement is the Popov-Belevitch-Hautus (PBH) test: the system is controllable if and only if rank([A − λI | B]) = n for every eigenvalue λ of A. PBH lets you check controllability one eigenvalue at a time, which is much more numerically stable than computing the rank of a potentially ill-conditioned Wc.

Observability — can we see the state?

The dual question: given the output history y(t) and the input history u(t), can we reconstruct x(t)? Build the observability matrix

         ⎡    C    ⎤
         ⎢   CA    ⎥
O_b =    ⎢   CA²   ⎥                ∈ ℝⁿᵖˣⁿ
         ⎢    ⋮    ⎥
         ⎣  CAⁿ⁻¹  ⎦

If rank(O_b) = n, the pair (A, C) is observable: every state x is distinguishable from every other through the resulting y trajectory. If rank(O_b) < n, there is an unobservable subspace of states that produce identical outputs and are therefore indistinguishable.

Kalman noticed that observability of (A, C) is mathematically identical to controllability of (Aᵀ, Cᵀ). The two concepts are exact duals — every theorem about one has a transposed twin about the other. From this duality the Kalman filter falls out: estimating the state from noisy measurements is the dual of driving the state with bounded inputs. State-space made that connection visible; classical control never had a clean way of saying it.

Pole placement and Ackermann's formula

Once a system is controllable, design becomes a matter of placing closed-loop poles wherever you want. Use linear state feedback:

u = −K x        (full state feedback)
ẋ = A x + B (−K x) = (A − BK) x

So the closed-loop dynamics matrix is A − BK. Choose K so that its eigenvalues match a desired set p = {p₁, p₂, ..., pₙ}, and you have placed the poles.

For single-input systems, Ackermann's formula (1972) gives K in closed form:

K = [ 0  0  ...  0  1 ] · W_c⁻¹ · p(A)

where p(A) is the desired closed-loop characteristic polynomial evaluated at A (substituting matrix powers for scalar powers). It works whenever (A, B) is controllable — which is what makes Wc invertible — and is purely algebraic.

For multi-input systems, the choice of K is no longer unique (you have more degrees of freedom than poles), and numerically robust methods like Kautsky-Nichols (1985) — the one MATLAB's place implements — pick K to also minimise sensitivity to parameter perturbations.

Pole placement gives you complete freedom but also complete responsibility. Move the poles too far into the left half plane and the gains blow up; the actuator saturates and the system can become worse than the open-loop design. The art is choosing poles that give acceptable transient response without demanding superhuman gain.

LQR — letting cost choose the poles

Pole placement asks the engineer to pick locations. The Linear Quadratic Regulator (LQR) reframes the question: instead of guessing pole locations, write down a cost that captures what you actually want, and let the math compute K.

minimise   J = ∫₀^∞ ( xᵀ Q x  +  uᵀ R u ) dt
subject to    ẋ = A x + B u

Q ⪰ 0 penalises state deviations; R ≻ 0 penalises control effort. The optimal gain is

K = R⁻¹ Bᵀ P
where P solves the continuous algebraic Riccati equation (CARE):
    Aᵀ P + P A − P B R⁻¹ Bᵀ P + Q = 0

P is the unique symmetric positive-semidefinite solution. The optimal cost from initial state x₀ is x₀ᵀ P x₀. Standard numerical solvers (Schur, doubling, Newton iterations) compute P in tens of microseconds for moderate-sized problems. In MATLAB it is K = lqr(A, B, Q, R); in Python it is scipy.linalg.solve_continuous_are.

LQR has remarkable structural properties. Its closed-loop poles are automatically in the left half plane (assuming Q observable through (A, sqrt(Q))). It guarantees phase margin of at least 60° and a gain margin of (1/2, ∞) — meaning you can halve or double-then-some the loop gain without going unstable. No other design method gives you those margins for free. Which is why, despite fifty years of fashionable alternatives, LQR remains the baseline anyone benchmarks against.

SISO versus MIMO — the killer feature

A fighter jet at high angle of attack has yaw and roll coupling so strong that moving the rudder rolls the aircraft and moving the ailerons yaws it. A six-degree-of-freedom robot arm has joints that affect each other through coupled inertia. A chemical reactor has temperatures, pressures, concentrations all influencing each other.

Classical SISO control deals with these by drawing m × p separate transfer functions and trying to design loops one at a time, with decouplers, gain-scheduled compensators, and lots of empirical tuning. It works for mild coupling. It breaks for the hard cases. The 1979 X-29 forward-swept-wing fighter, the YF-22 prototype, every relaxed-static-stability aircraft from the 1970s on — all required state-space MIMO design because no SISO toolbox could.

State-space makes the multi-channel case the default, not a special case. A is n × n, B is n × m, C is p × n: any combination of inputs and outputs slots into the same equations. K becomes a matrix gain, mapping the full state into the full input. One LQR or H∞ design handles all the cross-couplings simultaneously. The mathematics does not care whether m and p are 1 or 27.

Variants and extensions

  • Linear time-varying (LTV). A, B, C, D become functions of time. Most aerospace problems are LTV because aircraft mass changes as fuel burns and aerodynamic coefficients change with Mach number. The structural results carry over with extra integral conditions.
  • Linear parameter-varying (LPV). A, B, C, D depend on a scheduling parameter ρ that changes during operation. Modern flight control treats Mach and altitude as scheduling parameters and designs one controller that interpolates smoothly across the flight envelope.
  • Descriptor systems. E ẋ = A x + B u with possibly singular E. Models systems with algebraic constraints (mechanical contacts, network constraints in power systems).
  • Stochastic state-space. ẋ = Ax + Bu + Gw, y = Cx + v with w, v Gaussian process and measurement noise. The Kalman filter is the optimal state estimator for this model — and pairing it with an LQR controller (separation principle, or LQG) gives the optimal stochastic output-feedback controller.
  • Robust control (H∞, μ-synthesis). Adds modelled uncertainty bounds and designs controllers that maintain stability and performance across the entire uncertainty set. Mostly state-space-based; built on Kalman's framework but adds the worst-case analysis classical control could not do cleanly.
  • Nonlinear extensions. ẋ = f(x, u), y = h(x, u). State-space generalises smoothly to nonlinear systems; the linear theory is the local linearisation around an equilibrium. Lyapunov methods, geometric control (input-output linearisation, sliding mode), and nonlinear MPC all live in this framework.
  • Model-predictive control (MPC). At every step, solve a finite-horizon constrained optimisation in the state-space model. Apply the first input, then re-solve. The dominant industrial advanced-control method since the 1980s.

Where state-space runs the world

  • Aerospace autopilots. Every fly-by-wire aircraft since the F-16 uses state-space-based flight control, scheduled across Mach and altitude. Boeing 777, A380, F-35, the SpaceX Crew Dragon — all run state-space controllers, usually with an LQR or LQG inner loop and an MPC or guidance outer loop.
  • Robotics. Industrial robot arms (KUKA, ABB, FANUC), surgical robots (da Vinci), legged robots (Boston Dynamics Atlas, Spot) all use state-space inverse-dynamics control. The state vector includes joint positions, velocities, sometimes contact forces; the controller is computed at 1 kHz or faster.
  • Process control. Modern refineries and chemical plants run MPC controllers on top of distributed PID base layers. The MPC layer typically uses linear state-space models identified from plant step tests, with 20–200 states. Aspen DMCplus, Honeywell Profit, Shell SMOC are the dominant commercial packages.
  • Missile and projectile guidance. Proportional navigation and modern guidance laws are state-space designs. The state typically includes line-of-sight rate, range rate, and target acceleration estimates from a Kalman filter.
  • Power electronics and motor drives. Field-oriented control of brushless motors, grid-tied inverters, HVDC stations — all use state-space models with at least 4–6 states (d-q currents, fluxes, rotor speed, DC-link voltage).
  • Quadrotors and consumer drones. DJI, Skydio and academic platforms run cascaded state-space controllers, often with onboard MPC for trajectory tracking. The state includes attitude (quaternion), body rates, position, velocity — typically 12 states.
  • Spacecraft attitude control. Hubble, JWST, every comms satellite. The state captures attitude (quaternion or Euler angles) plus body rates plus reaction-wheel speeds; the controller is LQR or quaternion feedback, sometimes with MPC for momentum management.
  • Self-driving cars and autopilots. Tesla Autopilot, Waymo, Cruise — all use state-space planners and MPC for path tracking, on top of perception stacks. The state includes vehicle pose, velocity, steering angle, sometimes road-curvature lookahead.

Common pitfalls

  • Forgetting that the state is not unique. Any invertible coordinate transformation T gives an equivalent realisation x̃ = Tx, Ã = TAT⁻¹, B̃ = TB, C̃ = CT⁻¹. Stability, controllability, observability and transfer functions are all invariant under T. Don't argue about whether a particular set of state variables is "right" — argue about whether they are numerically well-conditioned.
  • Mixing up controllability and stabilisability. A system can be uncontrollable but stabilisable: the uncontrollable modes are themselves stable. You don't need to move them — they decay on their own. The PBH test cleanly separates the two: stabilisable means rank([A − λI | B]) = n for every eigenvalue λ with Re λ ≥ 0.
  • Ignoring the conditioning of Wc. Controllability matrix tests can be misleadingly close to rank-deficient numerically even when the system is mathematically controllable. Use PBH or the controllability gramian for production code, not rank(ctrb(A, B)).
  • Trusting pole placement blindly. Moving poles deep into the left half plane demands huge gains; the resulting K saturates actuators or amplifies noise. Pole placement is a tool, not a recipe. LQR encodes the tradeoff explicitly through Q and R and almost always produces a more reasonable design.
  • Forgetting that state feedback assumes full state. u = −Kx requires every component of x to be known. In real systems you measure y, not x. The correct architecture is observer-based feedback: a Kalman filter (or Luenberger observer) estimates x̂ from y, and the controller uses u = −Kx̂. The separation principle says you can design the gain and the observer independently — but only if you actually do design both.
  • Linearising about the wrong operating point. The state-space form is local to an equilibrium. If your trajectory takes you far from that equilibrium (a quadrotor at extreme attitude, a rocket during reorientation), linear state-space breaks down and you need gain scheduling, LPV control, or full nonlinear methods.
  • Confusing the open-loop matrix A with the closed-loop matrix A − BK. The poles of A are the open-loop poles; only after applying feedback do the poles move to A − BK. People who only look at A and conclude "the system is unstable" are missing the point — that's why you build a controller.

Frequently asked questions

What does ẋ = Ax + Bu actually mean?

It is a vector differential equation. x is the state, a column of all the variables you need to predict the system's future — typically position, velocity, current, temperature, whatever the physics demands. A is the n×n dynamics matrix: it says how x changes on its own. B is the n×m input matrix: it says how the control u pushes the state around. ẋ is the time derivative of the state. So at every instant, the rate of change of x is a linear combination of where x is now and what u you are applying. Integrate, and you get the trajectory.

Why does stability reduce to eigenvalues of A?

The unforced system ẋ = Ax has solution x(t) = e^(At) x(0). Expanding A in its eigenbasis, e^(At) decomposes into terms of the form e^(λt) along each eigenvector. If every λ has negative real part, every term decays and x → 0 — stability. If any λ has positive real part, that mode grows exponentially — instability. In discrete time x_{k+1} = A_d x_k, the same logic gives |λ| < 1 as the stability condition. The eigenvalues of A are exactly the poles a classical control engineer would draw on a root locus.

What is controllability and how do you test it?

A system is controllable if you can drive the state x from any starting point to any target in finite time, using some input signal u. The Kalman rank test makes this concrete: build the controllability matrix W_c = [B | AB | A²B | ... | A^(n-1)B]. If rank(W_c) = n, the system is controllable. If the rank is less than n, there is a subspace of the state — the uncontrollable subspace — that no input can ever move. Modes living in that subspace are stuck wherever they start; if any of them is unstable, no controller can save you.

What is observability, and why is it the dual of controllability?

A system is observable if the state x can be reconstructed from the output history y. Build the observability matrix O_b = [C; CA; CA²; ...; CA^(n-1)] (rows stacked). If rank(O_b) = n, every state is distinguishable from every other through some output trajectory. Kalman noticed that controllability of (A, B) is mathematically identical to observability of (Aᵀ, Bᵀ) — the two concepts are duals. From that duality the entire theory of observers and the Kalman filter falls out: a Kalman filter is essentially a controllability problem run backwards through the measurement equation.

How does pole placement work, and what is Ackermann's formula?

Pick the closed-loop poles you want. Compute a state-feedback gain K such that the closed-loop dynamics matrix A − BK has exactly those eigenvalues. For a single-input controllable system, Ackermann's formula gives K in closed form: K = [0 0 ... 0 1] · W_c⁻¹ · p(A), where p(A) is the desired closed-loop characteristic polynomial evaluated at A, and W_c is the controllability matrix. The control law u = −Kx then reshapes the dynamics so the system tracks the chosen pole pattern. In MATLAB the function is place(A, B, p); in Python control.place_poles.

What is LQR, and how is it different from pole placement?

LQR — Linear Quadratic Regulator — chooses K to minimise the cost integral ∫(x'Qx + u'Ru) dt instead of placing poles by hand. Q penalises state error, R penalises control effort, and the optimum K is the unique solution that balances them. Where pole placement asks "where do I want the poles?", LQR asks "how much do I care about state versus control?" and the poles fall out automatically. The solution comes from the algebraic Riccati equation: P solves AᵀP + PA − PBR⁻¹BᵀP + Q = 0, then K = R⁻¹BᵀP. LQR has guaranteed phase margin ≥ 60° and gain margin (1/2, ∞), which is why it remains the default modern-control baseline.

How does state-space handle MIMO systems that classical SISO can't?

Classical transfer functions are scalar — one input, one output. A real aircraft has elevators, ailerons, rudder, throttle, and you have to control roll, pitch, yaw, altitude, and airspeed simultaneously with interactions everywhere. Trying to handle that as a grid of independent SISO loops fails because the loops couple. State-space treats the whole system as a single vector equation; A, B, C are just bigger matrices. K is now a matrix too, and one LQR or H∞ design handles all the couplings at once. This is why no modern autopilot, no industrial robot, no satellite attitude controller is built from classical transfer functions alone.

What is the relationship to model-predictive control (MPC)?

MPC builds directly on state-space. At each time step, MPC solves a finite-horizon optimisation problem: starting from the current state x_k, predict the trajectory over the next N steps using the state-space model, choose the input sequence u_k, u_{k+1}, ..., u_{k+N-1} that minimises a cost subject to constraints on x and u, then apply only u_k and re-solve at the next step. Without a state-space model the prediction step would not work. MPC is what runs every modern oil refinery, every Tesla driving model, every quadrotor altitude controller — and it is unthinkable without the state-space formulation underneath.