satkit 0.3.8__tar.gz → 0.3.9__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.
Files changed (120) hide show
  1. {satkit-0.3.8 → satkit-0.3.9}/Cargo.toml +1 -1
  2. {satkit-0.3.8/python/satkit.egg-info → satkit-0.3.9}/PKG-INFO +1 -1
  3. {satkit-0.3.8 → satkit-0.3.9}/pyproject.toml +1 -1
  4. {satkit-0.3.8 → satkit-0.3.9}/python/satkit/satkit.pyi +3 -3
  5. {satkit-0.3.8 → satkit-0.3.9/python/satkit.egg-info}/PKG-INFO +1 -1
  6. {satkit-0.3.8 → satkit-0.3.9}/python/test/test.py +21 -0
  7. {satkit-0.3.8 → satkit-0.3.9}/src/ode/rk_adaptive.rs +94 -2
  8. {satkit-0.3.8 → satkit-0.3.9}/src/orbitprop/propagator.rs +16 -3
  9. {satkit-0.3.8 → satkit-0.3.9}/LICENSE +0 -0
  10. {satkit-0.3.8 → satkit-0.3.9}/MANIFEST.in +0 -0
  11. {satkit-0.3.8 → satkit-0.3.9}/README.md +0 -0
  12. {satkit-0.3.8 → satkit-0.3.9}/python/docs/source/conf.py +0 -0
  13. {satkit-0.3.8 → satkit-0.3.9}/python/satkit/__init__.py +0 -0
  14. {satkit-0.3.8 → satkit-0.3.9}/python/satkit/__init__.pyi +0 -0
  15. {satkit-0.3.8 → satkit-0.3.9}/python/satkit/density.pyi +0 -0
  16. {satkit-0.3.8 → satkit-0.3.9}/python/satkit/frametransform.pyi +0 -0
  17. {satkit-0.3.8 → satkit-0.3.9}/python/satkit/jplephem.pyi +0 -0
  18. {satkit-0.3.8 → satkit-0.3.9}/python/satkit/moon.pyi +0 -0
  19. {satkit-0.3.8 → satkit-0.3.9}/python/satkit/planets.pyi +0 -0
  20. {satkit-0.3.8 → satkit-0.3.9}/python/satkit/py.typed +0 -0
  21. {satkit-0.3.8 → satkit-0.3.9}/python/satkit/satprop.pyi +0 -0
  22. {satkit-0.3.8 → satkit-0.3.9}/python/satkit/sun.pyi +0 -0
  23. {satkit-0.3.8 → satkit-0.3.9}/python/satkit/utils.pyi +0 -0
  24. {satkit-0.3.8 → satkit-0.3.9}/python/satkit.egg-info/SOURCES.txt +0 -0
  25. {satkit-0.3.8 → satkit-0.3.9}/python/satkit.egg-info/dependency_links.txt +0 -0
  26. {satkit-0.3.8 → satkit-0.3.9}/python/satkit.egg-info/requires.txt +0 -0
  27. {satkit-0.3.8 → satkit-0.3.9}/python/satkit.egg-info/top_level.txt +0 -0
  28. {satkit-0.3.8 → satkit-0.3.9}/python/test/download_data.py +0 -0
  29. {satkit-0.3.8 → satkit-0.3.9}/python/test/download_from_json.py +0 -0
  30. {satkit-0.3.8 → satkit-0.3.9}/python/test/download_testvecs.py +0 -0
  31. {satkit-0.3.8 → satkit-0.3.9}/python/test/orbitprop_gps_fit.py +0 -0
  32. {satkit-0.3.8 → satkit-0.3.9}/python/test/sp3file.py +0 -0
  33. {satkit-0.3.8 → satkit-0.3.9}/setup.cfg +0 -0
  34. {satkit-0.3.8 → satkit-0.3.9}/src/astrotime.rs +0 -0
  35. {satkit-0.3.8 → satkit-0.3.9}/src/consts.rs +0 -0
  36. {satkit-0.3.8 → satkit-0.3.9}/src/duration.rs +0 -0
  37. {satkit-0.3.8 → satkit-0.3.9}/src/earth_orientation_params.rs +0 -0
  38. {satkit-0.3.8 → satkit-0.3.9}/src/earthgravity.rs +0 -0
  39. {satkit-0.3.8 → satkit-0.3.9}/src/frames.rs +0 -0
  40. {satkit-0.3.8 → satkit-0.3.9}/src/frametransform/ierstable.rs +0 -0
  41. {satkit-0.3.8 → satkit-0.3.9}/src/frametransform/mod.rs +0 -0
  42. {satkit-0.3.8 → satkit-0.3.9}/src/frametransform/qcirs2gcrs.rs +0 -0
  43. {satkit-0.3.8 → satkit-0.3.9}/src/itrfcoord.rs +0 -0
  44. {satkit-0.3.8 → satkit-0.3.9}/src/jplephem.rs +0 -0
  45. {satkit-0.3.8 → satkit-0.3.9}/src/kepler.rs +0 -0
  46. {satkit-0.3.8 → satkit-0.3.9}/src/lib.rs +0 -0
  47. {satkit-0.3.8 → satkit-0.3.9}/src/lpephem/mod.rs +0 -0
  48. {satkit-0.3.8 → satkit-0.3.9}/src/lpephem/moon.rs +0 -0
  49. {satkit-0.3.8 → satkit-0.3.9}/src/lpephem/planets.rs +0 -0
  50. {satkit-0.3.8 → satkit-0.3.9}/src/lpephem/sun.rs +0 -0
  51. {satkit-0.3.8 → satkit-0.3.9}/src/nrlmsise.rs +0 -0
  52. {satkit-0.3.8 → satkit-0.3.9}/src/ode/harmonic_oscillator.rs +0 -0
  53. {satkit-0.3.8 → satkit-0.3.9}/src/ode/mod.rs +0 -0
  54. {satkit-0.3.8 → satkit-0.3.9}/src/ode/nalgebra.rs +0 -0
  55. {satkit-0.3.8 → satkit-0.3.9}/src/ode/rk_adaptive_settings.rs +0 -0
  56. {satkit-0.3.8 → satkit-0.3.9}/src/ode/rk_explicit.rs +0 -0
  57. {satkit-0.3.8 → satkit-0.3.9}/src/ode/rkf45.rs +0 -0
  58. {satkit-0.3.8 → satkit-0.3.9}/src/ode/rkts54.rs +0 -0
  59. {satkit-0.3.8 → satkit-0.3.9}/src/ode/rkv65.rs +0 -0
  60. {satkit-0.3.8 → satkit-0.3.9}/src/ode/rkv65_table.rs +0 -0
  61. {satkit-0.3.8 → satkit-0.3.9}/src/ode/rkv87.rs +0 -0
  62. {satkit-0.3.8 → satkit-0.3.9}/src/ode/rkv87_table.rs +0 -0
  63. {satkit-0.3.8 → satkit-0.3.9}/src/ode/rkv98.rs +0 -0
  64. {satkit-0.3.8 → satkit-0.3.9}/src/ode/rkv98_nointerp.rs +0 -0
  65. {satkit-0.3.8 → satkit-0.3.9}/src/ode/rkv98_nointerp_table.rs +0 -0
  66. {satkit-0.3.8 → satkit-0.3.9}/src/ode/rkv98_table.rs +0 -0
  67. {satkit-0.3.8 → satkit-0.3.9}/src/ode/types.rs +0 -0
  68. {satkit-0.3.8 → satkit-0.3.9}/src/orbitprop/drag.rs +0 -0
  69. {satkit-0.3.8 → satkit-0.3.9}/src/orbitprop/mod.rs +0 -0
  70. {satkit-0.3.8 → satkit-0.3.9}/src/orbitprop/point_gravity.rs +0 -0
  71. {satkit-0.3.8 → satkit-0.3.9}/src/orbitprop/satproperties.rs +0 -0
  72. {satkit-0.3.8 → satkit-0.3.9}/src/orbitprop/satstate.rs +0 -0
  73. {satkit-0.3.8 → satkit-0.3.9}/src/orbitprop/settings.rs +0 -0
  74. {satkit-0.3.8 → satkit-0.3.9}/src/pybindings/mod.rs +0 -0
  75. {satkit-0.3.8 → satkit-0.3.9}/src/pybindings/mod_utils.rs +0 -0
  76. {satkit-0.3.8 → satkit-0.3.9}/src/pybindings/pyastrotime.rs +0 -0
  77. {satkit-0.3.8 → satkit-0.3.9}/src/pybindings/pyconsts.rs +0 -0
  78. {satkit-0.3.8 → satkit-0.3.9}/src/pybindings/pydensity.rs +0 -0
  79. {satkit-0.3.8 → satkit-0.3.9}/src/pybindings/pyduration.rs +0 -0
  80. {satkit-0.3.8 → satkit-0.3.9}/src/pybindings/pyframes.rs +0 -0
  81. {satkit-0.3.8 → satkit-0.3.9}/src/pybindings/pyframetransform.rs +0 -0
  82. {satkit-0.3.8 → satkit-0.3.9}/src/pybindings/pygravity.rs +0 -0
  83. {satkit-0.3.8 → satkit-0.3.9}/src/pybindings/pyitrfcoord.rs +0 -0
  84. {satkit-0.3.8 → satkit-0.3.9}/src/pybindings/pyjplephem.rs +0 -0
  85. {satkit-0.3.8 → satkit-0.3.9}/src/pybindings/pykepler.rs +0 -0
  86. {satkit-0.3.8 → satkit-0.3.9}/src/pybindings/pylpephem_moon.rs +0 -0
  87. {satkit-0.3.8 → satkit-0.3.9}/src/pybindings/pylpephem_planets.rs +0 -0
  88. {satkit-0.3.8 → satkit-0.3.9}/src/pybindings/pylpephem_sun.rs +0 -0
  89. {satkit-0.3.8 → satkit-0.3.9}/src/pybindings/pynrlmsise.rs +0 -0
  90. {satkit-0.3.8 → satkit-0.3.9}/src/pybindings/pypropagate.rs +0 -0
  91. {satkit-0.3.8 → satkit-0.3.9}/src/pybindings/pypropresult.rs +0 -0
  92. {satkit-0.3.8 → satkit-0.3.9}/src/pybindings/pypropsettings.rs +0 -0
  93. {satkit-0.3.8 → satkit-0.3.9}/src/pybindings/pyquaternion.rs +0 -0
  94. {satkit-0.3.8 → satkit-0.3.9}/src/pybindings/pysatproperties.rs +0 -0
  95. {satkit-0.3.8 → satkit-0.3.9}/src/pybindings/pysatstate.rs +0 -0
  96. {satkit-0.3.8 → satkit-0.3.9}/src/pybindings/pysgp4.rs +0 -0
  97. {satkit-0.3.8 → satkit-0.3.9}/src/pybindings/pysolarsystem.rs +0 -0
  98. {satkit-0.3.8 → satkit-0.3.9}/src/pybindings/pytle.rs +0 -0
  99. {satkit-0.3.8 → satkit-0.3.9}/src/pybindings/pyutils.rs +0 -0
  100. {satkit-0.3.8 → satkit-0.3.9}/src/sgp4/dpper.rs +0 -0
  101. {satkit-0.3.8 → satkit-0.3.9}/src/sgp4/dscom.rs +0 -0
  102. {satkit-0.3.8 → satkit-0.3.9}/src/sgp4/dsinit.rs +0 -0
  103. {satkit-0.3.8 → satkit-0.3.9}/src/sgp4/dspace.rs +0 -0
  104. {satkit-0.3.8 → satkit-0.3.9}/src/sgp4/getgravconst.rs +0 -0
  105. {satkit-0.3.8 → satkit-0.3.9}/src/sgp4/initl.rs +0 -0
  106. {satkit-0.3.8 → satkit-0.3.9}/src/sgp4/mod.rs +0 -0
  107. {satkit-0.3.8 → satkit-0.3.9}/src/sgp4/satrec.rs +0 -0
  108. {satkit-0.3.8 → satkit-0.3.9}/src/sgp4/sgp4.rs +0 -0
  109. {satkit-0.3.8 → satkit-0.3.9}/src/sgp4/sgp4_lowlevel.rs +0 -0
  110. {satkit-0.3.8 → satkit-0.3.9}/src/sgp4/sgp4init.rs +0 -0
  111. {satkit-0.3.8 → satkit-0.3.9}/src/solarsystem.rs +0 -0
  112. {satkit-0.3.8 → satkit-0.3.9}/src/spaceweather.rs +0 -0
  113. {satkit-0.3.8 → satkit-0.3.9}/src/tle.rs +0 -0
  114. {satkit-0.3.8 → satkit-0.3.9}/src/types.rs +0 -0
  115. {satkit-0.3.8 → satkit-0.3.9}/src/utils/datadir.rs +0 -0
  116. {satkit-0.3.8 → satkit-0.3.9}/src/utils/download.rs +0 -0
  117. {satkit-0.3.8 → satkit-0.3.9}/src/utils/mod.rs +0 -0
  118. {satkit-0.3.8 → satkit-0.3.9}/src/utils/skerror.rs +0 -0
  119. {satkit-0.3.8 → satkit-0.3.9}/src/utils/test.rs +0 -0
  120. {satkit-0.3.8 → satkit-0.3.9}/src/utils/update_data.rs +0 -0
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "satkit"
3
- version = "0.3.8"
3
+ version = "0.3.9"
4
4
  edition = "2021"
