Skip to content

Communications

RF link budget analysis for space communication systems.

Modulation Schemes

Name Bits per Symbol
BPSK, GMSK, 2FSK 1
QPSK, OQPSK, 4FSK 2
8PSK, 8APSK 3
16QAM, 16APSK 4
32QAM, 32APSK 5
64QAM, 64APSK 6
128QAM 7
256QAM 8

Antenna Patterns

Pattern Description
ParabolicPattern Airy disk model for parabolic reflector antennas
GaussianPattern Gaussian roll-off approximation
DipolePattern Short and general dipole radiation patterns

Pattern gain is evaluated at two angles: theta, the polar angle from boresight, and phi, the azimuth about boresight measured from the antenna-frame +X axis toward +Y. All built-in patterns are axially symmetric and ignore phi, so it can be omitted:

import lox_space as lox

pattern = lox.ParabolicPattern(diameter=0.98 * lox.m, efficiency=0.45)
gain = pattern.gain(29 * lox.GHz, theta=1.0 * lox.deg)

Antenna Frames

An AntennaFrame orients an antenna pattern in a parent frame as a right-handed orthonormal basis: +Z is the boresight (theta = 0) and +X is the phi = 0 reference direction. Construct it from a boresight and a reference direction, or use AntennaFrame.identity() for a frame aligned with the parent frame (boresight along +Z):

import lox_space as lox

frame = lox.AntennaFrame.from_boresight_and_reference(
    boresight=[1.0, 0.0, 0.0], reference=[0.0, 0.0, 1.0]
)
theta, phi = frame.angles_for([0.0, 0.0, 1.0])

A PatternedAntenna combines a pattern with a frame (identity by default) and can evaluate its gain directly toward a parent-frame direction vector via gain_toward:

pattern = lox.ParabolicPattern(diameter=0.98 * lox.m, efficiency=0.45)
antenna = lox.PatternedAntenna(pattern=pattern, frame=frame)
gain = antenna.gain_toward(29 * lox.GHz, [1.0, 0.0, 0.0])  # on boresight

A link terminal is one end of a radio link. The component tier composes an antenna with a radio, a feed loss, and the supported frequency range: a TxChain is an antenna fed by an AmplifierTransmitter, an RxChain is a NoiseTempReceiver or CascadeReceiver fed by an antenna. Components are pure physics (power, noise, gain patterns); the band lives on the terminal. Shared hardware is expressed by reusing the same component values — a diplexer-style transceiver is a TX and an RX chain sharing one dish:

import lox_space as lox

ka_band = lox.FrequencyRange(27.0 * lox.GHz, 31.0 * lox.GHz)

dish = lox.ConstantAntenna(gain=46.0 * lox.dB)
tx = lox.TxChain(
    dish,
    lox.AmplifierTransmitter(power=10 * lox.W),
    band=ka_band,
    feed_loss=1.0 * lox.dB,
)
rx = lox.RxChain(
    dish,
    lox.NoiseTempReceiver(noise_temperature=500 * lox.K),
    band=ka_band,
    antenna_noise_temperature=0.0 * lox.K,
    feed_loss=0.5 * lox.dB,
)

Wherever a band is expected, an IEEE letter-band name is accepted as shorthand for the full band range (case-insensitive):

tx = lox.TxChain(
    dish,
    lox.AmplifierTransmitter(power=10 * lox.W),
    band="Ka",  # 27–40 GHz
    feed_loss=1.0 * lox.dB,
)

Terminals expose their headline figures directly — eirp_at and gt_at evaluate at a carrier and an optional pointing:

eirp = tx.eirp_at(29.0 * lox.GHz)  # 46 + 10·log10(10) − 1 = 55 dBW
gt = rx.gt_at(29.0 * lox.GHz, angle=1.0 * lox.deg)
t_sys = rx.system_noise_temperature()

LinkBudget computes a link budget between two terminals. The carrier is a link-level input and must lie inside both terminals' frequency ranges; all outputs are bandwidth-free (C/N and noise power are derived views that take an explicit bandwidth):

link = lox.LinkBudget(
    tx,
    rx,
    carrier=29.0 * lox.GHz,
    range=1000.0 * lox.km,
)
print(f"C/N0 = {float(link.c_n0):.2f} dB·Hz")

Terminals attach to assets for scenario analysis as named collections via GroundStation(..., tx_terminals={...}, rx_terminals={...}) and Spacecraft(..., tx_terminals={...}, rx_terminals={...}); selecting a terminal by name is the configuration choice (e.g. high-gain vs. low-gain antenna).

Lumped EIRP and G/T

For early-phase mission studies — where manufacturer datasheets typically publish only aggregate figures — you can build a link budget directly from lumped EirpModel and GtModel terminals:

import lox_space as lox

