Generation of GNSS for research purposes
  • Python 99.8%
  • Shell 0.2%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
ykp 1bc79515b6
All checks were successful
ci / test (3.12) (push) Successful in 2m57s
ci / test (3.14) (push) Successful in 2m53s
ci / test (3.9) (push) Successful in 2m3s
ci / testgnss (3.12) (push) Successful in 2m3s
ci / testgnss (3.14) (push) Successful in 2m25s
ci / testgnss (3.9) (push) Successful in 2m13s
Merge pull request 'fix: downsample 3D surface for browser fallback' (#50) from fix/plotly-downsample into main
Reviewed-on: https://git.ymslws.v6.rocks/ykp/gengnss/pulls/50
2026-10-07 10:26:33 +02:00
.forgejo/workflows 108(testgnss): E2E tests + determinism + CI dedup 2026-10-06 18:49:46 +00:00
docs 109(gengnss): SigV3.1 export front-end wiring 2026-10-07 07:55:00 +00:00
scripts 015(release): e2e smoke script + CI e2e job, full README, v0.1.0, sidecar fdma_channel fix 2026-09-22 15:18:08 +00:00
src fix: downsample surface data for browser HTML fallback 2026-10-07 08:25:26 +00:00
tests 108(testgnss): E2E tests + determinism + CI dedup 2026-10-06 18:49:46 +00:00
.gitignore 001(core): ignore local Forgejo token file 2026-09-21 07:17:03 +00:00
LICENSE 001(core): project scaffold, packaging, ruff+pytest, Forgejo CI workflow 2026-09-21 06:39:01 +00:00
pyproject.toml 106(testgnss): Test GNSS GUI window 2026-10-06 17:40:19 +00:00
README.md release: v1.2.0 — version bump, almanac feature line, spec status 2026-10-01 18:20:04 +00:00
ruff.toml feat(compat): support Python 3.9 — CI leg, py39 lint target, floor guard test, zip strict fix 2026-09-28 18:26:12 +00:00

gengnss

GNSS open-service baseband signal generator — GPS, Galileo, GLONASS, BeiDou — for research, education and receiver testing.

Generates complex-baseband IQ samples of GNSS open-service signals with plausible (randomly drawn, reproducible) Doppler shifts and code delays, streamed to integer-IQ files with a full sidecar scenario record.

⚠️ Legal notice: this tool produces file/baseband output only. Radiating GNSS-like signals requires a license in virtually all jurisdictions (ITU RNSS allocations; interference with aviation receivers is prohibited, e.g. by FCC rules). Do not use this software to spoof real receivers.

Features (v1.2.0)

  • GPS: L1 C/A (PRN 1–37), L2C (CM/CL TDM), L5 (I/Q + NH codes), L1C (Weil codes + TMBOC(6,1,4/33)) — Tier-1 generators
  • GLONASS: L1OF/L2OF FDMA (shared 511-chip ST code, per-slot frequency channels) — Tier-1
  • BeiDou: B1I, B3I (SV 1–63), B1C (Weil codes + QMBOC(6,1,4/33)), B2a (Gold codes + 00010/100-chip Weil secondaries) — Tier-1
  • Galileo: E5a/E5b (QPSK(10) I/Q pairs, ICD Table 15–19 LFSR codes + CS4/CS20/CS100 secondary codes, 50 PRNs each), E1 OS (E1-B/E1-C memory codes + CBOC(6,1,1/11), E1-C on CS25_1) — Tier-1
  • GLONASS CDMA (L1OC/L2OC/L3OC): defined in the signal registry, Tier 2 — the ICD appendices are not publicly available (see docs/done/018b-bds-b2a.md)
  • BeiDou B2b: defined in the signal registry, Tier 2 — not yet implemented (ICD code tables pending)
  • Live feasibility computation: signals that do not fit the sample-rate bandwidth around the chosen center frequency are excluded with an explicit warning (never aliased, never a hard stop)
  • Reproducible scenarios: seeded Doppler/delay/phase/power draws recorded in a sidecar JSON; the same seed reproduces the file bit-for-bit
  • Streaming generation: memory independent of duration
  • Almanac-driven satellite selection: fetch a GPS almanac (CelesTrak Yuma/SEM, cached 24 h, offline mode) or import a local Yuma/SEM/JSON file, optionally filter to satellites visible from an observer (subpoint/look-angle math), and apply the healthy/visible set to the CLI selection or the GUI palettes (gengnss almanac, run/show --visible, GUI Load almanac…)
  • Planned: navigation-message encoders, AWGN, dynamic Doppler (v2) — see docs/spec.md §9/§10

Signal definitions: docs/gnss/ (one file per constellation, based on the official SIS ICDs). Functional spec: docs/spec.md. Implementation plan: docs/backlog/000-overview.md.

Install

pip install -e .[dev]     # plain pip; or: uv pip install -e .[dev]
pytest -q                 # GUI tests skip on a headless machine
ruff check src tests

Python ≥ 3.9 (CI runs 3.9, 3.12 and 3.14). Core dependencies: numpy, sdr==0.0.30.

CLI usage

# 8 GPS C/A PRNs, 1 second, at 4.092 Msps centered on L1
gengnss run --fs 4.092e6 --center 1575.42e6 --duration 1 --seed 2026 \
    --preset gps-l1x8 --output gps_l1.i16

# GLONASS FDMA: slots select the frequency channel (k)
gengnss run --fs 8e6 --center 1602e6 --duration 1 --seed 2026 \
    --signal glo_l1of:R2:-4 --signal glo_l1of:R10:0 \
    --output glonass_l1.i16

# BeiDou B1I (needs > 4.092 Msps: the B1I mainlobe is 4.092 MHz wide)
gengnss run --fs 4.2e6 --center 1561.098e6 --duration 1 --seed 2026 \
    --signal bds_b1i:C1 --signal bds_b1i:C5 --output beidou_b1i.i16

# inspect the resolved scenario + feasibility report without generating
gengnss show --signal gps_l1ca:PRN1 --seed 42

# what's in the sky right now (GPS almanac from CelesTrak, cached 24h)
gengnss almanac --lat 48.85 --lon 2.35

# simulate every healthy almanac satellite visible from an observer
# (selections are frozen in the sidecar -> regenerating stays bit-identical)
gengnss run --visible --lat 48.85 --lon 2.35 --seed 42 --output visible.i16

# regenerate bit-identically from a sidecar scenario
gengnss scenario gps_l1.i16.scenario.json --output gps_l1_again.i16

# open the GUI
gengnss --gui

GUI

A Tkinter desktop app (stdlib only, same engine as the CLI): notebook tabs for settings, signal selection and channel model, a live feasibility table, a scenario summary, and a Generate button with progress and cancel (gengnss --gui). Settings entries can be browsed to an output path, the current scenario can be saved to / loaded from a sidecar JSON, and a Generate scenario button writes just the scenario JSON (seed + drawn channels) for gengnss scenario FILE -o out.i16. Satellites are picked with point-and-click palettes of real ICD IDs per signal (GLONASS offers slot and frequency-channel views; the spec text entry stays for advanced use). A Load almanac… dialog fetches a GPS almanac (CelesTrak Yuma/SEM) in the background or imports a local Yuma/SEM/JSON file, optionally filters healthy satellites by visibility from an observer position, and pre-checks the matching satellites in the palettes. The headless equivalents are gengnss run / show / scenario.

Prerequisites: a graphical session (Windows desktop, Linux desktop, WSLg on Windows, or X11 forwarding over SSH) and a Python interpreter with Tkinter available.

Linux

The distribution Python usually needs Tkinter installed separately:

# Debian / Ubuntu (pick the package matching your Python version)
sudo apt install python3-tk        # e.g. python3.12-tk for Python 3.12
# Fedora
sudo dnf install python3-tkinter
# Arch
sudo pacman -S tk

Verify before launching: python3 -c "import tkinter" (prints nothing on success). Then install and launch:

# plain Python
python3 -m venv .venv
. .venv/bin/activate
pip install -e .
gengnss --gui

# uv
uv venv
uv pip install -e .
uv run gengnss --gui

Older interpreters (e.g. Python 3.9): replace python3 with your interpreter (python3.9 -m venv .venv) or uv venv --python 3.9 — everything else is identical.

Note: uv-managed Python interpreters on Linux do not bundle Tkinter (python-build-standalone). If uv run fails with ModuleNotFoundError: No module named 'tkinter', use a system Python with python3-tk installed instead.

Windows

Tkinter ships with every Windows Python (python.org installer, Microsoft Store app, and uv-managed interpreters), so no extra package is needed. In PowerShell:

# plain Python
py -3.12 -m venv .venv
.\venv\Scripts\Activate.ps1
python -m pip install -e .
gengnss --gui

# uv
uv venv
uv pip install -e .
uv run gengnss --gui

(cmd.exe: activate with .\venv\Scripts\activate.bat; under WSL, follow the Linux steps — the window renders via WSLg.)

Troubleshooting: if gengnss is not found, activate the virtualenv first (or re-create it); if the window fails to open, check import tkinter and that a display is available (a bare SSH session has none — use ssh -X).

Every generation writes <output>.scenario.json — the resolved scenario with drawn channels and the feasibility verdicts — so any file can be reproduced or fed into a receiver test harness.

End-to-end smoke run

sh scripts/e2e_smoke.sh

Generates one second per band-separated scenario (GPS L1 ×8, GLONASS L1OF ×4, BeiDou B1I ×2), validates every file with the spec-7.1 self-correlation harness (every drawn signal must be re-acquired within ±50 Hz Doppler and ±1 chip code phase), and prints SHA-256 sums. Runs locally (currently not in CI: the self-hosted runner's workspace checkout proved unreliable - see .forgejo/workflows/ci.yml header note).

Output format

Interleaved integer IQ (little-endian), i16 (default) or i8, peak normalized to the configured full-scale percentage. See the sidecar JSON for the exact scenario.

License

MIT (see LICENSE).