5
5
  description = "Satellite Toolkit"
6
6
  readme = "README.md"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: satkit
3
- Version: 0.3.8
3
+ Version: 0.3.9
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>
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "satkit"
7
- version = "0.3.8"
7
+ version = "0.3.9"
8
8
  dependencies = ["numpy>=1.0.0"]
9
9
  requires-python = ">= 3.8"
10
10
  authors = [{ name = "Steven Michael", email = "ssmichael@gmail.com" }]
@@ -1694,9 +1694,9 @@ def propagate(
1694
1694
  duration (satkit.duration): duration from "tm" at which new position & velocity will be computed.
1695
1695
  output_phi (bool): Output 6x6 state transition matrix between "starttime" and "stoptime" (and at intervals, if specified)
1696
1696
  propsettings (propsettings): "propsettings" object with input settings for the propagation. if left out, default will be used.
1697
- satproperties (satproperties_static): "SatPropertiesStatic" object with drag and radiation pressure succeptibility of satellite. If left out, drag and radiation pressure are neglected
1698
- 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
1699
-
1697
+ satproperties (satproperties_static): "SatPropertiesStatic" object with drag and radiation pressure succeptibility of satellite.
1698
+ output_dense: boolean indicting whether or not dense output should be recorded. Default is false.
1699
+
1700
1700
  Returns:
1701
1701
  (propresult): Propagation result object holding state outputs, statistics, and dense output if requested
1702
1702
  """
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: satkit
3
- Version: 0.3.8
3
+ Version: 0.3.9
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>
@@ -575,6 +575,27 @@ class TestGeodesicDistance:
575
575
 
576
576
  class TestHighPrecisionPropagation:
577
577
 
578
+ def test_interp(self):
579
+ starttime = sk.time(2015, 3, 20, 0, 0, 0)
580
+
581
+ pos = np.array([sk.consts.geo_r, 0, 0])
582
+ vel = np.array([0, m.sqrt(sk.consts.mu_earth/sk.consts.geo_r), 0])
583
+ stoptime = starttime + sk.duration.from_days(1.0)
584
+
585
+ # Propagate forward
586
+ res1 = sk.propagate(pos, vel, starttime, stoptime=stoptime, output_dense=True)
587
+ # Propagate backward and see if we recover original result
588
+ res2 = sk.propagate(res1.state[0:3], res1.state[3:6], stoptime, stoptime=starttime, output_dense=True)
589
+
590
+ assert res2.state[0:3] == pytest.approx(pos, abs=0.5)
591
+ assert res2.state[3:6] == pytest.approx(vel, abs=1e-5)
592
+
593
+ newtime = starttime + sk.duration.from_hours(4.332)
594
+ istate1 = res1.interp(newtime)
595
+ istate2 = res2.interp(newtime)
596
+
597
+ assert(istate1 == pytest.approx(istate2, rel=1e-8))
598
+
578
599
  def test_gps(self):
579
600
 
580
601
  # File contains test calculation vectors provided by NASA
@@ -18,15 +18,31 @@ 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
+ fn interpolate<S: ODEState>(xinterp: f64, sol: &ODESolution<S>) -> ODEResult<S> {
22
+ if sol.dense.is_none() {
23
+ return Err(Box::new(ODEError::NoDenseOutputInSolution));
24
+ }
25
+ let dense = sol.dense.as_ref().unwrap();
26
+
27
+ // These could probably be combined into a single function, but...
28
+ // keeping forward and backward separate makes it simpler in my mind
29
+ if sol.x > dense.x[0] {
30
+ return Self::interpolate_forward(xinterp, sol);
31
+ } else {
32
+ return Self::interpolate_backward(xinterp, sol);
33
+ }
34
+ }
35
+
21
36
  /// Interpolate densely calculated solution onto
22
37
  /// values that are evenly spaced in "x"
23
- ///
24
- fn interpolate<S: ODEState>(xinterp: f64, sol: &ODESolution<S>) -> ODEResult<S> {
38
+ /// for forward direction
39
+ fn interpolate_forward<S: ODEState>(xinterp: f64, sol: &ODESolution<S>) -> ODEResult<S> {
25
40
  if sol.dense.is_none() {
26
41
  return Err(Box::new(ODEError::NoDenseOutputInSolution));
27
42
  }
28
43
  let dense = sol.dense.as_ref().unwrap();
29
44
 
45
+ // Check if interpolation point is within bounds
30
46
  if sol.x < xinterp {
31
47
  return Err(Box::new(ODEError::InterpExceedsSolutionBounds {
32
48
  interp: xinterp,
@@ -93,6 +109,82 @@ pub trait RKAdaptive<const N: usize, const NI: usize> {
93
109
  Ok(y)
94
110
  }
95
111
 
112
+ /// Interpolate densely calculated solution onto
113
+ /// values that are evenly spaced in "x"
114
+ /// for backward direction
115
+ fn interpolate_backward<S: ODEState>(xinterp: f64, sol: &ODESolution<S>) -> ODEResult<S> {
116
+ if sol.dense.is_none() {
117
+ return Err(Box::new(ODEError::NoDenseOutputInSolution));
118
+ }
119
+ let dense = sol.dense.as_ref().unwrap();
120
+
121
+ // Check if interpolation point is within bounds
122
+ if sol.x > xinterp {
123
+ return Err(Box::new(ODEError::InterpExceedsSolutionBounds {
124
+ interp: xinterp,
125
+ start: dense.x[0],
126
+ stop: sol.x,
127
+ }));
128
+ }
129
+ if xinterp > dense.x[0] {
130
+ return Err(Box::new(ODEError::InterpExceedsSolutionBounds {
131
+ interp: xinterp,
132
+ start: dense.x[0],
133
+ stop: sol.x,
134
+ }));
135
+ }
136
+
137
+ // We know indices are monotonically increasing, so only search from
138
+ // last found position in the array forward
139
+ let mut idx = match dense.x.iter().position(|x| *x <= xinterp) {
140
+ Some(v) => v,
141
+ None => dense.x.len(),
142
+ };
143
+ if idx > 0 {
144
+ idx -= 1;
145
+ }
146
+
147
+ // t is fractional distance beween x at idx and idx+1
148
+ // and is in range [0,1]
149
+ let t = (xinterp - dense.x[idx]) / dense.h[idx];
150
+
151
+ // Compute interpolant coefficient as funciton of t
152
+ // note that t is in range [0,1]
153
+ //
154
+ // This is equation (6) of
155
+ // https://link.springer.com/article/10.1023/A:1021190918665
156
+ //
157
+ // Note: equation (6) of paper incorrectly has sum index "j"
158
+ // starting from 0. It should start from 1.
159
+ //
160
+ let bi: Vec<f64> = Self::BI
161
+ .iter()
162
+ .map(|biarr| {
163
+ // Coefficients multiply increasing powers of t
164
+ let mut tj = 1.0;
165
+ biarr.iter().fold(0.0, |acc, bij| {
166
+ tj = tj * t;
167
+ acc + bij * tj
168
+ })
169
+ })
170
+ .collect();
171
+
172
+ //
173
+ // Compute interpolated value
174
+ //
175
+ // This is equation(5) of:
176
+ // https://link.springer.com/article/10.1023/A:1021190918665
177
+ //
178
+ let mut y = dense.yprime[idx]
179
+ .iter()
180
+ .enumerate()
181
+ .fold(dense.y[idx].clone() / dense.h[idx], |acc, (ix, k)| {
182
+ acc + k.clone() * bi[ix]
183
+ });
184
+ y = y * dense.h[idx];
185
+ Ok(y)
186
+ }
187
+
96
188
  ///
97
189
  /// Runga-Kutta integration
98
190
  /// with Proportional-Integral controller
@@ -525,7 +525,7 @@ mod tests {
525
525
  #[test]
526
526
  fn test_interp() -> SKResult<()> {
527
527
  let starttime = AstroTime::from_datetime(2015, 3, 20, 0, 0, 0.0);
528
- let stoptime = starttime + Duration::Days(0.5);
528
+ let stoptime = starttime + Duration::Days(1.0);
529
529
 
530
530
  let mut state: SimpleState = SimpleState::zeros();
531
531
 
@@ -539,10 +539,23 @@ mod tests {
539
539
  settings.gravity_interp_dt_secs = 300.0;
540
540
  settings.use_jplephem = false;
541
541
 
542
+ // Propagate forward
542
543
  let res = propagate(&state, &starttime, &stoptime, &settings, None, true)?;
544
+ // propagate backward to original time
545
+ let res2 = propagate(&res.state_end, &stoptime, &starttime, &settings, None, true)?;
546
+ // Check that we recover the original state
547
+ for ix in 0..6 as usize {
548
+ assert!((state[ix] - res2.state_end[ix]).abs() < 1.0e-3);
549
+ }
543
550
 
544
- let newtime = starttime + Duration::Days(0.25);
545
- let _interp = res.interp(&newtime)?;
551
+ // Check interpolation forward and backward return the same result
552
+ let newtime = starttime + Duration::Days(0.45);
553
+ let interp = res.interp(&newtime)?;
554
+ let interp2 = res2.interp(&newtime)?;
555
+
556
+ for ix in 0..6 as usize {
557
+ assert!((interp[ix] - interp2[ix]).abs() < 1e-3);
558
+ }
546
559
  Ok(())
547
560
  }
548
561
 
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