link = lox.LinkBudget(
    lox.EirpModel("Ka", 55.0 * lox.dB),
    lox.GtModel("Ka", 3.01 * lox.dB),
    carrier=29.0 * lox.GHz,
    range=1000.0 * lox.km,
)
print(f"C/N0 = {float(link.c_n0):.2f} dB·Hz")

For lumped links, link.carrier_rx_power and link.noise_power(bandwidth) are None — the absolute carrier and noise power are not recoverable from EIRP and G/T alone. The carrier-to-noise density ratio (c_n0) and the carrier-to-noise ratio view (c_n(bandwidth)) remain available.

To compute modulation-aware figures (Es/N0, Eb/N0, link margin, data rate), modulate the budget with a Channel (the waveform: symbol rate, roll-off, optional DSSS chip rate) and a ModCod (the modulation and coding scheme with its Eb/N0 threshold). Everything bandwidth-dependent derives from the channel; the design margin is an input:

channel = lox.Channel(symbol_rate=5 * lox.MHz)
modcod = lox.ModCod("QPSK 1/2", lox.Modulation("QPSK"), 0.5, 10.0 * lox.dB)
modulated = link.modulate(channel, modcod, design_margin=3.0 * lox.dB)
print(f"Closes: {modulated.closes()}, margin = {float(modulated.margin):.2f} dB")

For standards-based links, use the built-in DVB-S2 table — 28 modes whose coding chains (BBFRAME, BCH, LDPC, PLFRAME) reproduce the spectral efficiencies and quasi-error-free thresholds of ETSI EN 302 307-1 Table 13 exactly — and ModCod.select for adaptive coding and modulation:

table = lox.ModCod.dvb_s2()
modcod = next(mc for mc in table if mc.name == "QPSK 3/4")
modulated = link.modulate(channel, modcod, design_margin=3.0 * lox.dB)

# Adaptive coding and modulation: the highest-efficiency mode that closes,
# selected and evaluated in one step (the result always closes):
best = link.modulate_best(channel, table, design_margin=3.0 * lox.dB)
print(f"{best.modcod.name}: {float(best.information_rate()) / 1e6:.1f} Mbit/s")

Budget Report

Both budget stages render as the line-item table engineers exchange — budget_lines() returns the data as (label, value, kind) tuples and str() renders it, with gains minus losses reproducing the C/N₀ total exactly:

print(modulated)
# + EIRP                            55.00 dB
# - Free-space path loss           181.70 dB
# - Rain attenuation                 2.00 dB
# + G/T                              3.01 dB
# - G/T degradation due to rain      0.99 dB
# + Boltzmann constant             228.60 dB
# = C/N0                           101.93 dB
# = C/N (occupied bandwidth)        93.64 dB
# = Es/N0                           34.94 dB
# = Eb/N0                           34.94 dB
# - Required Eb/N0 (QPSK 1/2)       10.00 dB
# - Design margin                    3.00 dB
# = Link margin                     21.94 dB

For bent-pipe/relay budgets, combine per-hop C/N contributions in the linear domain with combine_carrier_to_noise:

total = lox.combine_carrier_to_noise([uplink_c_n, downlink_c_n])

Use the component tier (configure antennas, amplifiers, receiver noise) when you need the full breakdown — for example for noise-budget allocation or detailed component trade studies.

Quick Example

An end-to-end budget for a LEO Earth-observation X-band downlink: a 500 km satellite transmitting in the 8.025–8.4 GHz EESS band to a 3.7 m ground station at 5° elevation. (The same scenario is available as a Rust example: cargo run --example x_band_downlink -p lox-space.)

import lox_space as lox

eess_band = lox.FrequencyRange(8.025 * lox.GHz, 8.4 * lox.GHz)
carrier = 8.2 * lox.GHz
elevation = 5.0 * lox.deg
slant_range = lox.slant_range(elevation, 6371.0 * lox.km, 500.0 * lox.km)

# Spacecraft: 0.25 m gimballed dish, 2 W amplifier, 0.8 dB feed run
spacecraft = lox.TxChain(
    lox.PatternedAntenna(pattern=lox.ParabolicPattern(0.25 * lox.m, 0.6)),
    lox.AmplifierTransmitter(power=2.0 * lox.W, output_back_off=0.5 * lox.dB),
    band=eess_band,
    feed_loss=0.8 * lox.dB,
)

# Ground station: 3.7 m dish, Friis-cascade front end (LNA → downconverter),
# 0.3 dB feed run, 60 K clear-sky antenna noise temperature
front_end = lox.CascadeReceiver(
    stages=[
        lox.NoiseStage(35.0 * lox.dB, 50.0 * lox.K),
        lox.NoiseStage(0.0 * lox.dB, 1540.0 * lox.K),  # NF ≈ 8 dB
    ],
    demodulator_loss=0.5 * lox.dB,
    implementation_loss=0.5 * lox.dB,
)
ground_station = lox.RxChain(
    lox.PatternedAntenna(pattern=lox.ParabolicPattern(3.7 * lox.m, 0.6)),
    front_end,
    band=eess_band,
    antenna_noise_temperature=60.0 * lox.K,
    feed_loss=0.3 * lox.dB,
)

