satkit 0.8.5__tar.gz → 0.9.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.
- {satkit-0.8.5 → satkit-0.9.0}/CHANGES.md +13 -1
- {satkit-0.8.5 → satkit-0.9.0}/Cargo.toml +3 -2
- {satkit-0.8.5 → satkit-0.9.0}/PKG-INFO +29 -24
- {satkit-0.8.5 → satkit-0.9.0}/README.md +25 -23
- {satkit-0.8.5 → satkit-0.9.0}/pyproject.toml +6 -4
- satkit-0.9.0/python/docs/source/TLE.md +118 -0
- {satkit-0.8.5 → satkit-0.9.0}/python/docs/source/examples/Eclipse.ipynb +17 -17
- {satkit-0.8.5 → satkit-0.9.0}/python/docs/source/examples/High Precision Propagation.ipynb +4 -4
- satkit-0.9.0/python/docs/source/examples/Orbital Mean-Element Message.ipynb +147 -0
- {satkit-0.8.5 → satkit-0.9.0}/python/docs/source/examples/Plots.ipynb +9 -9
- {satkit-0.8.5 → satkit-0.9.0}/python/docs/source/index.md +3 -2
- {satkit-0.8.5 → satkit-0.9.0}/python/requirements.txt +2 -1
- {satkit-0.8.5 → satkit-0.9.0}/python/satkit/_version.py +2 -2
- {satkit-0.8.5 → satkit-0.9.0}/python/satkit/satkit.pyi +67 -26
- {satkit-0.8.5 → satkit-0.9.0}/python/satkit.egg-info/PKG-INFO +29 -24
- {satkit-0.8.5 → satkit-0.9.0}/python/satkit.egg-info/SOURCES.txt +2 -0
- {satkit-0.8.5 → satkit-0.9.0}/python/satkit.egg-info/requires.txt +4 -0
- {satkit-0.8.5 → satkit-0.9.0}/python/test/test.py +54 -5
- {satkit-0.8.5 → satkit-0.9.0}/src/lib.rs +5 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/ode/rk_adaptive.rs +17 -17
- {satkit-0.8.5 → satkit-0.9.0}/src/ode/types.rs +2 -2
- satkit-0.9.0/src/omm/mod.rs +353 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/orbitprop/precomputed.rs +16 -16
- {satkit-0.8.5 → satkit-0.9.0}/src/orbitprop/propagator.rs +32 -32
- {satkit-0.8.5 → satkit-0.9.0}/src/orbitprop/settings.rs +12 -12
- {satkit-0.8.5 → satkit-0.9.0}/src/pybindings/pyinstant.rs +24 -1
- {satkit-0.8.5 → satkit-0.9.0}/src/pybindings/pypropagate.rs +33 -33
- {satkit-0.8.5 → satkit-0.9.0}/src/pybindings/pypropresult.rs +16 -16
- {satkit-0.8.5 → satkit-0.9.0}/src/pybindings/pypropsettings.rs +2 -2
- satkit-0.9.0/src/pybindings/pysgp4.rs +498 -0
- satkit-0.9.0/src/sgp4/mod.rs +82 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/sgp4/sgp4_impl.rs +68 -70
- {satkit-0.8.5 → satkit-0.9.0}/src/tle/fitting.rs +5 -4
- {satkit-0.8.5 → satkit-0.9.0}/src/tle/mod.rs +40 -6
- satkit-0.8.5/python/docs/source/TLE.md +0 -61
- satkit-0.8.5/src/pybindings/pysgp4.rs +0 -277
- satkit-0.8.5/src/sgp4/mod.rs +0 -44
- {satkit-0.8.5 → satkit-0.9.0}/.github/workflows/build.yml +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/.github/workflows/wheels.yml +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/.gitignore +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/.readthedocs.yaml +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/CONTRIBUTING.md +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/LICENSE +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/MANIFEST.in +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/build.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/extern/nrlmsise/DOCUMENTATION +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/extern/nrlmsise/nrlmsise-00.c +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/extern/nrlmsise/nrlmsise-00.h +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/extern/nrlmsise/nrlmsise-00_data.c +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/python/Pipfile +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/python/docs/Makefile +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/python/docs/jsdoc_config.json +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/python/docs/jsdoc_plugin.js +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/python/docs/make.bat +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/python/docs/source/_static/density_vs_solar_cycle.svg +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/python/docs/source/_static/force_vs_altitude.svg +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/python/docs/source/_static/theme_mods.css +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/python/docs/source/api/consts.md +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/python/docs/source/api/density.md +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/python/docs/source/api/earthgravity.md +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/python/docs/source/api/frametransform.md +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/python/docs/source/api/itrfcoord.md +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/python/docs/source/api/jplephem.md +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/python/docs/source/api/kepler.md +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/python/docs/source/api/quaternion.md +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/python/docs/source/api/satprop.md +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/python/docs/source/api/satstate.md +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/python/docs/source/api/time.md +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/python/docs/source/api/tle.md +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/python/docs/source/api/utils.md +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/python/docs/source/conf.py +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/python/docs/source/datafiles.md +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/python/docs/source/density.md +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/python/docs/source/examples/ITRF Coordinates.ipynb +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/python/docs/source/examples/Satellite Ground Contacts.ipynb +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/python/docs/source/examples/TLE Fitting.ipynb +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/python/docs/source/examples/Two-Line Element Set.ipynb +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/python/docs/source/examples/riseset.ipynb +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/python/docs/source/frametransform.md +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/python/docs/source/install.md +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/python/docs/source/itrfcoord.md +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/python/docs/source/quaternion.md +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/python/docs/source/references.md +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/python/docs/source/satprop.md +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/python/docs/source/satstate.md +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/python/docs/source/time.md +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/python/satkit/__init__.py +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/python/satkit/__init__.pyi +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/python/satkit/density.pyi +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/python/satkit/frametransform.pyi +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/python/satkit/jplephem.pyi +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/python/satkit/moon.pyi +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/python/satkit/planets.pyi +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/python/satkit/py.typed +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/python/satkit/sun.pyi +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/python/satkit/utils.pyi +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/python/satkit.egg-info/dependency_links.txt +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/python/satkit.egg-info/top_level.txt +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/python/test/download_data.py +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/python/test/download_from_json.py +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/python/test/download_testvecs.py +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/python/test/sp3file.py +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/setup.cfg +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/consts.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/earth_orientation_params.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/earthgravity.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/filters/mod.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/filters/ukf.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/frames.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/frametransform/ierstable.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/frametransform/mod.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/frametransform/qcirs2gcrs.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/itrfcoord.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/jplephem.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/kepler.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/lpephem/mod.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/lpephem/moon.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/lpephem/planets.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/lpephem/sun.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/mathtypes.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/nrlmsise.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/ode/adaptive_solvers/mod.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/ode/adaptive_solvers/rkf45.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/ode/adaptive_solvers/rkts54.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/ode/adaptive_solvers/rkv65.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/ode/adaptive_solvers/rkv65_table.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/ode/adaptive_solvers/rkv87.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/ode/adaptive_solvers/rkv87_table.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/ode/adaptive_solvers/rkv98.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/ode/adaptive_solvers/rkv98_efficient.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/ode/adaptive_solvers/rkv98_efficient_table.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/ode/adaptive_solvers/rkv98_nointerp.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/ode/adaptive_solvers/rkv98_nointerp_table.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/ode/adaptive_solvers/rkv98_table.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/ode/mod.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/ode/nalgebra_bindings.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/ode/ode_tests.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/ode/rk_adaptive_settings.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/ode/rk_explicit.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/orbitprop/drag.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/orbitprop/mod.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/orbitprop/point_gravity.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/orbitprop/satproperties.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/orbitprop/satstate.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/pybindings/mod.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/pybindings/mod_utils.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/pybindings/pyconsts.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/pybindings/pydensity.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/pybindings/pyduration.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/pybindings/pyframes.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/pybindings/pyframetransform.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/pybindings/pygravity.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/pybindings/pyitrfcoord.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/pybindings/pyjplephem.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/pybindings/pykepler.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/pybindings/pylpephem_moon.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/pybindings/pylpephem_planets.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/pybindings/pylpephem_sun.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/pybindings/pympsuccess.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/pybindings/pynrlmsise.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/pybindings/pyquaternion.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/pybindings/pysatproperties.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/pybindings/pysatstate.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/pybindings/pysolarsystem.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/pybindings/pytle.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/pybindings/pyukf.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/pybindings/pyutils.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/sgp4/dpper.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/sgp4/dscom.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/sgp4/dsinit.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/sgp4/dspace.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/sgp4/getgravconst.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/sgp4/initl.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/sgp4/satrec.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/sgp4/sgp4_lowlevel.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/sgp4/sgp4init.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/solarsystem.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/spaceweather.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/time/duration.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/time/instant.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/time/instant_err.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/time/instant_ops.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/time/instantparse.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/time/mod.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/time/tests.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/time/timescale.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/time/weekday.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/utils/datadir.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/utils/download.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/utils/mod.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/utils/pypackage.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/utils/test.rs +0 -0
- {satkit-0.8.5 → satkit-0.9.0}/src/utils/update_data.rs +0 -0
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
|
|
3
4
|
## 0.5.5 - 2025-01-27
|
|
4
5
|
|
|
5
6
|
### Low-Precision Ephemeris
|
|
6
|
-
- Coefficients for low-precision planetary ephemerides did not match paper or JPL website referenced in documentation. Not sure where original
|
|
7
|
+
- Coefficients for low-precision planetary ephemerides did not match paper or JPL website referenced in documentation. Not sure where original nu mbers came from. Some plantes (e.g., Mercury) matched. Others (e.g., Mars) did not, although numbers for Mars did match a google search. Very strange ... regardless, update so they match. Coefficients for years 1800 to 2050 AD are correct and remain unchanged.
|
|
7
8
|
- Add Pluto as a planet for low-precision ephemerides (it is included in reference paper, but not JPL website)
|
|
8
9
|
|
|
9
10
|
### Two-Line Element Sets
|
|
@@ -143,3 +144,14 @@
|
|
|
143
144
|
- Add "x", "y", "z", "w" property getters to quaternion in python
|
|
144
145
|
- Add pickle serialize/deserialize tests in python testing
|
|
145
146
|
- allow for duration division by float and by other duration in python
|
|
147
|
+
|
|
148
|
+
-----------------
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
## Rust 0.9.0, Python 0.9.0
|
|
152
|
+
- Support Orbital Mean-Element Messages (OMM) in JSON format
|
|
153
|
+
- Add OMM documentation, tests, and python example
|
|
154
|
+
- Structured output of SGP4 propagator in rust
|
|
155
|
+
- add "as_datetime" function in python for satkit.time (for consistent nomenclature)
|
|
156
|
+
- Rename time-interval boundary nomenclature from `start/stop` to `begin/end` across Rust + Python APIs (including propagation functions and related settings/results).
|
|
157
|
+
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "satkit"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.9.0"
|
|
4
4
|
edition = "2021"
|
|
5
5
|
description = "Satellite Toolkit"
|
|
6
6
|
readme = "README.md"
|
|
@@ -12,7 +12,7 @@ keywords = ["satellite", "orbit", "ephemeris", "tle", "astrodynamics"]
|
|
|
12
12
|
categories = ["aerospace", "algorithms", "mathematics", "science"]
|
|
13
13
|
|
|
14
14
|
|
|
15
|
-
# See more keys and their definitions at
|
|
15
|
+
# See more keys and their definitions at
|
|
16
16
|
# https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
17
17
|
[lib]
|
|
18
18
|
name = "satkit"
|
|
@@ -34,6 +34,7 @@ ureq = "3.1.2"
|
|
|
34
34
|
json = "0.12.4"
|
|
35
35
|
process_path = "0.1.4"
|
|
36
36
|
serde = { version = "1.0", features = ["derive"] }
|
|
37
|
+
serde_json = "1.0"
|
|
37
38
|
serde-pickle = "1.2.0"
|
|
38
39
|
itertools = "0.14.0"
|
|
39
40
|
anyhow = "1"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: satkit
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.9.0
|
|
4
4
|
Summary: Satellite Orbital Dynamics Toolkit
|
|
5
5
|
Author-email: Steven Michael <ssmichael@gmail.com>
|
|
6
6
|
Maintainer-email: Steven Michael <ssmichael@gmail.com>
|
|
@@ -40,6 +40,9 @@ Description-Content-Type: text/markdown
|
|
|
40
40
|
License-File: LICENSE
|
|
41
41
|
Requires-Dist: numpy>=1.0.0
|
|
42
42
|
Requires-Dist: satkit-data>=0.7.0
|
|
43
|
+
Provides-Extra: test
|
|
44
|
+
Requires-Dist: pytest; extra == "test"
|
|
45
|
+
Requires-Dist: xmltodict; extra == "test"
|
|
43
46
|
Dynamic: license-file
|
|
44
47
|
|
|
45
48
|
# Satellite Toolkit (satkit)
|
|
@@ -48,7 +51,7 @@ Dynamic: license-file
|
|
|
48
51
|
|
|
49
52
|
Satkit provides robust, high-performance satellite orbital mechanics calculations with a clean, intuitive API. Built from the ground up in Rust for maximum performance and memory safety, it offers complete Python bindings for all functionality, making advanced orbital mechanics accessible to both systems programmers and data scientists.
|
|
50
53
|
|
|
51
|
-
-----
|
|
54
|
+
-----
|
|
52
55
|
|
|
53
56
|

