Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

iLQR and Differential Dynamic Programming

A boat approaching a quay must arrive in the right place, face along the berth, and lose its remaining momentum. A sequence of thrust commands determines all three outcomes. The shooting formulation turns this task into an optimization over those commands: simulate a candidate sequence, measure its cost, and improve it. How can an optimizer use the time structure of the simulation when computing that improvement?

Linearizing the dynamics along the current trajectory and quadratically approximating its costs gives a problem whose controls can be eliminated backward, one time step at a time. The resulting correction is then tested through the nonlinear simulator. Repeating these operations gives the iterative linear-quadratic regulator, or iLQR. Keeping additional curvature from the dynamics gives differential dynamic programming, or DDP. Both methods compute corrections around the current plan. The local problem is the linear-quadratic regulator solved by dynamic programming in the previous chapter, and its backward recursion can also be read as substitution and quadratic minimization.

The chapter is a bridge between the exact dynamic programming of the previous chapter and the stochastic dynamic programming of the next. iLQR reuses the LQR backward recursion, but only locally: its quadratic models and its feedback gains describe a neighborhood of one trajectory, not the whole state space.

Learning Goals

After working through the derivations and examples, you should be able to:

Prerequisites

The chapter uses the finite-horizon optimal-control formulation, single shooting, the linear-quadratic regulator from finite-horizon dynamic programming, and first and second derivatives. The SQP section of the nonlinear-programming appendix introduces general SQP subproblems, and the initial-value-problem appendix reviews numerical integration.

A Docking Problem

Docking requires the boat to reach the berth, align with the quay, and shed its momentum. If the boat reaches the right position with appreciable translational or angular velocity, its momentum will carry it away again.

Consider a two-metre boat moving in the horizontal plane. Its state and control are

x=(px,py,ψ,vx,vy,ω),u=(uL,uR)∈[−1,1]2.\mathbf x=(p_x,p_y,\psi,v_x,v_y,\omega),\qquad \mathbf u=(u_L,u_R)\in[-1,1]^2.

The position and velocity are measured in fixed world coordinates, ψ\psi is the heading, and ω\omega is the angular velocity. Each control is a fraction of maximum thrust. Positive commands push forward and negative commands push backward. Unequal thrusts turn the boat. There is no directly commanded sideways force, so an approach with sideways momentum requires a maneuver.

Let e(ψ)=(cos⁡ψ,sin⁡ψ)⊤\mathbf e(\psi)=(\cos\psi,\sin\psi)^\top point along the boat and n(ψ)=(−sin⁡ψ,cos⁡ψ)⊤\mathbf n(\psi)=(-\sin\psi,\cos\psi)^\top point across it. The simplified inertial model is

p˙=v,ψ˙=ω,mv˙=Fmax⁡(uL+uR)e−d∥(e⊤v)e−d⊥(n⊤v)n,Iω˙=bFmax⁡(uR−uL)−dωω.\begin{aligned} \dot{\mathbf p}&=\mathbf v,&\qquad \dot\psi&=\omega,\\ m\dot{\mathbf v} &=F_{\max}(u_L+u_R)\mathbf e -d_\parallel(\mathbf e^\top\mathbf v)\mathbf e -d_\perp(\mathbf n^\top\mathbf v)\mathbf n,\\ I\dot\omega&=bF_{\max}(u_R-u_L)-d_\omega\omega. \end{aligned}

The drag opposes velocity along each boat axis, with stronger resistance to sideways motion. Thrust changes acceleration, so releasing the controls does not stop the boat immediately. These equations are a synthetic teaching model for calm water, with neither contact forces nor waves.

QuantityValue
Mass mm50 kg50\ \mathrm{kg}
Angular inertia II20 kg m220\ \mathrm{kg\,m^2}
Thruster lever arm bb0.4 m0.4\ \mathrm m
Maximum force per thruster Fmax⁡F_{\max}25 N25\ \mathrm N
Longitudinal drag d∥d_\parallel8 N s/m8\ \mathrm{N\,s/m}
Lateral drag d⊥d_\perp30 N s/m30\ \mathrm{N\,s/m}
Angular drag dωd_\omega10 N m s10\ \mathrm{N\,m\,s}
Rectangular hull length and width2 m2\ \mathrm m, 0.8 m0.8\ \mathrm m

The quay occupies py≤0p_y\leq0, and the desired arrival state is x⋆=(0,1,0,0,0,0)\mathbf x_\star=(0,1,0,0,0,0). The boat should lie parallel to the quay with its center one metre from the edge. The angled approach starts from (−8,5,−0.5,0.2,−0.1,0)(-8,5,-0.5,0.2,-0.1,0). The sideways-drift case changes only vyv_y to −0.5 m/s-0.5\ \mathrm{m/s}. Angles are in radians. Both experiments use T−1=200T-1=200 piecewise-constant controls, each held for h=0.1 sh=0.1\ \mathrm s, for a total of 20 seconds. Thus x1\mathbf x_1 is the initial state and xT\mathbf x_T is the arrival state, as in the preceding chapters. One fourth-order Runge--Kutta step gives xt+1=ft(xt,ut)\mathbf x_{t+1}=\mathbf f_t(\mathbf x_t,\mathbf u_t) for t=1,…,T−1t=1,\ldots,T-1.

To discourage the hull from approaching the quay, let yj(x)y_j(\mathbf x) be the world-coordinate height of rectangular corner jj. With a desired buffer a=0.2 ma=0.2\ \mathrm m and smoothing length s=0.08 ms=0.08\ \mathrm m, define

ρ(z)=slog⁡(1+exp⁡(z/s)),P(x)=200∑j=14ρ(a−yj(x))2.\rho(z)=s\log(1+\exp(z/s)),\qquad \mathcal P(\mathbf x)=200\sum_{j=1}^4\rho(a-y_j(\mathbf x))^2.

This is a smooth penalty for violating the buffer. Its finite weight permits violations, so the final trajectories will also undergo a separate geometric clearance check. The full rectangle is used for that check, including the area outside the pointed boat icon in the figures.

For ep=p−(0,1)⊤\mathbf e_p=\mathbf p-(0,1)^\top, the running and terminal costs are

ct(x,u)=h[0.03∥ep∥2+0.1(1−cos⁡ψ)+0.1∥v∥2+0.1ω2+0.2∥u∥2+P(x)],cT(x)=300∥ep∥2+100(1−cos⁡ψ)+200∥v∥2+100ω2+P(x).\begin{aligned} c_t(\mathbf x,\mathbf u) &=h\big[0.03\|\mathbf e_p\|^2+0.1(1-\cos\psi) +0.1\|\mathbf v\|^2+0.1\omega^2 +0.2\|\mathbf u\|^2+\mathcal P(\mathbf x)\big],\\ c_T(\mathbf x) &=300\|\mathbf e_p\|^2+100(1-\cos\psi) +200\|\mathbf v\|^2+100\omega^2+\mathcal P(\mathbf x). \end{aligned}

These numerical weights apply to the stated SI coordinates and dimensionless thrust commands. The periodic heading penalty assigns the same cost to angles that differ by a full turn. The simulator retains an unwrapped angle; it does not insert a discontinuity at ±π\pm\pi into the differentiated transition.

The initial control sequence is zero, so the boat coasts and slows under drag. It stops far from the berth. Successive control updates can first bring it closer and then adjust the arrival heading and velocity.

Accepted iLQR iterates for the angled approach. Every curve is a nonlinear
rollout from the same initial state. Boat outlines are spaced four seconds
apart; their overlap indicates slow motion. The dotted outline marks the
desired berth. The first update reduces the position error substantially,
while later updates refine the turn and stopping maneuver.

Figure 1:Accepted iLQR iterates for the angled approach. Every curve is a nonlinear rollout from the same initial state. Boat outlines are spaced four seconds apart; their overlap indicates slow motion. The dotted outline marks the desired berth. The first update reduces the position error substantially, while later updates refine the turn and stopping maneuver.

Taylor Models of Dynamics and Cost

The local model describes the change in cost caused by a small change in the thrust sequence. Start from the finite-horizon problem

min⁡UJ(U):=cT(xT)+∑t=1T−1ct(xt,ut),s.t.xt+1=ft(xt,ut),t=1,…,T−1,x1=xinit.\begin{aligned} \min_{\mathbf U}\quad &J(\mathbf U) :=c_T(\mathbf x_T)+\sum_{t=1}^{T-1}c_t(\mathbf x_t,\mathbf u_t),\\ \text{s.t.}\quad &\mathbf x_{t+1}=\mathbf f_t(\mathbf x_t,\mathbf u_t), \quad t=1,\ldots,T-1,\\ &\mathbf x_1=\mathbf x_{\mathrm{init}}. \end{aligned}

Here U=(u1,…,uT−1)\mathbf U=(\mathbf u_1,\ldots,\mathbf u_{T-1}) is the complete control sequence. Its rollout determines every later state. This is an open-loop problem: the decision variable is a sequence of commands fixed in advance, not a rule that reacts to the state. iLQR returns such a sequence. The feedback gains KtK_t that appear below are a by-product of the computation. Near the returned plan they tell how to adjust each command when the state drifts from the planned one, through u=uˉ+K(x−xˉ)\mathbf u=\bar{\mathbf u}+K(\mathbf x-\bar{\mathbf x}), and they say nothing about states far from it.