# Atmospherics at X-band, 5° elevation (static values; lox-itur computes
# them from the ITU-R P-series maps)
losses = lox.PropagationLosses(
    rain=1.2 * lox.dB,
    gaseous=0.4 * lox.dB,
    scintillation=0.3 * lox.dB,
    cloud=0.1 * lox.dB,
)

# DVB-S2 QPSK 3/4 at 150 Msps; the table carries the exact Table 13
# thresholds and coding chains.
channel = lox.Channel(symbol_rate=150 * lox.MHz, roll_off=0.25)
modcod = next(mc for mc in lox.ModCod.dvb_s2() if mc.name == "QPSK 3/4")

# 2° residual pointing error on the spacecraft gimbal; the station
# autotracks on boresight. On downlinks the budget uses the rain-degraded
# G/T (ITU-R P.618 §8.2).
link = lox.LinkBudget(
    spacecraft,
    ground_station,
    carrier=carrier,
    range=slant_range,
    tx_angle=2.0 * lox.deg,
    losses=losses,
    link_type="downlink",
)
modulated = link.modulate(channel, modcod, design_margin=3.0 * lox.dB)

print(f"EIRP:        {float(link.eirp):.2f} dBW")
print(f"FSPL:        {float(link.fspl):.2f} dB")
print(f"G/T:         {float(link.gt):.2f} dB/K (clear sky)")
print(f"G/T:         {float(link.gt_degraded):.2f} dB/K (rain)")
print(f"C/N0:        {float(link.c_n0):.2f} dB·Hz")
print(f"Eb/N0:       {float(modulated.eb_n0):.2f} dB")
print(f"Data rate:   {float(modulated.information_rate()) / 1e6:.1f} Mbit/s")
print(f"Link margin: {float(modulated.margin):.2f} dB")

# Regulatory check: PFD on the ground vs. the RR Art. 21.16 mask
pfd = lox.power_flux_density(link.eirp, slant_range, channel.bandwidth(), 4.0 * lox.kHz)
mask = lox.PfdMask.art_21_16(-150.0 * lox.dB)
assert float(pfd) <= float(mask.value_at(elevation))

Direction-Aware Pointing

For patterned antennas the link budget can derive the pattern angles directly from a line-of-sight vector expressed in the antenna's parent frame, using the antenna's AntennaFrame:

import lox_space as lox

# Dish boresight along +X
frame = lox.AntennaFrame(boresight=[1.0, 0.0, 0.0], reference=[0.0, 0.0, 1.0])
antenna = lox.PatternedAntenna(
    pattern=lox.ParabolicPattern(0.25 * lox.m, 0.6), frame=frame
)
spacecraft = lox.TxChain(
    antenna,
    lox.AmplifierTransmitter(power=2.0 * lox.W),
    band=eess_band,
    feed_loss=0.8 * lox.dB,
)

link = lox.LinkBudget(
    spacecraft,
    ground_station,
    carrier=carrier,
    range=slant_range,
    tx_direction=[0.9, 0.1, 0.0],  # line of sight in the TX parent frame
)

Working with Decibels

import lox_space as lox

# Create from dB value or linear ratio
gain = 30.0 * lox.dB
gain_linear = lox.Decibel.from_linear(1000.0)

# Arithmetic
total = gain + 3.0 * lox.dB   # 33.0 dB
diff = gain - 10.0 * lox.dB   # 20.0 dB

# Convert back
print(f"{float(gain)} dB = {gain.to_linear():.0f} linear")

Free-Space Path Loss

import lox_space as lox

# FSPL at 1000 km range and 29 GHz
loss = lox.fspl(distance=1000 * lox.km, frequency=29 * lox.GHz)
print(f"FSPL: {float(loss):.1f} dB")

Propagation Losses

PropagationLosses holds itemized excess-path losses as labelled lines. total() is the carrier attenuation; absorptive() is the part that also heats the receive antenna (rain, gaseous, cloud — used for the rain-degraded G/T on downlinks):

import lox_space as lox

losses = lox.PropagationLosses(
    rain=2.0 * lox.dB,
    gaseous=0.3 * lox.dB,
    other=[("Radome wetting", 0.5 * lox.dB, True)],
)
print(f"Total: {float(losses.total()):.1f} dB")
print(f"Absorptive: {float(losses.absorptive()):.1f} dB")

# Pass to LinkBudget via the losses parameter
link = lox.LinkBudget(
    spacecraft,
    ground_station,
    carrier=carrier,
    range=slant_range,
    losses=losses,
)

Decibel

A value in decibels.

Parameters:

  • value

    The value in dB.

Methods:

  • from_linear

    Creates a Decibel value from a linear power ratio.

  • to_linear

    Returns the linear power ratio.

from_linear staticmethod

from_linear(value: float) -> Decibel