|
|
54
57
|

|
|
@@ -62,7 +65,7 @@ Satkit provides robust, high-performance satellite orbital mechanics calculation
|
|
|
62
65
|

|
|
63
66
|

|
|
64
67
|

|
|
65
|
-
|
|
68
|
+
|
|
66
69
|
------
|
|
67
70
|
|
|
68
71
|
## Language Bindings
|
|
@@ -84,7 +87,7 @@ High-precision conversions between multiple reference frames with full support f
|
|
|
84
87
|
- **CIRF** - Celestial Intermediate Reference Frame (IAU-2006 intermediate)
|
|
85
88
|
- **TIRF** - Terrestrial Intermediate Reference Frame (Earth-rotation intermediate)
|
|
86
89
|
- **Geodetic** - Latitude, longitude, altitude with WGS-84 ellipsoid
|
|
87
|
-
|
|
90
|
+
|
|
88
91
|
### Orbit Propagation
|
|
89
92
|
Multiple propagation methods optimized for different accuracy and performance requirements:
|
|
90
93
|
- **Numerical Integration**: High-precision propagation using adaptive Runge-Kutta 9(8) methods with dense output
|
|
@@ -95,27 +98,29 @@ Multiple propagation methods optimized for different accuracy and performance re
|
|
|
95
98
|
- Full AFSPC and improved mode support
|
|
96
99
|
- TLE fitting from high-precision states with drag estimation
|
|
97
100
|
- Batch processing for multiple satellites
|
|
101
|
+
- Support TLE and Orbital Mean-Element Messages
|
|
98
102
|
- **Keplerian**: Fast analytical two-body propagation for preliminary analysis
|
|
99
|
-
|
|
100
|
-
### Force Models
|
|
103
|
+
|
|
104
|
+
### Numerical Integration Force Models
|
|
101
105
|
Comprehensive perturbation modeling for high-fidelity orbit propagation:
|
|
102
106
|
- **Earth Gravity**: Spherical harmonic models up to degree/order 360
|
|
103
107
|
- Multiple models: JGM2, JGM3, EGM96, ITU GRACE16
|
|
104
108
|
- Efficient computation with configurable truncation order
|
|
105
109
|
- Gravity gradient support for state transition matrix
|
|
106
110
|
- **Third-Body Gravity**: Solar and lunar perturbations using JPL ephemerides
|
|
107
|
-
- **Atmospheric Drag**:
|
|
111
|
+
- **Atmospheric Drag**:
|
|
112
|
+
- NRLMSISE-00 density model with space weather integration
|
|
108
113
|
- Automatic space weather data updates (F10.7, Ap index)
|
|
109
114
|
- Configurable ballistic coefficients
|
|
110
115
|
- **Solar Radiation Pressure**: Cannon-ball model with shadow function
|
|
111
|
-
|
|
112
|
-
### Ephemerides
|
|
116
|
+
|
|
117
|
+
### Solar System Ephemerides
|
|
113
118
|
Access to high-precision solar system body positions:
|
|
114
119
|
- **JPL DE440/DE441**: State-of-the-art planetary ephemerides
|
|
115
120
|
- Chebyshev polynomial interpolation for accuracy
|
|
116
121
|
- Support for all major planets, sun, moon, and solar system barycenter
|
|
117
122
|
- **Low-Precision Models**: Fast analytical models for sun and moon when high precision isn't required
|
|
118
|
-
|
|
123
|
+
|
|
119
124
|
### Time Systems
|
|
120
125
|
Comprehensive support for all standard astronomical time scales:
|
|
121
126
|
- **UTC** - Coordinated Universal Time with leap second handling
|
|
@@ -125,7 +130,7 @@ Comprehensive support for all standard astronomical time scales:
|
|
|
125
130
|
- **UT1** - Universal Time with Earth orientation corrections
|
|
126
131
|
- **GPS** - GPS Time
|
|
127
132
|
- Automatic conversion between all time scales with microsecond precision
|
|
128
|
-
|
|
133
|
+
|
|
129
134
|
### Geodetic Utilities
|
|
130
135
|
- **Geodesic Calculations**: Accurate distance and azimuth between ground locations using Vincenty's formulae
|
|
131
136
|
- **Coordinate Conversions**: ITRF ↔ Geodetic ↔ East-North-Up ↔ North-East-Down
|
|
@@ -178,12 +183,12 @@ The library requires external data files for various calculations. These are aut
|
|
|
178
183
|
- DE440/DE441 planetary ephemerides (~100 MB)
|
|
179
184
|
- Provides positions of sun, moon, planets, and solar system barycenter
|
|
180
185
|
- Valid for years 1550-2650 CE
|
|
181
|
-
|
|
186
|
+
|
|
182
187
|
- **Gravity Models** ([ICGEM](http://icgem.gfz-potsdam.de/home))
|
|
183
188
|
- JGM2, JGM3, EGM96, ITU GRACE16 spherical harmonic coefficients
|
|
184
189
|
- International Centre for Global Earth Models standardized format
|
|
185
190
|
- Up to degree/order 360 for high-fidelity propagation
|
|
186
|
-
|
|
191
|
+
|
|
187
192
|
- **IERS Nutation Tables** ([IERS Conventions](https://www.iers.org/IERS/EN/Publications/TechnicalNotes/tn36.html))
|
|
188
193
|
- IAU-2006 nutation series coefficients
|
|
189
194
|
- Required for GCRF ↔ ITRF transformations
|
|
@@ -196,7 +201,7 @@ The library requires external data files for various calculations. These are aut
|
|
|
196
201
|
- Ap geomagnetic index
|
|
197
202
|
- Critical for atmospheric density modeling and drag calculations
|
|
198
203
|
- Updated daily by NOAA Space Weather Prediction Center
|
|
199
|
-
|
|
204
|
+
|
|
200
205
|
- **Earth Orientation Parameters** ([Celestrak](https://celestrak.org/SpaceData/))
|
|
201
206
|
- Polar motion (x, y)
|
|
202
207
|
- UT1-UTC time difference
|
|
@@ -218,15 +223,15 @@ The library includes comprehensive test suites ensuring correctness of calculati
|
|
|
218
223
|
- **JPL Ephemerides**: Validated against JPL-provided test vectors for Chebyshev polynomial interpolation
|
|
219
224
|
- Over 10,000 test cases covering all planets and time ranges
|
|
220
225
|
- Accuracy verified to within JPL's published tolerances (sub-meter precision)
|
|
221
|
-
|
|
226
|
+
|
|
222
227
|
- **SGP4**: Verified using official test vectors from the original C++ distribution
|
|
223
228
|
- All test cases from Vallado's SGP4 implementation
|
|
224
229
|
- Includes edge cases and error conditions
|
|
225
|
-
|
|
230
|
+
|
|
226
231
|
- **Coordinate Transformations**: Cross-validated against multiple reference implementations
|
|
227
232
|
- SOFA library comparisons for IAU-2006 transformations
|
|
228
233
|
- Vallado test cases for GCRF ↔ ITRF conversions
|
|
229
|
-
|
|
234
|
+
|
|
230
235
|
- **Numerical Propagation**: Validated against high-precision commercial tools
|
|
231
236
|
- Orbit fits to GPS SP3 ephemerides
|
|
232
237
|
- Multi-day propagations with sub-meter accuracy
|
|
@@ -266,7 +271,7 @@ pip install satkit
|
|
|
266
271
|
|
|
267
272
|
Pre-built binary wheels are available for:
|
|
268
273
|
- **Windows**: AMD64
|
|
269
|
-
- **macOS**: Intel (x86_64) and Apple Silicon (ARM64)
|
|
274
|
+
- **macOS**: Intel (x86_64) and Apple Silicon (ARM64)
|
|
270
275
|
- **Linux**: x86_64 and ARM64 (aarch64)
|
|
271
276
|
- **Python versions**: 3.8, 3.9, 3.10, 3.11, 3.12, 3.13, 3.14
|
|
272
277
|
|
|
@@ -336,9 +341,9 @@ settings.gravity_order = 8
|
|
|
336
341
|
|
|
337
342
|
# Propagate for 1 day
|
|
338
343
|
result = sk.propagate(
|
|
339
|
-
state0,
|
|
340
|
-
time0,
|
|
341
|
-
|
|
344
|
+
state0,
|
|
345
|
+
time0,
|
|
346
|
+
end=time0 + sk.duration.from_days(1),
|
|
342
347
|
propsettings=settings
|
|
343
348
|
)
|
|
344
349
|
|
|
@@ -375,13 +380,13 @@ use satkit::{Instant, SolarSystem, jplephem};
|
|
|
375
380
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
376
381
|
// Create time instant
|
|
377
382
|
let time = Instant::from_datetime(2024, 1, 1, 0, 0, 0.0)?;
|
|
378
|
-
|
|
383
|
+
|
|
379
384
|
// Get Moon position and velocity in GCRF
|
|
380
385
|
let (pos, vel) = jplephem::geocentric_state(SolarSystem::Moon, &time)?;
|
|
381
|
-
|
|
386
|
+
|
|
382
387
|
println!("Moon position: {:?}", pos);
|
|
383
388
|
println!("Moon velocity: {:?}", vel);
|
|
384
|
-
|
|
389
|
+
|
|
385
390
|
Ok(())
|
|
386
391
|
}
|
|
387
392
|
```
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
Satkit provides robust, high-performance satellite orbital mechanics calculations with a clean, intuitive API. Built from the ground up in Rust for maximum performance and memory safety, it offers complete Python bindings for all functionality, making advanced orbital mechanics accessible to both systems programmers and data scientists.
|
|
6
6
|
|
|
7
|
-
-----
|
|
7
|
+
-----
|
|
8
8
|
|
|
9
9
|

|
|
10
10
|

|
|
@@ -18,7 +18,7 @@ Satkit provides robust, high-performance satellite orbital mechanics calculation
|
|
|
18
18
|

|
|
19
19
|

|
|
20
20
|

|
|
21
|
-
|
|
21
|
+
|
|
22
22
|
------
|
|
23
23
|
|
|
24
24
|
## Language Bindings
|
|
@@ -40,7 +40,7 @@ High-precision conversions between multiple reference frames with full support f
|
|
|
40
40
|
- **CIRF** - Celestial Intermediate Reference Frame (IAU-2006 intermediate)
|
|
41
41
|
- **TIRF** - Terrestrial Intermediate Reference Frame (Earth-rotation intermediate)
|
|
42
42
|
- **Geodetic** - Latitude, longitude, altitude with WGS-84 ellipsoid
|
|
43
|
-
|
|
43
|
+
|
|
44
44
|
### Orbit Propagation
|
|
45
45
|
Multiple propagation methods optimized for different accuracy and performance requirements:
|
|
46
46
|
- **Numerical Integration**: High-precision propagation using adaptive Runge-Kutta 9(8) methods with dense output
|
|
@@ -51,27 +51,29 @@ Multiple propagation methods optimized for different accuracy and performance re
|
|
|
51
51
|
- Full AFSPC and improved mode support
|
|
52
52
|
- TLE fitting from high-precision states with drag estimation
|
|
53
53
|
- Batch processing for multiple satellites
|
|
54
|
+
- Support TLE and Orbital Mean-Element Messages
|
|
54
55
|
- **Keplerian**: Fast analytical two-body propagation for preliminary analysis
|
|
55
|
-
|
|
56
|
-
### Force Models
|
|
56
|
+
|
|
57
|
+
### Numerical Integration Force Models
|
|
57
58
|
Comprehensive perturbation modeling for high-fidelity orbit propagation:
|
|
58
59
|
- **Earth Gravity**: Spherical harmonic models up to degree/order 360
|
|
59
60
|
- Multiple models: JGM2, JGM3, EGM96, ITU GRACE16
|
|
60
61
|
- Efficient computation with configurable truncation order
|
|
61
62
|
- Gravity gradient support for state transition matrix
|
|
62
63
|
- **Third-Body Gravity**: Solar and lunar perturbations using JPL ephemerides
|
|
63
|
-
- **Atmospheric Drag**:
|
|
64
|
+
- **Atmospheric Drag**:
|
|
65
|
+
- NRLMSISE-00 density model with space weather integration
|
|
64
66
|
- Automatic space weather data updates (F10.7, Ap index)
|
|
65
67
|
- Configurable ballistic coefficients
|
|
66
68
|
- **Solar Radiation Pressure**: Cannon-ball model with shadow function
|
|
67
|
-
|
|
68
|
-
### Ephemerides
|
|
69
|
+
|
|
70
|
+
### Solar System Ephemerides
|
|
69
71
|
Access to high-precision solar system body positions:
|
|
70
72
|
- **JPL DE440/DE441**: State-of-the-art planetary ephemerides
|
|
71
73
|
- Chebyshev polynomial interpolation for accuracy
|
|
72
74
|
- Support for all major planets, sun, moon, and solar system barycenter
|
|
73
75
|
- **Low-Precision Models**: Fast analytical models for sun and moon when high precision isn't required
|
|
74
|
-
|
|
76
|
+
|
|
75
77
|
### Time Systems
|
|
76
78
|
Comprehensive support for all standard astronomical time scales:
|
|
77
79
|
- **UTC** - Coordinated Universal Time with leap second handling
|
|
@@ -81,7 +83,7 @@ Comprehensive support for all standard astronomical time scales:
|
|
|
81
83
|
- **UT1** - Universal Time with Earth orientation corrections
|
|
82
84
|
- **GPS** - GPS Time
|
|
83
85
|
- Automatic conversion between all time scales with microsecond precision
|
|
84
|
-
|
|
86
|
+
|
|
85
87
|
### Geodetic Utilities
|
|
86
88
|
- **Geodesic Calculations**: Accurate distance and azimuth between ground locations using Vincenty's formulae
|
|
87
89
|
- **Coordinate Conversions**: ITRF ↔ Geodetic ↔ East-North-Up ↔ North-East-Down
|
|
@@ -134,12 +136,12 @@ The library requires external data files for various calculations. These are aut
|
|
|
134
136
|
- DE440/DE441 planetary ephemerides (~100 MB)
|
|
135
137
|
- Provides positions of sun, moon, planets, and solar system barycenter
|
|
136
138
|
- Valid for years 1550-2650 CE
|
|
137
|
-
|
|
139
|
+
|
|
138
140
|
- **Gravity Models** ([ICGEM](http://icgem.gfz-potsdam.de/home))
|
|
139
141
|
- JGM2, JGM3, EGM96, ITU GRACE16 spherical harmonic coefficients
|
|
140
142
|
- International Centre for Global Earth Models standardized format
|
|
141
143
|
- Up to degree/order 360 for high-fidelity propagation
|
|
142
|
-
|
|
144
|
+
|
|
143
145
|
- **IERS Nutation Tables** ([IERS Conventions](https://www.iers.org/IERS/EN/Publications/TechnicalNotes/tn36.html))
|
|
144
146
|
- IAU-2006 nutation series coefficients
|
|
145
147
|
- Required for GCRF ↔ ITRF transformations
|
|
@@ -152,7 +154,7 @@ The library requires external data files for various calculations. These are aut
|
|
|
152
154
|
- Ap geomagnetic index
|
|
153
155
|
- Critical for atmospheric density modeling and drag calculations
|
|
154
156
|
- Updated daily by NOAA Space Weather Prediction Center
|
|
155
|
-
|
|
157
|
+
|
|
156
158
|
- **Earth Orientation Parameters** ([Celestrak](https://celestrak.org/SpaceData/))
|
|
157
159
|
- Polar motion (x, y)
|
|
158
160
|
- UT1-UTC time difference
|
|
@@ -174,15 +176,15 @@ The library includes comprehensive test suites ensuring correctness of calculati
|
|
|
174
176
|
- **JPL Ephemerides**: Validated against JPL-provided test vectors for Chebyshev polynomial interpolation
|
|
175
177
|
- Over 10,000 test cases covering all planets and time ranges
|
|
176
178
|
- Accuracy verified to within JPL's published tolerances (sub-meter precision)
|
|
177
|
-
|
|
179
|
+
|
|
178
180
|
- **SGP4**: Verified using official test vectors from the original C++ distribution
|
|
179
181
|
- All test cases from Vallado's SGP4 implementation
|
|
180
182
|
- Includes edge cases and error conditions
|
|
181
|
-
|
|
183
|
+
|
|
182
184
|
- **Coordinate Transformations**: Cross-validated against multiple reference implementations
|
|
183
185
|
- SOFA library comparisons for IAU-2006 transformations
|
|
184
186
|
- Vallado test cases for GCRF ↔ ITRF conversions
|
|
185
|
-
|
|
187
|
+
|
|
186
188
|
- **Numerical Propagation**: Validated against high-precision commercial tools
|
|
187
189
|
- Orbit fits to GPS SP3 ephemerides
|
|
188
190
|
- Multi-day propagations with sub-meter accuracy
|
|
@@ -222,7 +224,7 @@ pip install satkit
|
|
|
222
224
|
|
|
223
225
|
Pre-built binary wheels are available for:
|
|
224
226
|
- **Windows**: AMD64
|
|
225
|
-
- **macOS**: Intel (x86_64) and Apple Silicon (ARM64)
|
|
227
|
+
- **macOS**: Intel (x86_64) and Apple Silicon (ARM64)
|
|
226
228
|
- **Linux**: x86_64 and ARM64 (aarch64)
|
|
227
229
|
- **Python versions**: 3.8, 3.9, 3.10, 3.11, 3.12, 3.13, 3.14
|
|
228
230
|
|
|
@@ -292,9 +294,9 @@ settings.gravity_order = 8
|
|
|
292
294
|
|
|
293
295
|
# Propagate for 1 day
|
|
294
296
|
result = sk.propagate(
|
|
295
|
-
state0,
|
|
296
|
-
time0,
|
|
297
|
-
|
|
297
|
+
state0,
|
|
298
|
+
time0,
|
|
299
|
+
end=time0 + sk.duration.from_days(1),
|
|
298
300
|
propsettings=settings
|
|
299
301
|
)
|
|
300
302
|
|
|
@@ -331,13 +333,13 @@ use satkit::{Instant, SolarSystem, jplephem};
|
|
|
331
333
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
332
334
|
// Create time instant
|
|
333
335
|
let time = Instant::from_datetime(2024, 1, 1, 0, 0, 0.0)?;
|
|
334
|
-
|
|
336
|
+
|
|
335
337
|
// Get Moon position and velocity in GCRF
|
|
336
338
|
let (pos, vel) = jplephem::geocentric_state(SolarSystem::Moon, &time)?;
|
|
337
|
-
|
|
339
|
+
|
|
338
340
|
println!("Moon position: {:?}", pos);
|
|
339
341
|
println!("Moon velocity: {:?}", vel);
|
|
340
|
-
|
|
342
|
+
|
|
341
343
|
Ok(())
|
|
342
344
|
}
|
|
343
345
|
```
|
|
@@ -9,7 +9,7 @@ requires-python = ">= 3.8"
|
|
|
9
9
|
authors = [{ name = "Steven Michael", email = "ssmichael@gmail.com" }]
|
|
10
10
|
maintainers = [{ name = "Steven Michael", email = "ssmichael@gmail.com" }]
|
|
11
11
|
readme = "README.md"
|
|
12
|
-
version = "0.
|
|
12
|
+
version = "0.9.0"
|
|
13
13
|
license = { file = "LICENSE" }
|
|
14
14
|
description = "Satellite Orbital Dynamics Toolkit"
|
|
15
15
|
keywords = [
|
|
@@ -37,6 +37,8 @@ classifiers = [
|
|
|
37
37
|
"Programming Language :: Python :: 3.13",
|
|
38
38
|
"Programming Language :: Python :: 3.14",
|
|
39
39
|
]
|
|
40
|
+
[project.optional-dependencies]
|
|
41
|
+
test = ["pytest", "xmltodict"]
|
|
40
42
|
|
|
41
43
|
|
|
42
44
|
[tool.setuptools.packages.find]
|
|
@@ -69,7 +71,7 @@ before-build = [
|
|
|
69
71
|
]
|
|
70
72
|
environment = { PATH = "$PATH:$HOME/.cargo/bin", MACOSX_DEPLOYMENT_TARGET = "10.12" }
|
|
71
73
|
# Skip trying to test arm64 builds on Intel Macs
|
|
72
|
-
test-requires = "pytest"
|
|
74
|
+
test-requires = "pytest xmltodict"
|
|
73
75
|
test-command = [
|
|
74
76
|
"SATKIT_DATA={package}/astro-data SATKIT_TESTVEC_ROOT={package}/satkit-testvecs pytest {project}/python/test/test.py",
|
|
75
77
|
]
|
|
@@ -83,7 +85,7 @@ before-build = [
|
|
|
83
85
|
"curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain=stable --profile=minimal -y",
|
|
84
86
|
"rustup show",
|
|
85
87
|
]
|
|
86
|
-
test-requires = "pytest"
|
|
88
|
+
test-requires = "pytest xmltodict"
|
|
87
89
|
test-command = [
|
|
88
90
|
"SATKIT_DATA={package}/astro-data SATKIT_TESTVEC_ROOT={package}/satkit-testvecs pytest {project}/python/test/test.py",
|
|
89
91
|
]
|
|
@@ -98,7 +100,7 @@ before-build = [
|
|
|
98
100
|
"rustup override set stable-x86_64-pc-windows-msvc",
|
|
99
101
|
"rustup show",
|
|
100
102
|
]
|
|
101
|
-
test-requires = "pytest"
|
|
103
|
+
test-requires = "pytest xmltodict"
|
|
102
104
|
before-test = [
|
|
103
105
|
"set SATKIT_DATA={package}\\astro-data",
|
|
104
106
|
"set SATKIT_TESTVEC_ROOT={package}\\satkit-testvecs",
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# SGP4, Two-Line Element Sets (TLEs), and Orbital Mean-Element Messages (OMMs)
|
|
2
|
+
|
|
3
|
+
## Satellite Catalog
|
|
4
|
+
|
|
5
|
+
The United States maintains a public catalog of Earth-orbiting objects, including active satellites, rocket bodies, and debris.
|
|
6
|
+
|
|
7
|
+
There are multiple places to access the catalog, including:
|
|
8
|
+
* <https://www.celestrak.org/>
|
|
9
|
+
* <https://www.space-track.org/>
|
|
10
|
+
|
|
11
|
+
## SGP4
|
|
12
|
+
|
|
13
|
+
**SGP4 (Simplified General Perturbations No. 4)** is an analytical orbital propagation model created in the **1960s–1970s by NORAD** to efficiently predict the motion of **Earth-orbiting satellites** from **Two-Line Element (TLE)** data.
|
|
14
|
+
|
|
15
|
+
It was developed to support U.S. space surveillance as a fast, closed-form alternative to numerical integration, modeling Earth’s oblateness (J2–J4), atmospheric drag via the TLE *B\** term, and key secular and periodic perturbations.
|
|
16
|
+
|
|
17
|
+
Today, SGP4 is the standard propagator for TLEs published by organizations like NORAD and CelesTrak, and is widely used for satellite tracking, visualization, conjunction screening, and mission planning—though its accuracy is fundamentally limited by TLE quality and simplifying assumptions.
|
|
18
|
+
|
|
19
|
+
## Ephemeris Representation
|
|
20
|
+
|
|
21
|
+
### TLE
|
|
22
|
+
A **Two-Line Element Set (TLE)** is a compact, legacy format (originally constrained by punch-card era line lengths) for describing satellite orbits. Despite its age, it remains widely used because it is easy to publish and often provides sufficient accuracy for many applications.
|
|
23
|
+
|
|
24
|
+
In addition to the familiar (mean) Keplerian elements, TLEs include parameters related to perturbations (e.g., atmospheric drag via $B^*$, and derivatives of mean motion).
|
|
25
|
+
|
|
26
|
+
TLEs are designed to be used with **SGP4**, an analytic model that produces orbital state vectors (position and velocity) from the augmented mean elements in the TLE. The perturbations modeled include Earth oblateness (which produces precession) and drag.
|
|
27
|
+
|
|
28
|
+
TLEs are often preceded by an additional “line 0” containing the satellite name. For an overview, see <https://en.wikipedia.org/wiki/Two-line_element_set>.
|
|
29
|
+
|
|
30
|
+
### Orbital Mean-Element Messages
|
|
31
|
+
**Orbital Mean-Element Messages (OMMs)** are a more modern way of representing mean-element ephemerides. They are described by a CCSDS standard (<https://ccsds.org/Pubs/502x0b3e1.pdf>), although real-world sources may not adhere to the standard perfectly.
|
|
32
|
+
|
|
33
|
+
OMMs are commonly published as:
|
|
34
|
+
* JSON
|
|
35
|
+
* XML
|
|
36
|
+
* KVN (key–value notation)
|
|
37
|
+
|
|
38
|
+
The satkit Python interface does not load OMM files directly. Instead, it expects you to provide the decoded OMM as a Python `dict` (for example, parsed from JSON or XML). The interface supports OMM dictionary layouts produced by CelesTrak and Space-Track.
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
## Example Usage
|
|
44
|
+
|
|
45
|
+
### SGP4 state computation from TLE
|
|
46
|
+
|
|
47
|
+
```python
|
|
48
|
+
import satkit as sk
|
|
49
|
+
|
|
50
|
+
# The two-line element set
|
|
51
|
+
# Let's pick a random Starlink satellite
|
|
52
|
+
# The lines below were downloaded from https://www.celestrak.org
|
|
53
|
+
tle_lines = [
|
|
54
|
+
'0 STARLINK-30477',
|
|
55
|
+
'1 57912U 23146X 24099.49439401 .00006757 00000+0 51475-3 0 9997',
|
|
56
|
+
'2 57912 43.0018 157.5807 0001420 272.5369 87.5310 15.02537576 31746'
|
|
57
|
+
]
|
|
58
|
+
|
|
59
|
+
# Create a TLE object
|
|
60
|
+
starlink30477 = sk.TLE.from_lines(tle_lines)
|
|
61
|
+
|
|
62
|
+
# We want the orbital state at April 9 2024, 12:00pm UTC
|
|
63
|
+
thetime = sk.time(2024, 4, 9, 12, 0, 0)
|
|
64
|
+
|
|
65
|
+
# The state is output in the "TEME" frame, which is an approximate inertial
|
|
66
|
+
# frame that does not include precession or nutation
|
|
67
|
+
# pTEME is geocentric position in meters
|
|
68
|
+
# vTEME is geocentric velocity in meters / second
|
|
69
|
+
# for now we will ignore the velocity
|
|
70
|
+
pTEME, _vTEME = sk.sgp4(starlink30477, thetime)
|
|
71
|
+
|
|
72
|
+
# Suppose we want currrent latitude, longitude, and altitude of satellite:
|
|
73
|
+
# we need to rotate into an Earth-fixed frame, the ITRF
|
|
74
|
+
# We use a "quaternion" to represent the rotation. Quaternion rotations
|
|
75
|
+
# in the satkit toolbox can be represented as multiplications of a 3-vector
|
|
76
|
+
pITRF = sk.frametransform.qteme2itrf(thetime) * pTEME
|
|
77
|
+
|
|
78
|
+
# Now lets make a "ITRFCoord" object to extract geodetic coordinates
|
|
79
|
+
coord = sk.itrfcoord(pITRF)
|
|
80
|
+
|
|
81
|
+
# Get the latitude, longitude, and
|
|
82
|
+
# altitude (height above ellipsoid, or hae) of the satellite
|
|
83
|
+
print(coord)
|
|
84
|
+
|
|
85
|
+
# this should produce:
|
|
86
|
+
# ITRFCoord(lat: 29.3890 deg, lon: 170.8051 deg, hae: 560.11 km)
|
|
87
|
+
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### SGP4 State Computation from OMM representation of International Space Station (ISS)
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
|
|
94
|
+
import satkit as sk
|
|
95
|
+
import requests
|
|
96
|
+
import json
|
|
97
|
+
|
|
98
|
+
# Query the current ephemeris for the International Space Station (ISS)
|
|
99
|
+
# from celestrak.org
|
|
100
|
+
url = 'https://celestrak.org/NORAD/elements/gp.php?CATNR=25544&FORMAT=json'
|
|
101
|
+
with requests.get(url) as response:
|
|
102
|
+
omm = response.json()
|
|
103
|
+
|
|
104
|
+
# Get a representative time from the output
|
|
105
|
+
epoch = sk.time(omm[0]['EPOCH'])
|
|
106
|
+
# create a list of times .. once every 10 minutes
|
|
107
|
+
time_array = [epoch + sk.duration(minutes=i*10) for i in range(6)]
|
|
108
|
+
|
|
109
|
+
# TEME (inertial) output from SGP4
|
|
110
|
+
pTEME, _vTEME = sk.sgp4(omm[0], time_array)
|
|
111
|
+
|
|
112
|
+
# Rotate to Earth-fixed
|
|
113
|
+
pITRF = [sk.frametransform.qteme2itrf(t) * p for t, p in zip(time_array, pTEME)]
|
|
114
|
+
|
|
115
|
+
# Geodetic coordinates of space station at given times
|
|
116
|
+
coord = [sk.itrfcoord(x) for x in pITRF]
|
|
117
|
+
|
|
118
|
+
```
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"# Project the moon to the surface of the Earth along the Sun vector\n",
|
|
45
45
|
"# This is projecting onto the surface of a sphere. However, the Earth is actually\n",
|
|
46
46
|
"# an oblate spheroid. We can account for this by scaling the z axis by the flattening\n",
|
|
47
|
-
"# of the Earth
|
|
47
|
+
"# of the Earth.\n",
|
|
48
48
|
"scalefac = 1.0 / (1.0 - sk.consts.wgs84_f)\n",
|
|
49
49
|
"moon_itrf_scaled = moon_itrf\n",
|
|
50
50
|
"moon_itrf_scaled[:,2] = moon_itrf_scaled[:,2] * scalefac\n",
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"# via the law of Cosines and the quadratic equation\n",
|
|
57
57
|
"lcostheta = np.sum(sun_itrf_scaled_hat * moon_itrf_scaled, axis=1)\n",
|
|
58
58
|
"sqrtterm = lcostheta**2 - np.sum(moon_itrf_scaled**2, axis=1) + sk.consts.earth_radius**2\n",
|
|
59
|
-
"# Valid indices (where the projection hits the earth) are where the term under
|
|
59
|
+
"# Valid indices (where the projection hits the earth) are where the term under\n",
|
|
60
60
|
"# the square root is positive\n",
|
|
61
61
|
"vidx = np.argwhere(sqrtterm > 0).flatten()\n",
|
|
62
62
|
"\n",
|
|
@@ -171,13 +171,13 @@
|
|
|
171
171
|
"\n",
|
|
172
172
|
" if len(eidx) > 0:\n",
|
|
173
173
|
" data[\"total\"] = {\n",
|
|
174
|
-
" \"
|
|
175
|
-
" \"
|
|
174
|
+
" \"begin\": timearr[eidx[0][0]].datetime(), # type: ignore\n",
|
|
175
|
+
" \"end\": timearr[eidx[-1][0]].datetime(), # type: ignore\n",
|
|
176
176
|
" \"duration_seconds\": (timearr[eidx[-1][0]] - timearr[eidx[0][0]]).seconds, # type: ignore\n",
|
|
177
177
|
" }\n",
|
|
178
178
|
" data[\"partial\"] = {\n",
|
|
179
|
-
" \"
|
|
180
|
-
" \"
|
|
179
|
+
" \"begin\": timearr[pidx[0][0]].datetime(),\n",
|
|
180
|
+
" \"end\": timearr[pidx[-1][0]].datetime(),\n",
|
|
181
181
|
" \"duration_seconds\": (timearr[pidx[-1][0]] - timearr[pidx[0][0]]).seconds, # type: ignore\n",
|
|
182
182
|
" \"peak\": None,\n",
|
|
183
183
|
" \"minangle_deg\": None,\n",
|
|
@@ -208,10 +208,10 @@
|
|
|
208
208
|
" max_frac_diam_occluded = 1 - (sun_extent_rad + mintheta - moon_extent_rad) / (\n",
|
|
209
209
|
" 2 * sun_extent_rad\n",
|
|
210
210
|
" )\n",
|
|
211
|
-
"
|
|
211
|
+
"\n",
|
|
212
212
|
" data[\"partial\"] = {\n",
|
|
213
|
-
" \"
|
|
214
|
-
" \"
|
|
213
|
+
" \"begin\": timearr[pidx[0][0]].datetime(), # type: ignore\n",
|
|
214
|
+
" \"end\": timearr[pidx[-1][0]].datetime(), # type: ignore\n",
|
|
215
215
|
" \"peak\": timearr[idx].datetime(), # type: ignore\n",
|
|
216
216
|
" \"duration_seconds\": (timearr[pidx[-1][0]] - timearr[pidx[0][0]]).seconds, # type: ignore\n",
|
|
217
217
|
" \"minangle_deg\": np.min(theta) * 180.0 / m.pi,\n",
|
|
@@ -266,11 +266,11 @@
|
|
|
266
266
|
" [\n",
|
|
267
267
|
" {\n",
|
|
268
268
|
" \"Location\": loc[\"name\"],\n",
|
|
269
|
-
" \"Total Eclipse
|
|
270
|
-
" \"Total Eclipse
|
|
269
|
+
" \"Total Eclipse Begin\": loc[\"stats\"][\"total\"][\"begin\"] if loc[\"stats\"][\"total\"] else None,\n",
|
|
270
|
+
" \"Total Eclipse End\": loc[\"stats\"][\"total\"][\"end\"] if loc[\"stats\"][\"total\"] else None,\n",
|
|
271
271
|
" \"Total Eclipse Duration (s)\": loc[\"stats\"][\"total\"][\"duration_seconds\"] if loc[\"stats\"][\"total\"] else None,\n",
|
|
272
|
-
" \"Partial Eclipse
|
|
273
|
-
" \"Partial Eclipse
|
|
272
|
+
" \"Partial Eclipse Begin\": loc[\"stats\"][\"partial\"][\"begin\"] if loc[\"stats\"][\"partial\"] else None,\n",
|
|
273
|
+
" \"Partial Eclipse End\": loc[\"stats\"][\"partial\"][\"end\"] if loc[\"stats\"][\"partial\"] else None,\n",
|
|
274
274
|
" \"Partial Eclipse Peak\": loc[\"stats\"][\"partial\"][\"peak\"] if loc[\"stats\"][\"partial\"] else None,\n",
|
|
275
275
|
" \"Partial Eclipse Duration (s)\": loc[\"stats\"][\"partial\"][\"duration_seconds\"] if loc[\"stats\"][\"partial\"] else None,\n",
|
|
276
276
|
" \"Min Seperation (deg)\": loc[\"stats\"][\"partial\"][\"minangle_deg\"] if loc[\"stats\"][\"partial\"] else None,\n",
|
|
@@ -280,10 +280,10 @@
|
|
|
280
280
|
" for loc in locations\n",
|
|
281
281
|
" ]\n",
|
|
282
282
|
")\n",
|
|
283
|
-
"df.style.format({\"Total Eclipse
|
|
284
|
-
" \"Total Eclipse
|
|
285
|
-
" \"Partial Eclipse
|
|
286
|
-
" \"Partial Eclipse
|
|
283
|
+
"df.style.format({\"Total Eclipse Begin\": lambda x: x.strftime(\"%H:%M:%S\") if not pd.isnull(x) else 'N/A',\n",
|
|
284
|
+
" \"Total Eclipse End\": lambda x: x.strftime(\"%H:%M:%S\") if not pd.isnull(x) else 'N/A',\n",
|
|
285
|
+
" \"Partial Eclipse Begin\": lambda x: x.strftime(\"%H:%M:%S\") if not pd.isnull(x) else 'N/A',\n",
|
|
286
|
+
" \"Partial Eclipse End\": lambda x: x.strftime(\"%H:%M:%S\") if not pd.isnull(x) else 'N/A',\n",
|
|
287
287
|
" \"Partial Eclipse Peak\": lambda x: x.strftime(\"%H:%M:%S\") if not pd.isnull(x) else 'N/A',\n",
|
|
288
288
|
" \"Total Eclipse Duration (s)\": lambda x: f\"{x:.0f}\" if not pd.isnull(x) else 'N/A',\n",
|
|
289
289
|
" \"Partial Eclipse Duration (s)\": lambda x: f\"{x:.0f}\" if not pd.isnull(x) else 'N/A',\n",
|
|
@@ -136,8 +136,8 @@
|
|
|
136
136
|
"\n",
|
|
137
137
|
" res = sk.propagate(\n",
|
|
138
138
|
" np.concatenate((pgcrf[0, :], v[0:3])),\n",
|
|
139
|
-
"
|
|
140
|
-
"
|
|
139
|
+
" begin=tstart,\n",
|
|
140
|
+
" end=tend,\n",
|
|
141
141
|
" propsettings=settings,\n",
|
|
142
142
|
" satproperties=satprops,\n",
|
|
143
143
|
" )\n",
|
|
@@ -157,8 +157,8 @@
|
|
|
157
157
|
"satprops = sk.satproperties_static(craoverm = r.x[3])\n",
|
|
158
158
|
"res = sk.propagate(\n",
|
|
159
159
|
" np.concatenate((pgcrf[0, :], r.x[0:3])),\n",
|
|
160
|
-
"
|
|
161
|
-
"
|
|
160
|
+
" begin=timearr[0],\n",
|
|
161
|
+
" end=timearr[-1],\n",
|
|
162
162
|
" propsettings=settings,\n",
|
|
163
163
|
" satproperties=satprops,\n",
|
|
164
164
|
")\n",
|