gnsskit 0.4.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
gnsskit-0.4.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023-2026 Francesco Ioli
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
gnsskit-0.4.0/PKG-INFO ADDED
@@ -0,0 +1,72 @@
1
+ Metadata-Version: 2.4
2
+ Name: gnsskit
3
+ Version: 0.4.0
4
+ Summary: RTKLIB-based GNSS post-processing toolkit: RINEX tools, RTKLIB wrappers, static baselines and network adjustment, kinematic trajectories
5
+ Keywords: gnss,gps,rtklib,ppk,surveying,least-squares
6
+ Author: Francesco Ioli
7
+ Author-email: Francesco Ioli <francesco.ioli@polimi.it>
8
+ License-Expression: MIT
9
+ License-File: LICENSE
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Intended Audience :: Science/Research
12
+ Classifier: Topic :: Scientific/Engineering :: GIS
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Typing :: Typed
19
+ Requires-Dist: numpy
20
+ Requires-Dist: pandas>=2
21
+ Requires-Dist: scipy ; extra == 'network'
22
+ Requires-Dist: pyproj ; extra == 'network'
23
+ Requires-Dist: matplotlib ; extra == 'plot'
24
+ Requires-Python: >=3.10
25
+ Project-URL: Repository, https://github.com/franioli/gnsskit
26
+ Project-URL: Issues, https://github.com/franioli/gnsskit/issues
27
+ Provides-Extra: network
28
+ Provides-Extra: plot
29
+ Description-Content-Type: text/markdown
30
+
31
+ # gnsskit
32
+
33
+ Shared tools for post-processing GNSS data with [RTKLIB](https://www.rtklib.com/) `rnx2rtkp`, used by
34
+ [djippk](https://github.com/franioli/djippk) (drone PPK) and [stopgo](https://github.com/franioli/stopgo)
35
+ (stop-and-go surveys).
36
+
37
+ - **RTKLIB wrappers** (`gnsskit.rtklib`): `RtkConfig`, a typed, immutable set of `rnx2rtkp` options
38
+ (`from_file`, `updated`, `with_options`, `with_base_llh`, `write`); `run_rnx2rtkp` and `find_rnx2rtkp`;
39
+ `read_pos` (llh, xyz and enu `.pos` files).
40
+ - **RINEX** (`gnsskit.rinex`): `rinex_span`, `header_llh`, `trim_rinex`; inspection with `obs_summary`
41
+ (span, sampling, gaps, satellites), `read_visibility` and `plot_visibility` (RTKPLOT-style satellite
42
+ visibility, needs the `plot` extra).
43
+ - **Static** (`gnsskit.static`): `solve_static` (one solution over a time window), `process_baseline`
44
+ (static baselines with covariance), baseline IO and `loop_closures` (misclosure of every triangle of baselines); least-squares adjustment of a redundant baseline
45
+ network in `gnsskit.static.network` (needs the `network` extra).
46
+ - **Kinematic** (`gnsskit.kinematic`): trajectory interpolation and averaging.
47
+ - **Reference systems** (`gnsskit.refsys`): GPST/UTC, ellipsoids, ECEF/geodetic conversions and
48
+ `ENUFrame`, a local east-north-up frame at a point (points, vectors and covariances, both ways).
49
+
50
+ ## Install
51
+
52
+ ```sh
53
+ pip install gnsskit # library
54
+ pip install "gnsskit[network]" # + network adjustment (scipy, pyproj)
55
+ pip install "gnsskit[network,plot]" # + satellite visibility plots (matplotlib)
56
+ pip install git+https://github.com/franioli/gnsskit # development version
57
+ ```
58
+
59
+ `rnx2rtkp` is not installed by pip. Build the [demo5 fork](https://github.com/rtklibexplorer/RTKLIB) and put it on
60
+ your `PATH`; if it is missing, `run_rnx2rtkp` raises an error with instructions. Developed with `rnx2rtkp ver.EX 2.5.1`.
61
+
62
+ ## Example
63
+
64
+ ```python
65
+ from gnsskit import RtkConfig, read_pos, run_rnx2rtkp
66
+
67
+ config = RtkConfig(posmode="static", navsys="GEC", solformat="llh").with_base_llh(46.2, 9.8, 2300.0)
68
+ pos_file = run_rnx2rtkp(rover_obs, base_obs, [nav], config, "out.pos")
69
+ pos = read_pos(pos_file)
70
+ ```
71
+
72
+ See [example/](https://github.com/franioli/gnsskit/tree/main/example) for complete static, kinematic and network adjustment examples.
@@ -0,0 +1,42 @@
1
+ # gnsskit
2
+
3
+ Shared tools for post-processing GNSS data with [RTKLIB](https://www.rtklib.com/) `rnx2rtkp`, used by
4
+ [djippk](https://github.com/franioli/djippk) (drone PPK) and [stopgo](https://github.com/franioli/stopgo)
5
+ (stop-and-go surveys).
6
+
7
+ - **RTKLIB wrappers** (`gnsskit.rtklib`): `RtkConfig`, a typed, immutable set of `rnx2rtkp` options
8
+ (`from_file`, `updated`, `with_options`, `with_base_llh`, `write`); `run_rnx2rtkp` and `find_rnx2rtkp`;
9
+ `read_pos` (llh, xyz and enu `.pos` files).
10
+ - **RINEX** (`gnsskit.rinex`): `rinex_span`, `header_llh`, `trim_rinex`; inspection with `obs_summary`
11
+ (span, sampling, gaps, satellites), `read_visibility` and `plot_visibility` (RTKPLOT-style satellite
12
+ visibility, needs the `plot` extra).
13
+ - **Static** (`gnsskit.static`): `solve_static` (one solution over a time window), `process_baseline`
14
+ (static baselines with covariance), baseline IO and `loop_closures` (misclosure of every triangle of baselines); least-squares adjustment of a redundant baseline
15
+ network in `gnsskit.static.network` (needs the `network` extra).
16
+ - **Kinematic** (`gnsskit.kinematic`): trajectory interpolation and averaging.
17
+ - **Reference systems** (`gnsskit.refsys`): GPST/UTC, ellipsoids, ECEF/geodetic conversions and
18
+ `ENUFrame`, a local east-north-up frame at a point (points, vectors and covariances, both ways).
19
+
20
+ ## Install
21
+
22
+ ```sh
23
+ pip install gnsskit # library
24
+ pip install "gnsskit[network]" # + network adjustment (scipy, pyproj)
25
+ pip install "gnsskit[network,plot]" # + satellite visibility plots (matplotlib)
26
+ pip install git+https://github.com/franioli/gnsskit # development version
27
+ ```
28
+
29
+ `rnx2rtkp` is not installed by pip. Build the [demo5 fork](https://github.com/rtklibexplorer/RTKLIB) and put it on
30
+ your `PATH`; if it is missing, `run_rnx2rtkp` raises an error with instructions. Developed with `rnx2rtkp ver.EX 2.5.1`.
31
+
32
+ ## Example
33
+
34
+ ```python
35
+ from gnsskit import RtkConfig, read_pos, run_rnx2rtkp
36
+
37
+ config = RtkConfig(posmode="static", navsys="GEC", solformat="llh").with_base_llh(46.2, 9.8, 2300.0)
38
+ pos_file = run_rnx2rtkp(rover_obs, base_obs, [nav], config, "out.pos")
39
+ pos = read_pos(pos_file)
40
+ ```
41
+
42
+ See [example/](https://github.com/franioli/gnsskit/tree/main/example) for complete static, kinematic and network adjustment examples.
@@ -0,0 +1,64 @@
1
+ [project]
2
+ name = "gnsskit"
3
+ version = "0.4.0"
4
+ description = "RTKLIB-based GNSS post-processing toolkit: RINEX tools, RTKLIB wrappers, static baselines and network adjustment, kinematic trajectories"
5
+ readme = "README.md"
6
+ license = "MIT"
7
+ license-files = ["LICENSE"]
8
+ keywords = [
9
+ "gnss",
10
+ "gps",
11
+ "rtklib",
12
+ "ppk",
13
+ "surveying",
14
+ "least-squares",
15
+ ]
16
+ classifiers = [
17
+ "Development Status :: 3 - Alpha",
18
+ "Intended Audience :: Science/Research",
19
+ "Topic :: Scientific/Engineering :: GIS",
20
+ "Programming Language :: Python :: 3",
21
+ "Programming Language :: Python :: 3.10",
22
+ "Programming Language :: Python :: 3.11",
23
+ "Programming Language :: Python :: 3.12",
24
+ "Programming Language :: Python :: 3.13",
25
+ "Typing :: Typed",
26
+ ]
27
+ requires-python = ">=3.10"
28
+ dependencies = [
29
+ "numpy",
30
+ "pandas>=2",
31
+ ]
32
+
33
+ [[project.authors]]
34
+ name = "Francesco Ioli"
35
+ email = "francesco.ioli@polimi.it"
36
+
37
+ [project.optional-dependencies]
38
+ network = [
39
+ "scipy",
40
+ "pyproj",
41
+ ]
42
+ plot = ["matplotlib"]
43
+
44
+ [project.urls]
45
+ Repository = "https://github.com/franioli/gnsskit"
46
+ Issues = "https://github.com/franioli/gnsskit/issues"
47
+
48
+ [dependency-groups]
49
+ dev = [
50
+ "pytest",
51
+ "scipy",
52
+ "pyproj",
53
+ "matplotlib",
54
+ ]
55
+
56
+ [build-system]
57
+ requires = ["uv_build>=0.12.23,<0.13.0"]
58
+ build-backend = "uv_build"
59
+
60
+ [tool.pytest.ini_options]
61
+ testpaths = ["tests"]
62
+
63
+ [tool.ruff]
64
+ line-length = 100
@@ -0,0 +1,43 @@
1
+ [project]
2
+ name = "gnsskit"
3
+ version = "0.4.0"
4
+ description = "RTKLIB-based GNSS post-processing toolkit: RINEX tools, RTKLIB wrappers, static baselines and network adjustment, kinematic trajectories"
5
+ readme = "README.md"
6
+ license = "MIT"
7
+ license-files = ["LICENSE"]
8
+ authors = [{ name = "Francesco Ioli", email = "francesco.ioli@polimi.it" }]
9
+ keywords = ["gnss", "gps", "rtklib", "ppk", "surveying", "least-squares"]
10
+ classifiers = [
11
+ "Development Status :: 3 - Alpha",
12
+ "Intended Audience :: Science/Research",
13
+ "Topic :: Scientific/Engineering :: GIS",
14
+ "Programming Language :: Python :: 3",
15
+ "Programming Language :: Python :: 3.10",
16
+ "Programming Language :: Python :: 3.11",
17
+ "Programming Language :: Python :: 3.12",
18
+ "Programming Language :: Python :: 3.13",
19
+ "Typing :: Typed",
20
+ ]
21
+ requires-python = ">=3.10"
22
+ dependencies = ["numpy", "pandas>=2"]
23
+
24
+ [project.optional-dependencies]
25
+ network = ["scipy", "pyproj"]
26
+ plot = ["matplotlib"]
27
+
28
+ [project.urls]
29
+ Repository = "https://github.com/franioli/gnsskit"
30
+ Issues = "https://github.com/franioli/gnsskit/issues"
31
+
32
+ [dependency-groups]
33
+ dev = ["pytest", "scipy", "pyproj", "matplotlib"]
34
+
35
+ [build-system]
36
+ requires = ["uv_build>=0.12.23,<0.13.0"]
37
+ build-backend = "uv_build"
38
+
39
+ [tool.pytest.ini_options]
40
+ testpaths = ["tests"]
41
+
42
+ [tool.ruff]
43
+ line-length = 100
@@ -0,0 +1,76 @@
1
+ """Shared RTKLIB-based GNSS post-processing tools."""
2
+
3
+ from importlib.metadata import version
4
+
5
+ from .kinematic import interpolate
6
+ from .refsys import (
7
+ GPS_EPOCH,
8
+ GPST_UTC_OFFSET_S,
9
+ GRS80,
10
+ WGS84,
11
+ Ellipsoid,
12
+ ENUFrame,
13
+ enu_diff,
14
+ gpst_to_local,
15
+ utc_to_gpst,
16
+ )
17
+ from .rinex import (
18
+ find_rinex_obs,
19
+ header_llh,
20
+ obs_summary,
21
+ plot_visibility,
22
+ read_visibility,
23
+ rinex_span,
24
+ satellite_stats,
25
+ signal_stats,
26
+ trim_rinex,
27
+ )
28
+ from .rtklib import (
29
+ RtkConfig,
30
+ navsys_mask,
31
+ read_header,
32
+ read_pos,
33
+ read_ref_pos,
34
+ run_rnx2rtkp,
35
+ )
36
+ from .static import (
37
+ baselines_to_df,
38
+ df_to_baselines,
39
+ loop_closures,
40
+ process_baseline,
41
+ solve_static,
42
+ )
43
+
44
+ __version__ = version("gnsskit")
45
+ __all__ = [
46
+ "GPST_UTC_OFFSET_S",
47
+ "GPS_EPOCH",
48
+ "GRS80",
49
+ "WGS84",
50
+ "ENUFrame",
51
+ "Ellipsoid",
52
+ "RtkConfig",
53
+ "baselines_to_df",
54
+ "df_to_baselines",
55
+ "enu_diff",
56
+ "find_rinex_obs",
57
+ "gpst_to_local",
58
+ "header_llh",
59
+ "interpolate",
60
+ "loop_closures",
61
+ "navsys_mask",
62
+ "obs_summary",
63
+ "plot_visibility",
64
+ "process_baseline",
65
+ "read_header",
66
+ "read_pos",
67
+ "read_ref_pos",
68
+ "read_visibility",
69
+ "rinex_span",
70
+ "run_rnx2rtkp",
71
+ "satellite_stats",
72
+ "signal_stats",
73
+ "solve_static",
74
+ "trim_rinex",
75
+ "utc_to_gpst",
76
+ ]
@@ -0,0 +1,5 @@
1
+ """Kinematic processing: interpolation and averaging of trajectories from .pos solutions."""
2
+
3
+ from .trajectory import average, interpolate
4
+
5
+ __all__ = ["average", "interpolate"]
@@ -0,0 +1,84 @@
1
+ """Sampling a kinematic trajectory (`read_pos` output): at given times or inside windows."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import numpy as np
6
+ import pandas as pd
7
+
8
+ from ..refsys import GPS_EPOCH, enu_diff
9
+ from ..rtklib.pos import POS_COORD_COLS, POS_SD_COLS
10
+
11
+
12
+ def interpolate(pos: pd.DataFrame, gps_s: np.ndarray) -> pd.DataFrame:
13
+ """Linear interpolation of the trajectory at the given times.
14
+
15
+ Q is the worse of the two neighbouring epochs, ns the smaller. Times outside the
16
+ trajectory are not allowed.
17
+
18
+ Args:
19
+ pos: Trajectory from `read_pos`, with at least two epochs.
20
+ gps_s: Times to interpolate at, seconds since the GPS epoch.
21
+
22
+ Returns:
23
+ DataFrame in the format of `pos`, one row per requested time.
24
+ """
25
+ fmt = pos.attrs["format"]
26
+ t = pos["gps_s"].to_numpy()
27
+ idx = np.searchsorted(t, gps_s).clip(1, len(pos) - 1)
28
+ lo, hi = idx - 1, idx
29
+ q, ratio = pos["Q"].to_numpy(), pos["ratio"].to_numpy()
30
+ cols = POS_COORD_COLS[fmt] + POS_SD_COLS[fmt]
31
+ out = pd.DataFrame({c: np.interp(gps_s, t, pos[c]) for c in cols})
32
+ out["Q"] = np.maximum(q[lo], q[hi])
33
+ out["ns"] = np.minimum(pos["ns"].to_numpy()[lo], pos["ns"].to_numpy()[hi])
34
+ out["ratio"] = np.where(q[lo] == 1, ratio[lo], ratio[hi])
35
+ out["age"] = 0.0
36
+ out["gps_s"] = gps_s
37
+ out["t"] = GPS_EPOCH + pd.to_timedelta(gps_s, unit="s")
38
+ out.attrs["format"] = fmt
39
+ return out
40
+
41
+
42
+ def average(
43
+ pos: pd.DataFrame, start: pd.Timestamp, end: pd.Timestamp, fix_only: bool = True
44
+ ) -> dict[str, float | int | bool]:
45
+ """Mean position of the llh epochs in [start, end] with the scatter in E, N, U.
46
+
47
+ Args:
48
+ pos: llh trajectory from `read_pos`.
49
+ start: Window start, GPST.
50
+ end: Window end, GPST.
51
+ fix_only: Average the fixed epochs (Q == 1) only.
52
+
53
+ Returns:
54
+ Dict with n_epochs, fix_pct, n_used and, if any epoch is used, fixed, lat, lon, h
55
+ [deg, deg, m] and sd_e, sd_n, sd_u [m] (sample standard deviations).
56
+
57
+ Raises:
58
+ ValueError: If `pos` is not in llh format.
59
+ """
60
+ if pos.attrs.get("format") != "llh":
61
+ raise ValueError("average needs a llh trajectory (out-solformat=llh)")
62
+ seg = pos[(pos.t >= start) & (pos.t <= end)]
63
+ n_all = len(seg)
64
+ row: dict[str, float | int | bool] = {
65
+ "n_epochs": n_all,
66
+ "fix_pct": 100.0 * (seg.Q == 1).sum() / n_all if n_all else 0.0,
67
+ }
68
+ if fix_only:
69
+ seg = seg[seg.Q == 1]
70
+ row["n_used"] = len(seg)
71
+ if len(seg):
72
+ lat, lon, h = seg.lat.mean(), seg.lon.mean(), seg.h.mean()
73
+ e, n, u = enu_diff(seg.lat, seg.lon, seg.h, lat, lon, h).T
74
+ ddof = 1 if len(seg) > 1 else 0
75
+ row |= {
76
+ "fixed": bool((seg.Q == 1).all()),
77
+ "lat": lat,
78
+ "lon": lon,
79
+ "h": h,
80
+ "sd_e": e.std(ddof=ddof),
81
+ "sd_n": n.std(ddof=ddof),
82
+ "sd_u": u.std(ddof=ddof),
83
+ }
84
+ return row
@@ -0,0 +1,16 @@
1
+ """Precise Point Positioning (PPP) with RTKLIB. Placeholder: nothing is implemented yet.
2
+
3
+ Planned scope:
4
+ - single-receiver static and kinematic solutions with rnx2rtkp (`posmode` "ppp-static",
5
+ "ppp-kine" or "ppp-fixed"), reusing `gnsskit.rtklib` for configuration, running and
6
+ reading the .pos output;
7
+ - helpers for the precise products PPP needs: SP3 orbits, CLK clocks, ANTEX antenna
8
+ models (satellite and receiver), and optionally DCB/OSB biases and ocean loading;
9
+ - a PPP preset of `RtkConfig` (dual-frequency iono-free, `sateph="precise"`,
10
+ `tropopt="est-ztd"`).
11
+
12
+ To do before the first function:
13
+ - add "ppp-kine", "ppp-static" and "ppp-fixed" to `PosMode` in `gnsskit.rtklib.config`.
14
+ """
15
+
16
+ __all__: list[str] = []
File without changes