Creates a Decibel value from a linear power ratio.

to_linear

to_linear() -> float

Returns the linear power ratio.


Modulation

Digital modulation scheme.

Parameters:

  • name

    One of "BPSK", "QPSK", "8PSK", "16QAM", "32QAM", "64QAM", "128QAM", "256QAM".

Methods:

bits_per_symbol

bits_per_symbol() -> int

Returns the number of bits per symbol.


ParabolicPattern

Parabolic antenna gain pattern.

Parameters:

  • diameter

    Antenna diameter as Distance.

  • efficiency

    Aperture efficiency (0, 1].

Methods:

  • beamwidth

    Returns the half-power beamwidth, or None when the

  • from_beamwidth

    Creates a parabolic pattern from a desired beamwidth.

  • gain

    Returns the gain in dBi at the given frequency and pattern angles.

  • peak_gain

    Returns the peak gain in dBi.

beamwidth

beamwidth(frequency: Frequency) -> Angle | None

Returns the half-power beamwidth, or None when the antenna diameter is smaller than ~0.51 wavelengths at this frequency.

from_beamwidth staticmethod

Creates a parabolic pattern from a desired beamwidth.

Parameters:

  • beamwidth

    (Angle) –

    Half-power beamwidth as Angle.

  • frequency

    (Frequency) –

    Frequency.

  • efficiency

    (float) –

    Aperture efficiency (0, 1].

gain

gain(frequency: Frequency, theta: Angle, phi: Angle | None = None) -> Decibel

Returns the gain in dBi at the given frequency and pattern angles.

peak_gain

peak_gain(frequency: Frequency) -> Decibel

Returns the peak gain in dBi.


GaussianPattern

Gaussian antenna gain pattern.

Parameters:

  • diameter

    Antenna diameter as Distance.

  • efficiency

    Aperture efficiency (0, 1].

Methods:

  • beamwidth

    Returns the half-power beamwidth.

  • gain

    Returns the gain in dBi at the given frequency and pattern angles.

  • peak_gain

    Returns the peak gain in dBi.

beamwidth

beamwidth(frequency: Frequency) -> Angle

Returns the half-power beamwidth.

gain

gain(frequency: Frequency, theta: Angle, phi: Angle | None = None) -> Decibel

Returns the gain in dBi at the given frequency and pattern angles.

peak_gain

peak_gain(frequency: Frequency) -> Decibel

Returns the peak gain in dBi.


DipolePattern

Dipole antenna gain pattern.

Parameters:

  • length

    Dipole length as Distance.

Methods:

  • gain

    Returns the gain in dBi at the given frequency and pattern angles.

  • peak_gain

    Returns the peak gain in dBi.

gain

gain(frequency: Frequency, theta: Angle, phi: Angle | None = None) -> Decibel

Returns the gain in dBi at the given frequency and pattern angles.

peak_gain

peak_gain(frequency: Frequency) -> Decibel

Returns the peak gain in dBi.


ConstantAntenna

An antenna with constant gain.

Parameters:

  • gain

    Peak gain as Decibel.


AntennaFrame

Right-handed antenna coordinate frame expressed in a parent frame.

Parameters:

  • boresight

    Antenna +Z axis as [x, y, z].

  • reference

    Direction used to define the antenna +X axis after projection into the plane perpendicular to boresight.

Methods:

  • angles_for

    Returns the pattern angles for a parent-frame direction vector.

  • from_boresight_and_reference

    Creates an antenna frame from boresight and reference directions.

  • identity

    Creates an antenna frame aligned with the parent frame.

  • x

    Returns the antenna-frame +X axis in the parent frame.

  • y

    Returns the antenna-frame +Y axis in the parent frame.

  • z

    Returns the antenna-frame +Z axis in the parent frame.

angles_for

angles_for(direction: list[float]) -> tuple[Angle, Angle]

Returns the pattern angles for a parent-frame direction vector.

from_boresight_and_reference staticmethod

from_boresight_and_reference(
    boresight: list[float], reference: list[float]
) -> AntennaFrame

Creates an antenna frame from boresight and reference directions.

identity staticmethod

identity() -> AntennaFrame

Creates an antenna frame aligned with the parent frame.

x

x() -> list[float]

Returns the antenna-frame +X axis in the parent frame.

y

y() -> list[float]

Returns the antenna-frame +Y axis in the parent frame.

z

z() -> list[float]

Returns the antenna-frame +Z axis in the parent frame.


PatternedAntenna

An antenna with a physics-based gain pattern and antenna frame.

Parameters:

  • pattern

    An antenna pattern (ParabolicPattern, GaussianPattern, or DipolePattern).

  • frame

    Antenna frame defining the pattern orientation. Defaults to identity.

Methods:

  • beamwidth

    Returns the half-power beamwidth, or None when the underlying

  • gain

    Returns the gain in dBi at the given frequency and pattern angles.

  • gain_toward

    Returns the gain in dBi toward a parent-frame direction vector.

  • peak_gain

    Returns the peak gain in dBi.

