nrl-tracker 0.21.4__py3-none-any.whl → 1.7.5__py3-none-any.whl

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 (95) hide show
  1. {nrl_tracker-0.21.4.dist-info → nrl_tracker-1.7.5.dist-info}/METADATA +57 -10
  2. nrl_tracker-1.7.5.dist-info/RECORD +165 -0
  3. pytcl/__init__.py +4 -3
  4. pytcl/assignment_algorithms/__init__.py +28 -0
  5. pytcl/assignment_algorithms/data_association.py +2 -7
  6. pytcl/assignment_algorithms/gating.py +10 -10
  7. pytcl/assignment_algorithms/jpda.py +40 -40
  8. pytcl/assignment_algorithms/nd_assignment.py +379 -0
  9. pytcl/assignment_algorithms/network_flow.py +371 -0
  10. pytcl/assignment_algorithms/three_dimensional/assignment.py +3 -3
  11. pytcl/astronomical/__init__.py +162 -8
  12. pytcl/astronomical/ephemerides.py +533 -0
  13. pytcl/astronomical/reference_frames.py +865 -56
  14. pytcl/astronomical/relativity.py +473 -0
  15. pytcl/astronomical/sgp4.py +710 -0
  16. pytcl/astronomical/special_orbits.py +532 -0
  17. pytcl/astronomical/tle.py +558 -0
  18. pytcl/atmosphere/__init__.py +45 -3
  19. pytcl/atmosphere/ionosphere.py +512 -0
  20. pytcl/atmosphere/nrlmsise00.py +809 -0
  21. pytcl/clustering/dbscan.py +2 -2
  22. pytcl/clustering/gaussian_mixture.py +3 -3
  23. pytcl/clustering/hierarchical.py +15 -15
  24. pytcl/clustering/kmeans.py +4 -4
  25. pytcl/containers/__init__.py +28 -21
  26. pytcl/containers/base.py +219 -0
  27. pytcl/containers/cluster_set.py +2 -1
  28. pytcl/containers/covertree.py +26 -29
  29. pytcl/containers/kd_tree.py +94 -29
  30. pytcl/containers/measurement_set.py +1 -9
  31. pytcl/containers/rtree.py +200 -1
  32. pytcl/containers/vptree.py +21 -28
  33. pytcl/coordinate_systems/conversions/geodetic.py +272 -5
  34. pytcl/coordinate_systems/jacobians/jacobians.py +2 -2
  35. pytcl/coordinate_systems/projections/__init__.py +4 -2
  36. pytcl/coordinate_systems/projections/projections.py +2 -2
  37. pytcl/coordinate_systems/rotations/rotations.py +10 -6
  38. pytcl/core/__init__.py +18 -0
  39. pytcl/core/validation.py +333 -2
  40. pytcl/dynamic_estimation/__init__.py +26 -0
  41. pytcl/dynamic_estimation/gaussian_sum_filter.py +434 -0
  42. pytcl/dynamic_estimation/imm.py +15 -18
  43. pytcl/dynamic_estimation/kalman/__init__.py +30 -0
  44. pytcl/dynamic_estimation/kalman/constrained.py +382 -0
  45. pytcl/dynamic_estimation/kalman/extended.py +9 -12
  46. pytcl/dynamic_estimation/kalman/h_infinity.py +613 -0
  47. pytcl/dynamic_estimation/kalman/square_root.py +60 -573
  48. pytcl/dynamic_estimation/kalman/sr_ukf.py +302 -0
  49. pytcl/dynamic_estimation/kalman/ud_filter.py +410 -0
  50. pytcl/dynamic_estimation/kalman/unscented.py +9 -10
  51. pytcl/dynamic_estimation/particle_filters/bootstrap.py +15 -15
  52. pytcl/dynamic_estimation/rbpf.py +589 -0
  53. pytcl/dynamic_estimation/smoothers.py +1 -5
  54. pytcl/dynamic_models/discrete_time/__init__.py +1 -5
  55. pytcl/dynamic_models/process_noise/__init__.py +1 -5
  56. pytcl/gravity/egm.py +13 -0
  57. pytcl/gravity/spherical_harmonics.py +98 -37
  58. pytcl/gravity/tides.py +6 -6
  59. pytcl/logging_config.py +328 -0
  60. pytcl/magnetism/__init__.py +10 -14
  61. pytcl/magnetism/emm.py +10 -3
  62. pytcl/magnetism/wmm.py +260 -23
  63. pytcl/mathematical_functions/combinatorics/combinatorics.py +5 -5
  64. pytcl/mathematical_functions/geometry/geometry.py +5 -5
  65. pytcl/mathematical_functions/interpolation/__init__.py +2 -2
  66. pytcl/mathematical_functions/numerical_integration/quadrature.py +6 -6
  67. pytcl/mathematical_functions/signal_processing/detection.py +24 -24
  68. pytcl/mathematical_functions/signal_processing/filters.py +14 -14
  69. pytcl/mathematical_functions/signal_processing/matched_filter.py +12 -12
  70. pytcl/mathematical_functions/special_functions/__init__.py +2 -2
  71. pytcl/mathematical_functions/special_functions/bessel.py +15 -3
  72. pytcl/mathematical_functions/special_functions/debye.py +136 -26
  73. pytcl/mathematical_functions/special_functions/error_functions.py +3 -1
  74. pytcl/mathematical_functions/special_functions/gamma_functions.py +4 -4
  75. pytcl/mathematical_functions/special_functions/hypergeometric.py +81 -15
  76. pytcl/mathematical_functions/transforms/fourier.py +8 -8
  77. pytcl/mathematical_functions/transforms/stft.py +12 -12
  78. pytcl/mathematical_functions/transforms/wavelets.py +9 -9
  79. pytcl/navigation/__init__.py +14 -10
  80. pytcl/navigation/geodesy.py +246 -160
  81. pytcl/navigation/great_circle.py +101 -19
  82. pytcl/navigation/ins.py +1 -5
  83. pytcl/plotting/coordinates.py +7 -7
  84. pytcl/plotting/tracks.py +2 -2
  85. pytcl/static_estimation/maximum_likelihood.py +16 -14
  86. pytcl/static_estimation/robust.py +5 -5
  87. pytcl/terrain/loaders.py +5 -5
  88. pytcl/trackers/__init__.py +3 -14
  89. pytcl/trackers/hypothesis.py +1 -1
  90. pytcl/trackers/mht.py +9 -9
  91. pytcl/trackers/multi_target.py +2 -5
  92. nrl_tracker-0.21.4.dist-info/RECORD +0 -148
  93. {nrl_tracker-0.21.4.dist-info → nrl_tracker-1.7.5.dist-info}/LICENSE +0 -0
  94. {nrl_tracker-0.21.4.dist-info → nrl_tracker-1.7.5.dist-info}/WHEEL +0 -0
  95. {nrl_tracker-0.21.4.dist-info → nrl_tracker-1.7.5.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,533 @@
1
+ """
2
+ JPL Ephemerides for High-Precision Celestial Mechanics
3
+
4
+ This module provides access to JPL Development Ephemeris (DE) files for computing
5
+ high-precision positions and velocities of celestial bodies (Sun, Moon, planets).
6
+
7
+ The module leverages the jplephem library, which provides optimized Fortran-based
8
+ interpolation of ephemeris kernels. Multiple DE versions are supported (DE405,
9
+ DE430, DE432s, DE440).
10
+
11
+ Constants
12
+ ---------
13
+ AU_PER_KM : float
14
+ Astronomical Unit in kilometers (1 AU = 149597870.7 km)
15
+ KM_PER_DAY_TO_AU_PER_DAY : float
16
+ Conversion factor for velocity from km/day to AU/day
17
+
18
+ Examples
19
+ --------
20
+ >>> from pytcl.astronomical.ephemerides import DEEphemeris
21
+ >>> from datetime import datetime
22
+ >>>
23
+ >>> # Load ephemeris (auto-downloads if needed)
24
+ >>> eph = DEEphemeris(version='DE440')
25
+ >>>
26
+ >>> # Query Sun position (AU)
27
+ >>> jd = 2451545.0 # J2000.0
28
+ >>> r_sun, v_sun = eph.sun_position(jd)
29
+ >>> print(f"Sun distance: {np.linalg.norm(r_sun):.6f} AU")
30
+ Sun distance: 0.983327 AU
31
+ >>>
32
+ >>> # Query Moon position
33
+ >>> r_moon, v_moon = eph.moon_position(jd)
34
+
35
+ Notes
36
+ -----
37
+ - Ephemeris files are auto-downloaded to ~/.jplephem/ on first use
38
+ - Time input is Julian Day (JD) in Terrestrial Time (TT) scale
39
+ - Positions returned in AU, velocities in AU/day in ICRF frame
40
+ - For highest precision, use DE440 (latest release) or DE432s (2013)
41
+
42
+ References
43
+ ----------
44
+ .. [1] Standish, E. M. (1995). "Report of the IAU WGAS Sub-group on
45
+ Numerical Standards". In Highlights of Astronomy (Vol. 10).
46
+ .. [2] Folkner, W. M., Williams, J. G., Boggs, D. H., Park, R. S., &
47
+ Kuchynka, P. (2014). "The Planetary and Lunar Ephemeris DE430 and DE431".
48
+ Interplanetary Network Progress Report, 42(196), 1-81.
49
+
50
+ """
51
+
52
+ from typing import Any, Literal, Optional, Tuple
53
+
54
+ import numpy as np
55
+ from numpy.typing import NDArray
56
+
57
+ # Constants for unit conversion
58
+ AU_PER_KM = 1.0 / 149597870.7 # 1 AU in km
59
+ KM_PER_DAY_TO_AU_PER_DAY = AU_PER_KM # velocity conversion factor
60
+ EPSILON_J2000 = 0.4090910179 # Mean obliquity of the ecliptic at J2000.0 (radians)
61
+
62
+ __all__ = [
63
+ "DEEphemeris",
64
+ "sun_position",
65
+ "moon_position",
66
+ "planet_position",
67
+ "barycenter_position",
68
+ ]
69
+
70
+
71
+ class DEEphemeris:
72
+ """High-precision JPL Development Ephemeris kernel wrapper.
73
+
74
+ This class manages access to JPL ephemeris files and provides methods
75
+ for querying positions and velocities of celestial bodies.
76
+
77
+ Parameters
78
+ ----------
79
+ version : {'DE405', 'DE430', 'DE432s', 'DE440'}, optional
80
+ Ephemeris version to load. Default is 'DE440' (latest).
81
+ - DE440: Latest JPL release (2020), covers 1550-2650
82
+ - DE432s: High-precision version (2013), covers 1350-3000
83
+ - DE430: Earlier release (2013), covers 1550-2650
84
+ - DE405: Older version (1998), compact, covers 1600-2200
85
+
86
+ Attributes
87
+ ----------
88
+ version : str
89
+ Ephemeris version identifier
90
+ kernel : jplephem.SpiceKernel
91
+ Loaded ephemeris kernel object
92
+ _cache : dict
93
+ Cache for frequently accessed positions
94
+
95
+ Raises
96
+ ------
97
+ ImportError
98
+ If jplephem is not installed
99
+ ValueError
100
+ If version is not recognized
101
+
102
+ Examples
103
+ --------
104
+ >>> eph = DEEphemeris(version='DE440')
105
+ >>> r_sun, v_sun = eph.sun_position(2451545.0)
106
+
107
+ """
108
+
109
+ # Valid ephemeris versions
110
+ _VALID_VERSIONS = {"DE405", "DE430", "DE432s", "DE440"}
111
+
112
+ # Supported bodies and their DE IDs
113
+ # See: https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/req/naif_ids.html
114
+ _BODY_IDS = {
115
+ "mercury": 1,
116
+ "venus": 2,
117
+ "earth": 3,
118
+ "moon": 301,
119
+ "mars": 4,
120
+ "jupiter": 5,
121
+ "saturn": 6,
122
+ "uranus": 7,
123
+ "neptune": 8,
124
+ "pluto": 9,
125
+ "sun": 10,
126
+ "earth_moon_barycenter": 3,
127
+ "solar_system_barycenter": 0,
128
+ }
129
+
130
+ def __init__(self, version: str = "DE440") -> None:
131
+ """Initialize ephemeris kernel.
132
+
133
+ Parameters
134
+ ----------
135
+ version : str, optional
136
+ Ephemeris version (default: 'DE440')
137
+
138
+ """
139
+ if version not in self._VALID_VERSIONS:
140
+ raise ValueError(
141
+ f"Ephemeris version must be one of {self._VALID_VERSIONS}, "
142
+ f"got '{version}'"
143
+ )
144
+
145
+ try:
146
+ import jplephem
147
+ except ImportError as e:
148
+ raise ImportError(
149
+ "jplephem is required for ephemeris access. "
150
+ "Install with: pip install jplephem"
151
+ ) from e
152
+
153
+ self.version = version
154
+ self._jplephem = jplephem
155
+ self._kernel: Optional[object] = None
156
+ self._cache: dict[str, Any] = {}
157
+
158
+ @property
159
+ def kernel(self) -> Optional[object]:
160
+ """Lazy-load ephemeris kernel on first access.
161
+
162
+ Note: This requires jplephem to be installed and the kernel file
163
+ to be available locally or downloadable from the JPL servers.
164
+ """
165
+ if self._kernel is None:
166
+ try:
167
+ # Try to load using jplephem SPK module
168
+ import os
169
+ import urllib.request
170
+
171
+ from jplephem.daf import DAF
172
+ from jplephem.spk import SPK
173
+
174
+ # Try to construct kernel filename
175
+ kernel_name = f"de{self.version[2:]}.bsp"
176
+ kernel_url = f"https://naif.jpl.nasa.gov/pub/naif/generic_kernels/spk/planets/{kernel_name}"
177
+
178
+ # Try to download if not exists
179
+ kernel_path = os.path.expanduser(f"~/.jplephem/{kernel_name}")
180
+ os_dir = os.path.dirname(kernel_path)
181
+ if not os.path.exists(os_dir):
182
+ os.makedirs(os_dir, exist_ok=True)
183
+
184
+ if not os.path.exists(kernel_path):
185
+ try:
186
+ urllib.request.urlretrieve(kernel_url, kernel_path)
187
+ except Exception as e:
188
+ raise RuntimeError(
189
+ f"Could not download ephemeris kernel from {kernel_url}. "
190
+ f"Please download manually and place at {kernel_path}"
191
+ ) from e
192
+
193
+ # Load the kernel using DAF and SPK
194
+ daf = DAF(open(kernel_path, "rb"))
195
+ self._kernel = SPK(daf)
196
+
197
+ except Exception as e:
198
+ raise RuntimeError(
199
+ f"Failed to load ephemeris kernel for version {self.version}. "
200
+ f"Ensure jplephem is installed and kernel files are accessible. "
201
+ f"Error: {str(e)}"
202
+ ) from e
203
+
204
+ return self._kernel
205
+
206
+ def sun_position(
207
+ self, jd: float, frame: Literal["icrf", "ecliptic"] = "icrf"
208
+ ) -> Tuple[NDArray[np.floating], NDArray[np.floating]]:
209
+ """Compute Sun position and velocity.
210
+
211
+ Parameters
212
+ ----------
213
+ jd : float
214
+ Julian Day in Terrestrial Time (TT)
215
+ frame : {'icrf', 'ecliptic'}, optional
216
+ Coordinate frame (default: 'icrf').
217
+ - 'icrf': International Celestial Reference Frame
218
+ - 'ecliptic': Ecliptic coordinate system (J2000.0)
219
+
220
+ Returns
221
+ -------
222
+ position : ndarray, shape (3,)
223
+ Sun position in AU
224
+ velocity : ndarray, shape (3,)
225
+ Sun velocity in AU/day
226
+
227
+ Notes
228
+ -----
229
+ The Sun's position is computed relative to the Solar System Barycenter
230
+ (SSB) in the ICRF frame.
231
+
232
+ Examples
233
+ --------
234
+ >>> eph = DEEphemeris()
235
+ >>> r, v = eph.sun_position(2451545.0)
236
+ >>> print(f"Distance: {np.linalg.norm(r):.6f} AU")
237
+
238
+ """
239
+ # Sun position relative to SSB (in km)
240
+ segment = self.kernel[0, 10]
241
+ position, velocity = segment.compute_and_differentiate(jd)
242
+
243
+ # Convert from km to AU
244
+ position = np.array(position) * AU_PER_KM
245
+ velocity = np.array(velocity) * KM_PER_DAY_TO_AU_PER_DAY
246
+
247
+ if frame == "ecliptic":
248
+ from . import reference_frames
249
+
250
+ position = reference_frames.equatorial_to_ecliptic(position, EPSILON_J2000)
251
+ velocity = reference_frames.equatorial_to_ecliptic(velocity, EPSILON_J2000)
252
+
253
+ return position, velocity
254
+
255
+ def moon_position(
256
+ self, jd: float, frame: Literal["icrf", "ecliptic", "earth_centered"] = "icrf"
257
+ ) -> Tuple[NDArray[np.floating], NDArray[np.floating]]:
258
+ """Compute Moon position and velocity.
259
+
260
+ Parameters
261
+ ----------
262
+ jd : float
263
+ Julian Day in Terrestrial Time (TT)
264
+ frame : {'icrf', 'ecliptic', 'earth_centered'}, optional
265
+ Coordinate frame (default: 'icrf').
266
+ - 'icrf': Moon position relative to Solar System Barycenter
267
+ - 'ecliptic': Ecliptic coordinates
268
+ - 'earth_centered': Position relative to Earth
269
+
270
+ Returns
271
+ -------
272
+ position : ndarray, shape (3,)
273
+ Moon position in AU (or relative to Earth for 'earth_centered')
274
+ velocity : ndarray, shape (3,)
275
+ Moon velocity in AU/day
276
+
277
+ Notes
278
+ -----
279
+ By default, returns Moon position relative to the Solar System Barycenter.
280
+ Use frame='earth_centered' for geocentric coordinates.
281
+
282
+ Examples
283
+ --------
284
+ >>> eph = DEEphemeris()
285
+ >>> r, v = eph.moon_position(2451545.0, frame='earth_centered')
286
+
287
+ """
288
+ if frame == "earth_centered":
289
+ # Moon relative to Earth
290
+ segment = self.kernel[3, 301]
291
+ position, velocity = segment.compute_and_differentiate(jd)
292
+ else:
293
+ # Moon relative to SSB: need to compute Earth->Moon, then add Earth->SSB
294
+ # Get Earth barycenter position
295
+ earth_segment = self.kernel[0, 3]
296
+ earth_pos, earth_vel = earth_segment.compute_and_differentiate(jd)
297
+
298
+ # Get Moon position relative to Earth
299
+ moon_segment = self.kernel[3, 301]
300
+ moon_rel_earth_pos, moon_rel_earth_vel = (
301
+ moon_segment.compute_and_differentiate(jd)
302
+ )
303
+
304
+ # Moon position relative to SSB
305
+ position = earth_pos + moon_rel_earth_pos
306
+ velocity = earth_vel + moon_rel_earth_vel
307
+
308
+ # Convert from km to AU
309
+ position = np.array(position) * AU_PER_KM
310
+ velocity = np.array(velocity) * KM_PER_DAY_TO_AU_PER_DAY
311
+
312
+ if frame == "ecliptic":
313
+ from . import reference_frames
314
+
315
+ position = reference_frames.equatorial_to_ecliptic(position, EPSILON_J2000)
316
+ velocity = reference_frames.equatorial_to_ecliptic(velocity, EPSILON_J2000)
317
+
318
+ return position, velocity
319
+
320
+ def planet_position(
321
+ self,
322
+ planet: Literal[
323
+ "mercury", "venus", "mars", "jupiter", "saturn", "uranus", "neptune"
324
+ ],
325
+ jd: float,
326
+ frame: Literal["icrf", "ecliptic"] = "icrf",
327
+ ) -> Tuple[np.ndarray[Any, Any], np.ndarray[Any, Any]]:
328
+ """Compute planet position and velocity.
329
+
330
+ Parameters
331
+ ----------
332
+ planet : str
333
+ Planet name: 'mercury', 'venus', 'mars', 'jupiter', 'saturn',
334
+ 'uranus', 'neptune'
335
+ jd : float
336
+ Julian Day in Terrestrial Time (TT)
337
+ frame : {'icrf', 'ecliptic'}, optional
338
+ Coordinate frame (default: 'icrf')
339
+
340
+ Returns
341
+ -------
342
+ position : ndarray, shape (3,)
343
+ Planet position in AU
344
+ velocity : ndarray, shape (3,)
345
+ Planet velocity in AU/day
346
+
347
+ Raises
348
+ ------
349
+ ValueError
350
+ If planet name is not recognized
351
+
352
+ Examples
353
+ --------
354
+ >>> eph = DEEphemeris()
355
+ >>> r, v = eph.planet_position('mars', 2451545.0)
356
+
357
+ """
358
+ planet_lower = planet.lower()
359
+ if planet_lower not in self._BODY_IDS or planet_lower == "sun":
360
+ raise ValueError(
361
+ f"Planet must be one of {set(self._BODY_IDS.keys()) - {'sun', 'moon'}}, "
362
+ f"got '{planet}'"
363
+ )
364
+
365
+ planet_id = self._BODY_IDS[planet_lower]
366
+ segment = self.kernel[0, planet_id]
367
+ position, velocity = segment.compute_and_differentiate(jd)
368
+
369
+ # Convert from km to AU
370
+ position = np.array(position) * AU_PER_KM
371
+ velocity = np.array(velocity) * KM_PER_DAY_TO_AU_PER_DAY
372
+
373
+ if frame == "ecliptic":
374
+ from . import reference_frames
375
+
376
+ position = reference_frames.equatorial_to_ecliptic(position, EPSILON_J2000)
377
+ velocity = reference_frames.equatorial_to_ecliptic(velocity, EPSILON_J2000)
378
+
379
+ return position, velocity
380
+
381
+ def barycenter_position(
382
+ self, body: str, jd: float
383
+ ) -> Tuple[NDArray[np.floating], NDArray[np.floating]]:
384
+ """Compute position of any body relative to Solar System Barycenter.
385
+
386
+ Parameters
387
+ ----------
388
+ body : str
389
+ Body name ('sun', 'moon', 'mercury', ..., 'neptune')
390
+ jd : float
391
+ Julian Day in Terrestrial Time (TT)
392
+
393
+ Returns
394
+ -------
395
+ position : ndarray, shape (3,)
396
+ Position in AU
397
+ velocity : ndarray, shape (3,)
398
+ Velocity in AU/day
399
+
400
+ """
401
+ if body.lower() == "sun":
402
+ return self.sun_position(jd)
403
+ elif body.lower() == "moon":
404
+ return self.moon_position(jd, frame="icrf")
405
+ else:
406
+ return self.planet_position(body, jd)
407
+
408
+ def clear_cache(self) -> None:
409
+ """Clear internal position cache."""
410
+ self._cache.clear()
411
+
412
+
413
+ # Module-level convenience functions
414
+
415
+ _default_eph: Optional[DEEphemeris] = None
416
+
417
+
418
+ def _get_default_ephemeris() -> DEEphemeris:
419
+ """Get or create default ephemeris instance."""
420
+ global _default_eph
421
+ if _default_eph is None:
422
+ _default_eph = DEEphemeris(version="DE440")
423
+ return _default_eph
424
+
425
+
426
+ def sun_position(
427
+ jd: float, frame: Literal["icrf", "ecliptic"] = "icrf"
428
+ ) -> Tuple[NDArray[np.floating], NDArray[np.floating]]:
429
+ """Convenience function: Compute Sun position and velocity.
430
+
431
+ Parameters
432
+ ----------
433
+ jd : float
434
+ Julian Day in Terrestrial Time (TT)
435
+ frame : {'icrf', 'ecliptic'}, optional
436
+ Coordinate frame (default: 'icrf')
437
+
438
+ Returns
439
+ -------
440
+ position : ndarray, shape (3,)
441
+ Sun position in AU
442
+ velocity : ndarray, shape (3,)
443
+ Sun velocity in AU/day
444
+
445
+ See Also
446
+ --------
447
+ DEEphemeris.sun_position : Full ephemeris class with caching
448
+
449
+ """
450
+ return _get_default_ephemeris().sun_position(jd, frame=frame)
451
+
452
+
453
+ def moon_position(
454
+ jd: float, frame: Literal["icrf", "ecliptic", "earth_centered"] = "icrf"
455
+ ) -> Tuple[NDArray[np.floating], NDArray[np.floating]]:
456
+ """Convenience function: Compute Moon position and velocity.
457
+
458
+ Parameters
459
+ ----------
460
+ jd : float
461
+ Julian Day in Terrestrial Time (TT)
462
+ frame : {'icrf', 'ecliptic', 'earth_centered'}, optional
463
+ Coordinate frame (default: 'icrf')
464
+
465
+ Returns
466
+ -------
467
+ position : ndarray, shape (3,)
468
+ Moon position in AU
469
+ velocity : ndarray, shape (3,)
470
+ Moon velocity in AU/day
471
+
472
+ See Also
473
+ --------
474
+ DEEphemeris.moon_position : Full ephemeris class with caching
475
+
476
+ """
477
+ return _get_default_ephemeris().moon_position(jd, frame=frame)
478
+
479
+
480
+ def planet_position(
481
+ planet: Literal[
482
+ "mercury", "venus", "mars", "jupiter", "saturn", "uranus", "neptune"
483
+ ],
484
+ jd: float,
485
+ frame: Literal["icrf", "ecliptic"] = "icrf",
486
+ ) -> Tuple[np.ndarray[Any, Any], np.ndarray[Any, Any]]:
487
+ """Convenience function: Compute planet position and velocity.
488
+
489
+ Parameters
490
+ ----------
491
+ planet : str
492
+ Planet name
493
+ jd : float
494
+ Julian Day in Terrestrial Time (TT)
495
+ frame : {'icrf', 'ecliptic'}, optional
496
+ Coordinate frame (default: 'icrf')
497
+
498
+ Returns
499
+ -------
500
+ position : ndarray, shape (3,)
501
+ Planet position in AU
502
+ velocity : ndarray, shape (3,)
503
+ Planet velocity in AU/day
504
+
505
+ See Also
506
+ --------
507
+ DEEphemeris.planet_position : Full ephemeris class with caching
508
+
509
+ """
510
+ return _get_default_ephemeris().planet_position(planet, jd, frame=frame)
511
+
512
+
513
+ def barycenter_position(
514
+ body: str, jd: float
515
+ ) -> Tuple[NDArray[np.floating], NDArray[np.floating]]:
516
+ """Convenience function: Position relative to Solar System Barycenter.
517
+
518
+ Parameters
519
+ ----------
520
+ body : str
521
+ Body name ('sun', 'moon', 'mercury', ..., 'neptune')
522
+ jd : float
523
+ Julian Day in Terrestrial Time (TT)
524
+
525
+ Returns
526
+ -------
527
+ position : ndarray, shape (3,)
528
+ Position in AU
529
+ velocity : ndarray, shape (3,)
530
+ Velocity in AU/day
531
+
532
+ """
533
+ return _get_default_ephemeris().barycenter_position(body, jd)