Figure 2 shows what “near the plan” means. The boat follows the final docking plan and receives a small push after two seconds. Replaying the planned thrusts ignores the push. The boats drift calmly but none reaches the berth: they miss it by 0.9 m on average and by up to 2.2 m. Applying the local feedback steers all twelve pushed runs back onto the plan, and they arrive within a millimetre of it. These runs stay inside a thin tube around the planned trajectory.

The tube has a limited width. With pushes twice as large, shown in the animation below, several feedback runs leave it and two never reach the berth. Their corrections ask for more thrust than the thrusters can give, and the boat moves far enough from the plan that the linear model is no longer accurate. The gains describe a neighborhood of one trajectory, and this whole chapter works inside such neighborhoods.

Twelve random pushes at 2 s (velocity changes up to 0.3 m/s in each direction,
with small heading and spin changes) applied to the final iLQR plan for the
angled approach. Left: the planned thrusts are replayed unchanged. Right: the
thrusts follow the local feedback law, clipped to the thruster limits. The
shaded tube, drawn in both panels, is the envelope of the feedback runs.
Circles mark the positions at 20 s.

Figure 2:Twelve random pushes at 2 s (velocity changes up to 0.3 m/s in each direction, with small heading and spin changes) applied to the final iLQR plan for the angled approach. Left: the planned thrusts are replayed unchanged. Right: the thrusts follow the local feedback law, clipped to the thruster limits. The shaded tube, drawn in both panels, is the envelope of the feedback runs. Circles mark the positions at 20 s.

Play or scrub simulation time, and switch to the larger pushes to see boats leave the tube. The counters report how many boats are inside the tube and at the berth at the selected time.

We cannot solve this nonlinear problem directly. The previous chapter showed that a linear-quadratic regulator problem can be solved exactly by a backward recursion. The idea of this chapter is to build an LQR problem that resembles ours near a current plan, solve it, use its solution to improve the plan, and repeat.

Set aside the control bounds while deriving this local problem. The current plan is a control sequence Uˉ\bar{\mathbf U} together with the states obtained by rolling it out, xˉt+1=ft(xˉt,uˉt)\bar{\mathbf x}_{t+1}=\mathbf f_t(\bar{\mathbf x}_t,\bar{\mathbf u}_t). For the boat, the first plan is the zero-thrust coast. The plan is our current guess, not a reference that the boat must track. To ask what happens if we change it, consider nudges δxt=xt−xˉt\delta\mathbf x_t=\mathbf x_t-\bar{\mathbf x}_t and δut=ut−uˉt\delta\mathbf u_t=\mathbf u_t-\bar{\mathbf u}_t, stacked as δzt=(δxt,δut)\delta\mathbf z_t=(\delta\mathbf x_t,\delta\mathbf u_t). These are hypothetical changes that we are free to choose, not measured errors.

The linear model of the transition follows the usual Taylor steps. A scalar function of one variable satisfies f(a+h)≈f(a)+f′(a)hf(a+h)\approx f(a)+f'(a)h. With two inputs the partial derivatives add: f(xˉ+δx,uˉ+δu)≈f(xˉ,uˉ)+∂xf δx+∂uf δuf(\bar x+\delta x,\bar u+\delta u)\approx f(\bar x,\bar u) +\partial_x f\,\delta x+\partial_u f\,\delta u. The transition ft\mathbf f_t has one such expansion for each of its nxn_x components. Each component gives one row, and stacking the rows gives the Jacobian matrices AtA_t and BtB_t:

ft(xˉt+δxt,uˉt+δut)=ft(xˉt,uˉt)+Atδxt+Btδut+O(∥δzt∥2),At=∂ft∂x∣(xˉt,uˉt),Bt=∂ft∂u∣(xˉt,uˉt).\begin{aligned} \mathbf f_t(\bar{\mathbf x}_t+\delta\mathbf x_t, \bar{\mathbf u}_t+\delta\mathbf u_t) &=\mathbf f_t(\bar{\mathbf x}_t,\bar{\mathbf u}_t) +A_t\delta\mathbf x_t+B_t\delta\mathbf u_t +O(\|\delta\mathbf z_t\|^2),\\ A_t&=\left.\frac{\partial\mathbf f_t}{\partial\mathbf x} \right|_{(\bar{\mathbf x}_t,\bar{\mathbf u}_t)},\\ B_t&=\left.\frac{\partial\mathbf f_t}{\partial\mathbf u} \right|_{(\bar{\mathbf x}_t,\bar{\mathbf u}_t)}. \end{aligned}

The left side is the transition evaluated at the nudged state and control, which is the new next state xt+1\mathbf x_{t+1}. Because the current plan is a rollout, the first term on the right is ft(xˉt,uˉt)=xˉt+1\mathbf f_t(\bar{\mathbf x}_t,\bar{\mathbf u}_t)=\bar{\mathbf x}_{t+1}. Subtracting xˉt+1\bar{\mathbf x}_{t+1} from both sides turns the left side into δxt+1\delta\mathbf x_{t+1} and cancels that term on the right. Dropping the quadratic remainder gives the linearized dynamics δxt+1=Atδxt+Btδut\delta\mathbf x_{t+1}=A_t\delta\mathbf x_t+B_t\delta\mathbf u_t. Both rollouts start from the same state, so δx1=0\delta\mathbf x_1=\mathbf0. There is no constant defect because the current plan satisfies the discrete dynamics. Independently chosen state guesses would generally leave such a defect. We write Ft=[At Bt]F_t=[A_t\ B_t] for the combined Jacobian.

The running cost is expanded by the same steps, one order higher. In one variable, f(a+h)≈f(a)+f′(a)h+12f′′(a)h2f(a+h)\approx f(a)+f'(a)h+\tfrac12f''(a)h^2. Applied to the stacked vector δzt\delta\mathbf z_t, the derivative becomes a gradient and the second derivative becomes a Hessian matrix. Splitting δzt\delta\mathbf z_t back into its state and control parts cuts the gradient into cx,tc_{x,t} and cu,tc_{u,t}, and cuts the Hessian into four blocks: cxx,tc_{xx,t} for curvature in the state, cuu,tc_{uu,t} for curvature in the control, and the mixed blocks cxu,tc_{xu,t} and cux,t=cxu,t⊤c_{ux,t}=c_{xu,t}^\top. The quadratic term therefore reads 12δxt⊤cxx,tδxt+δut⊤cux,tδxt+12δut⊤cuu,tδut\tfrac12\delta\mathbf x_t^\top c_{xx,t}\delta\mathbf x_t +\delta\mathbf u_t^\top c_{ux,t}\delta\mathbf x_t +\tfrac12\delta\mathbf u_t^\top c_{uu,t}\delta\mathbf u_t, where the two mixed blocks have combined into one term. In block-matrix form,

ct(xˉt+δxt,uˉt+δut)=cˉt+[cx,tcu,t] ⁣⊤δzt+12δzt⊤[cxx,tcxu,tcux,tcuu,t]δzt+o(∥δzt∥2).c_t(\bar{\mathbf x}_t+\delta\mathbf x_t, \bar{\mathbf u}_t+\delta\mathbf u_t) = \bar c_t+ \begin{bmatrix}c_{x,t}\\c_{u,t}\end{bmatrix}^{\!\top}\delta\mathbf z_t +\frac12\delta\mathbf z_t^\top \begin{bmatrix}c_{xx,t}&c_{xu,t}\\c_{ux,t}&c_{uu,t}\end{bmatrix} \delta\mathbf z_t+o(\|\delta\mathbf z_t\|^2).

Here cˉt=ct(xˉt,uˉt)\bar c_t=c_t(\bar{\mathbf x}_t,\bar{\mathbf u}_t) and cx,t=∇xct(xˉt,uˉt)c_{x,t}=\nabla_{\mathbf x}c_t(\bar{\mathbf x}_t,\bar{\mathbf u}_t); the other gradient and Hessian blocks are evaluated at the same pair from the current plan. We denote the stacked gradient by cz,tc_{z,t} and the displayed block Hessian by czz,tc_{zz,t}. Gradients are column vectors, matching the convention of the preceding chapters. We retain the linear terms: individual stage gradients need not vanish even at an optimal trajectory because the dynamics couple stages, and at a non-optimal plan they also drive its correction. The cxu,tc_{xu,t} block measures how the marginal cost of a control changes with the state. Even if the running cost has no such cross term, eliminating later controls can create one in the quadratic tail.

The terminal cost has the same expansion, with no control coordinate:

cT(xˉT+δxT)=cT(xˉT)+pT⊤δxT+12δxT⊤PTδxT+o(∥δxT∥2),pT=∇xcT(xˉT),PT=∇xx2cT(xˉT).\begin{aligned} c_T(\bar{\mathbf x}_T+\delta\mathbf x_T) &=c_T(\bar{\mathbf x}_T)+p_T^\top\delta\mathbf x_T\\ &\quad+\frac12\delta\mathbf x_T^\top P_T\delta\mathbf x_T +o(\|\delta\mathbf x_T\|^2),\\ p_T&=\nabla_{\mathbf x}c_T(\bar{\mathbf x}_T),\qquad P_T=\nabla^2_{\mathbf x\mathbf x}c_T(\bar{\mathbf x}_T). \end{aligned}

Dropping the remainders in these three Taylor expansions gives the local problem. Up to the constant ∑tcˉt+cT(xˉT)\sum_t\bar c_t+c_T(\bar{\mathbf x}_T), which does not depend on the nudges, it reads