beamwidth

beamwidth(frequency: Frequency) -> Angle | None

Returns the half-power beamwidth, or None when the underlying pattern does not define one.

gain

gain(frequency: Frequency, theta: Angle, phi: Angle | None = None) -> Decibel

Returns the gain in dBi at the given frequency and pattern angles.

gain_toward

gain_toward(frequency: Frequency, direction: list[float]) -> Decibel

Returns the gain in dBi toward a parent-frame direction vector.

peak_gain

peak_gain(frequency: Frequency) -> Decibel

Returns the peak gain in dBi.


AmplifierTransmitter

A radio transmitter with an RF power amplifier.

Parameters:

  • power

    Transmit power.

  • output_back_off

    Output back-off as Decibel (default Decibel(0)).

Attributes:

output_back_off property

output_back_off: Decibel

Output back-off.

power property

power: Power

Transmit power.


NoiseTempReceiver

A receiver characterised by a single equivalent noise temperature.

The figure is referred to the receiver's input connector; the system noise temperature at the antenna flange is assembled at link-budget setup from the chain's antenna noise temperature and feed loss. For a datasheet figure that already includes antenna and feed contributions, set both chain values to zero.

Parameters:

  • noise_temperature

    Equivalent noise temperature at the input connector.

Attributes:

noise_temperature property

noise_temperature: Temperature

Equivalent noise temperature referred to the receiver's input connector.


CascadeReceiver

An N-stage cascade receiver using the Friis noise formula.

Parameters:

  • stages

    Non-empty list of NoiseStage (ordered: LNA first, then downstream).

  • demodulator_loss

    Demodulator loss as Decibel (default Decibel(0)).

  • implementation_loss

    Other implementation losses as Decibel (default Decibel(0)).

Methods:

  • chain_gain

    Returns the total RF chain gain in dB.

  • chain_noise_temperature

    Returns the chain's equivalent noise temperature referred to its input connector, via the Friis formula.

  • from_lna_and_noise_figure

    Creates a two-stage model: LNA followed by a receiver characterised by noise figure.

chain_gain

chain_gain() -> Decibel

Returns the total RF chain gain in dB.

chain_noise_temperature

chain_noise_temperature() -> Temperature

Returns the chain's equivalent noise temperature referred to its input connector, via the Friis formula.

from_lna_and_noise_figure staticmethod

from_lna_and_noise_figure(
    lna_gain: Decibel,
    lna_noise_temperature: Temperature,
    receiver_noise_figure: Decibel,
    demodulator_loss: Decibel | None = None,
    implementation_loss: Decibel | None = None,
) -> CascadeReceiver

Creates a two-stage model: LNA followed by a receiver characterised by noise figure.


NoiseStage

A single stage in an RF receiver chain.

Parameters:

  • gain

    Stage gain as Decibel.

  • noise_temperature

    Stage equivalent noise temperature.


Channel

A communication channel: the waveform's occupancy of spectrum.

Parameters:

  • symbol_rate

    Symbol rate as Frequency.

  • roll_off

    Pulse-shaping roll-off factor (default 0.35).

  • chip_rate

    Chip rate for DSSS as Frequency (optional).

Methods:

  • bandwidth

    Returns the occupied channel bandwidth.

  • c_n

    Computes C/N from a given C/N0.

  • es_n0

    Computes Es/N0 from a given C/N0.

  • processing_gain

    Returns the DSSS processing gain in dB, or None for narrowband.

  • spreading_factor

    Returns the DSSS spreading factor, or None for narrowband.

Attributes:

chip_rate property

chip_rate: Frequency | None

DSSS chip rate, or None for narrowband.

roll_off property

roll_off: float

Pulse-shaping roll-off factor.

symbol_rate property

symbol_rate: Frequency

Symbol rate.

bandwidth

bandwidth() -> Frequency

Returns the occupied channel bandwidth.

c_n

c_n(c_n0: Decibel) -> Decibel

Computes C/N from a given C/N0.

es_n0

es_n0(c_n0: Decibel) -> Decibel

Computes Es/N0 from a given C/N0.

processing_gain

processing_gain() -> Decibel | None

Returns the DSSS processing gain in dB, or None for narrowband.

spreading_factor

spreading_factor() -> float | None

Returns the DSSS spreading factor, or None for narrowband.


ModCod

A modulation and coding scheme with its performance threshold.

Parameters:

  • name

    Name of the scheme.

  • modulation

    Modulation scheme.

  • code_rate

    Aggregate code rate in (0, 1].

  • required_eb_n0

    Eb/N0 threshold as Decibel.

  • metric

    Error metric ("BER", "WER", "FER", or "PER"; default "BER").

  • error_rate

    Error rate at the threshold (default 1e-6).

