Skip to Content

Link

POST/link
POST/link/chain
POST/link/interference

Purpose

POST /link computes a link budget across every contact between a constellation and one or more ground stations, returning per-station summaries plus the full sample and contact detail.

POST /link/chain cascades a multi-hop relay path. POST /link/interference screens a wanted link against an interfering constellation.

POST /link

Request

ParameterTypeUnitDefaultRequiredDescription
constellation_idstringn/a—YesIdentifier of an existing constellation.
ground_stationsarrayn/a—YesStations to analyze. Note the plural and the underscore; `stations` is silently ignored.
startstringRFC 3339 UTC2026-01-01T00:00:00ZNoAnalysis start epoch.
duration_hoursnumberh6NoAnalysis window length.
step_secondsnumbers60NoTime step.
propagation_modelstringn/atwo_bodyNoPropagation model. Underscored spelling.
rfobjectn/a—NoRF configuration. Omit for a Ku-band default, or supply EVERY field. See below.
weatherobjectn/a—NoLegacy weather state. Defaults to clear sky.
atmosphereobjectn/a—NoITU-R atmosphere configuration. When present, replaces the legacy weather model.
diversity_pairarrayn/a—NoTwo station identifiers for a site-diversity gain analysis. Requires a statistical `atmosphere`.

The rf object is all-or-nothing

rf has no per-field defaults. Omitting it entirely gives a complete, representative Ku-band downlink. Supplying it with one field fails:

Failed to deserialize the JSON body into the target type: rf: missing field `tx_power_dbw` at line 1 column 187

Worse is putting an RF field at the top level, where it belongs to no schema and is silently discarded. This request succeeds and reports frequency_ghz: 12.0, the default, despite asking for 20:

{ "constellation_id": "demo", "frequency_ghz": 20.0, "ground_stations": [] }

Always check analysis.rf in the response against what you intended to send. It is the only confirmation that your configuration was applied.

Every field of `rf` is required once the object is present.
ParameterTypeUnitDefaultRequiredDescription
frequency_ghznumberGHz—YesCarrier frequency.
tx_power_dbwnumberdBW—YesTransmit power.
tx_antenna_gain_dbinumberdBi—YesTransmit antenna gain.
rx_antenna_gain_dbinumberdBi—YesReceive antenna gain.
system_noise_temp_knumberK—YesSystem noise temperature.
bandwidth_hznumberHz—YesOccupied bandwidth.
data_rate_bpsnumberbit/s—YesInformation rate.
required_ebno_dbnumberdB—YesDemodulator threshold.
implementation_loss_dbnumberdB—YesImplementation loss.
pointing_loss_dbnumberdB—YesAntenna pointing loss.
polarization_loss_dbnumberdB—YesPolarization mismatch loss.
min_elevation_degnumberdeg—YesElevation mask.
tx_antennaobjectn/a—NoOptional parametric transmit antenna model.
rx_antennaobjectn/a—NoOptional parametric receive antenna model.

Example request

curl -s -X POST http://127.0.0.1:8080/link \ -H 'content-type: application/json' \ -d '{ "constellation_id": "demo", "duration_hours": 6.0, "ground_stations": [ { "id": "madrid", "name": "Madrid", "latitude_deg": 40.43, "longitude_deg": -3.7, "altitude_km": 0.6 } ], "rf": { "frequency_ghz": 20.0, "tx_power_dbw": 5.0, "tx_antenna_gain_dbi": 15.0, "rx_antenna_gain_dbi": 38.0, "system_noise_temp_k": 150.0, "bandwidth_hz": 20000000.0, "data_rate_bps": 10000000.0, "required_ebno_db": 6.0, "implementation_loss_db": 1.5, "pointing_loss_db": 0.5, "polarization_loss_db": 0.2, "min_elevation_deg": 10.0 } }'

Response

Top-level fields:

{ "scenario_id": "link-demo", "run_id": "link-demo-2026-08-13T18:08:53Z-0000", "status": "completed", "satellite_count": 60, "sample_count": 361, "ground_station_count": 1, "link_czml_url": "/api/scenarios/link-demo/czml", "analysis": {} }

The analysis object carries start, step_seconds, duration_seconds, ground_stations, rf, weather, samples, contacts, station_summaries, ground_tracks, and station_footprints.

Most callers want station_summaries:

[ { "ground_station_id": "madrid", "coverage_percent": 100.0, "max_simultaneous": 3, "mean_visible": 1.6703601108033241, "total_contacts": 92, "best_margin_db": 12.90753382633514 } ]
Station summary fields.
ParameterTypeUnitDefaultRequiredDescription
coverage_percentnumberpercent—NoFraction of the window with at least one satellite above the mask.
max_simultaneousintegercount—NoHighest number of satellites visible at once.
mean_visiblenumbercount—NoAverage number visible across the window.
total_contactsintegercount—NoDistinct access intervals.
best_margin_dbnumberdB—NoBest margin achieved. This is the BEST case, at the most favorable geometry.

best_margin_db is the best moment of the best pass. A link that shows positive best margin can still fail for most of every pass. Use the contacts and samples arrays for the distribution, and see link budgets for why the worst geometry is the one that matters.

Note that contacts and total_contacts count different things: in the run above, station_summaries reports 92 total contacts while the contacts array holds 35 entries, because the array is the detailed contact records retained for the window rather than a count of every access.

POST /link/chain

Cascades a multi-hop relay path, so that a ground-to-satellite-to-satellite-to-ground route is evaluated end to end rather than as independent hops. The limiting hop governs the chain.

POST /link/interference

Screens a wanted link against an interfering constellation, reporting carrier to interference and the combined carrier to noise plus interference.

See also

Question? Give us feedbackDocuments Varaha Constellation Designer main (pre-release)
Last updated on