Course 13 · Advanced
Closed-loop ascent guidance
From a fixed pitch table to a guidance law that re-solves the rest of the climb every cycle and puts the vehicle into the orbit it was asked for.
When Aster's first stage separates off the coast of Florida, two and a half minutes after lift-off, the gravity turn of course 04 has done its work. The vehicle is 73 km up, above nearly all the air, climbing at 1,162 m/s and moving horizontally at 2,474 m/s, counting the Earth's rotation. The upper stage has five minutes of propellant and one job: to put the payload into a circular orbit 200 km up.
Three numbers have to be right at the instant its engine stops: the distance from the Earth's centre, a vertical speed of zero, and a horizontal speed of 7,784 m/s, the circular speed at that height. They have to be right together, because from that instant the path is a conic fixed by the state at cutoff (course 05). Arrive at 200 km with the right speed but still climbing at 50 m/s, and the orbit is an ellipse whose low point is about 40 km lower; arrive with the right speed at the wrong height and it is an ellipse too.
So the upper stage has to steer, for five minutes, so that three quantities come right at once, at a moment it does not know in advance. There are two ways to do it. It can fly a plan made before launch, or it can make a new plan every second from where it actually is. This lesson is about the second, and about why the first is not enough.
A pitch table, and why it misses
The simplest guidance is a table: pitch against time, worked out before the flight by simulating the vehicle as it is expected to be. In flight the computer looks up the time and steers to the pitch it finds, and the engine is cut when a velocity condition is met. Nothing measured in flight changes the pitch. That is open-loop guidance, and it is how the first long-range rockets flew: the V-2 turned over on a programme against time and cut its engine at a measured speed. It survived long after in the first stage: the Saturn V's first stage flew a pitch programme against time, and the Space Shuttle flew its first stage, with the solid boosters, on a stored profile.
Inside the air there is a good reason for that, and it is the one in course 04: the vehicle has to keep its nose on the velocity to keep the bending load down, so there is little freedom to spend. Above the air the reason disappears, and the weakness of a table shows. A table is a record of one flight. It is right for the vehicle it was computed for, on the day it was computed for, and for no other.
The figure below flies Aster's upper stage in a two-dimensional model — vacuum, a round Earth, the engine cut the moment the orbit's energy is right — from the state it stages at over the Cape. The table is the nominal flight's own pitch history, so with nothing changed it flies a perfect insertion. It opens with the stage 5 % down on thrust.
Figure · open loop and closed loop
- OUTCOME
- Falls back into the air
- ORBIT
- 93 × 307 km
- BURN
- 317.2 s
- PROPELLANT LEFT
- 6,931 kg
Five per cent less thrust, and the stage takes 16 s longer to gain its speed. The table lowers the nose on schedule regardless, before the horizontal speed that should by then be holding the vehicle up has been built. The stage tops out at 195 km and is falling through 185 km when the orbit's energy is finally right. The energy cutoff makes the orbit the right size — energy fixes the semi-major axis — but not the right shape: 93 × 307 km instead of 200 × 200. Five per cent too much thrust gives nearly the same miss, 100 × 300 km, from the opposite cause: the speed arrives early, while the nose is still high, and the stage is climbing through 212 km at cutoff. Three tonnes of extra payload lower the acceleration as a thrust shortfall does: 145 × 256 km. A first stage that hands over a flight path 5° steeper than planned — a pure gravity turn amplifies a small error in its kick into several degrees of flight-path angle by staging — sends the upper stage into a 31 × 369 km orbit whose low point is back in the air.
Switch the figure to the closed loop and every one of those cases arrives in a 200 × 200 km orbit. The closed loop does not know the thrust was low or the payload heavier. It does not need to: it sees that the vehicle is not where the last plan said it would be, and makes a new plan from where it is. How it makes that plan is the rest of this lesson, and it starts with what the best plan would be.
The ascent as an optimal-control problem
State the upper stage's problem precisely. The vehicle's position and velocity evolve under gravity and thrust. The engine runs at full thrust, so the mass is a known function of time and so is the thrust acceleration . The only thing to choose is the direction of the thrust, a unit vector . The aim is to reach the end conditions — the target radius, zero vertical speed, circular horizontal speed — at a final time that is itself free, using as little propellant as possible. At full thrust the propellant burned is proportional to the burn time, so this is the same as reaching the target as soon as possible: minimise .
To see the structure of the answer, flatten the problem first. Take a flat Earth with uniform gravity and no air, horizontal coordinate and vertical , velocities and , and the thrust at an angle above the horizontal:
The end conditions are , and . The downrange distance is left free: an orbit does not care where along the ground it was entered.
Pontryagin's minimum principle turns this into a condition on the steering at each instant. Attach a multiplier, a costate, to each equation of motion and form the Hamiltonian
The optimal steering minimises at every instant, and the costates evolve as . Here that is short work:
Because the final downrange distance is free, its costate must vanish at the end, , and since it never changes, it is zero throughout. So is a constant. The vertical position's costate is constant too, so changes linearly with time. Minimising over points the thrust along , which gives
This is the linear tangent law: the tangent of the optimal steering angle is a straight line in time. Three things about it are worth holding on to.
- The thrust history does not appear. cancelled out. The law holds for any thrust and any mass flow, which is what makes it useful for a rocket whose acceleration grows sixfold as its tanks empty.
- The assumptions do appear. Uniform gravity is what made constant; a gravity that weakens with height, or a centrifugal term that grows as the vehicle speeds up, makes depend on the state and bends the line. Drag would do the same. The law is exact for a flat Earth in vacuum and an approximation everywhere else.
- Two numbers and a time describe the whole burn. The constants and are fixed by the two vertical end conditions, and by the horizontal one. A whole steering programme has become three unknowns.
Seeing it
For Aster's upper stage the angles are small enough that tangent, sine and angle nearly coincide, and that shows something about optimal steering in general. Solve the model's burn exactly for the best straight line in each of the three — the constants found by shooting until the vehicle arrives at 200 km with no vertical speed — and compare:
| Steering law, constants solved exactly | Pitch, start → cutoff | Burn | Propellant left |
|---|---|---|---|
| 16.9° → 1.7° | 301.33 s | 6,928.1 kg | |
| 17.1° → 1.8° | 301.33 s | 6,928.4 kg | |
| 17.1° → 1.8° | 301.33 s | 6,928.3 kg |
The three laws differ by 0.3 kg in a burn of 92 tonnes. The optimum is flat: near the best steering, a different steering costs almost nothing, as long as it meets the end conditions. That is the real lesson of the linear tangent law for guidance. What matters is arriving at the right state; the exact shape of the path there matters much less. A guidance law can afford an approximate shape if it keeps correcting towards the right end.
Explicit guidance
That suggests the scheme. Do not store a trajectory. Store the target, and at every guidance cycle solve, from the vehicle's present state, for the steering constants and the time to go that would take it there. Fly those for one cycle, then solve again. The steering law is simple enough to solve in closed form in a few microseconds, so re-solving it every second costs nothing.
This is explicit guidance, and its best-known forms flew on the upper stages of the Saturn V, as the Iterative Guidance Mode, and on the Space Shuttle, as Powered Explicit Guidance (PEG), which took over from the stored profile once the solid boosters had gone. What follows is a simplified PEG for a burn in one plane: enough to fly Aster's upper stage into orbit in the playground, and to show where each part of the full method comes from.
The thrust integrals
At full thrust with an exhaust velocity , the thrust acceleration grows as the mass falls:
where is the time it would take to burn the whole vehicle, and is measured from now. Four integrals of it over the time to go have closed forms, and they carry everything the steering needs to know about the engine:
is simply the rocket equation: the velocity the engine adds in time . For Aster's upper stage, = 3,050 m/s, the mass flow is 305.6 kg/s and = 362 s at ignition; the whole burn uses 301 of those seconds, and the acceleration climbs from 8.4 m/s² to 50 m/s², just over 5 g.
The steering constants
Steer with the sine of the pitch linear in time, — for the small angles of this burn, the linear tangent law in its most convenient form. The vertical thrust acceleration is then , and integrating it once and twice with the integrals above gives the vertical speed and the radius the vehicle will have at the end:
Here and are the present radius and vertical speed, the target radius, and , the single and double integrals over the time to go of what pulls the vehicle down: gravity less the centrifugal term of moving round a round Earth,
where is the horizontal speed. At staging this is 9.58 − 0.95 = 8.63 m/s². On arrival in a circular orbit it is exactly zero, which is what a circular orbit means. In between it has to be estimated, because it depends on the trajectory being solved for. Taking it as falling in a straight line from its present value to zero is the crudest estimate, and it works: the vehicle still arrives, because the error is corrected every cycle. But it costs 81 kg of propellant on this burn, flying a plan that is repeatedly wrong. Simpson's rule, through the present value, the value half-way (at the horizontal speed the rocket equation predicts there) and zero at the end, brings the burn to within 0.1 kg of the exact optimum in the table above.
Two linear equations, two unknowns: and follow directly, and with them the pitch to fly now, .
The time to go
The integrals need , and is what the rocket equation says the remaining velocity change will take:
The velocity still to be gained, , has a horizontal part — the circular speed less the present horizontal speed — and a vertical part: the upward speed the thrust must supply, . Their resultant is the estimate. But depends on , so the estimate is iterated: guess , compute the integrals and , solve for and , re-estimate , repeat.
At Aster's staging the first pass from any reasonable guess gives = 299.6 s, = 5,348 m/s, and a plan whose pitch falls from 19.7° at ignition to −0.3° at cutoff. The second pass changes by less than 0.01 s. The burn then takes 301.3 s.
Every cycle, from where it is
The plan made at ignition is not the burn that is flown. A second later the guidance solves again from the new state, and again every second after that. Two things happen over the five minutes.
The time to go converges on the truth. The first estimate is 1.7 s short, because the rocket equation's assumes the thrust points the same way throughout; a steering that turns spends 83 m/s more than the straight resultant. As the remaining burn shortens there is less turning left, and the error shrinks with it: 0.9 s short with four minutes to go, 0.1 s with two, and nothing measurable in the last minute. The upper plot of the next figure shows it.
The plan changes as it is flown. The line fitted at ignition ends at −0.3°; the pitch actually flown falls from 19.6° to 3.1°. Each cycle's straight line is a little different from the last, because each carries a better estimate of the gravity integrals than the one before. The shape moves; the end point does not. And because the optimum is flat, the burn still comes out at 301.33 s with 6,928 kg left, as good as the best single straight line.
That is the whole difference from a table. A table fixes the path and hopes the end point follows. Explicit guidance fixes the end point and lets the path follow.
The last seconds
Near cutoff the method turns on itself. Write the integrals for a short time to go, when the acceleration is nearly constant: , , . The determinant of the two equations is then , and an error in the radius or in the vertical speed that the guidance believes changes the commanded sine of the pitch by
Ten seconds from cutoff, where Aster's upper stage accelerates at about 43 m/s², a navigation error of 20 m in the radius moves the pitch by 1.6°. Two seconds from cutoff the same 20 m moves it by 38°. The vehicle's own navigation noise, amplified by , would throw the nose about in the final seconds, wasting propellant on steering that no longer has time to achieve anything.
So every explicit guidance scheme has a terminal phase. When the time to go falls below a threshold, it stops re-solving and flies the last constants it computed, with still counting, and the engine is cut on a velocity condition. Freezing costs almost nothing, for the same reason the optimum is flat: by then the constants have converged, and ten seconds of a slightly stale straight line barely moves the end point.
The cutoff itself needs one more correction. An engine does not stop when told to. In the playground a shutdown is a 0.25 s ramp to zero thrust, which at 5 g adds 6 m/s — 17 to 20 km of apoapsis. A guidance law that cuts when the target speed is reached arrives 6 m/s over it. The fix is to cut early, when the speed still missing equals what the tail-off will add.
Figure · time to go, and the last seconds
- ORBIT
- 199.7 × 200.3 km
- PITCH SWING, LAST 20 s
- 2.3 °
- PROPELLANT LEFT
- 6,928 kg
- SOLVES
- 293
With navigation errors on — far larger than any the playground's sensors make, to make the effect visible — and the freeze at 10 s, the pitch in the last 20 s stays within about 2°, and the orbit is 199.7 × 200.3 km. Set the freeze to never and the last two seconds swing the nose from −30° to +33°; the vehicle still arrives, but the steering spends 169 kg of propellant doing nothing useful. Freezing earlier than needed is nearly free: at 60 s the orbit is 199.9 × 200.1 km. Turn the navigation errors off and, even with no freeze, the pitch barely moves, which is the point: the terminal problem is not in the equations, but in what they do to errors.
What the playground's reference program does
The Full mission example, full-mission.js, flies its upper stage on a
closed-loop law of the same family, written for a single tick rather than a
cycle. Every 20 ms, in the upper phase, it:
- estimates the time to go from the rocket equation, using only the horizontal speed still missing: ;
- asks for a vertical acceleration that arrives at the target altitude with no vertical speed in that time — the zero-effort-miss law of powered descent guidance applied to the vertical channel alone, , where is how far the vehicle would miss the target height if its vertical speed stayed as it is;
- adds gravity less the centrifugal term to get the vertical thrust it needs, and sets the pitch whose sine gives it, , limited to between about −37° and 58°;
- freezes the pitch once is under 5 s, and cuts the engine when the orbit's semi-major axis, plus the rise the engine's 0.25 s tail-off will still add, reaches the target radius — or when the propellant is down to the landing reserve.
The horizontal channel has no law of its own: it takes whatever thrust the vertical one leaves. The time to go ignores the vertical speed, which happens not to matter much at Aster's staging, where the upward speed carried into the burn and the gravity it has to fight nearly cancel. On the classic equatorial range this flies the burn in 302 s and cuts off into a 199.6 × 201.3 km orbit; from Cape Canaveral, in calm air, 199.9 × 202.8 km.
It did not always. Until the third physics audit the same program ended in a
195 × 259 km orbit from the Cape, and the reason is worth knowing. The law
steered fc.altitude, the height above the Earth's ellipsoid, to 200 km, while
the cutoff test read fc.orbit.periapsis, which is measured from the equatorial
radius. At the Cape's latitude the ellipsoid's surface lies about 5 km inside
that radius, so a vehicle held at 200 km of altitude could never show a
periapsis above 195 km, and the burn ran on until a fallback on the semi-major
axis stopped it. No closed loop can correct that. The loop drove the vehicle
faithfully to the target it was given, and the target was stated in two
different sets of terms. The fix was to state it once: the law now steers the
geocentric radius and the inertial radial speed from fc.state, towards the
same radius the cutoff measures — which also saves the stage 86 kg of
propellant.
Before the upper stage, the first stage is a closed loop of another kind. On a real site it steers the gravity turn onto a table of flight-path angle against speed — 62° at 400 m/s, 41° at 1,050, 30° by staging at 2,300 — with the nose leading or lagging the velocity by twice the error, at most 5°. The table is a target, not a steering history, so a gust or a small kick error is corrected on the way instead of carried to staging.
The four destination programs, the Moon and Mars flybys and landings, insert differently: they climb on a vertical-speed schedule (the pitch leads the velocity by 0.055° for every m/s the vertical speed falls short of the remaining height divided by 90 s), throttle down as the apoapsis nears the parking height, coast to apoapsis and circularise with a second burn. That is a feedback law with a target, but not an explicit one: it never solves for the rest of the burn.
The simulator itself has no ascent guidance. What the flight computer offers are the pieces to build one:
fc.state— position and velocity in the inertial frame, about the body being flown about; the radius and the vertical and horizontal speeds come from it.fc.orbit— the osculating orbit, heights measured from the equatorial radius, with the oblateness term in its apsides.fc.gravity— the gravity felt at the vehicle, included.fc.isp,fc.maxThrustandfc.mass— the engine and the vehicle as they are now.fc.burnTime(dv)— the rocket equation's burn time, , which is exactly the time to go above.
The steering and guidance page describes the orbit plane that
fc.steer() measures pitch in once fc.setPlane('orbit') has been called.
A closed-loop program
Here is the simplified PEG of this lesson, written against the flight
computer. Call peg(fc) every tick from the upper-stage phase, with the
guidance plane set to 'orbit' so that pitch is measured above the local
horizontal in the orbit plane. It returns true on the tick it cuts the
engine.
// ── Closed-loop insertion: a simplified Powered Explicit Guidance ──
const TARGET = 200e3; // m — circular, above the equatorial radius (as fc.orbit counts heights)
const CYCLE = 1; // s — re-solve once a second
const FREEZE = 10; // s — in the last 10 s, fly the last solution
const TAIL = 0.125; // s — the 0.25 s tail-off after fc.shutdown() pushes like 0.125 s at full thrust
function peg(fc) {
const m = fc.mem, s = fc.state;
const r = Math.hypot(s.r.x, s.r.y, s.r.z);
const v = Math.hypot(s.v.x, s.v.y, s.v.z);
const vr = (s.r.x * s.v.x + s.r.y * s.v.y + s.r.z * s.v.z) / r;
const vt = Math.sqrt(Math.max(0, v * v - vr * vr));
const mu = fc.gravity * r * r; // the pull felt here, J2 included
const rT = EARTH_RADIUS + TARGET, vT = Math.sqrt(mu / rT);
const ve = fc.isp * G0, a0 = fc.maxThrust / fc.mass, tau = ve / a0;
if (m.solvedAt === undefined || (fc.t - m.solvedAt >= CYCLE && m.tgo - (fc.t - m.solvedAt) > FREEZE)) {
let T = m.tgo || 300, A = 0, B = 0;
for (let i = 0; i < 3; i++) {
T = Math.min(T, 0.99 * tau);
const L = -ve * Math.log(1 - T / tau); // ∫a dt: the Δv the engine gives in T
const J = tau * L - ve * T; // ∫a·t dt
const S = L * T - J; // ∫∫a dt dt
const Q = S * tau - ve * T * T / 2; // ∫∫a·t dt dt
// gravity less the centrifugal term: now, half-way there (predicted), and zero on arrival
const g0 = mu / (r * r) - vt * vt / r;
const rm = (r + rT) / 2, vm = vt + (vT - vt) * -ve * Math.log(1 - T / 2 / tau) / L;
const gm = mu / (rm * rm) - vm * vm / rm;
const G1 = T / 6 * (g0 + 4 * gm), G2 = T * T / 6 * (g0 + 2 * gm);
// arrive at rT with no vertical speed
const k1 = G1 - vr, k2 = rT - r - vr * T + G2;
const det = L * Q - J * S;
A = (k1 * Q - J * k2) / det;
B = (L * k2 - S * k1) / det;
T = tau * (1 - Math.exp(-Math.hypot(k1, vT - vt) / ve)); // rocket equation → time to go
}
m.A = A; m.B = B; m.tgo = T; m.solvedAt = fc.t;
}
fc.steer(deg(Math.asin(clamp(m.A + m.B * (fc.t - m.solvedAt), -0.7, 0.9))), 0);
fc.throttle(1);
// cut when the orbit's energy will be the target's once the tail-off has pushed
if (v >= Math.sqrt(mu * (2 / r - 1 / rT)) - a0 * TAIL) { fc.shutdown(); return true; }
return false;
}
Three choices in it are worth a comment. The radius and speeds come from
fc.state, and the target is a radius measured the way fc.orbit measures,
so the law steers and stops on the same terms. Gravity is taken as a point mass
whose strength matches fc.gravity at the vehicle: the Earth's oblateness makes
gravity at the equator about 0.15 % stronger than , which in a circular
orbit is worth 6 m/s of speed and, left out, 20 km of periapsis on an equatorial
orbit. And the cutoff is an energy test, which makes the semi-major axis right;
the steering has been making the vertical speed and radius right all along, so
the orbit comes out circular.
What it leaves out is also worth knowing. It flies in one plane and never yaws, so it cannot correct an orbit's inclination. It knows nothing of throttle limits or of a second stage. And on an inclined orbit the term varies around the orbit, so "circular" can only be met to a few kilometres: flown from Vandenberg, whose orbit crosses the high latitudes, it ends in a 200 × 211 km orbit.
Try it
Choose the Aster preset, launch from Cape Canaveral with the weather set to Custom — wind, gusts and turbulence at zero — and Hardware dispersions off under Failures & sensors, and fly the Full mission example to the end. The flight report gives the orbit the upper stage coasted in: 199.9 × 202.8 km. It finished its insertion burn with 7,232 kg of propellant.
Now open the program and find const TAIL_OFF = 0.125; near the top. Set it to
0, so that the engine is cut when the target radius is reached rather than just
before, and fly again. The orbit becomes 200.0 × 223.3 km, and the stage has
37 kg less left: the 0.25 s tail-off the cutoff no longer anticipates. Put it
back.
Then try the peg function above in its place. Paste it at the end of the
program; in the case 'upper': block, select everything from the line that
begins const R = fc.state.r down to the last line before break; — the
program's own law, its cutoff and its reserve branch — and replace it all with
if (peg(fc)) { fc.shutdown(); go(fc, 'orbit'); }
else if (fc.propellant < (fc.hasLegs ? RESERVE : DISPOSAL_RESERVE)) { fc.shutdown(); go(fc, 'orbit'); }
Fly again. The report gives 200.0 × 200.9 km, and the stage finishes its burn
with 7,256 kg — 24 kg more than the program's own law left it. The two laws are
cousins, both re-solving the rest of the burn every cycle, one on the vertical
channel alone and the other on both, and the rest of the mission flies as
before, down to a bullseye on LZ-1. Flown on three random weather
days with hardware dispersions on, peg inserts within 1.5 km of 200 × 200;
with 3 t more payload, into 199.5 × 200.6 km.
Now set TAIL = 0 in peg, and the orbit's apoapsis climbs by about 20 km, for
the same reason as before. Then put TAIL back, set the sensors to Hard
under Failures & sensors, and try FREEZE = 0. Nothing much happens —
200 × 201 km either way — and the reason is instructive. The playground's
navigation errors are not the independent jitter of the figure above: they
wander slowly, over 30 to 60 s, so two solves a second apart see nearly the
same error and there is nothing for the to amplify. A terminal phase is
insurance against errors that change quickly from one solve to the next.
What carries forward
The insertion burn ends in a parking orbit: a circle 200 km up, from which the upper stage can go anywhere else it has the propellant for. For a mission to another planet the next question is when to leave it, and in which direction, so that the vehicle and the planet arrive at the same point at the same time. That is Lambert's problem, and the launch windows it opens and closes.