Methods:

  • dvb_s2

    Returns the DVB-S2 MODCOD table (normal FECFRAME, no pilots),

  • information_rate

    Returns the information bit rate at the given symbol rate.

  • select

    Selects the highest-efficiency MODCOD that closes at the given

Attributes:

code_rate property

code_rate: float

Overall code rate: the product of the coding chain's rates.

codes property

codes: list[tuple[str, float]]

The coding chain as (name, rate) tuples in encoding order.

error_rate property

error_rate: float

Error rate at the threshold.

info_bits_per_symbol property

info_bits_per_symbol: float

Information bits per symbol including all coding and framing overhead.

metric property

metric: str

Error metric of the threshold.

modulation property

modulation: Modulation

Modulation scheme.

name property

name: str

Name of the scheme.

reference property

reference: str

Source of the mode definition.

required_eb_n0 property

required_eb_n0: Decibel

Required Eb/N0 threshold.

required_es_n0 property

required_es_n0: Decibel

Required Es/N0 threshold.

dvb_s2 staticmethod

dvb_s2() -> list[ModCod]

Returns the DVB-S2 MODCOD table (normal FECFRAME, no pilots), per ETSI EN 302 307-1 Table 13.

information_rate

information_rate(symbol_rate: Frequency) -> Frequency

Returns the information bit rate at the given symbol rate.

select staticmethod

select(es_n0: Decibel, margin: Decibel, table: list[ModCod]) -> ModCod | None

Selects the highest-efficiency MODCOD that closes at the given Es/N0 with the given margin, or None when none does.


PropagationLosses

Itemized excess propagation losses along a link path, beyond free-space path loss.

Parameters:

  • rain

    Rain attenuation (optional).

  • gaseous

    Gaseous absorption (optional).

  • cloud

    Cloud attenuation (optional).

  • scintillation

    Scintillation loss (optional).

  • depolarization

    Depolarization loss (optional).

  • other

    Custom lines as (label, value, absorptive) tuples (optional).

Methods:

  • absorptive

    Returns the absorptive part of the loss — the attenuation that

  • none

    Returns zero propagation losses.

  • total

    Returns the total excess loss.

Attributes:

lines property

lines: list[tuple[str, Decibel, bool]]

The loss lines as (label, value, absorptive) tuples, in insertion order.

absorptive

absorptive() -> Decibel

Returns the absorptive part of the loss — the attenuation that also raises the receive antenna noise temperature.

none staticmethod

Returns zero propagation losses.

total

total() -> Decibel

Returns the total excess loss.


LinkBudget

A modulation-agnostic link budget between two link terminals.

All outputs are bandwidth-free; use modulate to apply a waveform and MODCOD, or the c_n/noise_power methods for ad-hoc bandwidths.

Parameters:

  • tx

    The transmit terminal (TxChain or EirpModel).

  • rx

    The receive terminal (RxChain or GtModel).

  • carrier

    Carrier frequency.

  • range

    Slant range as Distance.

  • tx_angle

    Off-boresight angle at transmitter as Angle (optional).

  • rx_angle

    Off-boresight angle at receiver as Angle (optional).

  • tx_direction

    Line-of-sight direction at transmitter as [x, y, z] (optional).

  • rx_direction

    Line-of-sight direction at receiver as [x, y, z] (optional).

  • losses

    PropagationLosses (optional, defaults to none).

  • "uplink", "downlink", or "crosslink" (optional). On downlinks the budget uses the rain-degraded G/T (ITU-R P.618 §8.2).

Methods:

  • budget_lines

    Returns the budget as ordered (label, value, kind) report lines,

  • c_n

    Returns C/N in dB for the given noise bandwidth.

  • modulate

    Applies a waveform and a MODCOD to this budget. Everything

  • modulate_best

    Selects and applies the best MODCOD from a table (ACM). The

  • noise_power

    Returns the noise power in dBW for the given bandwidth. None

Attributes:

c_n0 property

c_n0: Decibel

Carrier-to-noise density ratio in dB·Hz.

carrier_rx_power property

carrier_rx_power: Decibel | None

Received carrier power in dBW. None for lumped G/T receivers.

eirp property

eirp: Decibel

EIRP in dBW.

frequency property

frequency: Frequency

Link frequency.

fspl property

fspl: Decibel

Free-space path loss in dB.

gt property

gt: Decibel

Receiver G/T in dB/K under clear-sky conditions.

gt_degraded property

gt_degraded: Decibel | None

Rain-degraded receiver G/T in dB/K. None unless the link is a downlink with a component receive chain.

link_type: str | None

Link direction ("uplink", "downlink", or "crosslink"), if specified.

slant_range property

slant_range: Distance

Slant range.

budget_lines

budget_lines() -> list[tuple[str, Decibel, str]]

Returns the budget as ordered (label, value, kind) report lines, where kind is "gain", "loss", "subtotal", or "total".

c_n

c_n(bandwidth: Frequency) -> Decibel

Returns C/N in dB for the given noise bandwidth.

