Join transmitters to catalog records
No single database holds both what a satellite transmits and where it is. This notebook joins SatNOGS DB to OrbitalWiki on the NORAD catalog number, charts the bands you could actually receive, and ends at a real TLE.
- Runtime
- 30 min
- API requests
- 7
Download
.ipynb file. Nothing executes until you run it.
Anonymous callers share 50 requests per day per network. A free account raises that to 1,000 per day. Each notebook states what one full run costs.
How to run it
- 1Install the packages listed above, for example: pip install requests pandas matplotlib
- 2Open Jupyter (jupyter lab) with the downloaded .ipynb, or upload it to any hosted notebook service.
- 3Run the cells top to bottom. No API key is needed; add one in the first cell if you want the higher limit.
What you will learn
- Join two independently maintained datasets on a key neither of them owns.
- Convert transmitter frequencies into amateur bands using stated thresholds rather than a supplied label.
- Separate "the transmitter is believed to work" from "you will hear it".
- Comply with both licences at once when redistributing a joined dataset, including a share-alike one.
Before you start
- pandas joins and value counts.
- No amateur radio licence and no receiver required; this notebook only reads data.
Python packages
pip install requests pandas matplotlib
Which data
Six amateur spacecraft (25544, 43017, 27607, 39444, 40967, 44909) joined against SatNOGS DB, which is a separate project with its own quota and its own licence. OrbitalWiki has no public transmitter endpoint, so the notebook goes to that upstream directly rather than pretending one exists.
Endpoints it calls
Every request the notebook makes, and why. Nothing here is illustrative: these are the calls it runs.
GET /api/v1/satellites/{norad_cat_id}The catalog record for each of six amateur spacecraft.GET /api/v1/satellites/{norad_cat_id}/tleCurrent reconstructed two-line elements, to hand off to a pass prediction.
From the notebook
Excerpts copied verbatim from the file. A test fails if the notebook changes and these do not.
def band_of(hz):
"""Band name from a frequency in hertz. None when outside the modelled range."""
if hz is None or hz <= 0:
return None
mhz = hz / 1e6
if mhz < 30:
return "HF"
if mhz < 300:
return "VHF"
if mhz < 1000:
return "UHF"What you end up with
- A joined table of 60-odd transmitter rows carrying orbit, mode, downlink in MHz and band.
- A bar chart of active transmitters by band, dominated by VHF and UHF for a reason the notebook explains.
- A freshness table showing when each transmitter record was last confirmed by a human.
- A real TLE with its epoch, and the two limits on what a pass prediction can promise.
How to cite
Both licences travel with the joined table: "Transmitter data from SatNOGS DB contributors (CC BY-SA 4.0), joined to OrbitalWiki catalog records (ODbL-1.0) on NORAD catalog number, retrieved 2026-08-04." Share-alike is the obligation people forget.
Sources
- OrbitalWiki API, machine-readable OpenAPI 3.1 spec (endpoints and parameters)Retrieved 2026-08-04Confirmed
- SatNOGS DB transmitter API (Libre Space Foundation), CC BY-SA 4.0, community-reportedRetrieved 2026-08-04Probable