min⁡δu1,…,δuT−1∑t=1T−1(cz,t⊤δzt+12δzt⊤czz,t δzt)+pT⊤δxT+12δxT⊤PT δxT,s.t.δxt+1=Atδxt+Btδut,t=1,…,T−1,δx1=0.\begin{aligned} \min_{\delta\mathbf u_1,\ldots,\delta\mathbf u_{T-1}}\quad &\sum_{t=1}^{T-1}\Big(c_{z,t}^\top\delta\mathbf z_t +\frac12\delta\mathbf z_t^\top c_{zz,t}\,\delta\mathbf z_t\Big) +p_T^\top\delta\mathbf x_T +\frac12\delta\mathbf x_T^\top P_T\,\delta\mathbf x_T,\\ \text{s.t.}\quad &\delta\mathbf x_{t+1}=A_t\delta\mathbf x_t+B_t\delta\mathbf u_t, \quad t=1,\ldots,T-1,\\ &\delta\mathbf x_1=\mathbf0. \end{aligned}

This is an LQR problem of the kind solved in the previous chapter: linear dynamics in the nudges, and a cost that is quadratic in them. Compared with the standard LQR problem it has linear cost terms and a state--control cross term, which the next section handles. Solving it gives a proposed change to the plan.

Notice what is missing from this local problem. Only the costs were expanded to second order. The dynamics were expanded to first order, so their curvature appears nowhere in (9). A general SQP method also forms a local quadratic subproblem, but not quite this one. SQP takes a quadratic model of the Lagrangian and linearizes the constraints. Here the constraints are the dynamics, so the Hessian of the Lagrangian is the cost Hessian plus the sum over ii of the multiplier λi\lambda_i times the Hessian of the iith component of the transition. The shooting formulation is unconstrained only in the controls, because the simulator enforces the dynamics, but the local problem above still has the linearized dynamics as constraints on the nudges. iLQR is therefore SQP with the multiplier-weighted dynamics Hessians dropped. Those terms return in the DDP section, where the coefficient pt+1p_{t+1} of the eliminated tail plays the role of the multiplier, the costate.

Backward Elimination

The local problem (9) is a deterministic finite-horizon problem with linear dynamics and quadratic costs. It is an LQR problem, so the backward induction of the previous chapter solves it. This section recalls that algorithm, specializes it to LQR, and then applies the same specialization to the local problem. Each backup minimizes over one control and removes it from the problem, which is why the backward pass of iLQR is often called backward elimination.

Backward induction

For a deterministic problem with dynamics xt+1=ft(xt,ut)\mathbf x_{t+1}=\mathbf f_t(\mathbf x_t,\mathbf u_t), stage costs ctc_t and terminal cost cTc_T, Algorithm 1 computes the optimal cost-to-go Jt⋆J_t^\star backward in time:

JT⋆(x)=cT(x),Jt⋆(x)=min⁡u[ct(x,u)+Jt+1⋆(ft(x,u))],t=T−1,…,1.\begin{aligned} J_T^\star(\mathbf x)&=c_T(\mathbf x),\\ J_t^\star(\mathbf x)&=\min_{\mathbf u}\Big[c_t(\mathbf x,\mathbf u) +J_{t+1}^\star\big(\mathbf f_t(\mathbf x,\mathbf u)\big)\Big], \qquad t=T-1,\ldots,1. \end{aligned}

The minimizer at each state defines the policy πt⋆(x)\pi_t^\star(\mathbf x). A forward pass from the initial state then applies ut=πt⋆(xt)\mathbf u_t=\pi_t^\star(\mathbf x_t) and recovers the optimal trajectory. In general Jt⋆J_t^\star is a function on the whole state space, which the previous chapter stored on a grid.

The LQR case: the Riccati recursion

With linear dynamics xt+1=Atxt+Btut\mathbf x_{t+1}=A_t\mathbf x_t+B_t\mathbf u_t, stage cost 12x⊤Qtx+12u⊤Rtu\tfrac12\mathbf x^\top Q_t\mathbf x+\tfrac12\mathbf u^\top R_t\mathbf u and terminal cost 12x⊤QTx\tfrac12\mathbf x^\top Q_T\mathbf x, every cost-to-go is quadratic, Jt⋆(x)=12x⊤PtxJ_t^\star(\mathbf x)=\tfrac12\mathbf x^\top P_t\mathbf x, so the backup only has to update a matrix. Substituting the dynamics into Jt+1⋆J_{t+1}^\star makes the bracket a quadratic function of the stacked state and control,

12[xu] ⁣⊤[Qt+At⊤Pt+1AtAt⊤Pt+1BtBt⊤Pt+1AtRt+Bt⊤Pt+1Bt][xu].\frac12 \begin{bmatrix}\mathbf x\\\mathbf u\end{bmatrix}^{\!\top} \begin{bmatrix} Q_t+A_t^\top P_{t+1}A_t & A_t^\top P_{t+1}B_t\\ B_t^\top P_{t+1}A_t & R_t+B_t^\top P_{t+1}B_t \end{bmatrix} \begin{bmatrix}\mathbf x\\\mathbf u\end{bmatrix}.

Setting its control gradient to zero gives the linear feedback ut⋆=−Ktx\mathbf u_t^\star=-K_t\mathbf x, and substituting it back gives the Riccati recursion of Algorithm 3:

Kt=(Rt+Bt⊤Pt+1Bt)−1Bt⊤Pt+1At,Pt=Qt+At⊤Pt+1At−At⊤Pt+1Bt(Rt+Bt⊤Pt+1Bt)−1Bt⊤Pt+1At,\begin{aligned} K_t&=(R_t+B_t^\top P_{t+1}B_t)^{-1}B_t^\top P_{t+1}A_t,\\ P_t&=Q_t+A_t^\top P_{t+1}A_t -A_t^\top P_{t+1}B_t(R_t+B_t^\top P_{t+1}B_t)^{-1}B_t^\top P_{t+1}A_t, \end{aligned}

starting from PT=QTP_T=Q_T.

Riccati for the local problem

The local problem has the same structure, with the nudges δxt,δut\delta\mathbf x_t,\delta\mathbf u_t as state and control. Its terminal cost-to-go is the terminal Taylor model, and its backup is

St(δx)=min⁡δu[cz,t⊤δz+12δz⊤czz,t δz+St+1(Atδx+Btδu)],δz=(δx,δu).S_t(\delta\mathbf x)=\min_{\delta\mathbf u}\Big[ c_{z,t}^\top\delta\mathbf z+\frac12\delta\mathbf z^\top c_{zz,t}\,\delta\mathbf z +S_{t+1}(A_t\delta\mathbf x+B_t\delta\mathbf u)\Big], \qquad \delta\mathbf z=(\delta\mathbf x,\delta\mathbf u).

Two features differ from textbook LQR. The current plan is generally not optimal, so the local costs have linear terms, the gradients cz,tc_{z,t} and pTp_T. The stage cost may also contain a state--control cross term cux,tc_{ux,t}. Because of the linear terms, the cost-to-go needs a linear part as well:

St+1(δx)=st+1+pt+1⊤δx+12δx⊤Pt+1δx,S_{t+1}(\delta\mathbf x)=s_{t+1}+p_{t+1}^\top\delta\mathbf x +\frac12\delta\mathbf x^\top P_{t+1}\delta\mathbf x,

with pTp_T and PTP_T the gradient and Hessian of cTc_T at the end of the plan. Substituting the linear dynamics into St+1S_{t+1} makes the bracket a quadratic in δz\delta\mathbf z with linear coefficient qtq_t and Hessian MtM_t. Written in blocks, next to the LQR matrix above,

qx,t=cx,t+At⊤pt+1,Mxx,t=cxx,t+At⊤Pt+1At,qu,t=cu,t+Bt⊤pt+1,Mux,t=cux,t+Bt⊤Pt+1At,Muu,t=cuu,t+Bt⊤Pt+1Bt.\begin{aligned} q_{x,t}&=c_{x,t}+A_t^\top p_{t+1}, & M_{xx,t}&=c_{xx,t}+A_t^\top P_{t+1}A_t,\\ q_{u,t}&=c_{u,t}+B_t^\top p_{t+1}, & M_{ux,t}&=c_{ux,t}+B_t^\top P_{t+1}A_t,\\ & & M_{uu,t}&=c_{uu,t}+B_t^\top P_{t+1}B_t. \end{aligned}

The Hessian blocks are the LQR blocks with QtQ_t replaced by cxx,tc_{xx,t}, RtR_t by cuu,tc_{uu,t}, and the cross term cux,tc_{ux,t} added. The vector qtq_t is new. In stacked form, with Ft=[At Bt]F_t=[A_t\ B_t], these are qt=cz,t+Ft⊤pt+1q_t=c_{z,t}+F_t^\top p_{t+1} and Mt=czz,t+Ft⊤Pt+1FtM_t=c_{zz,t}+F_t^\top P_{t+1}F_t. We use MtM_t for this Hessian because HtH_t denoted the Hamiltonian in the Pontryagin chapter.

Setting the control gradient to zero, Muu,tδu+Mux,tδx+qu,t=0M_{uu,t}\delta\mathbf u+M_{ux,t}\delta\mathbf x+q_{u,t}=0, gives an affine law instead of a linear one:

δut=kt+Ktδxt,kt=−Muu,t−1qu,t,Kt=−Muu,t−1Mux,t.\delta\mathbf u_t=k_t+K_t\delta\mathbf x_t,\qquad k_t=-M_{uu,t}^{-1}q_{u,t},\qquad K_t=-M_{uu,t}^{-1}M_{ux,t}.