Raises:

  • ValueError

    if the bandwidth is not finite and positive.

modulate

modulate(
    channel: Channel, modcod: ModCod, design_margin: Decibel | None = None
) -> ModulatedLinkBudget

Applies a waveform and a MODCOD to this budget. Everything bandwidth-dependent derives from the channel.

modulate_best

modulate_best(
    channel: Channel, table: list[ModCod], design_margin: Decibel | None = None
) -> ModulatedLinkBudget | None

Selects and applies the best MODCOD from a table (ACM). The result always closes; None means no mode in the table closes.

noise_power

noise_power(bandwidth: Frequency) -> Decibel | None

Returns the noise power in dBW for the given bandwidth. None for lumped G/T receivers.

Raises:

  • ValueError

    if the bandwidth is not finite and positive.


ModulatedLinkBudget

Link-budget output with a modulation and coding scheme applied.

Methods:

  • budget_lines

    Returns the budget as ordered (label, value, kind) report lines,

  • closes

    Returns whether the link closes: margin >= 0.

  • information_rate

    Information bit rate: symbol rate × info bits per symbol.

  • with_interference

    Computes interference statistics for a given interferer power.

Attributes:

budget property

budget: LinkBudget

The underlying modulation-agnostic link budget.

c_n property

c_n: Decibel

C/N in dB in the channel's occupied bandwidth.

channel property

channel: Channel

The waveform the link was evaluated on.

design_margin property

design_margin: Decibel

Design margin applied on top of the MODCOD threshold.

eb_n0 property

eb_n0: Decibel

Eb/N0 (energy per information bit to noise spectral density) in dB.

es_n0 property

es_n0: Decibel

Es/N0 (energy per symbol to noise spectral density) in dB.

margin property

margin: Decibel

Link margin in dB.

modcod property

modcod: ModCod

The modulation and coding scheme the link was evaluated against.

symbol_rate property

symbol_rate: Frequency

Symbol rate from the channel.

budget_lines

budget_lines() -> list[tuple[str, Decibel, str]]

Returns the budget as ordered (label, value, kind) report lines, extended with C/N, Es/N0, Eb/N0, threshold, and margins.

closes

closes() -> bool

Returns whether the link closes: margin >= 0.

information_rate

information_rate() -> Frequency

Information bit rate: symbol rate × info bits per symbol.

with_interference

with_interference(interference_power: Power) -> InterferenceStats

Computes interference statistics for a given interferer power.


fspl builtin

Computes the free-space path loss in dB.

Parameters:

Returns:

  • Decibel

    Free-space path loss as a Decibel value.


freq_overlap builtin

Computes the frequency overlap factor between a receiver and an interferer.

Parameters:

  • rx_freq

    (Frequency) –

    Receiver center frequency.

  • rx_bw

    (Frequency) –

    Receiver bandwidth.

  • tx_freq

    (Frequency) –

    Interferer center frequency.

  • tx_bw

    (Frequency) –

    Interferer bandwidth.

Returns:

  • float

    Overlap factor in [0, 1].


power_flux_density builtin

Computes the power flux density in dBW/m²/ref_bw.

Parameters:

  • eirp

    (Decibel) –

    EIRP as Decibel.

  • distance

    (Distance) –

    Distance.

  • occupied_bw

    (Frequency) –

    Occupied bandwidth as Frequency.

  • reference_bw

    (Frequency) –

    ITU reference bandwidth as Frequency.

Returns:


PfdMask

A piecewise-linear PFD mask over elevation in dBW/m²/ref_bw.

The mask is linear in elevation between consecutive breakpoints and constant below the first and above the last.

Parameters:

  • nodes

    (elevation, value) breakpoints with strictly ascending elevations.

Methods:

  • art_21_16

    The ITU RR Article 21.16 mask shape for a given low-elevation limit.

  • nodes

    Returns the mask breakpoints as (elevation, value) tuples.

  • value_at

    Returns the mask value at the given elevation angle.

art_21_16 staticmethod

art_21_16(start: Decibel) -> PfdMask

The ITU RR Article 21.16 mask shape for a given low-elevation limit.

Rises from start at 5° elevation by 0.5 dB per degree to start + 10 dB at 25° and is constant outside that range.

nodes

nodes() -> list[tuple[Angle, Decibel]]

Returns the mask breakpoints as (elevation, value) tuples.

value_at

value_at(elevation: Angle) -> Decibel

Returns the mask value at the given elevation angle.


FrequencyRange

A contiguous frequency range with inclusive bounds.

Parameters:

  • min

    Lower frequency bound.

  • max

    Upper frequency bound.

Methods:

  • contains

    Returns whether the frequency lies within the range (bounds inclusive).

  • from_wavelengths

    Creates a frequency range from wavelength bounds (e.g. optical bands).

  • max

    Returns the upper frequency bound.

  • min

    Returns the lower frequency bound.

contains

contains(frequency: Frequency) -> bool

