Skip to content

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:

  • asset

    –

    Identifier of the ground station or spacecraft.

  • name

    –

    The terminal's name on that asset.

Attributes:

  • asset (str) –

    Identifier of the asset carrying this terminal.

  • name (str) –

    The terminal's name on its asset.

asset property

asset: str

Identifier of the asset carrying this terminal.

name property

name: str

The terminal's name on its asset.


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:

  • carrier

    –

    Carrier frequency.

  • channel

    –

    The waveform the link is evaluated on.

  • modcods

    –

    Candidate MODCODs, e.g. ModCod.dvb_s2().

  • design_margin

    –

    Margin applied on top of the MODCOD threshold. Defaults to 0 dB.

  • losses

    –

    Propagation losses applied to every sample. Defaults to none.

  • detection_modcod

    –

    MODCOD whose margin defines the window boundaries. Must be one of modcods.

Attributes:

carrier property

carrier: Frequency

Carrier frequency.

channel property

channel: Channel

The waveform the link is evaluated on.

design_margin property

design_margin: Decibel

Design margin applied on top of the MODCOD threshold.

detection_modcod property

detection_modcod: ModCod

MODCOD whose margin defines the window boundaries.

losses property

Propagation losses applied to every sample.

modcods property

modcods: list[ModCod]

Candidate MODCODs for adaptive coding and modulation.


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:

  • scenario

    –

    The scenario whose assets carry the terminals.

  • visibility

    –

    Results of a visibility analysis over the same scenario.

  • plan

    –

    Default carrier plan applied to every link.

  • ensemble

    –

    Optional propagated trajectories. Propagated automatically when omitted.

  • step

    –

    Sampling step for detection. Must be positive. Defaults to 60 seconds.

  • overrides

    –

    Optional 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:

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() -> dict[tuple[str, str], list[LinkWindow]]

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:

Returns:

  • float –

    Data volume in bits, or 0.0 for a pair that is not a link.

is_empty

is_empty() -> bool

True when no link closed anywhere.

link_ids() -> list[tuple[TerminalId, TerminalId]]

The terminal pairs that form a link.

num_links() -> int

Number of links that closed at least once.

total_windows

total_windows() -> int

Total number of windows across all links.

windows

Windows in which the link between two terminals closes.

Parameters:

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 property

data_volume: float

Data volume deliverable over the window in bits, integrating the adaptively selected information rate.

direction property

direction: str

Direction of the link: "uplink", "downlink", or "crosslink".

interval property

interval: Interval

The interval over which the link closes.

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.