Terminus: rings over twilight
Proposal section 4: the fleet
Ride along with one of our satellites for an orbit. It crests the north pole and falls down the night side, two hours of frozen blackness scrolling below, no lights, no one to serve. Then a thin red line rises over the horizon — the twilight band, glowing with the scattered lamps of every town on the planet — and for a quarter of an hour the satellite is working, relaying a thousand conversations, before the band slides behind it and the day side's empty glare takes over. Around the bottom of the world and back up into darkness. A satellite here spends most of its life commuting and a sliver of it on shift.
This section designs the constellation: how many such commuters we need, and on which roads. The survey gave us the shelf menu; the trap taught us the rings must stay fixed among the stars while the band sweeps past them. Now we lay actual rings in the actual sky — and then, because the RFP demands evidence rather than confidence, we simulate every town on the planet for a full rotation and see whether our first design holds.
It will not. That is what simulations are for.
Before we lay the first ring, here is the fleet we are about to build. Press Play on the model below and watch the six rings wheel slowly past the twilight band, each taking its turn as the ring that serves it. Much of it will not make sense yet — why the rings run over the poles, why so many satellites sit dark, why the fleet flies at 2,200 km and not lower. By the end of this section, every piece of it will have earned its place.
The baseline access fleet: six polar rings 30° apart, 72 satellites at 2,200 km. The amber ring is the one on duty, lying closest to the twilight band. Bright satellites are carrying traffic; the dark ones are coasting between shifts.
Why the rings run pole to pole
The twilight band is the line where day meets night, and that line has a useful property: it passes through both poles. Day and night each claim half the planet, and the frontier between them runs top to bottom, like the seam on a two-colored ball. So a satellite ring that also runs pole to pole — a polar orbit — can lie right along the band. Tilted rings would cross the band at an angle, wasting their arc on day and night country; polar rings can spend their whole circle near the line.
But the lesson of the trap never sleeps: the rings are pinned to the stars, and the line turns with the planet — 32 degrees per day. One perfectly placed polar ring drifts out of alignment within hours. So we do not build one ring. We build a wheel of them: six polar rings, their planes fanned evenly like spokes, 30 degrees apart. At any moment one of them lies closest to the band and carries most of its traffic; call that one the duty ring. As the planet turns, the line rotates from one spoke to the next, and the next ring inherits the duty:
- every 22.4 hours (30° at 32.14°/day), the duty ring changes — a planet-scale shift schedule, slow and predictable;
- every 11 minutes or so, one satellite hands a town's conversations to the satellite behind it — the fast rhythm, set by how closely the ring files its satellites rather than by how long any one of them could serve.
Hold onto the word duty. It is a real and useful idea — one ring does lie closest to the band, and it does carry the most traffic — but we will find, when the simulation is done with us, that it never works alone.
The wheel below is that schedule, running, seen from straight above the north pole. The three-dimensional model near the top of this page holds the same view: scroll back up, press Pole view · North, and the two pictures line up. Nothing in it maneuvers: the six planes are pinned to the stars exactly as the trap insisted they must be, and the planet's own rotation does the scheduling. But watch the misalignment readout through a shift. It is zero only for an instant, in the middle of the shift, when the band lies straight along the duty ring; it climbs from there, and at the moment of handover it stands at its worst — 15 degrees off the ring going off duty and 15 degrees off the one coming on. The shift change and the sourest geometry of the shift are the same event. Remember that; it is where this design breaks.
Six ring planes, fixed among the stars and fanned 30° apart; the band turns past them at 32.14° a day.
Two rhythms, hours and minutes, and every piece of protocol we design later must dance to both. With 12 satellites spaced around each ring, the fleet is 6 × 12 = 72 spacecraft. That was our seed design, at 1,800 km — the survey's middle ground. It looks right. Most wrong designs do.
Two numbers place a satellite
We have been describing the wheel in words — six rings, fanned like spokes, 30 degrees apart. The simulation needs to know where every one of the seventy-two spacecraft is, at every instant, and it gets that from two numbers per satellite. A third, the inclination — the tilt of the orbit's plane measured from the equator — is already settled: 90 degrees, a plane standing square to the equator and so passing straight over the poles, for the reason the last section gave. What remains is which plane a satellite flies in, and where in that plane it sits.
The first number names the plane. An orbit is a circle in space, and a circle through both poles cuts the equator at exactly two opposite points — one where the satellite is heading north, one where it is heading south. The northbound crossing is the ascending node, and the angle at which it happens is the plane's right ascension of the ascending node: RAAN, the name it carries in every orbital catalog.
Both halves of that phrase are key, so it is worth taking apart. Ascending node is the northbound crossing we have just found, as opposed to the descending one half a circle away — naming the plane by one of its two equator crossings, and picking the northbound one by convention. Right ascension is the astronomer's longitude: an angle measured around the equator like any other, but reckoned against the fixed stars rather than against the ground, from a zero direction the sky agrees on, and no planet can drag with it. Earth's catalogs use the First Point of Aries; ours will use a reference star far beyond this system, and any star will do, so long as it is far enough that no turning of the ground can shift its direction. The right in the name is the old word for straight, from the view of an observer on the equator, where stars rise straight up rather than at a slant; it says nothing about which side the angle is taken on. That distinction is the whole difference between a RAAN and a longitude you could paint on a map. A town's longitude turns with the planet. A plane's right ascension does not, because nothing fastens the plane to the planet: it is a circle in space, and space does not turn.
Give a polar orbit its right ascension, and you have named the plane completely; every satellite in it rides the same circle.
A polar ring · i = 90°
Its own opposite. Turn the node 180° along the equator and the
plane you get is the one you started with, run the other way: the same circle, with its
ascending node where the descending one was. Six polar rings therefore divide 180°,
not 360° — the PI in k * PI / planes.
i, is the tilt of the orbital
plane measured up from the equatorial plane at the ascending node, the crossing where the
satellite is heading north; the descending node, where it comes back down, is on the far
side of the globe. For the wheel i is 90°, and the ring stands square to
the equator. RAAN, the right ascension of the ascending node, Ω, is how far
along the equator that crossing sits, reckoned from a zero direction fixed among the stars
rather than from any meridian on the ground, which is why it never turns with the planet.
The reference star stands for that zero: a star so far beyond this system that no turning
of the planet can shift its direction, the same convention Earth's catalogs follow with the
First Point of Aries. Drawn for the wheel's third ring, Ω = 60°, at the
access shelf's 2,200 km.
So a wheel of six rings needs six values of RAAN, and here the obvious guess is wrong in a way worth slowing down for. Six things spread evenly around a circle sit 60 degrees apart. Our rings sit 30 degrees apart, and their RAANs are 0°, 30°, 60°, 90°, 120°, and 150° — they stop halfway around and never finish the circle. Look at the wheel above, and you can see why: each ring is drawn as a diameter, not a spoke, because a polar orbit passes over both poles and so reaches clean across the planet. The three-dimensional model near the top of this page shows the same thing from Pole view · North: the rings you have been watching as loops flatten into six straight lines through the middle of the world. The plane you would place at 180° is the plane already sitting at 0°. It is the same circle in the same piece of sky, traversed in the opposite direction: in the figure above, its ascending node would sit where the descending one is now. A polar plane is its own opposite, so N polar rings divide 180 degrees rather than 360:
let raan = k as f64 * std::f64::consts::PI / c.planes as f64; // PI, not 2 * PI
That single PI is the reason the shift schedule has twelve shifts and not
six. The band sweeps a full circle in a local year and meets a plane every
30 degrees of that sweep — but there are only six planes, so each one
takes duty twice, once as its ascending half swings into the band and once,
half a year later, as its descending half does. The roster on the plate's rim
carries every ring number twice for exactly this reason.
The second number places the satellite along the ring. Twelve satellites, evenly filed, 30 degrees of arc apart:
let theta0 = j as f64 * 2.0 * std::f64::consts::PI / c.sats_per_plane as f64 // here, the full circle
+ k as f64 * c.interplane_phase; // zero in the seed design
The full circle this time, because a satellite genuinely can be anywhere on the ring and a position and its opposite are two different places. Those 30-degree slots are what set the fast rhythm: the handover cadence we are about to quote is the time it takes the ring to advance by one slot.
The second line is the one to notice. It offsets each ring's slot pattern from its neighbor's by a fixed angle, and the seed design sets that angle to zero, so every ring files its satellites at the same phase. The simulator carries the term anyway, because nothing in this design gets to assume a value for it. A satellite reaches its ring when the launch site swings beneath that plane, and where it lands along the ring depends on the minute the launch left the ground; a campaign that slips a window by a day arrives at a different phase, and nothing later corrects it for free. So the relationship between adjacent rings is not a number the design chooses. It is a number the fleet ends up with, and a coverage claim has to hold for whatever that turns out to be. The simulation tests exactly that before this section is over, dealing every ring an arbitrary phase and asking whether the band still holds.
The arrows on the plate are worth one more look, because they carry a fact we will need twice more before this section is done. Walk around the rim, and you pass six rings running inward — climbing north over the pole — and then six running outward, back down the far side. Between those two runs are two places where a ring's nearest neighbor, 30 degrees away, is flying the other way entirely. These are the wheel's seams. They are unavoidable: the nodes span half a circle, the traffic spans a whole one, and something has to give at the join. When we try to interleave the rings like a honeycomb later on, the seams are what defeat it.
One last consequence, and it closes the loop with
the trap. The planes hold their right
ascensions forever, because that is what being measured against the stars
means; the planet turns underneath at 32.14° a day. In the planet's own frame,
then, every node walks steadily backward — node = raan - spin * t, one
line in
polar_sat_position
— and that backward walk is the shift schedule.
The wheel does not hand over because anything aboard it decides to. It hands
over because the ground keeps moving and the nodes do not.
When the backbone puts a navigation shell above this one, it will spread its nodes over a full 360 degrees instead. Nothing has changed about the arithmetic; those planes are tilted 55 degrees rather than 90, and a tilted plane is not its own opposite — flip it halfway around the planet, and it leans the other way. Only the polar case gets to halve its circle.
Both claims are easier to test than to read. The model below is the construction from the figure above with its two numbers unfixed. Drag RAAN and the ascending node walks along the equator; drag inclination and the plane leans over the node line. Then, with the ring polar, press Turn the node 180°: the ring sweeps half a circle and lands exactly on the dashed ghost of where it started, with its arrows reversed. Set the inclination to the backbone's 55° and press it again. The ring lands somewhere else. Two camera presets make one number each plain: North pole looks straight down the spin axis, where RAAN is an angle on a dial, and Equator looks along the node line, where the inclination is the lean of the ring against the equator.
Ω = 60°, i = 90°: the wheel's third ring, as the figure above draws it. Drag the sliders, then turn the node.
The ground stands still
Before the simulation runs, one thing about where it runs. A satellite tracker on Earth keeps two coordinate frames, because two things are simple in two different places. An orbit is simple among the stars: its plane holds still and its motion is Kepler's, so trackers propagate orbits in an Earth-centered inertial frame, ECI, whose axes point at fixed directions in the sky. The ground is simple on the ground: a city, a dish, a GPS fix all have coordinates that never change in an Earth-centered, Earth-fixed frame, ECEF, whose axes turn with the planet. The two frames rotate against each other once a sidereal day, and every pass prediction converts between them: a rotation about the pole by the Earth's rotation angle, with small corrections for precession, nutation, and polar motion when the job is precise. A dish that sits still in ECEF is moving at 465 meters a second in ECI. Neither frame is wrong. The conversion is the price of using each where it is simple.
The terminus simulator keeps only the ground frame. Its axes are the
planet's own: z the pole, the red dwarf along -x forever, the terminator
the great circle in the x = 0 plane, the band straddling it. In that frame,
every ground point is a constant unit vector, the ground_unit the counting
loop is handed, and the 216 sample points of the band are built once, from
an azimuth around the terminator and an offset toward the night side, and
never move again. The orbital planes are what move. They are fixed among the
stars, so in the planet's frame they regress at the spin rate, and the
conversion Earth applies to the ground is applied here to the planes
instead, in one line, the node walking back. Satellite positions come out in
the ground frame directly, and counting who can see whom is a dot product
against constant vectors.
The figure below draws the same day twice, once in each frame, with the planet's center at the origin of both. The left panel is fixed to the stars, Earth's ECI: one polar ring holds still, and the ghost of the red dwarf shows where the ground and everything on it will have turned to a day later. The right panel is fixed to the ground, Earth's ECEF and the simulator's own: the band and its 216 sample points hold still, and the ghost ring shows where the node will have walked back to. Nothing in the sky differs between the two; only the axes do.
The same day in two planet-centered frames. Both keep the planet's center at the origin; they differ only in what the axes are fixed to. On the left the axes are fixed to the stars, Earth's ECI, and the ring holds while the ground turns. On the right they are fixed to the ground, Earth's ECEF and the simulator's own frame, and the band holds while the ring's node walks back. The ghosts show where things will be one day later.
Planet-centered, fixed to the stars · Earth's ECI
The ring holds. Nothing fastens an orbital plane to the planet, so among the stars it never moves. Everything on the ground does: the twilight band, the 216 points the sweep samples along it, and the red dwarf they all face, turning together 32.14° a day.
Planet-centered, fixed to the ground · Earth's ECEF
The ground holds. The same day, from the band's own point of view:
the ground points are constants, the red dwarf never moves, and the ring is what drifts, its
node walking back 32.14° along the equator — node = raan - spin * t,
the one conversion the simulator makes.
ground_unit is a constant vector,
and the planes are moved into its frame by regressing their nodes.
Now the same two frames as an animation, so the still figures above can be watched turning. Both keep the planet's center at the origin and differ only in what the axes are fixed to. Press Play with fixed to the stars selected: the six rings are fixed in space, and the planet moves, its band and its red dwarf sliding round together beneath the rings. Switch to fixed to the ground, and you have the planet's own perspective: the red dwarf and the ground stand still, and the constellation and the stars are what move, the rings drifting the other way while the star field sweeps past behind them. Then press North in the pole view. Fixed to the stars, the six rings flatten into six fixed diameters, and the green band sweeps round like the hand of a clock; fixed to the ground, the band stands still and the six diameters wheel past it, which is the duty plate from earlier in this section, now in three dimensions. The green points on the band are the sweep's 216 sample points. Nothing in the sky differs between the two views; only the axes do.
The same day, both ways, from the planet's center. Fixed to the stars, the rings hold and the ground turns; fixed to the ground, the band holds and the rings drift. The green dots are the 216 ground points the sweep samples. One turn of the planet takes 11.2 days.
One thing in that view looks like a mistake and is not: fixed to the stars, the star field holds still and Proxima Centauri does not. The distant stars are, for every purpose here, infinitely far away, so the planet's motion along its orbit does not change their directions. Proxima Centauri is close, and the planet circles it once every 11.2 days, so from a frame pinned to the planet's center the star's direction sweeps a full circle in that time. The tidal lock makes that sweep match the spin exactly, which is why the globe, its band, and the red dwarf turn as one rigid thing in the first view and stand still together in the second.
That is also why one frame is enough. The conversion is the same arithmetic
on both worlds, a rotation about the pole by the spin rate times the time;
what differs is what the ground frame fixes. Earth's ECEF pins the ground
and nothing else: the Sun sweeps round it once a day, and even in ECI its
direction drifts a degree a day, which is what a sun-synchronous orbit is
built to follow. On a tidally locked planet the frame that pins the ground
also pins the red dwarf, the day side, the terminator, and the band. The
whole problem stands still, and only the wheel moves through it. The zero
direction the last section reckoned RAAN from is, in the code, simply the
planet's own +x axis as it stood at time zero, the direction straight away
from the red dwarf at that instant, fixed among the stars from then on.
The interrogation
We put the whole planet under simulation: sample the inhabited band — its
center line and both edges, all the way around — and every 30 seconds for a
full 11.2-day rotation, count how many satellites each sample point can
actually use, meaning satellites at least 25 degrees above that
point's horizon. The counting core,
visible_count
in the simulator's constellation module, is plain brute force:
/// Number of the constellation's satellites at or above `min_elevation`
/// (rad) as seen from `ground_unit` at time `t`.
pub fn visible_count(
body: &CentralBody,
c: &PolarConstellation,
ground_unit: [f64; 3],
min_elevation: f64,
t: f64,
) -> usize {
let mut count = 0;
for k in 0..c.planes {
let raan = k as f64 * std::f64::consts::PI / c.planes as f64;
for j in 0..c.sats_per_plane {
let theta0 = j as f64 * 2.0 * std::f64::consts::PI / c.sats_per_plane as f64
+ k as f64 * c.interplane_phase;
let sat = polar_sat_position(body, c.altitude, raan, theta0, t);
if elevation(body, ground_unit, sat) >= min_elevation {
count += 1;
}
}
}
count
}
Two things about that signature. ground_unit is not a place on a map but
a direction: a unit vector from the planet's center, in the frame of the
last section, that the sampler builds from an azimuth around the terminator
and an offset toward the night side. It is the analogue of an ECEF direction
on Earth, minus the ellipsoid. The planet is a sphere here, the radius is
applied inside
elevation,
and every terminal is taken to sit on the
surface, a simplification that costs nothing at 2,200 km but would need
revisiting for a terminal on a mountain. And the function answers for one
point at one instant. The sweep,
band_coverage
in the same file, calls it for every one of the 216 sample points at every
30-second step of the 11.2-day rotation, about seven million calls, each
walking all seventy-two satellites, which is where the hundreds of millions
of geometry evaluations the closing section warns about come from. The
access_constellation
example that prints the tables below is what drives that sweep.
One caution about what the count means. It is what a town can see: every satellite above the mask is counted, whether or not it is radiating. What a town needs is a different and much smaller number, and a later section will use this same machinery to find it.
The number that matters is the minimum — the worst moment of the worst town's whole year. An average means nothing to a village whose connection died at shift change. And for the 72-satellite seed at 1,800 km, the minimum is zero.
Somewhere in the band, sometime in the rotation, a town looks up and finds no usable satellite at all.
Anatomy of a silence
The gap lives at the seams of the wheel. When the twilight band lies midway between two rings, a town at the band's center sits about 15 degrees off either ring's track. From that far aside, a passing satellite stands high enough to use for only a short stretch of its arc — about ±13 degrees of along-track travel. But the satellites in a ring are spaced 30 degrees apart. 13-degree windows, 30-degree spacing: between one satellite's setting and the next one's rising there is a sliver of silence, sweeping the mid-seam country like a slow blade, several times an orbit, every 22.4 hours when the geometry sours.
Both flanking rings are in the same predicament at the same moment, and — in this first design — in the same rhythm: every ring files its satellites at identical phase, so their windows open and shut in unison and their gaps line up perfectly. The silence is not one ring's failure. It is all of them blinking together. Nor is it only the mid-seam towns that suffer: the band reaches 20 degrees to either side of the terminator, and its two edges lie farther from every ring than its center does, so the outer margins of the inhabited zone go dark slightly more often than the middle.
Our first coverage sweep was under-sampled in time, and the error it produced is worth recording. At a two-minute step, staggering the rings' phasing appeared to close the gap, and we nearly filed that as the fix. At a 30-second step the gap reappeared through every stagger we tried: the silences were narrower than two minutes and had slipped between the samples. Coverage claims in this proposal are therefore made only at fine sampling, as a standing rule.
Buying coverage with altitude instead of hardware
Two honest fixes exist. The brute-force one: more satellites, tightening
the spacing until the windows overlap — at 1,800 km that takes 84. The
elegant one: raise the whole fleet, which widens every satellite's
footprint, stretching the along-track window until 12 per ring suffice
again. The simulation prices both. The example takes several minutes to
run, because it sweeps the whole rotation at 30-second steps for every row
of the table, and it needs --release:
cargo run --release -p terminus-orbits --example access_constellation
alt (km) rings sats/ring total min visible mean visible
1800 6 12 72 0 2.68
1800 6 14 84 1 3.13
1800 7 12 84 1 3.13
2000 6 12 72 1 3.07
2200 6 12 72 1 3.45
2400 6 12 72 1 3.81
Climbing 200 km closes the gap with the same 72 spacecraft — but at 2,000 km the along-track window beats the spacing by under three percent, a margin we decline to bet a civilization on. At 2,200 km the margin is real, the average town sees about three and a half satellites, and the edge-of-footprint latency has crept only from about ten to about twelve milliseconds — still comfortably inside the RFP's budget. The evaluation rule in TER-REQ-016 makes the choice for us: altitude is free forever; twelve extra spacecraft are not.
The baseline access fleet, recorded as ADR-0003: six polar rings, twelve satellites each, at 2,200 km. The old 1,800 km label is retired from the reference architecture.
With the altitude settled, the fast rhythm gets its exact value — and it is worth a sentence of its own, because the obvious guess is wrong. A satellite up here could serve a town for 16.6 minutes: that is the pass the survey measured, the whole arc of a satellite that happens to cross straight overhead. But a town is never given a whole pass. The next satellite in the ring rises behind it, climbs higher in the sky, and the link moves. One orbit, 131.6 minutes, divided by twelve satellites, is 11 minutes — and that, not the pass, is the nominal interval every later protocol has to survive. Handover cadence is the ring's spacing, not the satellite's pass duration. Treat 11 minutes as a ceiling rather than a promise: as the next section shows, the satellite that rises next is not always in the same ring, and a link that moves between rings moves sooner. It is also a lever: a satellite added to a ring buys coverage and costs handovers in exact proportion; a ring added to the wheel buys coverage and costs none.
One debt is flagged in the ADR rather than hidden: a minimum of one visible satellite is coverage without redundancy. Lose that satellite — or ask, as we soon will, for a second one to be visible before the first lets go of a conversation — and the count must rise. The simulation has already priced it: eighteen satellites per ring instead of twelve, 108 instead of seventy-two, buys a minimum of two. We will pay that bill when we design the handover machinery, and pay it knowingly.
Who is actually on duty
We have been saying "the duty ring" as though the wheel takes turns, one ring working while five coast. The simulation has been quietly telling us otherwise the whole time, because it never counted rings — it counted satellites, wherever they were. So ask it directly: when a town looks up, how many rings can it actually see?
The answer depends on where the town stands, and the reason is a piece of geometry we have been using all along without following it through. Polar rings are 30 degrees apart at the equator, but every one of them passes over both poles. They are not parallel; they are a fan, splayed at the waist and pinched at the ends. One example answers this question and the two that follow it. Its output comes in three parts, A, B, and C, each quoted on this page where its result is used, and it takes several minutes to run, nearly all of them in part C:
cargo run --release -p terminus-orbits --example duty_ring_trade
- Part A asks whether one ring could serve the band alone. It is quoted below, where we price the fleet that would have to fly at 7,300 km.
- Part B counts the rings a town can reach and the rings actually serving it, by latitude. Condensed, it is the table that follows.
- Part C deals every ring an arbitrary phase, 64 times per design, and asks whether coverage survives. It closes this section.
The example is
duty_ring_trade.rs;
the reach and ring-count functions it calls live in
duty.rs.
Part B, condensed to the columns the argument needs:
| Town's latitude | Rings within reach | Duty ring's share of its sky |
|---|---|---|
| 0–15° | 1–2 | 49% |
| 15–30° | 1–2 | 44% |
| 30–50° | 1–3 | 37% |
| 50–70° | 2–6 | 19% |
| 70–90° | all 6 | 17% |
The model below opens at the moment of a shift change, 0.47 days in. Two rings sit 15 degrees off the band, one falling away from it and one arriving, and the amber duty label has just passed to the arriving one, still 15 degrees short and closing. Every ring's footprints are drawn, and the band is covered end to end all the same, largely by satellites the new duty ring does not own. Press Play and watch the amber ring settle onto the band over the next half day; press North in the pole view and the fan is plain to see, six diameters pinched together at the poles and splayed at the equator, which is why a town near the pole has every ring overhead and a town near the equator has two.
The moment of a shift change, 0.47 days in: the duty has just passed to the amber ring, still 15° short of the band, while the ring it replaces is 15° past it — yet the band is covered all the same, by its neighbors. Note how few satellites are lit.
Near the equator — where most of the band's area lies, and most of its towns — the wheel is a two-ring affair. The duty ring is genuinely the workhorse there, supplying about half of everything the town can see, with a single neighbor covering the rest and, crucially, covering the moments when the duty ring's own satellites are between slots. Walk toward a pole, and the rings crowd together until all six are overhead at once, and "duty" stops meaning anything: the on-duty ring's share falls to 17 percent, which is exactly the one-sixth a town would get if the label were assigned at random.
So the duty ring survives as an idea, and the shift schedule is real. What does not survive is the notion that it works alone. A town at the band's edge, at the sourest moment of the shift, can be 35 degrees of arc from the duty ring's track — and a satellite at 2,200 km can reach only about 23 degrees. That town is not underserved by the duty ring; it is outside it altogether. No number of satellites added to that ring would reach it, because the failure is one of reach, not of spacing. We priced the alternative honestly: a fleet where the duty ring really did serve alone would have to fly at 7,300 km, nearly tripling edge latency from 12 to 32 milliseconds, or drop its elevation mask to 5 degrees and surrender the rain margin this cloudy, wind-driven band cannot spare. That is part A of the example's output, first as geometry and then as a simulation to confirm it:
A. Could one ring serve the band alone?
alt (km) mask lambda (deg) reach needed sats/ring needed
2200 25d 22.65d 35.00d impossible at any count
3000 25d 26.96d 35.00d impossible at any count
4000 25d 31.17d 35.00d impossible at any count
5200 25d 35.07d 35.00d 79
6000 25d 37.18d 35.00d 14
7300 25d 40.02d 35.00d 9
2200 10d 32.94d 35.00d impossible at any count
2200 5d 37.23d 35.00d 14
Simulated, to confirm the analysis:
alt (km) mask sats/ring total min (duty only) edge 1-way
2200 25d 12 72 0 12.1 ms
2200 25d 24 144 0 12.1 ms
2200 25d 48 288 0 12.1 ms
2200 5d 14 84 1 17.4 ms
6000 25d 14 84 1 27.5 ms
7300 25d 9 54 1 32.4 ms
Read the first three simulated rows together. Doubling the duty ring to 24 satellites, and doubling it again to 48, leaves the minimum at zero, which is the reach wall in numbers: a ring that cannot see the town does not start seeing it by getting crowded.
There is a gift hidden in this, and it is worth more than the tidiness we gave up. We re-ran the whole rotation 64 times per design, each time dealing every ring a different, arbitrary starting phase — the sort of scramble a real launch campaign produces when windows slip. The minimum never moved. Not once in 256 attempts did a scrambled wheel cover the band worse than a perfectly synchronized one. That is part C of the example's output, and a warning before you run it: those 256 attempts are each a full rotation at 30-second steps, so this part is where nearly all of the example's minutes go, even spread across every core the machine has.
C. Does coverage depend on inter-ring phasing?
alt (km) rings sats/ring total phase-locked min worst random min failures
2200 6 12 72 1 1 0/64
2200 6 18 108 2 2 0/64
2400 6 12 72 1 1 0/64
2200 8 12 96 1 1 0/64
The second row is also the receipt for a bill mentioned earlier: eighteen satellites per ring, 108 in all, holds a minimum of two under every scramble as well.
We should say precisely what that does and does not prove, because we
tested one more idea and it failed. A cellular network covers a city by
offsetting each ring of towers half a step from the last, so their cells
interlock like a honeycomb — the densest way known to tile a flat plane
with circles. Try the same trick here, giving each ring half a satellite's
head start on its neighbor, and the wheel gets worse: at our twelve
satellites per ring, it opens a gap that the plainly aligned wheel does not
have —
--example phasing_options
walks the whole profile, and the result is
not even monotone in satellite count, because "half a slot" means
360°/satellites and so changes meaning every time you add one. The honeycomb
does not survive the trip from a plane to a sphere.
Every ring runs over both poles, so the cells that were tidy hexagons at
the equator pinch shut at the caps; and because a ring is a closed circle,
it serves the band at two opposite longitudes at once, climbing north on
one side while falling south on the other, so there is no single offset to
tune. Where the wheel closes on itself, neighboring rings run in opposite
directions outright.
So the freedom we have is narrower than it first looked, and worth stating honestly: the fleet is free to ignore inter-ring phase, not free to choose it badly. Uncoordinated is safe. Clever is not.
That matters enormously for how this fleet gets built. A launch reaches a given ring only when the launch site swings beneath its plane, and on a world that turns once every 11.2 days, those windows are precious — one per ring per rotation, each ring's window 22.4 hours after its neighbor's. Had coverage depended on the rings staying in step, every launch would have had to hit not just its window but a particular minute inside it, and then the fleet would have had to hold that arrangement forever: a satellite injected just 100 meters off its intended altitude drifts a full slot within about fourteen months. It costs almost nothing to correct — a nudge of about forty millimeters per second — but it is a nudge that never stops being due, on all seventy-two spacecraft, for as long as the constellation flies.
We owe none of it. The rings may be launched in any order, in any year, at any phase, and a slipped window costs exactly one late satellite and not one second of anyone's coverage.
Most of the fleet is asleep
Look again at that latitude table, and something should nag. A town near the pole has all six rings overhead, half a dozen satellites for one town with one sky's worth of demand, and the fleet keeps every one of its seventy-two transmitters radiating to achieve that. Why run the whole fleet to serve a band that never needs more than a handful of satellites over any one place?
We would not. Visible and needed are different questions, and we have been answering the wrong one. So ask the right one: at each instant, what is the smallest set of satellites that still serves every point of the band? That is a classic problem — minimum set cover — and our instances are small enough that we do not have to guess at the answer. We can prove it.
One definition first, because the rest of the series depends on it. A satellite is lit when its access radio is on and serving the band, and dark, or asleep in this section's language, when that radio is off. Dark is not powered down. The spacecraft's bus, its attitude control, and its laser terminals stay up, and a dark satellite goes on relaying traffic along its ring; a later section leans on exactly that when it routes conversations to the anchors through satellites whose radios are off. Everything switched, counted, and saved below is the radio.
cargo run --release -p terminus-orbits --example activation_plan| Policy | Mean lit | Peak | Duty cycle | Switches/hour | Coverage |
|---|---|---|---|---|---|
| everything on | 72 | 72 | 100% | 0 | complete |
| duty ring only | 12 | 12 | 17% | 0 | fails always |
| duty ring, patch holes, then prune | 23.1 | 30 | 32% | 253 | complete |
| greedy set cover | 22.4 | 30 | 31% | 373 | complete |
| proved minimum | 21.4 | 28 | 30% | 423 | complete |
Read the second row as an epitaph. Lighting only the duty ring — the design we spent this section dismantling — leaves the band uncovered at every single instant we sampled. It never works, not once in eleven days.
Read the last row as the prize. Twenty-one satellites, on average, can hold the entire twilight band. Roughly seventy percent of the fleet can be dark at any given moment. That is not an estimate; a branch-and-bound search — the kind that discards whole families of plans at once until only the provably best remains — closed on the true optimum at all 16,128 instants we tested (the same 11.2-day rotation, planned at a one-minute step rather than the interrogation's 30 seconds), so the number is a floor and not a hopeful heuristic.
But we are not going to fly the optimum, and the reason is instructive. The optimal plan is free to reshuffle its entire active set every minute, and it uses that freedom: it switches satellites on and off 423 times an hour, against 253 for the duty-first policy in the third row, and every switch is a thermal cycle and a power-electronics cycle on a radio we would like to last decades. What it buys for all that churn is under two satellites.
So we take the policy in the third row, which an operator can still state in one sentence: light the duty ring, add satellites from the neighboring rings wherever a hole remains, then switch off anything that turns out to be serving no one. The duty ring keeps its meaning — it is genuinely the block that goes on first — and the wheel fills in behind it.
Here is the whole algorithm — first as a shape, then as something you could implement from. There is nothing clever in either, and that is the point: every step is one a ground controller could check by hand.
The flowchart shows the shape; the loop at its heart deserves stating exactly, because everything turns on how the next satellite is chosen:
# lit = access radio on, dark = access radio off. Laser links stay up on
# every satellite regardless; the planner never touches them.
plan(t):
duty ← ring whose plane lies closest to the terminator at t
lit ← every satellite in duty # radios on as a block, before measuring
for each of the 216 band points p:
reach[p] ← satellites ≥ 25° above p at t
while some p has no satellite in lit:
best ← argmax over dark satellites s of
|{ p : reach[p] ∩ lit = ∅ and s ∈ reach[p] }|
ties broken toward s already lit at t−1
lit ← lit ∪ {best} # radio on
for s in lit, dark-last-instant first, then least useful first:
if every p reached by s has another satellite in lit:
lit ← lit \ {s} # radio off: prune
return lit
smooth(plans): # across time, not within
for each satellite s:
close every off-gap shorter than 180 s # lazy off: keep the radio on
extend every on-run backward by the warm-up # warm start: radio on early
The Rust this is drawn from is
crates/orbits/src/activation.rs
— duty_first_activation is the planner, smooth_schedule the pass over
time, and exact_activation the branch-and-bound that produced the proved
minimum we decided not to fly.
Five things in there are doing real work.
The duty ring goes on as a block, before anything is measured. That is not an optimization — it is what keeps the plan explainable. The ring nearest the band will carry most of the traffic anyway, so starting from it costs little and means the answer always has a shape a human recognizes. The prune pass may hand one or two of them back at the end, but the block is where every plan starts.
The score counts holes, not coverage. Read the argmax again: a dark
satellite is judged purely on how many currently unserved points it would
rescue — not on how much sky it can see, and not on how much it would
reinforce places already covered. A satellite hanging over a stretch of band
that three others already serve scores zero and stays dark, however good its
view.
The last pass undoes the greedy loop's own mistakes. Each pick is the best one available at the moment it is made, and that is exactly the weakness: a satellite lit to close hole A often also covers hole C, which a later pick made for hole B then covers again. The early pick is now carrying nothing the plan needs, and nothing in a forward-only loop will ever notice. So the planner finishes by walking everything it has lit and switching off any satellite whose every point would remain covered without it. It is worth 1.1 satellites — and the surplus it removes is not spread evenly. It piles up over the poles, where all six planes converge, and one patch of ground ends up served several times over by satellites each chosen for a different hole. That is precisely where this section began, and precisely the over-serving it set out to disprove.
Ties go to whoever was already awake. When two satellites would close the same number of holes, the one lit a moment ago wins. It costs nothing, and it stops the plan from reshuffling itself for no reason — the churn that made the theoretically optimal policy so expensive two paragraphs ago.
The smoothing happens across time, not within an instant. plan(t) sees
one moment and nothing else, which is exactly what makes a satellite flicker:
needed, not needed, needed again, in the space of a couple of minutes. Planned
that way, a satellite blinks on and off 787 times a day for no gain at all.
The lazy-off rule kills every one of those for about one and a half extra
satellites lit, and it can be exact rather than a guess, because the geometry
is known years ahead — "will this be needed again shortly?" has a real answer.
That last point is what makes the whole scheme practical. This is a timetable, not a negotiation. Nothing in the diagram runs on a spacecraft; it runs on the ground, weeks early, and each satellite is told when to switch its radio on.
One honesty check before we bank the savings. A dark radio cannot take a conversation the instant it is asked; it has to be warmed up before it is needed. Charge the plan for that lead time, and the numbers move:
| Warm-up lead | none | 2 min | 5 min | 10 min |
|---|---|---|---|---|
| Satellites lit | 23.1 | 26.7 | 30.4 | 34.9 |
Even granting a full ten minutes of warm-up — far more than any radio needs — the fleet still runs under half lit. And notice what the lead time does to the prune pass. It saves 1.1 satellites with nothing charged for warm-up, and 0.1 at five minutes, where the plan with the pass (30.4) and the plan without it (30.5) are indistinguishable. On the averages alone it stops paying for itself almost immediately.
We keep it anyway, and the reason is not arithmetic. A pruned satellite is not one the plan suspects is idle; it is one the plan has proved serves no point that needs it. There is no defending a transmitter radiating at nobody when the check that finds it is free and runs on the ground weeks in advance. The averages stop rewarding the step long before the argument for it runs out — which is worth remembering the next time an optimization is judged by its mean.
Two things this does not buy, and the RFP will ask about both. It does not shrink the fleet: all seventy-two spacecraft are still required, because the satellites dark now are working in twenty minutes. And it does not relax the handover design — quite the opposite: since a link may only ever be handed to a satellite whose radio is already up, the activation timetable and the handover plan have to be generated together. We will honor that when we build the handover machinery.
Running it yourself
Nothing in this section is a claim you have to take on trust. The simulator is terminus, it is open source, and every table above is one command away. You need a Rust toolchain (1.79 or newer); nothing else.
git clone https://github.com/eventhelix/terminus
cd terminus
cargo run --release -p terminus-orbits --example access_constellation
Four examples carry this section:
| Example | What it prints | Runtime |
|---|---|---|
activation_plan | the four activation policies, the proved minimum, warm-up costs | ~1 min |
access_constellation | the altitude trade — where 1,800 km fails and 2,200 km holds | ~3 min |
duty_ring_trade | A: the duty ring's reach wall; B: the latitude table; C: the phase sweep | ~7 min |
phasing_options | aligned vs half-slot vs random, and why the honeycomb fails | ~8 min |
One practical note, and it is not optional: keep --release. These sweeps
evaluate a full 11.2-day rotation against 216 sample points — at 30-second
resolution for the coverage sweeps, one-minute steps for the activation
planner — hundreds of millions of geometry evaluations — and a debug build turns
those minutes into an afternoon. The runtimes above are from an ordinary
laptop; treat them as the shape of the cost rather than a promise. That cost is
the honest price of the fine sampling this section insisted on, and it is
exactly why our first pass sampled every two minutes and got the wrong answer.
If you would rather read the code than run it, the counting core is
crates/orbits/src/constellation.rs,
the duty-ring and activation logic are
duty.rs and
activation.rs, and
cargo test -p terminus-orbits checks every claim in this section — including
the seed's failure at 1,800 km and its recovery at 2,200 km,
and the one that caught us out, that
the half-slot stagger breaks the very baseline
it looks like it should improve. The coarse-sampling lesson lives in the
examples rather than in a test: the sweeps run at 30-second steps because
two-minute steps let real gaps through. Every link on this page points at the tag
terminus-post-5b, the state of the code these numbers came from, so the
line numbers hold even as the repository moves on.
The wheel, turning
So picture the finished thing from far above the pole: six silver rings fanned around a dark world, seventy-two points of light sliding along them; a red ribbon of civilization turning slowly beneath, and duty passing from ring to ring like a watch changing in the night. Every town under at least one satellite, every second, for as long as the fleet is maintained.
And every one of those conversations is now arriving at a satellite 2,200 km up and asking to reach a large language model. Where is the model? On the satellite overhead, which vanishes in a quarter of an hour? Spread across the fleet? Parked out at those strange balance points the star cannot steal? The next section takes on the question the whole proposal has been circling: where does the mind live?