Link Budget Analysis
Visibility analysis answers whether two assets can see each other. A link budget analysis refines those windows down to the intervals in which a radio link between a pair of terminals actually closes — where the link margin is non-negative — and annotates each surviving window with the throughput it supports.
Terminals pair up automatically
Ground stations and spacecraft carry named terminals (see Communications). Every transmit terminal is matched against every receive terminal on the other asset whose band contains the carrier, in both directions, so a single visible pair can yield several links:
| Pair | Links | Direction |
|---|---|---|
| ground ↔ space | spacecraft transmit → station receive | "downlink" |
| station transmit → spacecraft receive | "uplink" |
|
| space ↔ space | either spacecraft's transmit → the other's receive | "crosslink" |
Terminals model hardware and know nothing about symbol rates, so the carrier,
waveform and coding come from a CarrierPlan held by the analysis. Pass
overrides to give a particular terminal pair a plan of its own.
Results are keyed by TerminalId, which pairs an asset identifier with the
terminal's name on that asset — a terminal name alone is only unique within
its asset.
What "closes" means
A CarrierPlan carries a table of candidate MODCODs and a detection MODCOD,
which defaults to the most robust entry in the table. The window boundaries are
the roots of the margin against that single detection MODCOD; adaptive coding
and modulation then annotates each window with the highest-efficiency mode that
closes at its peak.
The split matters. Selecting the best mode at every sample would make the margin jump back to near zero each time the selection climbs a rung, leaving nothing for a root finder to bracket. Detecting against one fixed mode keeps the margin smooth and unimodal — it peaks at closest approach, where both path loss and atmospheric loss are smallest.
Propagation losses
Losses carried on the plan are applied to every sample. They default to none,
so a plan without them is a clear-sky analysis. To model the atmosphere, build
a PropagationLosses — by hand, or from the ITU-R models in
Atmospheric Propagation — and attach it with the losses argument.
Note that ITU-R attenuation is quoted against an exceedance probability, so a plan built that way answers "when does the link close at that availability?" rather than "when does the link close right now".
Pointing
Both ends are evaluated at antenna boresight, which is the right model for a tracking dish and for a nadir-pointed spacecraft antenna. Off-boresight loss needs spacecraft attitude, which a scenario does not yet model.
Quick Example
import lox_space as lox
# A spacecraft that downlinks in X band, and a station that receives it.
sat = lox.Spacecraft(
"sat-7",
sgp4,
tx_terminals={"downlink": lox.EirpModel("X", 6.0 * lox.dB)},
)
station = lox.GroundStation(
"Kiruna",
lox.EllipsoidLocation("IAU_EARTH", 20.96688 * lox.deg, 67.858428 * lox.deg, 0 * lox.km),
min_elevation=5 * lox.deg,
rx_terminals={"main": lox.GtModel("X", 16.0 * lox.dB)},
)
scenario = lox.Scenario(t0, t1, spacecraft=[sat], ground_stations=[station])
visibility = lox.VisibilityAnalysis(scenario).compute()
plan = lox.CarrierPlan(
8.2 * lox.GHz,
lox.Channel(20.0 * lox.MHz),
lox.ModCod.dvb_s2(),
design_margin=3.0 * lox.dB,
)
results = lox.LinkBudgetAnalysis(scenario, visibility, plan).compute()
tx = lox.TerminalId("sat-7", "downlink")
rx = lox.TerminalId("Kiruna", "main")
for window in results.windows(tx, rx):
print(
f"{window.interval.start()} "
f"peak {float(window.peak_margin):.1f} dB "
f"{window.peak_modcod.name} "
f"{window.data_volume / 8e9:.2f} GB"
)
print(f"Total downlinked: {results.data_volume(tx, rx) / 8e9:.1f} GB")
TerminalId
Identifies one terminal: the asset carrying it and its name on that asset.
Terminal names are unique only within an asset, so neither half identifies a terminal on its own.
Parameters:
-
–assetIdentifier of the ground station or spacecraft.
-
–nameThe terminal's name on that asset.
Attributes:
CarrierPlan
The carrier, waveform, and coding a link is evaluated against.
The MODCOD table drives adaptive coding and modulation: each closing window is annotated with the highest-efficiency mode that closes at its peak. The detection MODCOD — by default the most robust entry in the table — defines the window boundaries themselves.
Parameters:
-
–carrierCarrier frequency.
-
–channelThe waveform the link is evaluated on.
-
–modcodsCandidate MODCODs, e.g.
ModCod.dvb_s2(). -
–design_marginMargin applied on top of the MODCOD threshold. Defaults to 0 dB.
-
–lossesPropagation losses applied to every sample. Defaults to none.
-
–detection_modcodMODCOD whose margin defines the window boundaries. Must be one of
modcods.
Attributes:
-
carrier(Frequency) –Carrier frequency.
-
channel(Channel) –The waveform the link is evaluated on.
-
design_margin(Decibel) –Design margin applied on top of the MODCOD threshold.
-
detection_modcod(ModCod) –MODCOD whose margin defines the window boundaries.
-
losses(PropagationLosses) –Propagation losses applied to every sample.
-
modcods(list[ModCod]) –Candidate MODCODs for adaptive coding and modulation.
detection_modcod
property
detection_modcod: ModCod
MODCOD whose margin defines the window boundaries.
LinkBudgetAnalysis
Refines visibility windows into the intervals in which links close.
Pairs every transmit terminal with every receive terminal on the other asset whose band contains the plan's carrier, in both directions, and scans each resulting link inside the visibility windows the pair already has.
Parameters:
-
–scenarioThe scenario whose assets carry the terminals.
-
–visibilityResults of a visibility analysis over the same scenario.
-
–planDefault carrier plan applied to every link.
-
–ensembleOptional propagated trajectories. Propagated automatically when omitted.
-
–stepSampling step for detection. Must be positive. Defaults to 60 seconds.
-
–overridesOptional list of (tx, rx, plan) triples overriding the default plan.
Methods:
-
compute–Compute the intervals in which each compatible link closes.
compute
compute() -> LinkBudgetResults
Compute the intervals in which each compatible link closes.
Returns:
-
LinkBudgetResults–LinkBudgetResults keyed by terminal pair.
Raises:
-
ValueError–If the step is not positive, if a spacecraft in the scenario has no trajectory in the ensemble, or if two assets share an id.
LinkBudgetResults
Results of a link budget analysis.
Methods:
-
all_windows–All windows keyed by ("asset/name", "asset/name") terminal pair.
-
data_volume–Total data volume in bits deliverable over a link.
-
is_empty–True when no link closed anywhere.
-
link_ids–The terminal pairs that form a link.
-
num_links–Number of links that closed at least once.
-
total_windows–Total number of windows across all links.
-
windows–Windows in which the link between two terminals closes.
all_windows
All windows keyed by ("asset/name", "asset/name") terminal pair.
data_volume
data_volume(tx: TerminalId, rx: TerminalId) -> float
Total data volume in bits deliverable over a link.
Parameters:
-
(txTerminalId) –Transmit terminal.
-
(rxTerminalId) –Receive terminal.
Returns:
-
float–Data volume in bits, or 0.0 for a pair that is not a link.
windows
windows(tx: TerminalId, rx: TerminalId) -> list[LinkWindow]
Windows in which the link between two terminals closes.
Parameters:
-
(txTerminalId) –Transmit terminal.
-
(rxTerminalId) –Receive terminal.
Returns:
-
list[LinkWindow]–List of LinkWindow objects, or an empty list for a pair that is not a link.
LinkWindow
An interval in which a link closes, with the throughput it supports.
Attributes:
-
data_volume(float) –Data volume deliverable over the window in bits, integrating the
-
direction(str) –Direction of the link: "uplink", "downlink", or "crosslink".
-
interval(Interval) –The interval over which the link closes.
-
min_margin(Decibel) –Lowest margin within the window.
-
peak_information_rate(Frequency) –Information rate supported at the peak, or zero when no MODCOD closes there.
-
peak_margin(Decibel) –Highest margin reached within the window, against the detection MODCOD.
-
peak_modcod(ModCod | None) –MODCOD adaptive coding and modulation selects at the peak, or None when
data_volume
property
data_volume: float
Data volume deliverable over the window in bits, integrating the adaptively selected information rate.
min_margin
property
min_margin: Decibel
Lowest margin within the window.
Zero at a boundary the root finder placed, and positive only where the window was clipped against the start or the end of a visibility interval.
peak_information_rate
property
peak_information_rate: Frequency
Information rate supported at the peak, or zero when no MODCOD closes there.
peak_margin
property
peak_margin: Decibel
Highest margin reached within the window, against the detection MODCOD.
peak_modcod
property
peak_modcod: ModCod | None
MODCOD adaptive coding and modulation selects at the peak, or None when no entry in the table closes there.