Metadata-Version: 2.4
Name: sidereon
Version: 0.8.0
Classifier: Programming Language :: Rust
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Scientific/Engineering
Requires-Dist: numpy>=1.21
Requires-Dist: httpx>=0.24
Requires-Dist: platformdirs>=3
Requires-Dist: pytest>=7 ; extra == 'test'
Provides-Extra: test
Summary: Python bindings for the Sidereon GNSS positioning engine (SP3 loading and SPP/RTK/PPP solves)
Keywords: gnss,sp3,positioning,rtk,ppp
License: MIT
Requires-Python: >=3.9
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM

# sidereon (Python)

Python bindings for the Sidereon GNSS positioning engine. This package is a thin,
Pythonic surface over the Rust `sidereon` crate: it normalizes input, marshals
types, and raises real exceptions. It adds no modeling of its own, so every solve
returns exactly the numbers the engine produces.

## Install

Build from source with [maturin](https://www.maturin.rs/) into an active virtual
environment. The compiled extension links the `sidereon-core` engine statically,
so the only runtime dependency is numpy.

    python -m venv .venv
    source .venv/bin/activate
    pip install maturin numpy

    # from bindings/python:
    maturin develop            # dev build into the active venv
    # or
    maturin build --release    # produce a wheel under dist/, then pip install it

Verify the import:

    python -c "import sidereon; print(sidereon.__version__)"

## Example

Load an SP3 precise-ephemeris product, then run a single-point positioning solve.
Pseudoranges are given as typed `SppObservation` records inside `SppConfig`; the
position comes back as a numpy float64 array of ECEF metres.

```python
import sidereon

with open("product.sp3", "rb") as fh:
    sp3 = sidereon.load_sp3(fh.read())

print(sp3)  # Sp3(epochs=96, satellites=...)

config = sidereon.SppConfig(
    observations=[
        sidereon.SppObservation("G01", 21_000_123.4),
        sidereon.SppObservation("G08", 22_517_889.1),
    ],  # ...more sats
    t_rx_j2000_s=...,            # receiver time, seconds past J2000
    t_rx_second_of_day_s=...,    # receiver time, second of day
    day_of_year=...,             # 1-based, fractional allowed
    initial_guess=[0.0, 0.0, 0.0, 0.0],  # [x_m, y_m, z_m, clock_state]
    corrections=sidereon.SppCorrections(ionosphere=False, troposphere=False),
    with_geodetic=True,
)
sol = sidereon.solve_spp(sp3, config)

print(sol.position)     # numpy array [x, y, z] in metres
print(sol.rx_clock_s)   # receiver clock bias, seconds
print(sol.used_sats)    # satellites that contributed
print(sol.geodetic)     # (lat_rad, lon_rad, height_m) or None
```

`solve_rtk_float`, `solve_rtk_fixed`, `solve_ppp_float`, and `solve_ppp_fixed`
follow the same shape: they take typed Python config objects and return result
objects with numpy positions, scalar attributes, enum statuses, and a `__repr__`.
A parse or solve failure raises `sidereon.SidereonError`. Full signatures are in the type stub
(`python/sidereon/__init__.pyi`).

## Tests

The binding's tests load committed crate-side fixtures and assert each solve
reproduces the engine reference numbers:

    pip install pytest
    pytest          # from bindings/python

## Attribution

The engine's SGP4 propagation is a Rust port of David Vallado's reference implementation (credit: David Vallado, AIAA 2006). See the `sidereon-core` crate for full attribution.