The feedback gain KtK_t plays the role of the LQR gain, written here with the sign included. The feedforward term ktk_t comes from the linear terms: it changes the plan even when the state nudge is zero. Substituting the control back gives the coefficients for the preceding step,

pt=qx,t−Mux,t⊤Muu,t−1qu,t,Pt=Mxx,t−Mux,t⊤Muu,t−1Mux,t.\begin{aligned} p_t&=q_{x,t}-M_{ux,t}^\top M_{uu,t}^{-1}q_{u,t},\\ P_t&=M_{xx,t}-M_{ux,t}^\top M_{uu,t}^{-1}M_{ux,t}. \end{aligned}

The update of PtP_t is the Riccati recursion. Written out, it reads Pt=cxx,t+At⊤Pt+1At−(cux,t+Bt⊤Pt+1At)⊤(cuu,t+Bt⊤Pt+1Bt)−1(cux,t+Bt⊤Pt+1At)P_t=c_{xx,t}+A_t^\top P_{t+1}A_t-(c_{ux,t}+B_t^\top P_{t+1}A_t)^\top (c_{uu,t}+B_t^\top P_{t+1}B_t)^{-1}(c_{ux,t}+B_t^\top P_{t+1}A_t), which is the LQR formula when cux,t=0c_{ux,t}=0. The update of ptp_t is the new part. It carries the cost gradients backward, and with zero gradients it stays zero and ktk_t vanishes. In code, these formulas are linear solves with Muu,tM_{uu,t}; an explicit matrix inverse is unnecessary.

The tail StS_t is the cost-to-go of the local problem only. It is accurate near the current plan, and it is not a value function of the nonlinear system over its whole state space. Unlike the grid of the previous chapter, it is stored as a vector and a matrix per step, so the backward pass costs a fixed amount of work per step and grows linearly with the horizon. For linear dynamics and quadratic costs it solves the original problem exactly whenever each Muu,tM_{uu,t} is positive definite. Along a nonlinear trajectory, AtA_t, BtB_t, and the cost derivatives describe only a local approximation. They must be recomputed after the plan changes. Exercise 1 carries out one backward pass by hand on a scalar problem.

Nonlinear Rollouts and iLQR

The backward pass returns, at every step, an affine law δut=kt+Ktδxt\delta\mathbf u_t=k_t+K_t\delta\mathbf x_t for the local problem. iLQR turns it into a new plan and repeats:

  1. Roll out. Simulate the current controls Uˉ\bar{\mathbf U} through the true dynamics. This gives the current plan xˉt\bar{\mathbf x}_t, uˉt\bar{\mathbf u}_t and its cost.

  2. Backward pass. Linearize the dynamics and expand the costs around this plan, then solve the local LQR problem with Algorithm 1. This gives ktk_t and KtK_t.

  3. Forward pass. Run the affine law in closed loop through the true simulator, starting from the same initial state:

    x1+=xinit,ut+=uˉt+kt+Kt(xt+−xˉt),xt+1+=ft(xt+,ut+).\begin{aligned} \mathbf x_1^+&=\mathbf x_{\mathrm{init}},\\ \mathbf u_t^+&=\bar{\mathbf u}_t+k_t+K_t(\mathbf x_t^+-\bar{\mathbf x}_t),\\ \mathbf x_{t+1}^+&=\mathbf f_t(\mathbf x_t^+,\mathbf u_t^+). \end{aligned}

    The new states and controls are the next plan.

  4. Repeat until the plan stops changing.

This loop is the iterative linear-quadratic regulator, iLQR Li & Todorov, 2004: an LQR problem is solved at every iteration, around a different trajectory. The control law in step 3 is the local solution u=uˉ+δu\mathbf u=\bar{\mathbf u}+\delta\mathbf u, with the nudge δxt\delta\mathbf x_t measured as the simulated state minus the planned one. The feedback term matters because the true simulator does not follow the linear model exactly. When the new states drift from the linear prediction, KtK_t adjusts the controls the way the local model says the best control changes with the state.

The loop always linearizes around a trajectory that the true dynamics produced. The gains from the old linearization generate the new trajectory, and that trajectory gives the next linearization. Everything in steps 2 and 3 follows from the derivation above: qtq_t, MtM_t, ktk_t, KtK_t, ptp_t and PtP_t all come out of the LQR algebra. Two safeguards are added by hand, a step size and a regularization, and the rest of this section explains why each is needed.

The local model is accurate only near the current plan. Far from the optimum, the full step of the forward pass can move the boat well outside that neighborhood, and the true cost can then go up instead of down. Nothing in the Riccati derivation prevents this.

The usual fix comes from numerical optimization. Treat the LQR solution as a search direction, as one would treat a Newton step, and decide separately how far to move along it. This is a damped Newton method. The step size α\alpha is not part of the Riccati derivation; it is added afterward and multiplies only the feedforward term:

ut+=uˉt+αkt+Kt(xt+−xˉt).\mathbf u_t^+=\bar{\mathbf u}_t+\alpha k_t+K_t(\mathbf x_t^+-\bar{\mathbf x}_t).

Putting α\alpha on ktk_t alone is a choice, and the reason is that it gives a path between two known trajectories. At α=0\alpha=0 every state nudge stays zero, by induction through the forward pass, and the old plan comes back. At α=1\alpha=1 the forward pass takes the full LQR step, which is the exact solution when the problem is linear-quadratic. In between, the gains keep each trial consistent with the true dynamics.

A line search chooses α\alpha at every iteration. Try the full step α=1\alpha=1, simulate, and keep the result if the true cost went down enough. Otherwise halve α\alpha and simulate again. Each trial is one run through the nonlinear simulator. The step size is therefore not a fixed hyperparameter; it adapts at every iteration. When the linear model is accurate, as near convergence, the full step usually passes at once. The real settings are the halving schedule and the meaning of “enough”.

The implementation tries 1,1/2,…,2−111,1/2,\ldots,2^{-11}. For “enough”, the backward pass predicts the reduction of the local model. With

d1=∑t=1T−1qu,t⊤kt,d2=12∑t=1T−1kt⊤Muu,tkt,d_1=\sum_{t=1}^{T-1}q_{u,t}^\top k_t,\qquad d_2=\frac12\sum_{t=1}^{T-1}k_t^\top M_{uu,t}k_t,

the predicted reduction is Δ^J(α)=−αd1−α2d2\widehat\Delta J(\alpha)=-\alpha d_1-\alpha^2d_2. A trial is accepted when its true cost decreases strictly and by at least a small fraction of this prediction, J(Uˉ)−J(U+)≥10−4max⁡(Δ^J(α),0)J(\bar{\mathbf U})-J(\mathbf U^+)\geq10^{-4}\max(\widehat\Delta J(\alpha),0). The prediction guides acceptance; it does not replace evaluation of the original objective.

Regularization

The second problem appears in the backward pass itself. Away from the optimum, the control curvature Muu,tM_{uu,t} may be indefinite or nearly singular, and then the control solve fails or proposes a huge change. Replace the matrix used in the control solve by Muu+μIM_{uu}+\mu I, where μ>0\mu>0. Increasing μ\mu makes the correction more conservative and can make the solve positive definite. The code checks a Cholesky factorization, increases μ\mu after a failed backward pass or line search, and decreases it after an accepted step. The numerical defaults start at 10-4, multiply by ten after failure, and divide by three after acceptance, with a floor of 10-9.

When regularization changes kk and KK, the formulas for ptp_t and PtP_t above no longer describe substitution into the original quadratic model. The implementation therefore uses the full expressions

pt=qx+Mux⊤k+K⊤qu+K⊤Muuk,Pt=Mxx+Mux⊤K+K⊤Mux+K⊤MuuK.\begin{aligned} p_t&=q_x+M_{ux}^\top k+K^\top q_u+K^\top M_{uu}k,\\ P_t&=M_{xx}+M_{ux}^\top K+K^\top M_{ux}+K^\top M_{uu}K. \end{aligned}

Here MuuM_{uu} is the original curvature block; regularization was used to choose the correction. These expressions also remain applicable when some controls are fixed at their bounds.

With both safeguards in place, the complete method reads as follows.

The iteration uses second derivatives of the costs but only first derivatives of the dynamics. It is often described as a Gauss--Newton approximation to DDP. That terminology should not obscure what is approximated: the omitted terms come from dynamics curvature, as the next section shows. If a nonlinear cost is itself a sum of squared residuals, replacing its Hessian by a residual-Jacobian product would be a further approximation; the docking code uses the exact cost Hessian.

The returned gains describe a neighborhood of the final plan. The docking animation below executes one stored plan. The gains used inside the optimizer do not imply that the animation replans as the boat moves.

Dynamics Curvature and DDP

iLQR drops the quadratic remainder in the transition’s Taylor expansion. For a turning boat, a change in heading changes the direction of thrust, so products of state and control changes can affect the next state. DDP keeps these second-order terms in the backward pass. Everything else stays the same.

The chain rule in one variable

Each backup minimizes a stage cost plus the cost-to-go evaluated at the next state. With one variable, write gg for the cost-to-go and ff for the dynamics. The second derivative of the composition has two terms:

