| Crates.io | geoveil_mp |
| lib.rs | geoveil_mp |
| version | 0.1.1 |
| created_at | 2026-01-21 14:23:13.075091+00 |
| updated_at | 2026-01-21 14:23:13.075091+00 |
| description | High-performance GNSS multipath analysis library with support for RINEX v2/v3/v4, SP3 precise orbits, and multi-constellation processing |
| homepage | https://github.com/miluta7/geoveil-mp |
| repository | https://github.com/miluta7/geoveil-mp |
| max_upload_size | |
| id | 2059338 |
| size | 384,592 |
A high-performance Rust library for GNSS multipath analysis with Python bindings. Part of the GeoVeil suite for GNSS signal quality analysis.
pip install geoveil-mp
[dependencies]
geoveil_mp = "0.1"
Or with all features:
[dependencies]
geoveil_mp = { version = "0.1", features = ["full"] }
# Clone the repository
git clone https://github.com/miluta7/geoveil-mp.git
cd geoveil-mp
# Build Rust library
cargo build --release
# Build Python wheel
pip install maturin
maturin develop --release --features python
import geoveil_mp as gm
# Read RINEX observation file
obs = gm.read_rinex_obs("observation.24o")
print(f"Loaded {obs.num_epochs} epochs, {obs.num_satellites} satellites")
# Read SP3 precise ephemeris (optional, for accurate elevations)
sp3 = gm.read_sp3("ephemeris.sp3")
# Create analyzer with elevation cutoff
analyzer = gm.MultipathAnalyzer(
obs,
elevation_cutoff=10.0,
systems=["G", "E", "R", "C"] # GPS, Galileo, GLONASS, BeiDou
)
# Run multipath analysis
results = analyzer.analyze()
# Compute satellite elevations from SP3
if sp3 and obs.approx_position:
computed, failed = results.compute_elevations(sp3, obs.approx_position)
print(f"Elevations: {computed} computed, {failed} failed")
# Access results
print(f"Total estimates: {results.total_estimates()}")
print(f"Cycle slips detected: {results.total_cycle_slips()}")
# Print statistics by signal
for stat in results.statistics:
print(f"{stat.signal}: RMS={stat.rms:.4f}m, Count={stat.count}")
# Export to CSV
import pandas as pd
data = [{
'satellite': e.satellite,
'epoch': e.epoch,
'mp_value': e.mp_value,
'elevation': e.elevation,
'signal': e.signal
} for e in results.estimates]
df = pd.DataFrame(data)
df.to_csv("multipath_results.csv", index=False)
use geoveil_mp::{
prelude::*,
RinexObsReader, Sp3Reader,
navigation::SatellitePositionProvider,
};
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Read RINEX observation file
let obs_data = RinexObsReader::new().read("observation.24o")?;
// Read SP3 precise ephemeris
let sp3_data = Sp3Reader::read("ephemeris.sp3")?;
// Configure analysis
let config = AnalysisConfig::default()
.with_elevation_cutoff(10.0)
.with_systems(&["G", "E", "R", "C"]);
// Run multipath analysis
let analyzer = MultipathAnalyzer::new(obs_data, config);
let results = analyzer.analyze()?;
// Export results
results.to_csv("results.csv")?;
// Print statistics
for (signal, stats) in &results.statistics {
println!("{}: RMS={:.4}m, Count={}", signal, stats.rms, stats.count);
}
Ok(())
}
# Analyze RINEX file with SP3 orbits
geoveil-mp analyze --obs observation.24o --sp3 ephemeris.sp3 --csv results.csv
# Get file information
geoveil-mp info observation.24o
# Estimate position from pseudoranges
geoveil-mp position --obs observation.24o --nav navigation.24n
The code multipath is estimated using the linear combination:
$$MP_1 = R_1 - \left(1+\frac{2}{\alpha - 1}\right)\Phi_1 + \left(\frac{2}{\alpha - 1}\right)\Phi_2$$
where:
This combination eliminates ionospheric delay and geometry, leaving only code multipath, code noise, and ambiguity-related biases.
| System | Code | Frequencies | Navigation |
|---|---|---|---|
| GPS | G | L1, L2, L5 | Keplerian |
| GLONASS | R | G1, G2, G3 | State Vector (RK4) |
| Galileo | E | E1, E5a, E5b, E6 | Keplerian |
| BeiDou | C | B1I, B1C, B2a, B2b, B3I | Keplerian |
| QZSS | J | L1, L2, L5, L6 | Keplerian |
| NavIC | I | L5, S, L1 | Keplerian |
| SBAS | S | L1, L5 | - |
ESA: http://navigation-office.esa.int/products/gnss-products/{week}/
GFZ: https://igs.bkg.bund.de/root_ftp/IGS/products/mgex/{week}/
CODE: https://igs.bkg.bund.de/root_ftp/IGS/products/mgex/{week}/
BKG: https://igs.bkg.bund.de/root_ftp/IGS/BRDC/{year}/{doy}/
IGN: https://igs.ign.fr/pub/igs/data/{year}/{doy}/
| Class | Description |
|---|---|
GnssSystem |
GNSS constellation identifier (G, R, E, C, J, I, S) |
Satellite |
Satellite PRN identifier (e.g., "G01", "E11") |
Epoch |
Time representation with GPS/Julian conversions |
Ecef |
Earth-Centered Earth-Fixed coordinates |
Geodetic |
Latitude/Longitude/Height coordinates |
RinexObsData |
RINEX observation data container |
Sp3Data |
SP3 precise orbit data container |
MultipathAnalyzer |
Main multipath analysis engine |
AnalysisResults |
Analysis results container |
| Function | Description |
|---|---|
read_rinex_obs(path) |
Read RINEX observation file |
read_rinex_obs_bytes(data, filename) |
Read RINEX from bytes |
read_sp3(path) |
Read SP3 precise orbit file |
get_frequency(system, band, fcn) |
Get signal frequency (Hz) |
get_wavelength(system, band, fcn) |
Get signal wavelength (m) |
calculate_azel(receiver, satellite) |
Compute azimuth/elevation |
compute_elevation(sp3, receiver, sat, epoch) |
Compute elevation from SP3 |
version() |
Get library version |
| Constant | Value | Description |
|---|---|---|
SPEED_OF_LIGHT |
299792458.0 | Speed of light (m/s) |
GM_WGS84 |
3.986005e14 | Earth gravitational parameter (mΒ³/sΒ²) |
EARTH_RADIUS |
6378137.0 | WGS84 Earth radius (m) |
geoveil_mp/
βββ src/
β βββ lib.rs # Library entry point
β βββ python.rs # Python bindings (PyO3)
β βββ rinex/ # RINEX parsing
β β βββ types.rs # Data structures
β β βββ obs_reader.rs # Observation file reader
β βββ navigation/ # Ephemeris handling
β β βββ types.rs # Ephemeris types
β β βββ kepler2ecef.rs # Keplerian to ECEF
β β βββ glonass.rs # GLONASS Runge-Kutta
β β βββ sp3.rs # SP3 Neville interpolation
β βββ analysis/ # Analysis algorithms
β β βββ multipath.rs # Multipath estimation
β β βββ cycle_slip.rs # Cycle slip detection
β β βββ position.rs # Position estimation
β βββ plotting/ # R integration
β βββ utils/ # Utilities
β βββ constants.rs # Physical constants
β βββ coordinates.rs # Coordinate transforms
β βββ time.rs # Time handling
β βββ error.rs # Error types
βββ examples/
βββ tests/
βββ r_scripts/ # R plotting scripts
Benchmarks on a typical 24-hour multi-GNSS RINEX file (~100MB):
| Operation | Time | Notes |
|---|---|---|
| Read RINEX 3.05 | ~500ms | Memory-mapped I/O |
| Read SP3 | ~50ms | Neville interpolation ready |
| Multipath analysis | ~200ms | Parallel processing |
| Position estimation | ~2s | All epochs |
MIT License - see LICENSE file for details.
Contributions are welcome! Please see CONTRIBUTING.md for guidelines.
See CHANGELOG.md for version history.