Skip to content
John Hodge

← Blog

opensatcom: an open toolkit for satcom link budgets and trade studies

A satellite link has to deliver enough signal over enough noise to close a margin, after the antennas, the RF chain, the geometry, and the atmosphere have each taken their cut. The link budget is the bookkeeping that adds those terms up, and it is where most satcom system decisions are won or lost.

I built opensatcom to make that bookkeeping fast, reproducible, and ready for early-stage engineering trade studies. It maps an antenna, an RF chain, a propagation model, and a mission time-series to link margin and estimated throughput, with typed inputs and outputs you can sweep. It uses simplified, ITU-R-inspired engineering models for early, system-level work. It does not replace STK, a full ITU-R implementation, or hardware test. (The project page has a shorter overview.)

A snapshot link budget is one function call. You describe two terminals, a scenario, the antennas, the RF chain, and a propagation model, and the engine returns the chain of intermediate quantities, not just the answer.

from opensatcom.core.models import (
    Terminal, Scenario, LinkInputs, RFChainModel, PropagationConditions,
)
from opensatcom.antenna.parametric import ParametricAntenna
from opensatcom.propagation import (
    CompositePropagation, FreeSpacePropagation, GaseousAbsorptionP676, RainAttenuationP618,
)
from opensatcom.link.engine import DefaultLinkEngine
from opensatcom.geometry.slant import slant_range_m

sat = Terminal("GEO-Sat", 0.0, 0.0, 35_786_000.0)
gnd = Terminal("Ground", 38.9, -77.0, 0.0, system_noise_temp_k=290.0)

link = LinkInputs(
    tx_terminal=sat, rx_terminal=gnd,
    scenario=Scenario(name="Ka-DL", direction="downlink", freq_hz=20e9,
                      bandwidth_hz=36e6, polarization="RHCP",
                      required_metric="ebn0_db", required_value=5.0),
    tx_antenna=ParametricAntenna(gain_dbi=38.0),
    rx_antenna=ParametricAntenna(gain_dbi=40.0),
    propagation=CompositePropagation([
        FreeSpacePropagation(), GaseousAbsorptionP676(), RainAttenuationP618(),
    ]),
    rf_chain=RFChainModel(tx_power_w=100.0, tx_losses_db=1.5, rx_noise_temp_k=120.0),
)

rng = slant_range_m(0.0, 35_786_000.0, 30.0)
result = DefaultLinkEngine().evaluate_snapshot(30.0, 0.0, rng, link, PropagationConditions())
print(f"margin {result.margin_db:.1f} dB,  C/N0 {result.cn0_dbhz:.1f} dB-Hz")

The result carries EIRP, G/T, path loss, C/N0, Eb/N0, margin, and throughput, so you can see which term moved when a parameter changes.

Propagation is where the margin goes

Free-space spreading sets the scale, and the atmosphere decides whether a clear-sky design survives weather. opensatcom composes free-space loss with simplified, ITU-R-inspired models: P.676 for gaseous absorption, P.618 for rain, and a scintillation term. Their sum climbs with frequency, which is one reason Ka-band links need more fade margin than C- or Ku-band links.

One-way atmospheric attenuation versus frequency from 1 to 50 GHz at 30 degrees elevation: total attenuation rises from under 1 dB to about 7 dB, the gaseous term shows a water-vapor bump near 22 GHz, rain at 25 mm/h climbs steeply, and scintillation rises slowly; the Ka-band region near 20 to 30 GHz is shaded

Composite atmospheric attenuation at 30 degrees elevation. The gaseous term peaks at the water-vapor line near 22 GHz, and rain climbs through Ka-band. These are the package’s simplified, ITU-R-inspired models, so read the trend rather than the absolute decibels; a full P.618 run gives larger rain figures.

Geometry and elevation

The same link looks different across the sky. At a low elevation angle the signal travels a longer slant path through more atmosphere, so margin falls, and rain pushes it down further. Sweeping the elevation through the engine shows where a design stops closing.

Link margin versus elevation angle for a 20 GHz downlink: clear-sky margin rises from about minus 2 dB at 5 degrees to about 10 dB near zenith; the rain curve sits roughly 3 dB lower and crosses zero near 9 degrees; a dashed line marks where the link closes

Margin against elevation for the 20 GHz downlink above. Clear sky closes down to about 8 degrees; with 25 mm/h rain the same link needs roughly 9 degrees or more. The shaded band is the rain penalty.

From C/N0 to bits

A link budget lands on a ratio like C/N0 or Eb/N0, and turning that into throughput is the modem’s job. opensatcom ships the 28 DVB-S2 ModCods with analytic BER curves and an adaptive coding and modulation policy, so a rising C/N0 steps the link up a staircase of spectral efficiency toward the Shannon limit.

Net spectral efficiency versus required Eb/N0 for the 28 DVB-S2 ModCods, forming a staircase from QPSK 1/4 near minus 2 dB and 0.4 bits per second per hertz up to 32APSK 9/10 near 16 dB and 3.75 bits per second per hertz, with the Shannon limit drawn as a dashed reference

The 28 DVB-S2 ModCods as a staircase of spectral efficiency against required Eb/N0 (at a block error rate of 1e-5), with the Shannon bound for reference. Each extra decibel of margin buys a step up in bits per hertz.

A single snapshot is the building block. The rest of opensatcom uses it at scale: a multi-beam payload layer builds beam sets and computes signal-to-interference-plus-noise maps with co-channel interference; a mission layer runs single-satellite passes, multi-satellite handover, and network-level traffic; and a trade-study layer drives designs of experiments (Latin hypercube, factorial, random), batch evaluation, and Pareto extraction. There is a command-line interface (opensatcom run, mission, beammap, doe, batch, pareto) and HTML reports with the charts embedded. Across all of it, opensatcom is meant as a transparent, reproducible sandbox for early link-budget reasoning, a step before validated tools, full ITU-R implementations, or measured hardware.

Try it

pip install opensatcom
opensatcom run --help

The repo, the documentation, and the PyPI package have the notebooks, the API reference, and the theory notes.

opensatcom is early-stage open-source software (MIT). The propagation models are simplified, ITU-R-inspired implementations, and the figures come from one geometry to show the method rather than a validated link. The references are public.

This is an independent project I build on my own time using public sources and open tooling. The views are my own and do not represent any current or former employer.