(g∘f)′′=g′′ (f′)2+g′ f′′.(g\circ f)''=g''\,(f')^2+g'\,f''.

The first term is the curvature of the cost-to-go times the squared slope of the dynamics. The second is the slope of the cost-to-go times the curvature of the dynamics. iLQR keeps the first term only. DDP keeps both.

One backup, expanded to second order

Write the quantity minimized in one backup as a function of the stacked nudge δzt=(δxt,δut)\delta\mathbf z_t=(\delta\mathbf x_t,\delta\mathbf u_t):

ct(zˉt+δzt)+St+1(ft(zˉt+δzt)−xˉt+1).c_t(\bar{\mathbf z}_t+\delta\mathbf z_t) +S_{t+1}\big(\mathbf f_t(\bar{\mathbf z}_t+\delta\mathbf z_t)-\bar{\mathbf x}_{t+1}\big).

Expand it to second order in δzt\delta\mathbf z_t. The next-state nudge has a linear part FtδztF_t\delta\mathbf z_t and, for component ii, a quadratic part 12δzt⊤fzz,tiδzt\tfrac12\delta\mathbf z_t^\top f^i_{zz,t}\delta\mathbf z_t, where fzz,tif^i_{zz,t} is the Hessian of the iith component of ft\mathbf f_t along the current plan. Inserted in the tail, the quadratic part of St+1S_{t+1} sees only the linear part; the rest is of order three or higher. The linear part pt+1⊤δxt+1p_{t+1}^\top\delta\mathbf x_{t+1} of the tail, however, sees both. The linear coefficient is the same qt=cz,t+Ft⊤pt+1q_t=c_{z,t}+F_t^\top p_{t+1} as before, and the quadratic coefficient is

Mt=czz,t+Ft⊤Pt+1Ft⏟g′′(f′)2+∑i=1nxpt+1,i fzz,ti⏟g′f′′.M_t=c_{zz,t} +\underbrace{F_t^\top P_{t+1}F_t}_{g''(f')^2} +\underbrace{\sum_{i=1}^{n_x}p_{t+1,i}\,f^i_{zz,t}}_{g'f''}.

iLQR drops the last term:

MtiLQR=czz,t+Ft⊤Pt+1Ft+∑ipt+1,i fzz,ti.M_t^{\mathrm{iLQR}}=c_{zz,t}+F_t^\top P_{t+1}F_t +\cancel{\textstyle\sum_i p_{t+1,i}\,f^i_{zz,t}}.

These are the multiplier-weighted dynamics Hessians that the local problem left out. The tail gradient pt+1p_{t+1} plays the role of the SQP multiplier: it is the costate, the sensitivity of the remaining cost to the next state.

DDP keeps the term

DDP Tassa et al., 2014 keeps the dynamics-curvature term. In blocks,

Mxx,tDDP=cxx,t+At⊤Pt+1At+∑ipt+1,ifxx,ti,Mux,tDDP=cux,t+Bt⊤Pt+1At+∑ipt+1,ifux,ti,Muu,tDDP=cuu,t+Bt⊤Pt+1Bt+∑ipt+1,ifuu,ti.\begin{aligned} M_{xx,t}^{\mathrm{DDP}}&=c_{xx,t}+A_t^\top P_{t+1}A_t +\sum_i p_{t+1,i} f^i_{xx,t},\\ M_{ux,t}^{\mathrm{DDP}}&=c_{ux,t}+B_t^\top P_{t+1}A_t +\sum_i p_{t+1,i} f^i_{ux,t},\\ M_{uu,t}^{\mathrm{DDP}}&=c_{uu,t}+B_t^\top P_{t+1}B_t +\sum_i p_{t+1,i} f^i_{uu,t}. \end{aligned}

Everything downstream is the same recipe with the new MtM_t: the formulas for ktk_t, KtK_t, ptp_t and PtP_t, the forward pass, the line search and the regularization. In Algorithm 2, only step 3 changes.

DDP does not build a new local problem with quadratic dynamics and solve it with Riccati. With quadratic dynamics the local problem would no longer be LQR. DDP instead expands each backup to second order directly, and the extra term lands in MtM_t.

The only line that differs from Algorithm 1 is the formula for MtM_t. The curvature choice can still change both the direction of a step and the amount of regularization needed to accept it.

For the boat, even the continuous acceleration contains a state--control cross derivative: ∂2v˙x/(∂ψ ∂uL)=−(Fmax⁡/m)sin⁡ψ\partial^2\dot v_x/(\partial\psi\,\partial u_L) =-(F_{\max}/m)\sin\psi. The discrete derivatives used by the solver also include how heading and velocity change within the RK4 step. Automatic differentiation is applied through that complete step. A differential equation that is affine in its controls need not yield a numerical transition whose second control derivatives vanish.

The extra curvature costs computation and can be indefinite. DDP therefore still needs regularization and nonlinear acceptance tests. Neither method guarantees the globally best docking maneuver. For affine dynamics the transition Hessians are zero, so the two backward constructions coincide when all other choices agree.

Thruster Limits and Stopping Criteria

The boat’s controls must remain in [−1,1]2[-1,1]^2, even when the unconstrained correction asks for more thrust. At zero state deviation, the feedforward step is the solution of the box-constrained quadratic problem

min⁡k qu⊤k+12k⊤(Muu+μI)k,−1−uˉt≤k≤1−uˉt.\min_k\ q_u^\top k+\frac12k^\top(M_{uu}+\mu I)k, \qquad -\mathbf1-\bar{\mathbf u}_t\leq k\leq\mathbf1-\bar{\mathbf u}_t.

For two controls, each coordinate is either free, fixed at its lower bound, or fixed at its upper bound. The teaching implementation checks the nine combinations, minimizes over each face, and keeps the best feasible candidate. Positive-definite curvature makes this a strictly convex QP. Larger systems can use an active-set solver rather than enumerate all combinations Tassa et al., 2014.

The feedback rows of saturated controls are zero while their active set stays fixed. For the free coordinates F\mathcal F, solve (Muu+μI)FFKF=−(Mux)F(M_{uu}+\mu I)_{\mathcal F\mathcal F}K_{\mathcal F} =-(M_{ux})_{\mathcal F}. Use the full substitution formulas to update the quadratic tail. With bounds, this tail describes a neighborhood with the selected active sets; across active-set changes the minimized expression is generally piecewise quadratic. During the nonlinear trial, project the resulting control onto its box before simulation. This enforces the physical bounds when a trial leaves the neighborhood represented by the backward pass. The nonlinear cost check then decides whether that trial should be retained.

The stopping test is separate from docking success. Let g=∇UJg=\nabla_{\mathbf U}J be the gradient of the original shooting objective, computed by the adjoint recursion along the current nonlinear rollout. With normalized controls, the solver stops when

∥U−clip⁡(U−g,−1,1)∥∞≤10−5.\left\|\mathbf U-\operatorname{clip}(\mathbf U-g,-1,1)\right\|_\infty \leq10^{-5}.

At an interior optimum this reduces to a small control gradient. At a bound it also allows a gradient that points toward a forbidden improvement. The experiment permits at most 120 accepted updates. If regularization exceeds 1012 without an acceptable trial, the solver retains its last accepted trajectory and reports failure to make progress. A small residual certifies approximate first-order stationarity, not a globally optimal path or a successful arrival.

Docking Trajectories and Recorded Futures

Do the two curvature choices produce the same maneuver from the same starting plan? Both methods receive the coasting initialization, identical costs and control limits, and the same stopping settings. The following tables report their final nonlinear costs and arrival checks. Each final control sequence is also replayed with four RK4 substeps per control interval, giving a 0.025 s0.025\ \mathrm s validation grid.

ApproachMethodCostAccepted updates
Angled approachiLQR8.051518
Angled approachDDP11.987934
Sideways driftiLQR7.667413
Sideways driftDDP7.667445

The arrival checks below use the finer replay.

ApproachMethodPosition error (m)Heading error (°)Speed (m/s)Clearance (m)
Angled approachiLQR0.0001258.98e-056.89e-050.599
Angled approachDDP0.001250.1390.01440.352
Sideways driftiLQR3.89e-052.65e-064.25e-050.600
Sideways driftDDP3.89e-053.71e-064.25e-050.600

All four runs satisfy the stopping test and the docking checks: position error below 0.2 m0.2\ \mathrm m, heading error below 3∘3^\circ, speed below 0.05 m/s0.05\ \mathrm{m/s}, angular speed below 1∘/s1^\circ/\mathrm s, bounded thrust, and positive hull clearance. The maximum position difference between the planning trajectory and the finer replay is below 10−6 m10^{-6}\ \mathrm m in these runs. Clearance is checked on the finer grid; this remains a sampled validation, not a proof of continuous-time collision avoidance.

Final trajectories under the same initialization and objective. Solid blue
is iLQR and dashed orange is DDP; the dotted gray path is the initial coast.
Outlines show orientation every four seconds. DDP takes a different turning
maneuver in the angled approach. The two final paths nearly coincide in the
sideways-drift case.

Figure 4:Final trajectories under the same initialization and objective. Solid blue is iLQR and dashed orange is DDP; the dotted gray path is the initial coast. Outlines show orientation every four seconds. DDP takes a different turning maneuver in the angled approach. The two final paths nearly coincide in the sideways-drift case.

In the angled approach, iLQR reaches cost 8.0515 in 18 accepted updates, while DDP reaches a different stationary trajectory with cost 11.9879 in 34 updates. The DDP trajectory makes two full turns near the berth. Its final unwrapped heading is approximately 720∘720^\circ, which the periodic heading cost treats as the same orientation as zero. Reaching this stationary trajectory does not remove the extra motion accumulated on the way there. In the sideways-drift case, both reach cost 7.6674, with 13 accepted updates for iLQR and 45 for DDP. These are outcomes of two particular local solves, not a general ranking of the algorithms. The difference in the first case also shows why comparing iteration counts alone can hide a difference in the solutions obtained.

Actual nonlinear cost at every accepted iteration, including the initial
rollout at iteration zero. The vertical axis is logarithmic. Rejected trial
steps are excluded from the horizontal count; forward-evaluation and
backward-attempt counts are available in the downloadable diagnostics.

Figure 5:Actual nonlinear cost at every accepted iteration, including the initial rollout at iteration zero. The vertical axis is logarithmic. Rejected trial steps are excluded from the horizontal count; forward-evaluation and backward-attempt counts are available in the downloadable diagnostics.

Within one selected plan, simulation time has a different meaning from optimizer iteration. At two seconds, for example, the boat occupies the two-second state of that rollout. Its remaining states give a prediction of where it will go if the rest of the stored controls are applied. Outlines spaced equally in time spread apart while the boat is moving quickly and cluster as it comes to rest. Reverse thrust helps remove momentum before arrival.

The final iLQR plan for the angled approach. The filled boat marks the selected
simulation time; translucent outlines show future poses every two seconds.
The right panel gives speed and both physical thrusts. Negative thrust during
the approach brakes the boat. The vertical marker identifies the same time
as the filled boat.

Figure 6:The final iLQR plan for the angled approach. The filled boat marks the selected simulation time; translucent outlines show future poses every two seconds. The right panel gives speed and both physical thrusts. Negative thrust during the approach brakes the boat. The vertical marker identifies the same time as the filled boat.

Choose a scenario and optimizer iteration, then scrub or play simulation time within that fixed plan. The path ahead and boat outlines display its remaining predicted states. Arrival errors and plots belong to the selected iteration, including intermediate plans that do not dock successfully.

The replay reads recorded simulations, so exploring it does not rerun an optimizer. Recomputing a plan from newly observed states is the additional step introduced in receding-horizon control.

Pulling Down a Thermoacoustic Refrigerator

A standing-wave thermoacoustic refrigerator is a sealed, gas-filled tube with a loudspeaker at one end and a stack of thin parallel plates inside (Figure 8a). The loudspeaker excites a standing sound wave in the tube. Each gas parcel near a plate is pushed back and forth along it, compressing and heating as it moves toward the loudspeaker end and expanding and cooling as it moves away. At the loudspeaker end of its travel the parcel is warmer than the plate and gives up heat to it; at the far end it is cooler than the plate and takes heat from it. Every cycle therefore moves a little heat one step along the plate, and the parcels together act as a bucket brigade that transports heat from the far end of the stack toward the loudspeaker end. Sound is used to move heat from a cold place to a warmer one, against the direction it would flow on its own. A household heat pump does the same thing with a compressor when it extracts heat from cold outdoor air and delivers it indoors; a refrigerator is the same machine used for its cold side. A cold heat exchanger at the far end of the stack connects to the payload, the refrigeration term for the object or compartment being cooled, and a hot heat exchanger at the loudspeaker end rejects the heat to ambient air. There are no moving parts other than the loudspeaker, and the only knob is how hard it drives. The control problem is what refrigeration engineers call a pull-down: bringing the payload from ambient temperature down to its set point after switch-on. Here that means choosing a driver-amplitude schedule that brings the payload to a target temperature by a fixed deadline while spending little acoustic energy.

Figure 8:Geometry of the thermoacoustic refrigerator and its two-state abstraction. (a) The device: a loudspeaker piston at the left end of a sealed resonator, a hot heat exchanger, a stack of thin plates, and a cold heat exchanger. The dashed envelope is the standing-wave pressure amplitude. Gas parcels oscillating along the plates pump heat from the cold exchanger toward the hot one. (b) The lumped model the optimizer sees. The state is the pair of exchanger temperatures, the action is the driver amplitude, the stage cost charges acoustic work, and the terminal cost penalizes the final cold-side temperature error. In the online book the figure replays the recorded iLQR and DDP plans: the piston stroke, wave, and parcel motion follow the action, the exchanger and node tints follow the state, and the panels below compare the plan with a constant-amplitude schedule. The static version shows the same two panels.

In the online book, the replay reads the recorded plans and integrates only the constant-amplitude comparison; it does not rerun the optimizer.

Rather than simulate the acoustics, we lump the whole device into two thermal masses (Figure 8b): the cold exchanger together with its payload, and the hot exchanger. The state is their temperatures, xt=(Tc,t,Th,t)\mathbf x_t=(T_{c,t},T_{h,t}), and the action is the normalized driver amplitude ut∈[0,1]u_t\in[0,1], so this is a two-dimensional continuous-state, one-dimensional continuous-action problem. Let ΔT=Th−Tc\Delta T=T_h-T_c be the temperature span across the stack and η(ΔT)=1−ΔT/ΔT0\eta(\Delta T)=1-\Delta T/\Delta T_0 a pumping efficiency that decreases linearly with that span. The continuous-time dynamics are

Q˙c=kqu2η(ΔT),W˙=kwu2η(ΔT)+kvu2+k3u3,CcT˙c=−Q˙c+Qload,ChT˙h=Q˙c+W˙−UA(Th−Tamb).\begin{aligned} \dot Q_c &= k_q u^2\eta(\Delta T),& \dot W &= k_w u^2\eta(\Delta T)+k_vu^2+k_3u^3,\\ C_c\dot T_c &= -\dot Q_c+Q_{\mathrm{load}},& C_h\dot T_h &= \dot Q_c+\dot W-UA(T_h-T_{\mathrm{amb}}). \end{aligned}

Here Q˙c\dot Q_c is the heat pumped out of the cold side, W˙\dot W is the acoustic work the driver injects, QloadQ_{\mathrm{load}} is a parasitic heat leak into the payload, and UAUA is the hot exchanger’s conductance to ambient. Both heat flows scale with u2u^2 because acoustic power is quadratic in wave amplitude, and both weaken as the span grows; this is the short-stack approximation of thermoacoustics Swift, 1988Swift, 2017. Two loss terms complete the work: a viscous term in u2u^2 and a cubic term k3u3k_3u^3 that makes hard driving disproportionately expensive. The coupling matters for the optimizer. Driving hard pumps heat faster, but it also dumps that heat plus the work into the hot side, which raises ThT_h, widens the span, and lowers the efficiency of every later step. Refrigeration engineers measure this efficiency by the coefficient of performance (COP), the ratio Q˙c/W˙\dot Q_c/\dot W of heat pumped to work spent while the driver is on. Unlike an efficiency it can exceed one, because the work only moves heat rather than producing cold. In this model the COP falls as the span grows and, through the cubic term, as the amplitude grows; one scenario below removes the cubic term so that the COP no longer depends on amplitude. All coefficients are synthetic teaching values, not measurements of a particular device.

QuantityValue
Cold and hot heat capacities Cc,ChC_c,C_h20,50 J/K20,50\ \mathrm{J/K}
Hot conductance UAUA0.5 W/K0.5\ \mathrm{W/K}
Ambient temperature TambT_{\mathrm{amb}}20 ∘C20\ ^\circ\mathrm C
Parasitic cold-side load QloadQ_{\mathrm{load}}1 W1\ \mathrm W
Pumping coefficient kqk_q5 W5\ \mathrm W
Work and viscous coefficients kw,kvk_w,k_v4,1 W4,1\ \mathrm W
Cubic-loss coefficient k3k_32 W2\ \mathrm W
Critical temperature span ΔT0\Delta T_040 K40\ \mathrm K
Target temperature T⋆T^\star5 ∘C5\ ^\circ\mathrm C

Both temperatures begin at ambient, 20 ∘C20\ ^\circ\mathrm C. A fourth-order Runge--Kutta step of length h=1 sh=1\ \mathrm s defines the deterministic transition xt+1=ft(xt,ut)\mathbf x_{t+1}=\mathbf f_t(\mathbf x_t,u_t) over a horizon of T−1=300T-1=300 actions, so the episode is exactly five minutes. The cost uses the same stage-plus-terminal form as the docking problem:

ct(xt,ut)=h wEW˙(xt,ut),cT(xT)=wT(Tc,T−T⋆)2,wE=0.05,wT=10.c_t(\mathbf x_t,u_t)=h\,w_E\dot W(\mathbf x_t,u_t),\qquad c_T(\mathbf x_T)=w_T(T_{c,T}-T^\star)^2, \qquad w_E=0.05,\quad w_T=10.

The stage cost charges only energy, and the target enters only through the terminal cost, so the objective is sparse in the RL sense: nothing tells the optimizer how cold to be at intermediate times. The terminal penalty is soft, so a plan can trade some arrival error for lower energy. Both methods start from the constant open-loop sequence ut=0.5u_t=0.5 and use the same action bounds and stopping settings.

ExperimentMethodStatusAccepted updatesCostEnergy (J)Cold at 300 s (°C)
Baseline pull-downiLQRconverged2451.22410165.20
Baseline pull-downDDPconverged1251.22410165.20
No parasitic loadiLQRconverged2820.6524115.09
No parasitic loadDDPconverged820.6524115.09
Sluggish hot sideiLQRconverged2845.7169115.13
Sluggish hot sideDDPconverged1445.5859085.13
Amplitude-independent COPiLQRiteration_limit20033.3536665.08
Amplitude-independent COPDDPconverged2733.3536665.08
Target out of reach in 300 siLQRconverged2119.58214262.20
Target out of reach in 300 sDDPconverged10119.58214262.20

Costs are evaluated on the final accepted nonlinear trajectory. The iteration-limit row is a retained local plan, not a converged solve.

For comparison, constant full amplitude in the baseline case ends at 2.20 °C, uses 1426 J, and has cost 149.89.

Cold and hot temperatures under the baseline plan, with a constant
full-amplitude rollout for comparison. The lower panel shows their driver
amplitudes. The target line and temperature traces show the tradeoff between
energy use and final cold temperature.

Figure 9:Cold and hot temperatures under the baseline plan, with a constant full-amplitude rollout for comparison. The lower panel shows their driver amplitudes. The target line and temperature traces show the tradeoff between energy use and final cold temperature.

The baseline plan drives relatively hard at first, eases off, then ramps to full amplitude near the deadline. Early driving uses the initially small temperature span, but it also warms the hot side and weakens later pumping. The fixed load adds the same total heat over every 300-second plan. Control timing still changes the temperature span and therefore the final cold temperature. Running at full amplitude throughout uses about 1426 J1426\ \mathrm J and reaches 2.20 ∘C2.20\ ^\circ\mathrm C; its nonlinear cost is 149.886, versus 51.224 for the baseline local plan. The soft terminal cost need not favor the coldest possible final state.

Final computed amplitude schedules for the baseline, no-load,
sluggish-hot-side, and no-cubic-loss cases. The first three are iLQR plans;
the no-cubic-loss plan is from DDP. Removing the cold-side load flattens the
schedule, while changing the hot-side dynamics produces a long ramp.

Figure 10:Final computed amplitude schedules for the baseline, no-load, sluggish-hot-side, and no-cubic-loss cases. The first three are iLQR plans; the no-cubic-loss plan is from DDP. Removing the cold-side load flattens the schedule, while changing the hot-side dynamics produces a long ramp.

Without the parasitic load, a nearly constant amplitude is economical. To see the tendency, temporarily hold the temperature span fixed and write v=u2v=u^2. Heat pumped is then proportional to vv, while the cubic loss is proportional to v3/2v^{3/2}, a convex function for v≥0v\geq0. For a fixed total amount of pumping, Jensen’s inequality favors spreading vv through time. The actual schedule is not exactly constant because the span and hot-side temperature still respond to the controls. With Ch=200 J/KC_h=200\ \mathrm{J/K} and UA=0.2 W/KUA=0.2\ \mathrm{W/K}, the amplitude rises through most of the horizon, then turns off for the final two intervals. Both thermal storage and heat rejection changed in that experiment, so it does not isolate the effect of either parameter.

The DDP curvature term also has a direct physical interpretation here. For the continuous cold-side equation,

∂2T˙c∂u ∂ΔT=2kquCcΔT0.\frac{\partial^2\dot T_c}{\partial u\,\partial\Delta T} =\frac{2k_qu}{C_c\Delta T_0}.

Increasing the temperature span weakens pumping, and this mixed derivative measures how that effect changes with amplitude. The solver differentiates the complete RK4 transition, whose Hessian also contains effects from the intermediate integration stages.

Actual nonlinear cost after each accepted update for iLQR and DDP in the
baseline and no-cubic-loss cases. The vertical axis is logarithmic. The
curves compare these local solves from the same initial control sequence,
not a general ranking of the methods.

Figure 11:Actual nonlinear cost after each accepted update for iLQR and DDP in the baseline and no-cubic-loss cases. The vertical axis is logarithmic. The curves compare these local solves from the same initial control sequence, not a general ranking of the methods.

When k3=0k_3=0, both pumping and work are quadratic in amplitude at a fixed temperature span. Their instantaneous ratio then no longer depends on amplitude, leaving weaker preferences among some schedules. In the recorded run, iLQR reaches its iteration limit while DDP satisfies the stopping test; both reach nearly the same final cost. For the sluggish hot side, DDP reaches a different, slightly lower-cost local plan than iLQR. Lowering the target to 0 ∘C0\ ^\circ\mathrm C produces a plan saturated at ut=1u_t=1 throughout the fixed horizon, exercising the box-constrained backward step. These outcomes depend on the initial sequence. Starting the baseline from constant amplitudes 0.1 and 0.9 leads to other local plans, so neither result certifies a global minimum.

Scheduling Radiotherapy Fractions

Radiotherapy rarely delivers its dose in one sitting. A course is split into fractions, typically one per weekday over several weeks, because healthy tissue repairs part of its radiation damage between sessions while many tumors repair less. Every beam that reaches the tumor also crosses healthy organs on its way in and out, so a treatment plan must decide both how hard to irradiate on each day and from which directions. With one control vector per session and a state that summarizes the damage accumulated so far, this is again a finite-horizon optimal-control problem, and iLQR applies to it directly.

The example below is a synthetic slice of the chest with a tumor at the center and three organs around it: the spinal cord, the heart, and a lung. Three beams aim at the tumor, and each one crosses exactly one organ before reaching it (Figure 12). The control ut∈R3\mathbf u_t\in\mathbb R^3 holds the three beam intensities of session tt, each between 0 and 3 Gy3\ \mathrm{Gy}. The beams are scaled so that intensity ut,ju_{t,j} adds ut,ju_{t,j} gray to the tumor’s mean dose. The mean dose received by structure kk is dt,k=ak⊤utd_{t,k}=\mathbf a_k^\top\mathbf u_t, where the dose matrix with rows ak\mathbf a_k is computed once from the beam geometry. The tumor row is (1,1,1)(1,1,1), and each organ row has a single large entry, between 1.28 and 1.50, for the beam that crosses it. That beam enters through the organ before it has lost intensity in the tissue, so the organ receives more than the tumor does.

Figure 12:The fractionation problem and its optimized plan. Left: the synthetic slice, with the course dose of the final DDP plan. Arrows mark where the three beams enter. Top right: the dose that each session delivers to the tumor, split by beam, against the uniform 3 Gy plan (dashed). Bottom right: health of the tumor and the three organs under the optimized plan (solid) and the uniform plan (dotted). In the online book the figure replays the recorded plans session by session and lets the reader scrub through the accepted iLQR and DDP iterates.

The state is a health score for each structure, following the convention of the clinical planning work this example is adapted from Fu et al., 2019. The tumor starts at h1,tumor=1h_{1,\text{tumor}}=1 and is controlled when its health reaches 0. Each organ starts at 0, and its health becomes negative as damage accumulates; -1 is its tolerance. A session damages structure kk according to the linear-quadratic model of radiobiology Fowler, 1989, and the days until the next session then let the organs repair and the tumor regrow:

ht+1,k=(ht,k−αkdt,k+βkdt,k2Ek)ρk(t),ρk(t)={eλgt,k=tumor,e−rkgt,k an organ.h_{t+1,k}=\Big(h_{t,k}-\frac{\alpha_kd_{t,k}+\beta_kd_{t,k}^2}{E_k}\Big)\rho_k(t), \qquad \rho_k(t)=\begin{cases}e^{\lambda g_t},&k=\text{tumor},\\ e^{-r_kg_t},&k\ \text{an organ}.\end{cases}

Here gtg_t is the number of days until the next session: one from Monday to Thursday and three on Friday. The scale EkE_k is the accumulated effect that moves a structure by one unit of health, from untreated to controlled for the tumor and from intact to tolerance for an organ. The quadratic term βkd2\beta_kd^2 makes one large fraction more damaging than two half-size fractions with the same total dose. Late-responding healthy tissue has a larger β\beta relative to α\alpha than most tumors, and that difference makes splitting the course worthwhile. The coefficients below are synthetic teaching values with plausible ratios, not clinical parameters.

Structureαk\alpha_k (1/Gy)βk\beta_k (1/Gy²)Effect scale EkE_kDaily repair rkr_k or regrowth λ\lambda
Tumor0.300.03022regrowth 0.005
Spinal cord0.100.05020.01
Heart0.100.03020.04
Lung0.100.02020.10

The cost charges a small amount for beam intensity, penalizes organ health below tolerance at every session, requires the tumor to reach zero at the end of the course, and rewards organ health left at the end:

ct(h,u)=0.012∥u∥2+50∑k≠tumors(−hk−1),cT(h)=200 s(htumor)2+50∑k≠tumors(−hk−1)−∑k≠tumorhk,\begin{aligned} c_t(\mathbf h,\mathbf u)&=\tfrac{0.01}{2}\|\mathbf u\|^2+50\sum_{k\ne\text{tumor}}s(-h_k-1),\\ c_T(\mathbf h)&=200\,s(h_{\text{tumor}})^2+50\sum_{k\ne\text{tumor}}s(-h_k-1)-\sum_{k\ne\text{tumor}}h_k, \end{aligned}

where s(z)=log⁡(1+e25z)/25s(z)=\log(1+e^{25z})/25 is a smooth version of max⁡(z,0)\max(z,0), as in the docking costs. The course has T−1=20T-1=20 sessions over four weeks. Both solvers start from equal beams of 0.7 Gy0.7\ \mathrm{Gy}, a uniform plan of 2.1 Gy2.1\ \mathrm{Gy} per session that leaves the tumor uncontrolled, and use the same box-constrained backward pass as the docking problem.

PlanAccepted updatesCostTumor dose (Gy)Final tumor healthLowest cord, heart, lung health
Uniform, 3 Gy per session–436.07960.0-0.000-2.26, -1.05, -0.54
iLQR (converged)532.93256.2-0.001-0.72, -0.76, -0.79
DDP (converged)112.93256.2-0.001-0.72, -0.76, -0.79

Health -1 is the tolerance of each organ. Both solvers start from equal beams delivering 2.1 Gy per session, a plan that leaves the tumor uncontrolled.

The simplest curative alternative gives every session equal beams, raised until the tumor just reaches zero. That takes 3 Gy3\ \mathrm{Gy} per session and 60 Gy60\ \mathrm{Gy} in total, and it drives the spinal cord to a health of -2.26, more than twice its tolerance; the heart also ends just past its limit. The optimized plan controls the tumor with 56 Gy56\ \mathrm{Gy} and keeps every organ within tolerance. Three features of the schedule in Figure 12 follow from the model. The beam through the lung carries more than half of the dose, and the beam through the cord the least, because the lung repairs fastest and has the smallest β\beta while the cord repairs slowest and has the largest. The doses are front-loaded: early damage to an organ has more days to be repaired before the end of the course, and early tumor kill leaves less tumor to regrow. Fridays receive extra dose because three days of repair follow them. The organ health curves level off after the first week, where each session’s new damage is roughly balanced by repair. Clinical courses are not front-loaded this way; the pattern reflects the first-order repair model and the absence of acute toxicity limits, which a clinical planning model would include.

Left: actual nonlinear cost after each accepted update for iLQR and DDP from
the same uniform 2.1 Gy plan, on a logarithmic axis. Right: the dose that
selected DDP iterates deliver to the tumor in each session. The first update
pushes dose to the last sessions, where it is most directly tied to the
terminal tumor cost; later updates move it to the start of the course and to
the Fridays.

Figure 13:Left: actual nonlinear cost after each accepted update for iLQR and DDP from the same uniform 2.1 Gy plan, on a logarithmic axis. Right: the dose that selected DDP iterates deliver to the tumor in each session. The first update pushes dose to the last sessions, where it is most directly tied to the terminal tumor cost; later updates move it to the start of the course and to the Fridays.

Both methods reach the same plan, but DDP needs 11 accepted updates and iLQR 53. The transition explains the difference. It is linear in the health state and quadratic in the beams, so the only second-order transition term that DDP adds to the backward recursion is

∑kpt+1,k ∂2ht+1,k∂ut2=−2∑kpt+1,k βkρk(t)Ek akak⊤,\sum_kp_{t+1,k}\,\frac{\partial^2h_{t+1,k}}{\partial\mathbf u_t^2} =-2\sum_kp_{t+1,k}\,\frac{\beta_k\rho_k(t)}{E_k}\,\mathbf a_k\mathbf a_k^\top,

where pt+1,kp_{t+1,k} is the derivative of the cost-to-go with respect to ht+1,kh_{t+1,k}. Along the final plan this derivative is positive for the tumor, whose remaining health costs, and negative for each organ, whose health is rewarded. The organ terms therefore add positive curvature: they tell the backward pass that pushing a beam harder damages its organ more than in proportion. The tumor term subtracts curvature, because a larger fraction also kills the tumor more than in proportion. iLQR drops both terms and treats the effect of each extra gray as fixed around the current plan, so it needs more updates to discover the advantage of spreading dose over the sessions and beams.

Exercises

Solution to Exercise 1

The last control is u2=β(r−x2)/(1+β)u_2=\beta(r-x_2)/(1+\beta), and its minimized tail is β(x2−r)2/[2(1+β)]\beta(x_2-r)^2/[2(1+\beta)]. With x1=0x_1=0, minimizing the remaining expression gives u1=βr/(1+2β)u_1=\beta r/(1+2\beta), followed by the same value for u2u_2. Thus x3=2βr/(1+2β)x_3=2\beta r/(1+2\beta). For β=r=1\beta=r=1 this gives u1=u2=1/3u_1=u_2=1/3 and x3=2/3x_3=2/3, so J=118+118+118=1/6J=\tfrac1{18}+\tfrac1{18}+\tfrac1{18}=1/6. The final position falls short because the objective trades terminal error against effort; arrival is penalized, not imposed as an equality.

The function u2(x2)u_2(x_2) is a feedback law: if the state reaching the last step changes, the minimizing last control changes with it. In the vector case this dependence becomes the gain KtK_t. As the terminal weight grows, the two controls tend to r/2r/2 and the terminal state tends to rr.

Solution to Exercise 2

The local expansions are exact. Backward elimination therefore minimizes the original quadratic problem in perturbation coordinates, and α=1\alpha=1 recovers its solution. The affine simulator agrees exactly with the linearized perturbation dynamics. All transition Hessians vanish, so DDP produces the same correction. This is also a useful implementation test: compare the returned controls with a dense solve of the reduced quadratic objective.

Solution to Exercise 3

The Euler velocity update contains h(Fmax⁡/m)(uL+uR)cos⁡ψh(F_{\max}/m)(u_L+u_R)\cos\psi. The mixed derivative is therefore −h(Fmax⁡/m)sin⁡ψ-h(F_{\max}/m)\sin\psi. DDP multiplies it by the vxv_x component of pt+1p_{t+1} and adds it to the corresponding state--control curvature entry. iLQR uses the first-order transition, whose second derivatives are zero within the local model. The actual experiment differentiates RK4 instead, so its mixed derivative includes the intermediate integration stages.

Solution to Exercise 4

Use make_problem(velocity_weight=0.) and keep every other choice fixed for the first comparison. For the shorter experiment, set steps=80 in BoatParameters and regenerate the initial controls. Removing the terminal velocity term removes an explicit incentive to stop at the final time. Running position and velocity costs can still lead to a slow arrival, especially over the longer horizon, so failure is not inevitable. Measure the final speed independently of position error and retain the same docking tolerances for both objectives. A low-cost pass through the target is not a successful stationary arrival.

Solution to Exercise 5

Fixing one coordinate at a bound changes the stationarity equation for the other coordinate through the off-diagonal entry of MM. Componentwise clipping does not solve that new equation. The face minimization does. If no nonlinear trial is accepted, the solver retains its previous controls and states and reports that it could not make progress; it must not replace them with an unaccepted trial or report convergence from rejection alone.

Solution to Exercise 6

With no load, cooling obtained early is not directly undone by a constant heat leak. If the temperature span were fixed, a given amount of cooling would fix the sum of vt=ut2v_t=u_t^2. The cubic loss is proportional to vt3/2v_t^{3/2}, so Jensen’s inequality favors equal vtv_t across time. The temperature span still evolves, which explains the modest variation in the computed schedule. With the load restored, the longer horizon admits lower amplitude over more intervals, but the leak adds heat throughout that extra time. In this model, the 600 s600\ \mathrm s local solution starts near 0.59, reaches 0.89 by 550 s550\ \mathrm s, and uses full amplitude in the final intervals. Its approximately 1392 J1392\ \mathrm J of energy exceeds the shorter baseline’s use.

Computational Sources

The implementation separates the generic backward recursion from the physical models and artifact builders:

Run uv run python scripts/build_boat_docking_artifacts.py from the repository root to reproduce the solves, figures, results table, and browser data. Normal book builds read those artifacts. Tests independently check the derivatives, the composed DDP curvature, the scalar calculation, and agreement between backward elimination and a dense quadratic solve.

Run uv run python scripts/build_thermoacoustic_pulldown_artifacts.py to regenerate the refrigerator results table, figures, diagnostics, and the browser replay data. Run uv run python scripts/build_radiotherapy_fractionation_artifacts.py for the radiotherapy solves, figures, table, and replay data. That example is adapted from the ddp-fractionation repository, which applies box-constrained iLQR to a clinical phantom with a thousand beamlets.

Summary and Outlook

A feasible nonlinear rollout supplies the point around which dynamics and costs are approximated. Backward elimination of a local quadratic problem then supplies both a feedforward change and a state-dependent correction. iLQR repeats that calculation with linearized dynamics; DDP includes the second-order chain-rule terms from the transition. Nonlinear rollouts, regularization, and acceptance tests connect these local calculations to a decreasing sequence of actual trajectory costs. The refrigerator applies the same calculation to a bounded driver amplitude, with energy use and terminal temperature competing in the objective. The radiotherapy course applies it to three bounded beams over twenty sessions, where organ repair between sessions shapes the schedule and the quadratic dose response gives DDP curvature that iLQR ignores.

The quadratic tail produced by elimination is a local model of the cost-to-go along one trajectory. For linear-quadratic problems it is the optimal cost-to-go itself. When the model prescribes a distribution over successors instead of one next state, stochastic dynamic programming replaces the continuation cost by a conditional expectation.

References
  1. Li, W., & Todorov, E. (2004). Iterative Linear Quadratic Regulator Design for Nonlinear Biological Movement Systems. Proceedings of the First International Conference on Informatics in Control, Automation and Robotics, 1, 222–229. https://roboti.us/lab/papers/LiICINCO04.pdf
  2. Tassa, Y., Mansard, N., & Todorov, E. (2014). Control-Limited Differential Dynamic Programming. IEEE International Conference on Robotics and Automation, 1168–1175. 10.1109/ICRA.2014.6907001
  3. Swift, G. W. (1988). Thermoacoustic engines. The Journal of the Acoustical Society of America, 84(4), 1145–1180. 10.1121/1.396617
  4. Swift, G. W. (2017). Thermoacoustics: A Unifying Perspective for Some Engines and Refrigerators (2nd ed.). Springer Cham. 10.1007/978-3-319-66933-5
  5. Fu, A., Ungun, B., Xing, L., & Boyd, S. (2019). A convex optimization approach to radiation treatment planning with dose constraints. Optimization and Engineering, 20(1), 277–300.
  6. Fowler, J. F. (1989). The linear-quadratic formula and progress in fractionated radiotherapy. The British Journal of Radiology, 62(740), 679–694.