Hi all,
The first two weeks of this series both dealt with one satellite at a time. Week 1 asked whether a link would close, in general. Week 2 asked what a real pass of one specific satellite actually looked like. Both honest questions — but neither is the question a real network spends most of its engineering effort answering.
The real question is: when more than one satellite is visible at once — which is the normal case for a dense constellation like Starlink, not a rare edge case — which one should actually carry the link?
That's the whole point of using thousands of satellites in low orbit instead of a handful in geostationary orbit: continuous coverage, at the cost of a constant stream of hand-off decisions. As one satellite sets below the horizon, another is already rising to take over — and something has to decide which one, every time.
So this week I built the smallest honest version of that decision. Using the same live TLE feed from Celestrak as last week, I pull a batch of real Starlink satellites, work out which ones are actually visible over Aberdeen at each moment, calculate each one's link margin, and pick the best one — second by second. Every time that choice changes from one satellite to another, that's logged as a hand-off event, with the exact time and which satellite took over from which.
When I ran it against a real 3-hour window over Aberdeen, up to two Starlink satellites were visible at once, and the scheduler made five real hand-off decisions as each satellite rose and set.

Multi-satellite visibility over Aberdeen, with the scheduler's chosen satellite marked in black — 5 real hand-off events across a 3-hour window
I want to be upfront about a choice I made here: the scheduling rule is deliberately basic — "always pick the highest margin, right now." A real production network adds hysteresis (don't switch for a tiny momentary improvement) and a minimum dwell time (don't hand off more than once every few seconds). I've left both out on purpose. A rule I can fully verify beats a complicated one I can't yet explain properly.
Testing this needed two different approaches, which turned out to be a useful thing to think through. Checking that the tool correctly spots when a real satellite is visible is testable against a real, known pass — same as last week. But checking that the scheduler decides correctly needed something else: waiting for two independent real satellite orbits to happen to overlap during a test run makes the test's outcome unpredictable by definition. So I built the scheduler tests around fixed, hand-crafted scenarios instead — satellite A is closer, then B becomes closer, does the tool switch at exactly the right moment? All 7 tests pass.
Same honesty note as always: every satellite's position and visibility here is real, live orbital data. The transmit power and antenna figures used for margin are still estimated from published sources, not any operator's actual specs.
Three weeks in, the shape of where this is going is getting clearer. Week 1 built the physics. Week 2 connected it to a real orbit. Week 3 turned that into an actual decision — which satellite, right now. The natural next step is replacing that simple "highest margin wins" rule with something that learns from patterns across many passes — which is where the AI part of this series starts to actually earn its place, instead of being bolted on for the sake of a buzzword.
Until next time,
Shaif
Get the code → https://github.com/shaifiqbal/ntn-multi-sat-scheduler