Real geoveil-cn0 output · BOR1 (EPN) · 31 December 2025 · interactive version
geoveil-cn0
High-performance GNSS signal quality analysis — Rust core, Python API
Analyze RINEX observation files to compute signal quality scores, detect threats (jamming, spoofing, interference), generate per-constellation statistics, and produce skyplot data. Used in production at Romanian national geodetic network (ROMPOS), precision agriculture, and GNSS security research.
Features
|
🛡️ Threat Detection Jamming · Spoofing · Interference Three independent detectors Visibility-based spoofing (new in 0.3.8) |
📊 Quality Scoring Composite 0–100 score 5 weighted components A–F letter grade |
🌍 6 Constellations GPS · GLONASS · Galileo BeiDou · QZSS · NavIC Per-constellation stats |
|
⚡ Rust Performance 0.14–2.6 s per 24 h file Zero Python dependencies ThreadPool-parallel batches |
📡 RINEX Support v2.x / v3.x / v4.x Broadcast navigation Visibility prediction |
🔬 Full API JSON export · Timeseries Skyplot data · Anomaly list Desktop GUI script included |
Quality score and components from analyze_with_nav · BUCU (Bucharest) · 1 h at 1 Hz
Mean CN0 by elevation per constellation · BOR1 · 24 h at 30 s
Installation
pip install geoveil-cn0
No Rust toolchain required — pre-built wheels for Linux (x86_64 + ARM/piwheels), Windows, and macOS. Python 3.9–3.12.
Quick Start
from geoveil_cn0 import AnalysisConfig, CN0Analyzer
config = AnalysisConfig(
min_elevation=10.0, # mask angle, degrees
time_bin_seconds=60, # 1-minute bins
anomaly_sensitivity=0.5, # 0.0 = permissive, 1.0 = strict
interference_threshold_db=6.0,
)
analyzer = CN0Analyzer(config)
result = analyzer.analyze_file("COST00ROU_R_20260980000_01D_30S_MO.rnx")
q = result.quality_score
print(f"Quality score : {q.overall:.1f} / 100 ({q.rating})")
print(f"Jamming : {'DETECTED' if result.jamming_detected else 'clean'}")
print(f"Spoofing : {'DETECTED' if result.spoofing_detected else 'clean'}")
print(f"Interference : {'DETECTED' if result.interference_detected else 'clean'}")
print(f"Satellites : {result.total_satellites} tracked")
print(f"Constellations: {', '.join(result.get_systems())}")
geoveil-cn0 reads plain RINEX. Decompress Hatanaka (.crx, .??d) and gzip files first, for example with the hatanaka package: hatanaka.decompress_on_disk("file.crx.gz").
Spoofing: visibility-based detection (new in 0.3.8)
# Requires navigation file for ephemeris comparison
result = analyzer.analyze_with_nav(
"COST00ROU_R_20260408_0100_30S_MO.rnx",
"BRDC00IGS_R_20260408_01D_MN.rnx",
)
if result.has_visibility_prediction:
print(f"Confirmation rate: {result.visibility_confirmation_rate:.0f}%")
print(f"Unexpected sats : {result.visibility_mean_unexpected:.1f}")
print(f"Missing sats : {result.visibility_mean_missing:.1f}")
Architecture
flowchart LR
A["RINEX obs\n.rnx / .??o"] --> C
B["BRDC nav\n.nav/.rnx"] --> C
C["CN0Analyzer\nRust core"] --> D["Quality Score\n0–100"]
C --> E["Threat Flags\nJam/Spoof/Interf"]
C --> F["Visibility\nPrediction"]
C --> G["Timeseries\nCN0 per bin"]
C --> H["Skyplot\nAz/El tracks"]
D & E & F & G & H --> I["AnalysisResult\nJSON / Python API"]
Performance
Public IGS files from 31 December 2025, plain RINEX, one core of an Intel Xeon E5-2620 v3 (2014), median of three runs, min_elevation=10, 60 s bins:
| File | Size | Epochs × sats | analyze_file |
analyze_with_nav |
Peak memory |
|---|---|---|---|---|---|
| RINEX 2.11 · 24 h · 30 s · ZIMM (GPS) | 5.4 MB | 2,880 × 32 | 0.14 s | 4.31 s | 104 MB |
| RINEX 3.02 · 24 h · 30 s · BOR1 (6 GNSS) | 19.4 MB | 2,880 × 106 | 2.57 s | 7.97 s | 446 MB |
| RINEX 3.05 · 15 min · 1 Hz · BUCU | 9.6 MB | 900 × 44 | 0.99 s | 2.62 s | 201 MB |
| RINEX 3.05 · 1 h · 1 Hz · BUCU | 39.9 MB | 3,600 × 52 | 3.78 s | 9.98 s | 739 MB |
| RINEX 3.05 · 24 h · 1 Hz · BUCU | 948.1 MB | 86,400 × 127 | 129.1 s | 263.8 s | 14.2 GB |
The analysis is single-threaded; CN0Analyzer is stateless, so a ThreadPoolExecutor over files scales with the cores available. analyze_with_nav adds visibility prediction from broadcast ephemeris.
Quality Score Components
The composite quality score (0–100, result.quality_score) is computed from five weighted components:
| Component | Weight | Description |
|---|---|---|
| CN0 Quality | 30% | Mean signal strength: 0 at 30 dB-Hz, 100 at 45 dB-Hz |
| Availability | 25% | Satellites observed / satellites expected |
| Continuity | 20% | Absence of tracking gaps |
| Stability | 15% | Low CN0 standard deviation: 100 at 2 dB-Hz, 0 at 10 dB-Hz |
| Diversity | 10% | Constellations observed (4 = 100%) |
Rating: A ≥ 90 · B ≥ 80 · C ≥ 70 · D ≥ 60 · F < 60. result.score and result.quality_grade report the same score.
Threat Detection
| Threat | Algorithm | Default Threshold |
|---|---|---|
| Jamming | Rapid CN0 drop rate | >6 dB in <3 s |
| Spoofing | Unexpected satellite ratio (BRDC ephemeris comparison) | >40% ratio + >8 count + corroboration |
| Interference | Sustained CN0 degradation | >6 dB from baseline |
Spoofing detection requires a navigation file (
analyze_with_nav). The 0.3.8 algorithm compares observed satellites against ephemeris predictions — a high ratio of unexplained observations indicates signal replay attacks.
API Reference
AnalysisConfig
| Parameter | Type | Default | Description |
|---|---|---|---|
min_elevation |
float |
5.0 |
Mask angle in degrees |
time_bin_seconds |
int |
60 |
Seconds per analysis bin |
systems |
list[str] |
all | Constellations to analyze, e.g. ["G", "R", "E", "C"] |
detect_anomalies |
bool |
True |
Run the anomaly detectors |
anomaly_sensitivity |
float |
0.5 |
Detection sensitivity 0–1 |
interference_threshold_db |
float |
6.0 |
Interference trigger (dB) |
spoofing_unexpected_threshold |
float |
0.40 |
Fraction of unexpected satellites |
spoofing_min_unexpected_count |
float |
8 |
Minimum count to flag |
CN0Analyzer
| Method | Description |
|---|---|
analyze_file(obs_path) |
Analyze an observation file |
analyze_with_nav(obs_path, nav_path) |
Also predict visibility from broadcast ephemeris (spoofing check, skyplot) |
AnalysisResult — key members
| Member | Type | Description |
|---|---|---|
quality_score |
QualityScore |
overall, rating, cn0_quality, availability, continuity, stability, diversity |
quality_grade |
str |
Letter A–F |
jamming_detected / spoofing_detected / interference_detected |
bool |
Threat flags |
mean_cn0, min_cn0, max_cn0 |
float |
CN0 statistics (dB-Hz) |
total_epochs, total_satellites |
int |
File size in epochs and satellites |
visibility_confirmation_rate |
float |
Percent of predicted satellites observed (with nav) |
get_systems() |
list |
Constellations present |
get_constellation_summary(name) |
dict |
Per-constellation CN0 and satellite counts |
get_timeseries_data() |
dict |
hours, mean_cn0, satellite_count per epoch |
get_skyplot_data() |
list |
Per-satellite azimuth, elevation and CN0 tracks (with nav) |
get_anomalies() |
list |
Detected anomaly events |
to_json() |
str |
Full result as JSON |
Supported Formats
| Input | Extensions | Notes |
|---|---|---|
| RINEX 2.x observation | .??o, .obs |
|
| RINEX 3.x / 4.x observation | .rnx, .obs |
Mixed observation files |
| RINEX navigation | .rnx, .??n, .??p |
For analyze_with_nav |
Compressed files (Hatanaka .crx/.??d, gzip, ZIP) must be decompressed first.
Website
miluta7.github.io/geoveil-cn0: live CN0 skyplot, per-constellation signal curves and benchmarks from real geoveil-cn0 output.
Live Demo
batch.geoveil-rinex.eu — the GeoVeil batch dashboard runs this library in production: CN0 quality scoring, threat detection, skyplots and heatmaps for every processed RINEX file, plus advanced multipath sessions (per-code MP RMS, cycle slips, SNR-residual wavelet spectra, Fresnel zones) and long-term trend monitoring on daily 30 s station data.
Batch Processing
For large-scale processing this library is wrapped by the GeoVeil batch system (FastAPI + Celery + MongoDB + MinIO + React dashboard): parallel workers, automatic BRDC ephemeris download, per-session analysis settings, WebSocket progress, and result persistence. See the live demo above. For local scripting, CN0Analyzer is stateless — instantiate one per thread and process files with a ThreadPoolExecutor.
License
PolyForm Noncommercial 1.0.0 with an attribution term — see LICENSE.
Free for research, education, personal and other non-commercial use, provided you credit the author and cite the library (see Citation below). Commercial use requires a separate license — contact miluta.flueras@cartografie.ro.
Citation
@software{geoveil_cn0_2026,
title = {geoveil-cn0: High-performance GNSS signal quality analysis},
author = {Dulea-Flueras, Miluta},
year = {2026},
version = {0.4.2},
url = {https://github.com/miluta7/geoveil-cn0},
}
Metadata
Release files for geoveil-cn0 0.4.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| geoveil_cn0-0.4.2.tar.gz | 904.0 kB | Details |
Built distributions (wheels)
Total release size: 6.5 MB
Release files / geoveil_cn0-0.4.2.tar.gz
| Download URL | geoveil_cn0-0.4.2.tar.gz |
|---|---|
| Size | 904.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
dd96c4c915aa0aec3c4b86541a993f267f02b6a1544160ce83cec248154955dd
|
|
BLAKE2b-256 checksum How to use checksums |
35d5b120587f4fd1e95bb002cf3ba715f28e657098e10c8c9abdcbbd08b1558e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.16
|
Release files / geoveil_cn0-0.4.2-cp312-cp312-win_amd64.whl
| Download URL | geoveil_cn0-0.4.2-cp312-cp312-win_amd64.whl |
|---|---|
| Size | 447.4 kB |
| Tags | CPython 3.12 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
d5bef0f5e0ce8d171422f862778c5828b537d9f74923d936278fcb3a64d2e998
|
|
BLAKE2b-256 checksum How to use checksums |
f73e1bee3cc44f51d4b390334b40bb35dce88a575a66a5663d9f7ffa5020464b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.16
|
Release files / geoveil_cn0-0.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
| Download URL | geoveil_cn0-0.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
|---|---|
| Size | 496.4 kB |
| Tags | CPython 3.12 Linux glibc 2.17+ x86-64 |
|
SHA-256 checksum How to use checksums |
af568e0e0e4a4ea4d2638d352033527c45f7295978fc5e6beaffa95817bf3f6d
|
|
BLAKE2b-256 checksum How to use checksums |
e5c6a39be3fa0ed414a92a98f0bc12ff7236350f2532df7bf7e40b7f449b24ed
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.16
|
Release files / geoveil_cn0-0.4.2-cp312-cp312-macosx_11_0_arm64.whl
| Download URL | geoveil_cn0-0.4.2-cp312-cp312-macosx_11_0_arm64.whl |
|---|---|
| Size | 452.4 kB |
| Tags | CPython 3.12 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
dfc723476054ab1ce4727e89732ea0ef0d8f2fa11e655a2c9d22369797af0ab5
|
|
BLAKE2b-256 checksum How to use checksums |
b18086d8b37786cf9811cd811a04025dda81b8864e19c3dfbb869b48031ded66
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.16
|
Release files / geoveil_cn0-0.4.2-cp311-cp311-win_amd64.whl
| Download URL | geoveil_cn0-0.4.2-cp311-cp311-win_amd64.whl |
|---|---|
| Size | 446.0 kB |
| Tags | CPython 3.11 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
8acd6c23446af3d2d7522defc87019c9e97629cfc90469700ed0bd5ceb79b280
|
|
BLAKE2b-256 checksum How to use checksums |
5e0838a0705b19dd61cce51deb1cdc816ba7cc063f12af6fd45151f00e9c8eff
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.16
|
Release files / geoveil_cn0-0.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
| Download URL | geoveil_cn0-0.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
|---|---|
| Size | 495.8 kB |
| Tags | CPython 3.11 Linux glibc 2.17+ x86-64 |
|
SHA-256 checksum How to use checksums |
c7d31c82786dbddd52872f53604aec5de1e286ec2a7aad7caa2229c2796fe524
|
|
BLAKE2b-256 checksum How to use checksums |
0f261575afcb842bb4f6d15dcf139f7fe0b142bd44d8fd05aa9e15780a1da929
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.16
|
Release files / geoveil_cn0-0.4.2-cp311-cp311-macosx_11_0_arm64.whl
| Download URL | geoveil_cn0-0.4.2-cp311-cp311-macosx_11_0_arm64.whl |
|---|---|
| Size | 452.5 kB |
| Tags | CPython 3.11 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
f4162690a1ec3c04083df8f0948711dac7ba96bdb7bfe7d5be73a6533f202c88
|
|
BLAKE2b-256 checksum How to use checksums |
3557a78d0ac2eeb2ebbb6a1f0f8daa21ea3b1e6a793865afc8d0871448424592
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.16
|
Release files / geoveil_cn0-0.4.2-cp310-cp310-win_amd64.whl
| Download URL | geoveil_cn0-0.4.2-cp310-cp310-win_amd64.whl |
|---|---|
| Size | 446.1 kB |
| Tags | CPython 3.10 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
ed01ede02bf60336f8fea15e6fdfd7a8997a4d932ef7a9640839c1d284eaf032
|
|
BLAKE2b-256 checksum How to use checksums |
f93ef8e60a4399f383545f474e959c0f70078b7b1da605e06d8e5a50cb2a4d40
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.16
|
Release files / geoveil_cn0-0.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
| Download URL | geoveil_cn0-0.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
|---|---|
| Size | 495.6 kB |
| Tags | CPython 3.10 Linux glibc 2.17+ x86-64 |
|
SHA-256 checksum How to use checksums |
d8122cf1b0e641834a9bd2b418c11f3fbcf8960a8c2e96308afb6b22fdb9f972
|
|
BLAKE2b-256 checksum How to use checksums |
fdee580a7dfc34bf60c287a6bb1613f8baf56533c3f72429b44e469dc1fdfff2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.16
|
Release files / geoveil_cn0-0.4.2-cp310-cp310-macosx_11_0_arm64.whl
| Download URL | geoveil_cn0-0.4.2-cp310-cp310-macosx_11_0_arm64.whl |
|---|---|
| Size | 452.4 kB |
| Tags | CPython 3.10 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
217a9126f444f7b2daf326ef4acaeede7800adc06030c0ea6c78721045e1a8c5
|
|
BLAKE2b-256 checksum How to use checksums |
54174d9d40e9e2f29de5ff2418cb0a64f4ea8b62316e4c19769ec9bcace1a349
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.16
|
Release files / geoveil_cn0-0.4.2-cp39-cp39-win_amd64.whl
| Download URL | geoveil_cn0-0.4.2-cp39-cp39-win_amd64.whl |
|---|---|
| Size | 446.6 kB |
| Tags | CPython 3.9 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
11fd49d0268abc0b0994c5c11fa234c02863edd653e058b404867cedb9e52460
|
|
BLAKE2b-256 checksum How to use checksums |
db1136e588fed711e8ec05b3bd31be8f03b48c64bfb047595ebef306a55f218c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.16
|
Release files / geoveil_cn0-0.4.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
| Download URL | geoveil_cn0-0.4.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
|---|---|
| Size | 496.0 kB |
| Tags | CPython 3.9 Linux glibc 2.17+ x86-64 |
|
SHA-256 checksum How to use checksums |
1e108067cf823ef14fe502aa207aca51e73f233962c8d0adcfbef40019488e99
|
|
BLAKE2b-256 checksum How to use checksums |
0df9116c347628b046588351e94300702567b11baf5081eb9bce4a83083e9546
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.16
|
Release files / geoveil_cn0-0.4.2-cp39-cp39-macosx_11_0_arm64.whl
| Download URL | geoveil_cn0-0.4.2-cp39-cp39-macosx_11_0_arm64.whl |
|---|---|
| Size | 452.8 kB |
| Tags | CPython 3.9 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
326e41a0b0c11c8899da73c886144e35807f7d21902026d62a513b3352c6f429
|
|
BLAKE2b-256 checksum How to use checksums |
e0ea881d0bd84b721544521822f981680333fde2f3f7c8a1a4ef0091be897bc0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.16
|