satkit 0.3.0__tar.gz → 0.3.1__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.3.0 → satkit-0.3.1}/Cargo.toml +6 -6
- {satkit-0.3.0/python/satkit.egg-info → satkit-0.3.1}/PKG-INFO +1 -1
- {satkit-0.3.0 → satkit-0.3.1}/pyproject.toml +1 -1
- {satkit-0.3.0 → satkit-0.3.1}/python/satkit/satkit.pyi +1 -1
- {satkit-0.3.0 → satkit-0.3.1}/python/satkit/satprop.pyi +3 -5
- {satkit-0.3.0 → satkit-0.3.1}/python/satkit/utils.pyi +1 -1
- {satkit-0.3.0 → satkit-0.3.1/python/satkit.egg-info}/PKG-INFO +1 -1
- {satkit-0.3.0 → satkit-0.3.1}/python/test/orbitprop_gps_fit.py +33 -27
- {satkit-0.3.0 → satkit-0.3.1}/python/test/test.py +11 -5
- {satkit-0.3.0 → satkit-0.3.1}/src/earthgravity.rs +99 -3
- {satkit-0.3.0 → satkit-0.3.1}/src/ode/rk_adaptive.rs +19 -5
- {satkit-0.3.0 → satkit-0.3.1}/src/ode/rkv87.rs +2 -2
- {satkit-0.3.0 → satkit-0.3.1}/src/ode/rkv98.rs +2 -2
- {satkit-0.3.0 → satkit-0.3.1}/src/orbitprop/propagator.rs +9 -4
- {satkit-0.3.0 → satkit-0.3.1}/src/pybindings/pypropagate.rs +0 -1
- {satkit-0.3.0 → satkit-0.3.1}/src/pybindings/pysgp4.rs +18 -12
- {satkit-0.3.0 → satkit-0.3.1}/LICENSE +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/MANIFEST.in +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/README.md +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/python/docs/source/conf.py +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/python/satkit/__init__.py +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/python/satkit/__init__.pyi +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/python/satkit/density.pyi +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/python/satkit/frametransform.pyi +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/python/satkit/jplephem.pyi +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/python/satkit/moon.pyi +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/python/satkit/planets.pyi +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/python/satkit/py.typed +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/python/satkit/sun.pyi +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/python/satkit.egg-info/SOURCES.txt +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/python/satkit.egg-info/dependency_links.txt +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/python/satkit.egg-info/requires.txt +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/python/satkit.egg-info/top_level.txt +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/python/test/download_data.py +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/python/test/download_from_json.py +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/python/test/download_testvecs.py +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/python/test/sp3file.py +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/setup.cfg +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/astrotime.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/consts.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/duration.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/earth_orientation_params.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/frames.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/frametransform/ierstable.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/frametransform/mod.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/frametransform/qcirs2gcrs.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/itrfcoord.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/jplephem.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/kepler.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/lib.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/lpephem/mod.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/lpephem/moon.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/lpephem/planets.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/lpephem/sun.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/nrlmsise.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/ode/harmonic_oscillator.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/ode/mod.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/ode/nalgebra.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/ode/rk_adaptive_settings.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/ode/rk_explicit.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/ode/rkf45.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/ode/rkts54.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/ode/rkv65.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/ode/rkv65_table.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/ode/rkv87_table.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/ode/rkv98_nointerp.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/ode/rkv98_nointerp_table.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/ode/rkv98_table.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/ode/types.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/orbitprop/drag.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/orbitprop/mod.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/orbitprop/point_gravity.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/orbitprop/satproperties.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/orbitprop/satstate.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/orbitprop/settings.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/pybindings/mod.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/pybindings/mod_utils.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/pybindings/pyastrotime.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/pybindings/pyconsts.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/pybindings/pydensity.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/pybindings/pyduration.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/pybindings/pyframes.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/pybindings/pyframetransform.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/pybindings/pygravity.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/pybindings/pyitrfcoord.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/pybindings/pyjplephem.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/pybindings/pykepler.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/pybindings/pylpephem_moon.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/pybindings/pylpephem_planets.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/pybindings/pylpephem_sun.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/pybindings/pynrlmsise.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/pybindings/pypropresult.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/pybindings/pypropsettings.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/pybindings/pyquaternion.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/pybindings/pysatproperties.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/pybindings/pysatstate.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/pybindings/pysolarsystem.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/pybindings/pytle.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/pybindings/pyutils.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/sgp4/dpper.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/sgp4/dscom.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/sgp4/dsinit.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/sgp4/dspace.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/sgp4/getgravconst.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/sgp4/initl.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/sgp4/mod.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/sgp4/satrec.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/sgp4/sgp4.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/sgp4/sgp4_lowlevel.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/sgp4/sgp4init.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/solarsystem.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/spaceweather.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/tle.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/types.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/utils/datadir.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/utils/download.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/utils/mod.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/utils/skerror.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/utils/test.rs +0 -0
- {satkit-0.3.0 → satkit-0.3.1}/src/utils/update_data.rs +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "satkit"
|
|
3
|
-
version = "0.3.
|
|
3
|
+
version = "0.3.1"
|
|
4
4
|
edition = "2021"
|
|
5
5
|
description = "Satellite Toolkit"
|
|
6
6
|
readme = "README.md"
|
|
@@ -21,22 +21,22 @@ name = "satkit"
|
|
|
21
21
|
|
|
22
22
|
[dependencies]
|
|
23
23
|
nalgebra = "0.33.0"
|
|
24
|
-
ndarray = "0.15.
|
|
25
|
-
libc = "0.2"
|
|
24
|
+
ndarray = "0.15.4"
|
|
25
|
+
libc = "0.2.158"
|
|
26
26
|
chrono = "0.4.19"
|
|
27
27
|
cty = "0.2.2"
|
|
28
28
|
num-traits = "0.2"
|
|
29
|
-
thiserror = "1.0"
|
|
29
|
+
thiserror = "1.0.63"
|
|
30
30
|
simba = "0.9"
|
|
31
31
|
once_cell = "1.6.0"
|
|
32
32
|
numpy = { version = "0.21.0", optional = true }
|
|
33
33
|
pyo3 = { version = "0.21", features = ["extension-module"], optional = true }
|
|
34
|
-
ureq = "2.
|
|
34
|
+
ureq = "2.10.1"
|
|
35
35
|
json = "0.12.4"
|
|
36
36
|
process_path = "0.1.4"
|
|
37
37
|
|
|
38
38
|
[build-dependencies]
|
|
39
|
-
cc = { version = "1.
|
|
39
|
+
cc = { version = "1.1.15", features = ["parallel"] }
|
|
40
40
|
chrono = "0.4.38"
|
|
41
41
|
pyo3-build-config = { version = "0.21", optional = true }
|
|
42
42
|
|
|
@@ -1490,7 +1490,7 @@ class satstate:
|
|
|
1490
1490
|
Args:
|
|
1491
1491
|
time (satkit.time|satkit.duration): Time or duration from current time to which to propagate the state
|
|
1492
1492
|
|
|
1493
|
-
Keyword
|
|
1493
|
+
Keyword Args:
|
|
1494
1494
|
propsettings: satkit.satprop.propsettings object describing settings to use in the propagation. If omitted, default is used
|
|
1495
1495
|
|
|
1496
1496
|
Returns:
|
|
@@ -228,17 +228,15 @@ def propagate(
|
|
|
228
228
|
vel (npt.ArrayLike[float]): 3-element numpy array representing satellite GCRF velocity in m/s
|
|
229
229
|
tm (satkit.time): satkit.time object representing instant at which satellite is at "pos" & "vel"
|
|
230
230
|
|
|
231
|
-
Keyword
|
|
231
|
+
Keyword Args:
|
|
232
232
|
stop_time (satkit.time): satkit.time object representing instant at which new position and velocity will be computed
|
|
233
233
|
duration_secs (float): duration in seconds from "tm" for at which new position and velocity will be computed.
|
|
234
234
|
duration_days (float): duration in days from "tm" at which new position and velocity will be computed.
|
|
235
235
|
duration (satkit.duration): duration from "tm" at which new position & velocity will be computed.
|
|
236
236
|
output_phi (bool): Output 6x6 state transition matrix between "starttime" and "stoptime" (and at intervals, if specified)
|
|
237
237
|
propsettings (propsettings): "propsettings" object with input settings for the propagation. if left out, default will be used.
|
|
238
|
-
satproperties (satproperties_static): "SatPropertiesStatic" object with drag and radiation pressure succeptibility of satellite.
|
|
239
|
-
|
|
240
|
-
output_dense: boolean indicting whether or not dense output should be recorded. Default is false. If true, this will allow for calling the "interp" function
|
|
241
|
-
to query states at arbitrary times between the start time and the stop time
|
|
238
|
+
satproperties (satproperties_static): "SatPropertiesStatic" object with drag and radiation pressure succeptibility of satellite. If left out, drag and radiation pressure are neglected
|
|
239
|
+
output_dense: boolean indicting whether or not dense output should be recorded. Default is false. If true, this will allow for calling the "interp" function to query states at arbitrary times between the start time and the stop time
|
|
242
240
|
|
|
243
241
|
Returns:
|
|
244
242
|
(propresult): Propagation result object holding state outputs, statistics, and dense output if requested
|
|
@@ -12,7 +12,7 @@ import satkit
|
|
|
12
12
|
def update_datafiles(**kwargs):
|
|
13
13
|
"""Download & store data files needed for "satkit" computations
|
|
14
14
|
|
|
15
|
-
Keyword
|
|
15
|
+
Keyword Args:
|
|
16
16
|
|
|
17
17
|
overwrite (bool): Download and overwrite files if they already exist
|
|
18
18
|
dir(string): Target directory for files. Uses existing data directory if not specified. (see "datadir" function)
|
|
@@ -25,26 +25,20 @@ import os
|
|
|
25
25
|
basedir = os.getenv(
|
|
26
26
|
"SATKIT_TESTVEC_ROOT", default="../.." + os.path.sep + "satkit-testvecs"
|
|
27
27
|
)
|
|
28
|
+
fname = (
|
|
29
|
+
basedir + os.path.sep + "orbitprop" + os.path.sep
|
|
30
|
+
+ "ESA0OPSFIN_20233640000_01D_05M_ORB.SP3"
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
[pitrf, timearr] = read_sp3file(fname)
|
|
34
|
+
pgcrf = np.stack(
|
|
35
|
+
np.fromiter(
|
|
36
|
+
(q * p for q, p in zip(sk.frametransform.qitrf2gcrf(timearr), pitrf)),
|
|
37
|
+
list,
|
|
38
|
+
),
|
|
39
|
+
axis=0,
|
|
40
|
+
)
|
|
28
41
|
|
|
29
|
-
sp3names = ['mid22630.sp3', 'mid22631.sp3', 'mid22632.sp3',
|
|
30
|
-
'mid22633.sp3', 'mid22634.sp3', 'mid22635.sp3',
|
|
31
|
-
'mid22636.sp3']
|
|
32
|
-
|
|
33
|
-
sp3names = ['mid22630.sp3', 'mid22631.sp3', 'mid22632.sp3']
|
|
34
|
-
pitrf = np.zeros((0,3), np.float64)
|
|
35
|
-
timearr = np.array([])
|
|
36
|
-
|
|
37
|
-
for sp3name in sp3names:
|
|
38
|
-
fname = (
|
|
39
|
-
basedir
|
|
40
|
-
+ os.path.sep
|
|
41
|
-
+ "orbitprop"
|
|
42
|
-
+ os.path.sep
|
|
43
|
-
+ sp3name
|
|
44
|
-
)
|
|
45
|
-
[pitrf1, timearray1] = read_sp3file(fname)
|
|
46
|
-
pitrf = np.append(pitrf, pitrf1, axis=0)
|
|
47
|
-
timearr = np.append(timearr, timearray1)
|
|
48
42
|
|
|
49
43
|
print(pitrf.shape)
|
|
50
44
|
print(timearr.shape)
|
|
@@ -62,14 +56,15 @@ vgcrf = (pgcrf[1, :] - pgcrf[0, :]) / (timearr[1] - timearr[0]).seconds()
|
|
|
62
56
|
|
|
63
57
|
# Initial state for non-linear least squares is initial velocity
|
|
64
58
|
# and susceptibility to radiation pressuer : Cr A / m
|
|
65
|
-
v0 = np.array([vgcrf[0], vgcrf[1], vgcrf[2], 0.
|
|
66
|
-
|
|
59
|
+
#v0 = np.array([vgcrf[0], vgcrf[1], vgcrf[2], 0.02])
|
|
60
|
+
v0 = np.array([2.47130555e03, 2.94682777e03, -5.34171918e02, 2.13018578e-02])
|
|
67
61
|
|
|
68
62
|
def minfunc(v):
|
|
69
63
|
tstart = timearr[0]
|
|
70
64
|
tend = timearr[-1]
|
|
71
65
|
settings = sk.satprop.propsettings()
|
|
72
66
|
settings.use_jplephem = False
|
|
67
|
+
settings.gravity_order = 10
|
|
73
68
|
satprops = sk.satprop.satproperties_static()
|
|
74
69
|
satprops.craoverm = v[3]
|
|
75
70
|
|
|
@@ -78,12 +73,15 @@ def minfunc(v):
|
|
|
78
73
|
v[0:3],
|
|
79
74
|
tstart,
|
|
80
75
|
stoptime=tend,
|
|
81
|
-
dt=sk.duration.from_minutes(5),
|
|
82
76
|
propsettings=settings,
|
|
83
|
-
satproperties=satprops,
|
|
77
|
+
satproperties=satprops,
|
|
78
|
+
output_dense=True,
|
|
84
79
|
)
|
|
80
|
+
pest = np.zeros((len(timearr), 3))
|
|
81
|
+
for i in range(len(timearr)):
|
|
82
|
+
pest[i, :] = res.interp(timearr[i])[0:3]
|
|
85
83
|
|
|
86
|
-
return np.sum(np.sum((
|
|
84
|
+
return np.sum(np.sum((pest - pgcrf) ** 2, axis=1), axis=0)
|
|
87
85
|
|
|
88
86
|
|
|
89
87
|
# Minimize difference between true satellite state and propagated state
|
|
@@ -91,6 +89,10 @@ def minfunc(v):
|
|
|
91
89
|
r = minimize(minfunc, v0, method="Nelder-Mead")
|
|
92
90
|
print(r)
|
|
93
91
|
|
|
92
|
+
# %%
|
|
93
|
+
print(v0)
|
|
94
|
+
print(r.x)
|
|
95
|
+
|
|
94
96
|
# %%
|
|
95
97
|
import plotly.graph_objects as go
|
|
96
98
|
|
|
@@ -100,11 +102,15 @@ satprops = sk.satprop.satproperties_static()
|
|
|
100
102
|
satprops.craoverm = r.x[3]
|
|
101
103
|
res = sk.satprop.propagate(
|
|
102
104
|
pgcrf[0,:], r.x[0:3], timearr[0],
|
|
103
|
-
stoptime=timearr[-1],
|
|
104
|
-
propsettings=settings, satproperties=satprops
|
|
105
|
+
stoptime=timearr[-1],
|
|
106
|
+
propsettings=settings, satproperties=satprops,
|
|
107
|
+
output_dense=True
|
|
105
108
|
)
|
|
106
|
-
perr =
|
|
109
|
+
perr = np.zeros((len(timearr), 3))
|
|
110
|
+
for i in range(len(timearr)):
|
|
111
|
+
perr[i,:] = res.interp(timearr[i])[0:3] - pgcrf[i,:]
|
|
107
112
|
fig = go.Figure()
|
|
113
|
+
|
|
108
114
|
fig.add_trace(go.Scatter(x=[t.datetime() for t in timearr], y=perr[:,0], mode='lines', name='X'))
|
|
109
115
|
fig.add_trace(go.Scatter(x=[t.datetime() for t in timearr], y=perr[:,1], mode='lines', name='Y'))
|
|
110
116
|
fig.add_trace(go.Scatter(x=[t.datetime() for t in timearr], y=perr[:,2], mode='lines', name='Z'))
|
|
@@ -598,13 +598,19 @@ class TestHighPrecisionPropagation:
|
|
|
598
598
|
settings = sk.satprop.propsettings()
|
|
599
599
|
settings.use_jplephem = False
|
|
600
600
|
|
|
601
|
+
# Determined by orbitprop_gps_fit.py
|
|
602
|
+
fitparam = np.array(
|
|
603
|
+
[ 2.47130562e+03, 2.94682753e+03, -5.34172176e+02, 2.32565692e-02]
|
|
604
|
+
)
|
|
605
|
+
|
|
606
|
+
|
|
601
607
|
# Values for craoverm and velocity come from orbitprop_gps_fit.py
|
|
602
608
|
satprops = sk.satprop.satproperties_static()
|
|
603
|
-
satprops.craoverm =
|
|
604
|
-
|
|
609
|
+
satprops.craoverm = fitparam[3]
|
|
610
|
+
|
|
605
611
|
res = sk.satprop.propagate(
|
|
606
612
|
pgcrf[0, :],
|
|
607
|
-
|
|
613
|
+
fitparam[0:3],
|
|
608
614
|
timearr[0],
|
|
609
615
|
stoptime=timearr[-1],
|
|
610
616
|
propsettings=settings,
|
|
@@ -613,12 +619,12 @@ class TestHighPrecisionPropagation:
|
|
|
613
619
|
)
|
|
614
620
|
print(res)
|
|
615
621
|
|
|
616
|
-
# See if propagator is accurate to <
|
|
622
|
+
# See if propagator is accurate to < 8 meters over 1 day on
|
|
617
623
|
# each Cartesian axis
|
|
618
624
|
for iv in range(pgcrf.shape[0]-5):
|
|
619
625
|
state = res.interp(timearr[iv])
|
|
620
626
|
for ix in range(0, 3):
|
|
621
|
-
assert m.fabs(state[ix] - pgcrf[iv, ix]) <
|
|
627
|
+
assert m.fabs(state[ix] - pgcrf[iv, ix]) < 8
|
|
622
628
|
|
|
623
629
|
class TestSatState:
|
|
624
630
|
def test_lvlh(self):
|
|
@@ -159,7 +159,7 @@ type Mat3 = na::Matrix3<f64>;
|
|
|
159
159
|
/// * `pos` - Position as ITRF coordinate (satkit.itrfcoord) or numpy
|
|
160
160
|
/// 3-vector representing ITRF position in meters
|
|
161
161
|
///
|
|
162
|
-
/// * `order` - Order of the gravity model
|
|
162
|
+
/// * `order` - Order of the gravity model, up to 40
|
|
163
163
|
///
|
|
164
164
|
/// # References
|
|
165
165
|
///
|
|
@@ -199,8 +199,56 @@ impl Gravity {
|
|
|
199
199
|
self.accel_t::<14, 18>(pos)
|
|
200
200
|
} else if order == 15 {
|
|
201
201
|
self.accel_t::<15, 19>(pos)
|
|
202
|
-
} else {
|
|
202
|
+
} else if order == 16 {
|
|
203
203
|
self.accel_t::<16, 20>(pos)
|
|
204
|
+
} else if order == 17 {
|
|
205
|
+
self.accel_t::<17, 21>(pos)
|
|
206
|
+
} else if order == 18 {
|
|
207
|
+
self.accel_t::<18, 22>(pos)
|
|
208
|
+
} else if order == 19 {
|
|
209
|
+
self.accel_t::<19, 23>(pos)
|
|
210
|
+
} else if order == 20 {
|
|
211
|
+
self.accel_t::<20, 24>(pos)
|
|
212
|
+
} else if order == 21 {
|
|
213
|
+
self.accel_t::<21, 25>(pos)
|
|
214
|
+
} else if order == 22 {
|
|
215
|
+
self.accel_t::<22, 26>(pos)
|
|
216
|
+
} else if order == 23 {
|
|
217
|
+
self.accel_t::<23, 27>(pos)
|
|
218
|
+
} else if order == 24 {
|
|
219
|
+
self.accel_t::<24, 28>(pos)
|
|
220
|
+
} else if order == 25 {
|
|
221
|
+
self.accel_t::<25, 29>(pos)
|
|
222
|
+
} else if order == 26 {
|
|
223
|
+
self.accel_t::<26, 30>(pos)
|
|
224
|
+
} else if order == 27 {
|
|
225
|
+
self.accel_t::<27, 31>(pos)
|
|
226
|
+
} else if order == 28 {
|
|
227
|
+
self.accel_t::<28, 32>(pos)
|
|
228
|
+
} else if order == 29 {
|
|
229
|
+
self.accel_t::<29, 33>(pos)
|
|
230
|
+
} else if order == 30 {
|
|
231
|
+
self.accel_t::<30, 34>(pos)
|
|
232
|
+
} else if order == 31 {
|
|
233
|
+
self.accel_t::<31, 35>(pos)
|
|
234
|
+
} else if order == 32 {
|
|
235
|
+
self.accel_t::<32, 36>(pos)
|
|
236
|
+
} else if order == 33 {
|
|
237
|
+
self.accel_t::<33, 37>(pos)
|
|
238
|
+
} else if order == 34 {
|
|
239
|
+
self.accel_t::<34, 38>(pos)
|
|
240
|
+
} else if order == 35 {
|
|
241
|
+
self.accel_t::<35, 39>(pos)
|
|
242
|
+
} else if order == 36 {
|
|
243
|
+
self.accel_t::<36, 40>(pos)
|
|
244
|
+
} else if order == 37 {
|
|
245
|
+
self.accel_t::<37, 41>(pos)
|
|
246
|
+
} else if order == 37 {
|
|
247
|
+
self.accel_t::<38, 42>(pos)
|
|
248
|
+
} else if order == 39 {
|
|
249
|
+
self.accel_t::<39, 43>(pos)
|
|
250
|
+
} else {
|
|
251
|
+
self.accel_t::<40, 44>(pos)
|
|
204
252
|
}
|
|
205
253
|
}
|
|
206
254
|
|
|
@@ -235,8 +283,56 @@ impl Gravity {
|
|
|
235
283
|
self.accel_and_partials_t::<14, 18>(pos)
|
|
236
284
|
} else if order == 15 {
|
|
237
285
|
self.accel_and_partials_t::<15, 19>(pos)
|
|
238
|
-
} else {
|
|
286
|
+
} else if order == 16 {
|
|
239
287
|
self.accel_and_partials_t::<16, 20>(pos)
|
|
288
|
+
} else if order == 17 {
|
|
289
|
+
self.accel_and_partials_t::<17, 21>(pos)
|
|
290
|
+
} else if order == 18 {
|
|
291
|
+
self.accel_and_partials_t::<18, 22>(pos)
|
|
292
|
+
} else if order == 19 {
|
|
293
|
+
self.accel_and_partials_t::<19, 23>(pos)
|
|
294
|
+
} else if order == 20 {
|
|
295
|
+
self.accel_and_partials_t::<20, 24>(pos)
|
|
296
|
+
} else if order == 21 {
|
|
297
|
+
self.accel_and_partials_t::<21, 25>(pos)
|
|
298
|
+
} else if order == 22 {
|
|
299
|
+
self.accel_and_partials_t::<22, 26>(pos)
|
|
300
|
+
} else if order == 23 {
|
|
301
|
+
self.accel_and_partials_t::<23, 27>(pos)
|
|
302
|
+
} else if order == 24 {
|
|
303
|
+
self.accel_and_partials_t::<24, 28>(pos)
|
|
304
|
+
} else if order == 25 {
|
|
305
|
+
self.accel_and_partials_t::<25, 29>(pos)
|
|
306
|
+
} else if order == 26 {
|
|
307
|
+
self.accel_and_partials_t::<26, 30>(pos)
|
|
308
|
+
} else if order == 27 {
|
|
309
|
+
self.accel_and_partials_t::<27, 31>(pos)
|
|
310
|
+
} else if order == 28 {
|
|
311
|
+
self.accel_and_partials_t::<28, 32>(pos)
|
|
312
|
+
} else if order == 29 {
|
|
313
|
+
self.accel_and_partials_t::<29, 33>(pos)
|
|
314
|
+
} else if order == 30 {
|
|
315
|
+
self.accel_and_partials_t::<30, 34>(pos)
|
|
316
|
+
} else if order == 31 {
|
|
317
|
+
self.accel_and_partials_t::<31, 35>(pos)
|
|
318
|
+
} else if order == 32 {
|
|
319
|
+
self.accel_and_partials_t::<32, 36>(pos)
|
|
320
|
+
} else if order == 33 {
|
|
321
|
+
self.accel_and_partials_t::<33, 37>(pos)
|
|
322
|
+
} else if order == 34 {
|
|
323
|
+
self.accel_and_partials_t::<34, 38>(pos)
|
|
324
|
+
} else if order == 35 {
|
|
325
|
+
self.accel_and_partials_t::<35, 39>(pos)
|
|
326
|
+
} else if order == 36 {
|
|
327
|
+
self.accel_and_partials_t::<36, 40>(pos)
|
|
328
|
+
} else if order == 37 {
|
|
329
|
+
self.accel_and_partials_t::<37, 15>(pos)
|
|
330
|
+
} else if order == 38 {
|
|
331
|
+
self.accel_and_partials_t::<38, 16>(pos)
|
|
332
|
+
} else if order == 39 {
|
|
333
|
+
self.accel_and_partials_t::<39, 17>(pos)
|
|
334
|
+
} else {
|
|
335
|
+
self.accel_and_partials_t::<40, 20>(pos)
|
|
240
336
|
}
|
|
241
337
|
}
|
|
242
338
|
|
|
@@ -18,21 +18,33 @@ pub trait RKAdaptive<const N: usize, const NI: usize> {
|
|
|
18
18
|
/// (first compute of next iteration is same as last compute of last iteration)
|
|
19
19
|
const FSAL: bool;
|
|
20
20
|
|
|
21
|
+
/// Interpolate densely calculated solution onto
|
|
22
|
+
/// values that are evenly spaced in "x"
|
|
23
|
+
///
|
|
21
24
|
fn interpolate<S: ODEState>(xinterp: f64, sol: &ODESolution<S>) -> ODEResult<S> {
|
|
22
25
|
if sol.dense.is_none() {
|
|
23
26
|
return Err(Box::new(ODEError::NoDenseOutputInSolution));
|
|
24
27
|
}
|
|
28
|
+
if sol.x < xinterp {
|
|
29
|
+
return Err(Box::new(ODEError::InterpExceedsSolutionBounds));
|
|
30
|
+
}
|
|
25
31
|
let dense = sol.dense.as_ref().unwrap();
|
|
26
|
-
if
|
|
32
|
+
if sol.x < dense.x[0] {
|
|
27
33
|
return Err(Box::new(ODEError::InterpExceedsSolutionBounds));
|
|
28
34
|
}
|
|
35
|
+
|
|
36
|
+
// We know indices are monotonically increasing, so only search from
|
|
37
|
+
// last found position in the array forward
|
|
29
38
|
let mut idx = match dense.x.iter().position(|x| *x >= xinterp) {
|
|
30
39
|
Some(v) => v,
|
|
31
|
-
None => dense.x.len()
|
|
40
|
+
None => dense.x.len(),
|
|
32
41
|
};
|
|
33
42
|
if idx > 0 {
|
|
34
43
|
idx -= 1;
|
|
35
44
|
}
|
|
45
|
+
|
|
46
|
+
// t is fractional distance beween x at idx and idx+1
|
|
47
|
+
// and is in range [0,1]
|
|
36
48
|
let t = (xinterp - dense.x[idx]) / dense.h[idx];
|
|
37
49
|
|
|
38
50
|
// Compute interpolant coefficient as funciton of t
|
|
@@ -47,6 +59,7 @@ pub trait RKAdaptive<const N: usize, const NI: usize> {
|
|
|
47
59
|
let bi: Vec<f64> = Self::BI
|
|
48
60
|
.iter()
|
|
49
61
|
.map(|biarr| {
|
|
62
|
+
// Coefficients multiply increasing powers of t
|
|
50
63
|
let mut tj = 1.0;
|
|
51
64
|
biarr.iter().fold(0.0, |acc, bij| {
|
|
52
65
|
tj = tj * t;
|
|
@@ -60,14 +73,15 @@ pub trait RKAdaptive<const N: usize, const NI: usize> {
|
|
|
60
73
|
//
|
|
61
74
|
// This is equation(5) of:
|
|
62
75
|
// https://link.springer.com/article/10.1023/A:1021190918665
|
|
63
|
-
|
|
76
|
+
//
|
|
77
|
+
let mut y = dense.yprime[idx]
|
|
64
78
|
.iter()
|
|
65
79
|
.enumerate()
|
|
66
80
|
.fold(dense.y[idx].clone() / dense.h[idx], |acc, (ix, k)| {
|
|
67
81
|
acc + k.clone() * bi[ix]
|
|
68
82
|
});
|
|
69
|
-
|
|
70
|
-
Ok(
|
|
83
|
+
y = y * dense.h[idx];
|
|
84
|
+
Ok(y)
|
|
71
85
|
}
|
|
72
86
|
|
|
73
87
|
///
|
|
@@ -77,8 +77,8 @@ mod tests {
|
|
|
77
77
|
(0..100).for_each(|idx| {
|
|
78
78
|
let x = idx as f64 * PI / testcount as f64;
|
|
79
79
|
let interp = RKV87::interpolate(x, &sol).unwrap();
|
|
80
|
-
assert!((interp[0] - x.cos()).abs() < 1e-
|
|
81
|
-
assert!((interp[1] + x.sin()).abs() < 1e-
|
|
80
|
+
assert!((interp[0] - x.cos()).abs() < 1e-12);
|
|
81
|
+
assert!((interp[1] + x.sin()).abs() < 1e-12);
|
|
82
82
|
});
|
|
83
83
|
|
|
84
84
|
Ok(())
|
|
@@ -78,8 +78,8 @@ mod tests {
|
|
|
78
78
|
(0..100).for_each(|idx| {
|
|
79
79
|
let x = idx as f64 * PI / testcount as f64;
|
|
80
80
|
let interp = RKV98::interpolate(x, &sol).unwrap();
|
|
81
|
-
assert!((interp[0] - x.cos()).abs() < 1e-
|
|
82
|
-
assert!((interp[1] + x.sin()).abs() < 1e-
|
|
81
|
+
assert!((interp[0] - x.cos()).abs() < 1e-12);
|
|
82
|
+
assert!((interp[1] + x.sin()).abs() < 1e-12);
|
|
83
83
|
});
|
|
84
84
|
|
|
85
85
|
Ok(())
|
|
@@ -752,10 +752,15 @@ mod tests {
|
|
|
752
752
|
})
|
|
753
753
|
.collect();
|
|
754
754
|
|
|
755
|
-
let v0 = na::vector![
|
|
755
|
+
let v0 = na::vector![
|
|
756
|
+
2.47130562e+03,
|
|
757
|
+
2.94682753e+03,
|
|
758
|
+
-5.34172176e+02,
|
|
759
|
+
2.32565692e-02
|
|
760
|
+
];
|
|
756
761
|
|
|
757
762
|
let state0 = na::vector![pgcrf[0][0], pgcrf[0][1], pgcrf[0][2], v0[0], v0[1], v0[2]];
|
|
758
|
-
let satprops: SatPropertiesStatic = SatPropertiesStatic::new(0.0,
|
|
763
|
+
let satprops: SatPropertiesStatic = SatPropertiesStatic::new(0.0, v0[3]);
|
|
759
764
|
let settings = PropSettings::default();
|
|
760
765
|
|
|
761
766
|
let res = propagate(
|
|
@@ -769,10 +774,10 @@ mod tests {
|
|
|
769
774
|
|
|
770
775
|
// We've propagated over a day; assert that the difference in position on all three coordinate axes
|
|
771
776
|
// is less than 10 meters for all 5-minute intervals
|
|
772
|
-
for iv in 0..(pgcrf.len()
|
|
777
|
+
for iv in 0..(pgcrf.len()) {
|
|
773
778
|
let interp_state = res.interp(×[iv])?;
|
|
774
779
|
for ix in 0..3 {
|
|
775
|
-
assert!((pgcrf[iv][ix] - interp_state[ix]).abs() <
|
|
780
|
+
assert!((pgcrf[iv][ix] - interp_state[ix]).abs() < 8.0);
|
|
776
781
|
}
|
|
777
782
|
}
|
|
778
783
|
|
|
@@ -4,8 +4,8 @@ use pyo3::types::{PyDict, PyList};
|
|
|
4
4
|
use super::pyastrotime::ToTimeVec;
|
|
5
5
|
use super::pytle::PyTLE;
|
|
6
6
|
use crate::sgp4 as psgp4;
|
|
7
|
-
use numpy::{PyArray, PyArray1};
|
|
8
7
|
use numpy::PyArrayMethods;
|
|
8
|
+
use numpy::{PyArray, PyArray1};
|
|
9
9
|
|
|
10
10
|
// Thin Python wrapper around SGP4 Error
|
|
11
11
|
#[allow(non_camel_case_types)]
|
|
@@ -71,8 +71,6 @@ impl From<psgp4::SGP4Error> for PySGP4Error {
|
|
|
71
71
|
}
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
|
|
75
|
-
|
|
76
74
|
/// """SGP-4 propagator for TLE
|
|
77
75
|
///
|
|
78
76
|
/// Note:
|
|
@@ -95,7 +93,7 @@ impl From<psgp4::SGP4Error> for PySGP4Error {
|
|
|
95
93
|
/// Returns:
|
|
96
94
|
/// tuple[npt.ArrayLike[np.float64], npt.ArrayLike[np.float64]]: position and velocity in meters and meters/second, respectively, in the TEME frame at each of the "Ntime" input times and each of the "Ntle" tles
|
|
97
95
|
///
|
|
98
|
-
///
|
|
96
|
+
///
|
|
99
97
|
/// Example:
|
|
100
98
|
///
|
|
101
99
|
///
|
|
@@ -117,13 +115,17 @@ impl From<psgp4::SGP4Error> for PySGP4Error {
|
|
|
117
115
|
/// >>>
|
|
118
116
|
/// >>> # convert to ITRF coordinate object
|
|
119
117
|
/// >>> coord = satkit.itrfcoord.from_vector(pitrf)
|
|
120
|
-
/// >>>
|
|
118
|
+
/// >>>
|
|
121
119
|
/// >>> # Print ITRF coordinate object location
|
|
122
120
|
/// >>> print(coord)
|
|
123
121
|
/// ITRFCoord(lat: -0.0363 deg, lon: -2.2438 deg, hae: 35799.51 km)
|
|
124
122
|
#[pyfunction]
|
|
125
123
|
#[pyo3(signature=(tle, time, **kwds))]
|
|
126
|
-
pub fn sgp4(
|
|
124
|
+
pub fn sgp4(
|
|
125
|
+
tle: &Bound<'_, PyAny>,
|
|
126
|
+
time: &Bound<'_, PyAny>,
|
|
127
|
+
kwds: Option<&Bound<'_, PyDict>>,
|
|
128
|
+
) -> PyResult<PyObject> {
|
|
127
129
|
let mut output_err = false;
|
|
128
130
|
let mut opsmode: OpsMode = OpsMode::afspc;
|
|
129
131
|
let mut gravconst: GravConst = GravConst::wgs72;
|
|
@@ -161,11 +163,13 @@ pub fn sgp4(tle: &Bound<'_, PyAny>, time: &Bound<'_, PyAny>, kwds: Option<&Bound
|
|
|
161
163
|
// hence the switch
|
|
162
164
|
if output_err == false {
|
|
163
165
|
Ok((
|
|
164
|
-
PyArray1::from_slice_bound(py, r.data.as_slice())
|
|
166
|
+
PyArray1::from_slice_bound(py, r.data.as_slice())
|
|
167
|
+
.as_gil_ref()
|
|
165
168
|
.reshape(dims.clone())
|
|
166
169
|
.unwrap()
|
|
167
170
|
.to_object(py),
|
|
168
|
-
PyArray1::from_slice_bound(py, v.data.as_slice())
|
|
171
|
+
PyArray1::from_slice_bound(py, v.data.as_slice())
|
|
172
|
+
.as_gil_ref()
|
|
169
173
|
.reshape(dims)
|
|
170
174
|
.unwrap()
|
|
171
175
|
.to_object(py),
|
|
@@ -173,10 +177,12 @@ pub fn sgp4(tle: &Bound<'_, PyAny>, time: &Bound<'_, PyAny>, kwds: Option<&Bound
|
|
|
173
177
|
.to_object(py))
|
|
174
178
|
} else {
|
|
175
179
|
Ok((
|
|
176
|
-
PyArray1::from_slice_bound(py, r.data.as_slice())
|
|
180
|
+
PyArray1::from_slice_bound(py, r.data.as_slice())
|
|
181
|
+
.as_gil_ref()
|
|
177
182
|
.reshape(dims.clone())
|
|
178
183
|
.unwrap(),
|
|
179
|
-
PyArray1::from_slice_bound(py, v.data.as_slice())
|
|
184
|
+
PyArray1::from_slice_bound(py, v.data.as_slice())
|
|
185
|
+
.as_gil_ref()
|
|
180
186
|
.reshape(dims)
|
|
181
187
|
.unwrap(),
|
|
182
188
|
PyArray::from_owned_object_array_bound(
|
|
@@ -200,9 +206,9 @@ pub fn sgp4(tle: &Bound<'_, PyAny>, time: &Bound<'_, PyAny>, kwds: Option<&Bound
|
|
|
200
206
|
|
|
201
207
|
pyo3::Python::with_gil(|py| -> PyResult<PyObject> {
|
|
202
208
|
let n = tles.len() * tmarray.len() * 3;
|
|
203
|
-
|
|
209
|
+
|
|
204
210
|
let parr = PyArray1::zeros_bound(py, [n], false);
|
|
205
|
-
let varr= PyArray1::zeros_bound(py, [n], false);
|
|
211
|
+
let varr = PyArray1::zeros_bound(py, [n], false);
|
|
206
212
|
let ntimes = tmarray.len();
|
|
207
213
|
|
|
208
214
|
// I'd prefer to create this uninitialized, which would probably be a bit faster,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|