Returns whether the frequency lies within the range (bounds inclusive).

from_wavelengths staticmethod

from_wavelengths(min_wavelength: Distance, max_wavelength: Distance) -> FrequencyRange

Creates a frequency range from wavelength bounds (e.g. optical bands).

max

max() -> Frequency

Returns the upper frequency bound.

min

min() -> Frequency

Returns the lower frequency bound.


TxChain

A transmit chain: an antenna fed by a transmitter.

The feed loss between transmitter output and antenna subtracts from EIRP.

Parameters:

  • antenna

    ConstantAntenna or PatternedAntenna.

  • transmitter

    AmplifierTransmitter.

  • band

    Supported frequency range, as a FrequencyRange or an IEEE letter-band name like "Ka".

  • feed_loss

    Feed loss as Decibel (default Decibel(0)).

Methods:

  • eirp_at

    Returns the EIRP in dBW at the given carrier and pointing.

Attributes:

antenna property

The antenna radiating this chain.

band property

Supported frequency range of this chain.

feed_loss property

feed_loss: Decibel

Feed loss between transmitter output and antenna.

transmitter property

transmitter: AmplifierTransmitter

The transmitter driving this chain.

eirp_at

eirp_at(
    carrier: Frequency, angle: Angle | None = None, direction: list[float] | None = None
) -> Decibel

Returns the EIRP in dBW at the given carrier and pointing.

Raises ValueError when the carrier lies outside the chain's band.


RxChain

A receive chain: a receiver fed by an antenna.

The feed loss between antenna and receiver input is a noise contribution: it is synthesized as a passive attenuator at 290 K ahead of the receiver and referred back to the antenna flange.

Parameters:

  • antenna

    ConstantAntenna or PatternedAntenna.

  • receiver

    NoiseTempReceiver or CascadeReceiver.

  • band

    Supported frequency range, as a FrequencyRange or an IEEE letter-band name like "Ka".

  • antenna_noise_temperature

    Clear-sky antenna noise temperature at the flange.

  • feed_loss

    Feed loss as Decibel (default Decibel(0)).

Methods:

  • gt_at

    Returns the G/T in dB/K at the given carrier and pointing.

  • system_noise_temperature

    Returns the system noise temperature referred to the antenna flange.

Attributes:

antenna property

The antenna feeding this chain.

antenna_noise_temperature property

antenna_noise_temperature: Temperature

Clear-sky antenna noise temperature at the flange.

band property

Supported frequency range of this chain.

feed_loss property

feed_loss: Decibel

Feed loss between antenna and receiver input.

receiver property

The receiver terminating this chain.

gt_at

gt_at(
    carrier: Frequency, angle: Angle | None = None, direction: list[float] | None = None
) -> Decibel

Returns the G/T in dB/K at the given carrier and pointing.

Raises ValueError when the carrier lies outside the chain's band.

system_noise_temperature

system_noise_temperature() -> Temperature

Returns the system noise temperature referred to the antenna flange.


EirpModel

A lumped transmit terminal: an aggregate EIRP figure over a band.

Parameters:

  • band

    Frequency range over which the figure applies, as a FrequencyRange or an IEEE letter-band name like "Ka".

  • eirp

    Effective isotropic radiated power as Decibel (dBW).

Methods:

  • eirp_at

    Returns the EIRP in dBW at the given carrier; the pointing is ignored.

Attributes:

band property

Frequency range over which the figure applies.

eirp property

eirp: Decibel

Effective isotropic radiated power in dBW.

eirp_at

eirp_at(
    carrier: Frequency, angle: Angle | None = None, direction: list[float] | None = None
) -> Decibel

Returns the EIRP in dBW at the given carrier; the pointing is ignored.

Raises ValueError when the carrier lies outside the band.


GtModel

A lumped receive terminal: an aggregate G/T figure over a band.

The absolute gain and noise temperature are not recoverable from a G/T figure, so links using a GtModel carry no absolute carrier or noise powers.

Parameters:

  • band

    Frequency range over which the figure applies, as a FrequencyRange or an IEEE letter-band name like "Ka".

  • gt

    Gain-to-noise-temperature ratio as Decibel (dB/K).

Methods:

  • gt_at

    Returns the G/T in dB/K at the given carrier; the pointing is ignored.

Attributes:

band property

Frequency range over which the figure applies.

gt property

gt: Decibel

Gain-to-noise-temperature ratio in dB/K.

gt_at

gt_at(
    carrier: Frequency, angle: Angle | None = None, direction: list[float] | None = None
) -> Decibel

Returns the G/T in dB/K at the given carrier; the pointing is ignored.

Raises ValueError when the carrier lies outside the band.


slant_range builtin

Computes the slant range from a ground station to a satellite.

Parameters:

  • elevation

    (Angle) –

    Elevation angle.

  • earth_radius

    (Distance) –

    Earth radius as Distance.

  • altitude

    (Distance) –

    Satellite altitude as Distance.

Returns: