geoveil-cn0v0.4.1
GNSS signal quality · Rust core · Python API

Know how clean your signal is. Every satellite, every epoch.

geoveil-cn0 reads RINEX 2, 3 and 4 observation files and turns carrier-to-noise density into a 0–100 quality score, per-constellation statistics, CN0 skyplots and interference, jamming and spoofing checks. Give it a broadcast navigation file and it also predicts which satellites should be in view.

$pip install geoveil-cn0
–mean CN0, dB-Hz
–satellites tracked
2.6 sper 24 h file

Signal monitor

BOR1 · 2025-12-31 · real geoveil-cn0 output
Constellation
CN0, dB-Hz
≤30354045≥50

Tracks from broadcast ephemeris, sampled every 5 minutes. Timeline: mean CN0 of all satellites above 10° every 30 s, and the number tracked.

SignalsBOR1 · 24 h · 30 s

Signal strength rises with elevation. How fast is the story.

Mean CN0 in 5° elevation bins for each constellation, from the same BOR1 day. A healthy antenna gives a smooth climb. Dips at mid elevations point to obstructions or multipath, and a flat, low curve points to interference.

ConstellationMean CN0Std devMin – maxSatellitesObservations
From get_constellation_summary(). Satellites: observed and expected from the broadcast ephemeris.
QualityBUCU · 1 h · 1 Hz

One number per file, five reasons behind it

The quality score weighs signal strength, availability, continuity, stability and constellation diversity. These are the real components for one hour of 1 Hz data from BUCU, Bucharest.

Rating: A ≥ 90 · B ≥ 80 · C ≥ 70 · D ≥ 60 · F below. CN0 quality is 0 at a mean of 30 dB-Hz and 100 at 45 dB-Hz. Stability is 100 at a CN0 standard deviation of 2 dB-Hz and 0 at 10 dB-Hz.

Threats3 detectors

Three checks for a hostile sky

Each detector watches a different signature. Thresholds are part of AnalysisConfig, so a station on a noisy rooftop and one in an open field can be tuned differently.

Jamming

Sudden, shared CN0 drops

A jammer lowers CN0 on many satellites at once. The flag needs critical CN0 drops in more than 5 % of epochs, together with a low mean CN0 or drops shared across constellations.

jamming_detected
Interference

Sustained degradation

Interference is quieter and more frequent. The flag needs CN0 anomalies, drops beyond the configured thresholds, in more than 1 % of epochs.

interference_detectedinterference_threshold_db
Spoofing

Satellites that should not be there

With a navigation file, the library predicts which satellites are above the horizon. A spoofer replays signals that do not match, so a sustained high share of unexpected satellites raises the flag.

spoofing_detectedanalyze_with_nav
CheckSignatureDefault
JammingCritical drops in > 5 % of epochs, plus mean CN0 < 35 dB-Hz or drops across constellationscritical at interference_threshold_db = 6.0
InterferenceCN0 anomalies in > 1 % of epochs, at least 3anomaly_sensitivity = 0.5
SpoofingUnexpected satellites against broadcast ephemeris, sustained over 5 minutes or above 60 %> 40 % and > 8 satellites
SpeedXeon E5-2620 v3 · one core

A 24-hour station day in 2.6 seconds

Wall-clock time on public IGS files from 31 December 2025, the same set used for geoveil-mp, on a 2014 server CPU. The analysis runs on one core, so a batch of files scales with the cores you give it. Visibility prediction from broadcast ephemeris is the extra cost of analyze_with_nav.

Seconds per file, median of three runs. Files are plain RINEX; Hatanaka files were decompressed first.
Stress test

24 hours at 1 Hz: 86,400 epochs of 127 satellites take 129.1 s without navigation and 263.8 s with it, peaking at 14.2 GB.

FileEpochs × satsanalyze_filewith navPeak memoryQuality
RINEX 2.11 · 24 h · 30 s
ZIMM · GPS · 5.4 MB
2,880 × 320.14 s4.31 s104 MB66.5
RINEX 3.02 · 24 h · 30 s
BOR1 · 6 GNSS · 19.4 MB
2,880 × 1062.57 s7.97 s446 MB75.7
RINEX 3.05 · 15 min · 1 Hz
BUCU · 4 GNSS · 9.6 MB
900 × 440.99 s2.62 s201 MB96.9
RINEX 3.05 · 1 h · 1 Hz
BUCU · 4 GNSS · 39.9 MB
3,600 × 523.78 s9.98 s739 MB96.3
RINEX 3.05 · 24 h · 1 Hz
BUCU · 4 GNSS · 948.1 MB
86,400 × 127129.1 s263.8 s14.2 GB76.4
geoveil-cn0 0.4.1 release build, Python 3.13, min_elevation 10°, 60 s bins. Quality is the documented five-component score from analyze_with_nav.
In productionCRNM · 2026-08-14 · 30 s

Running on batch.geoveil-rinex.eu

The GeoVeil batch platform runs geoveil-cn0 on every station day it receives. These screenshots show one day of the CRNM station, a Trimble Alloy receiver. Select a chart to see it full size.

APIPython 3.9+

A station report in six lines

Install from PyPI, point it at a RINEX file, and read plain Python values back. Wheels for Linux, Windows and macOS.

import hatanaka
from geoveil_cn0 import AnalysisConfig, CN0Analyzer

obs = hatanaka.decompress_on_disk("BOR100POL_R_20253650000_01D_30S_MO.crx.gz")   # geoveil-cn0 reads plain RINEX
nav = hatanaka.decompress_on_disk("BRDC00IGS_R_20253650000_01D_MN.rnx.gz")

analyzer = CN0Analyzer(AnalysisConfig(min_elevation=10.0, time_bin_seconds=60))
result = analyzer.analyze_with_nav(str(obs), str(nav))

q = result.quality_score
print(q.overall, q.rating)                       # composite 0–100 and its letter
print(result.mean_cn0, result.total_satellites)   # 45.1 dB-Hz, 106 satellites for BOR1
print(result.get_constellation_summary("Galileo")["mean_cn0"])
tracks = result.get_skyplot_data()                # azimuth, elevation and CN0 per satellite
MemberReturns
analyze_file(obs)CN0 statistics, quality score, anomaly checks
analyze_with_nav(obs, nav)All of the above plus predicted visibility, skyplot and the spoofing check
quality_scoreoverall, rating and the five components
get_constellation_summary(name)Mean, spread and range of CN0, satellites observed and expected
get_timeseries_data()Mean CN0 and satellites tracked per epoch
get_skyplot_data()Azimuth, elevation and CN0 tracks per satellite
get_anomalies()Detected events with time, severity and affected satellites
to_json()The full result as JSON
LicensePolyForm Noncommercial 1.0.0

Free for science. Licensed for business.

From 0.4.0, geoveil-cn0 is source-available under PolyForm Noncommercial 1.0.0 with an attribution term.

Non-commercial use

Free, with credit

  • Research, teaching and personal projects.
  • Universities, public research bodies, charities and government agencies.
  • Credit "geoveil-cn0 by Miluta Dulea-Flueras" with a link to the repository, and cite it in publications.

Versions 0.3.9 and earlier remain available under the MIT license. The full terms are in the LICENSE file.

CitationBibTeX
geoveil_cn0.bib
@software{geoveil_cn0_2026,
  title   = {geoveil-cn0: High-performance GNSS signal quality analysis},
  author  = {Dulea-Flueras, Miluta},
  year    = {2026},
  version = {0.4.1},
  url     = {https://github.com/miluta7/geoveil-cn0},
  license = {PolyForm-Noncommercial-1.0.0}
}