nrl-tracker 0.21.4__py3-none-any.whl → 0.22.0__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 (138) hide show
  1. {nrl_tracker-0.21.4.dist-info → nrl_tracker-0.22.0.dist-info}/METADATA +2 -2
  2. nrl_tracker-0.22.0.dist-info/RECORD +150 -0
  3. pytcl/__init__.py +9 -11
  4. pytcl/assignment_algorithms/__init__.py +32 -42
  5. pytcl/assignment_algorithms/data_association.py +9 -10
  6. pytcl/assignment_algorithms/gating.py +7 -5
  7. pytcl/assignment_algorithms/jpda.py +10 -14
  8. pytcl/assignment_algorithms/three_dimensional/__init__.py +6 -8
  9. pytcl/assignment_algorithms/three_dimensional/assignment.py +6 -2
  10. pytcl/assignment_algorithms/two_dimensional/__init__.py +9 -13
  11. pytcl/assignment_algorithms/two_dimensional/assignment.py +5 -2
  12. pytcl/assignment_algorithms/two_dimensional/kbest.py +9 -9
  13. pytcl/astronomical/__init__.py +130 -89
  14. pytcl/astronomical/ephemerides.py +524 -0
  15. pytcl/astronomical/lambert.py +6 -15
  16. pytcl/astronomical/orbital_mechanics.py +1 -3
  17. pytcl/astronomical/reference_frames.py +1 -3
  18. pytcl/astronomical/relativity.py +466 -0
  19. pytcl/astronomical/time_systems.py +2 -1
  20. pytcl/atmosphere/__init__.py +12 -14
  21. pytcl/atmosphere/models.py +5 -5
  22. pytcl/clustering/__init__.py +28 -36
  23. pytcl/clustering/dbscan.py +5 -2
  24. pytcl/clustering/gaussian_mixture.py +10 -10
  25. pytcl/clustering/hierarchical.py +7 -7
  26. pytcl/clustering/kmeans.py +7 -5
  27. pytcl/containers/__init__.py +29 -43
  28. pytcl/containers/cluster_set.py +13 -20
  29. pytcl/containers/covertree.py +8 -2
  30. pytcl/containers/kd_tree.py +6 -2
  31. pytcl/containers/measurement_set.py +11 -16
  32. pytcl/containers/rtree.py +8 -7
  33. pytcl/containers/track_list.py +13 -13
  34. pytcl/containers/vptree.py +7 -2
  35. pytcl/coordinate_systems/__init__.py +69 -74
  36. pytcl/coordinate_systems/conversions/__init__.py +20 -24
  37. pytcl/coordinate_systems/conversions/geodetic.py +7 -17
  38. pytcl/coordinate_systems/conversions/spherical.py +4 -2
  39. pytcl/coordinate_systems/jacobians/__init__.py +10 -12
  40. pytcl/coordinate_systems/jacobians/jacobians.py +2 -1
  41. pytcl/coordinate_systems/projections/__init__.py +27 -23
  42. pytcl/coordinate_systems/projections/projections.py +14 -39
  43. pytcl/coordinate_systems/rotations/__init__.py +20 -22
  44. pytcl/coordinate_systems/rotations/rotations.py +3 -4
  45. pytcl/core/__init__.py +16 -22
  46. pytcl/core/array_utils.py +7 -7
  47. pytcl/core/constants.py +1 -3
  48. pytcl/core/validation.py +13 -19
  49. pytcl/dynamic_estimation/__init__.py +77 -86
  50. pytcl/dynamic_estimation/imm.py +10 -15
  51. pytcl/dynamic_estimation/information_filter.py +8 -6
  52. pytcl/dynamic_estimation/kalman/__init__.py +40 -48
  53. pytcl/dynamic_estimation/kalman/extended.py +4 -5
  54. pytcl/dynamic_estimation/kalman/linear.py +7 -3
  55. pytcl/dynamic_estimation/kalman/square_root.py +7 -8
  56. pytcl/dynamic_estimation/kalman/unscented.py +8 -6
  57. pytcl/dynamic_estimation/particle_filters/__init__.py +12 -14
  58. pytcl/dynamic_estimation/particle_filters/bootstrap.py +8 -8
  59. pytcl/dynamic_estimation/smoothers.py +9 -10
  60. pytcl/dynamic_models/__init__.py +37 -41
  61. pytcl/dynamic_models/continuous_time/__init__.py +11 -11
  62. pytcl/dynamic_models/continuous_time/dynamics.py +4 -2
  63. pytcl/dynamic_models/discrete_time/__init__.py +11 -17
  64. pytcl/dynamic_models/process_noise/__init__.py +11 -17
  65. pytcl/dynamic_models/process_noise/polynomial.py +2 -6
  66. pytcl/gravity/__init__.py +55 -65
  67. pytcl/gravity/clenshaw.py +4 -7
  68. pytcl/gravity/egm.py +9 -6
  69. pytcl/gravity/models.py +1 -3
  70. pytcl/gravity/spherical_harmonics.py +6 -11
  71. pytcl/gravity/tides.py +9 -17
  72. pytcl/magnetism/__init__.py +26 -36
  73. pytcl/magnetism/emm.py +7 -13
  74. pytcl/magnetism/igrf.py +5 -6
  75. pytcl/magnetism/wmm.py +4 -10
  76. pytcl/mathematical_functions/__init__.py +69 -87
  77. pytcl/mathematical_functions/basic_matrix/__init__.py +25 -19
  78. pytcl/mathematical_functions/basic_matrix/decompositions.py +6 -5
  79. pytcl/mathematical_functions/basic_matrix/special_matrices.py +2 -1
  80. pytcl/mathematical_functions/combinatorics/__init__.py +18 -14
  81. pytcl/mathematical_functions/combinatorics/combinatorics.py +5 -4
  82. pytcl/mathematical_functions/geometry/__init__.py +15 -15
  83. pytcl/mathematical_functions/geometry/geometry.py +10 -15
  84. pytcl/mathematical_functions/interpolation/__init__.py +11 -13
  85. pytcl/mathematical_functions/interpolation/interpolation.py +8 -5
  86. pytcl/mathematical_functions/numerical_integration/__init__.py +16 -10
  87. pytcl/mathematical_functions/numerical_integration/quadrature.py +6 -2
  88. pytcl/mathematical_functions/signal_processing/__init__.py +42 -30
  89. pytcl/mathematical_functions/signal_processing/detection.py +9 -9
  90. pytcl/mathematical_functions/signal_processing/filters.py +7 -8
  91. pytcl/mathematical_functions/signal_processing/matched_filter.py +8 -7
  92. pytcl/mathematical_functions/special_functions/__init__.py +75 -77
  93. pytcl/mathematical_functions/special_functions/bessel.py +2 -1
  94. pytcl/mathematical_functions/special_functions/debye.py +4 -2
  95. pytcl/mathematical_functions/special_functions/elliptic.py +3 -4
  96. pytcl/mathematical_functions/special_functions/error_functions.py +2 -1
  97. pytcl/mathematical_functions/special_functions/gamma_functions.py +3 -4
  98. pytcl/mathematical_functions/special_functions/hypergeometric.py +2 -1
  99. pytcl/mathematical_functions/special_functions/lambert_w.py +3 -4
  100. pytcl/mathematical_functions/special_functions/marcum_q.py +2 -1
  101. pytcl/mathematical_functions/statistics/__init__.py +27 -31
  102. pytcl/mathematical_functions/statistics/distributions.py +21 -40
  103. pytcl/mathematical_functions/statistics/estimators.py +3 -4
  104. pytcl/mathematical_functions/transforms/__init__.py +45 -51
  105. pytcl/mathematical_functions/transforms/fourier.py +5 -2
  106. pytcl/mathematical_functions/transforms/stft.py +8 -11
  107. pytcl/mathematical_functions/transforms/wavelets.py +13 -20
  108. pytcl/navigation/__init__.py +96 -102
  109. pytcl/navigation/geodesy.py +13 -33
  110. pytcl/navigation/great_circle.py +7 -13
  111. pytcl/navigation/ins.py +12 -16
  112. pytcl/navigation/ins_gnss.py +24 -37
  113. pytcl/navigation/rhumb.py +7 -12
  114. pytcl/performance_evaluation/__init__.py +21 -25
  115. pytcl/performance_evaluation/estimation_metrics.py +3 -1
  116. pytcl/performance_evaluation/track_metrics.py +4 -4
  117. pytcl/plotting/__init__.py +30 -38
  118. pytcl/plotting/coordinates.py +8 -18
  119. pytcl/plotting/ellipses.py +5 -2
  120. pytcl/plotting/metrics.py +5 -10
  121. pytcl/plotting/tracks.py +7 -12
  122. pytcl/static_estimation/__init__.py +37 -41
  123. pytcl/static_estimation/least_squares.py +5 -4
  124. pytcl/static_estimation/maximum_likelihood.py +8 -5
  125. pytcl/static_estimation/robust.py +5 -2
  126. pytcl/terrain/__init__.py +28 -34
  127. pytcl/terrain/dem.py +6 -9
  128. pytcl/terrain/loaders.py +9 -14
  129. pytcl/terrain/visibility.py +4 -8
  130. pytcl/trackers/__init__.py +17 -25
  131. pytcl/trackers/hypothesis.py +8 -8
  132. pytcl/trackers/mht.py +18 -24
  133. pytcl/trackers/multi_target.py +8 -6
  134. pytcl/trackers/single_target.py +5 -2
  135. nrl_tracker-0.21.4.dist-info/RECORD +0 -148
  136. {nrl_tracker-0.21.4.dist-info → nrl_tracker-0.22.0.dist-info}/LICENSE +0 -0
  137. {nrl_tracker-0.21.4.dist-info → nrl_tracker-0.22.0.dist-info}/WHEEL +0 -0
  138. {nrl_tracker-0.21.4.dist-info → nrl_tracker-0.22.0.dist-info}/top_level.txt +0 -0
@@ -12,11 +12,15 @@ References
12
12
  """
13
13
 
14
14
  from enum import Enum
15
- from typing import List, Literal, NamedTuple, Optional
15
+ from typing import List
16
+ from typing import Literal
17
+ from typing import NamedTuple
18
+ from typing import Optional
16
19
 
17
20
  import numpy as np
18
21
  from numba import njit
19
- from numpy.typing import ArrayLike, NDArray
22
+ from numpy.typing import ArrayLike
23
+ from numpy.typing import NDArray
20
24
 
21
25
 
22
26
  class LinkageType(Enum):
@@ -152,11 +156,7 @@ def _ward_linkage(
152
156
  """Ward's linkage: minimum variance merge."""
153
157
  total = size_i + size_j + size_k
154
158
  return np.sqrt(
155
- (
156
- (size_i + size_k) * dist_i**2
157
- + (size_j + size_k) * dist_j**2
158
- - size_k * dist_ij**2
159
- )
159
+ ((size_i + size_k) * dist_i**2 + (size_j + size_k) * dist_j**2 - size_k * dist_ij**2)
160
160
  / total
161
161
  )
162
162
 
@@ -10,10 +10,14 @@ References
10
10
  Careful Seeding," SODA 2007.
11
11
  """
12
12
 
13
- from typing import Literal, NamedTuple, Optional, Union
13
+ from typing import Literal
14
+ from typing import NamedTuple
15
+ from typing import Optional
16
+ from typing import Union
14
17
 
15
18
  import numpy as np
16
- from numpy.typing import ArrayLike, NDArray
19
+ from numpy.typing import ArrayLike
20
+ from numpy.typing import NDArray
17
21
  from scipy.spatial.distance import cdist
18
22
 
19
23
 
@@ -250,9 +254,7 @@ def kmeans(
250
254
  raise ValueError(f"n_clusters ({n_clusters}) > n_samples ({n_samples})")
251
255
 
252
256
  # Check if initial centers are provided
253
- if isinstance(init, np.ndarray) or (
254
- isinstance(init, (list, tuple)) and len(init) > 0
255
- ):
257
+ if isinstance(init, np.ndarray) or (isinstance(init, (list, tuple)) and len(init) > 0):
256
258
  init_centers = np.asarray(init, dtype=np.float64)
257
259
  if init_centers.shape != (n_clusters, n_features):
258
260
  raise ValueError(
@@ -5,49 +5,35 @@ This module provides spatial data structures for efficient
5
5
  nearest neighbor queries, spatial indexing, and tracking containers.
6
6
  """
7
7
 
8
- from pytcl.containers.cluster_set import (
9
- ClusterSet,
10
- ClusterStats,
11
- TrackCluster,
12
- cluster_tracks_dbscan,
13
- cluster_tracks_kmeans,
14
- compute_cluster_centroid,
15
- )
16
- from pytcl.containers.covertree import (
17
- CoverTree,
18
- CoverTreeNode,
19
- CoverTreeResult,
20
- )
21
- from pytcl.containers.kd_tree import (
22
- BallTree,
23
- KDNode,
24
- KDTree,
25
- NearestNeighborResult,
26
- )
27
- from pytcl.containers.measurement_set import (
28
- Measurement,
29
- MeasurementQuery,
30
- MeasurementSet,
31
- )
32
- from pytcl.containers.rtree import (
33
- BoundingBox,
34
- RTree,
35
- RTreeNode,
36
- RTreeResult,
37
- box_from_point,
38
- box_from_points,
39
- merge_boxes,
40
- )
41
- from pytcl.containers.track_list import (
42
- TrackList,
43
- TrackListStats,
44
- TrackQuery,
45
- )
46
- from pytcl.containers.vptree import (
47
- VPNode,
48
- VPTree,
49
- VPTreeResult,
50
- )
8
+ from pytcl.containers.cluster_set import ClusterSet
9
+ from pytcl.containers.cluster_set import ClusterStats
10
+ from pytcl.containers.cluster_set import TrackCluster
11
+ from pytcl.containers.cluster_set import cluster_tracks_dbscan
12
+ from pytcl.containers.cluster_set import cluster_tracks_kmeans
13
+ from pytcl.containers.cluster_set import compute_cluster_centroid
14
+ from pytcl.containers.covertree import CoverTree
15
+ from pytcl.containers.covertree import CoverTreeNode
16
+ from pytcl.containers.covertree import CoverTreeResult
17
+ from pytcl.containers.kd_tree import BallTree
18
+ from pytcl.containers.kd_tree import KDNode
19
+ from pytcl.containers.kd_tree import KDTree
20
+ from pytcl.containers.kd_tree import NearestNeighborResult
21
+ from pytcl.containers.measurement_set import Measurement
22
+ from pytcl.containers.measurement_set import MeasurementQuery
23
+ from pytcl.containers.measurement_set import MeasurementSet
24
+ from pytcl.containers.rtree import BoundingBox
25
+ from pytcl.containers.rtree import RTree
26
+ from pytcl.containers.rtree import RTreeNode
27
+ from pytcl.containers.rtree import RTreeResult
28
+ from pytcl.containers.rtree import box_from_point
29
+ from pytcl.containers.rtree import box_from_points
30
+ from pytcl.containers.rtree import merge_boxes
31
+ from pytcl.containers.track_list import TrackList
32
+ from pytcl.containers.track_list import TrackListStats
33
+ from pytcl.containers.track_list import TrackQuery
34
+ from pytcl.containers.vptree import VPNode
35
+ from pytcl.containers.vptree import VPTree
36
+ from pytcl.containers.vptree import VPTreeResult
51
37
 
52
38
  __all__ = [
53
39
  # K-D Tree
@@ -7,19 +7,18 @@ that move together (formations, convoys, etc.).
7
7
 
8
8
  from __future__ import annotations
9
9
 
10
- from typing import (
11
- Dict,
12
- Iterable,
13
- Iterator,
14
- List,
15
- NamedTuple,
16
- Optional,
17
- Tuple,
18
- Union,
19
- )
10
+ from typing import Dict
11
+ from typing import Iterable
12
+ from typing import Iterator
13
+ from typing import List
14
+ from typing import NamedTuple
15
+ from typing import Optional
16
+ from typing import Tuple
17
+ from typing import Union
20
18
 
21
19
  import numpy as np
22
- from numpy.typing import ArrayLike, NDArray
20
+ from numpy.typing import ArrayLike
21
+ from numpy.typing import NDArray
23
22
 
24
23
  from pytcl.clustering.dbscan import dbscan
25
24
  from pytcl.clustering.kmeans import kmeans
@@ -299,9 +298,7 @@ class ClusterSet:
299
298
  self._clusters = list(clusters)
300
299
 
301
300
  # Build lookups
302
- self._id_to_idx: Dict[int, int] = {
303
- c.id: i for i, c in enumerate(self._clusters)
304
- }
301
+ self._id_to_idx: Dict[int, int] = {c.id: i for i, c in enumerate(self._clusters)}
305
302
  self._track_to_cluster: Dict[int, int] = {}
306
303
  for cluster in self._clusters:
307
304
  for track_id in cluster.track_ids:
@@ -418,9 +415,7 @@ class ClusterSet:
418
415
  return self.get_cluster(cluster_id)
419
416
  return None
420
417
 
421
- def clusters_in_region(
422
- self, center: ArrayLike, radius: float
423
- ) -> List[TrackCluster]:
418
+ def clusters_in_region(self, center: ArrayLike, radius: float) -> List[TrackCluster]:
424
419
  """
425
420
  Get clusters with centroids within a spatial region.
426
421
 
@@ -569,9 +564,7 @@ class ClusterSet:
569
564
  """
570
565
  result = {}
571
566
  for cluster in self._clusters:
572
- stats = self.cluster_stats(
573
- cluster.id, tracks, state_indices, velocity_indices
574
- )
567
+ stats = self.cluster_stats(cluster.id, tracks, state_indices, velocity_indices)
575
568
  if stats is not None:
576
569
  result[cluster.id] = stats
577
570
  return result
@@ -11,10 +11,16 @@ References
11
11
  neighbor," ICML 2006.
12
12
  """
13
13
 
14
- from typing import Callable, List, NamedTuple, Optional, Set, Tuple
14
+ from typing import Callable
15
+ from typing import List
16
+ from typing import NamedTuple
17
+ from typing import Optional
18
+ from typing import Set
19
+ from typing import Tuple
15
20
 
16
21
  import numpy as np
17
- from numpy.typing import ArrayLike, NDArray
22
+ from numpy.typing import ArrayLike
23
+ from numpy.typing import NDArray
18
24
 
19
25
 
20
26
  class CoverTreeResult(NamedTuple):
@@ -13,10 +13,14 @@ References
13
13
  Finding Best Matches in Logarithmic Expected Time," ACM TOMS, 1977.
14
14
  """
15
15
 
16
- from typing import List, NamedTuple, Optional, Tuple
16
+ from typing import List
17
+ from typing import NamedTuple
18
+ from typing import Optional
19
+ from typing import Tuple
17
20
 
18
21
  import numpy as np
19
- from numpy.typing import ArrayLike, NDArray
22
+ from numpy.typing import ArrayLike
23
+ from numpy.typing import NDArray
20
24
 
21
25
 
22
26
  class KDNode:
@@ -7,18 +7,17 @@ with spatial query support.
7
7
 
8
8
  from __future__ import annotations
9
9
 
10
- from typing import (
11
- Iterable,
12
- Iterator,
13
- List,
14
- NamedTuple,
15
- Optional,
16
- Tuple,
17
- Union,
18
- )
10
+ from typing import Iterable
11
+ from typing import Iterator
12
+ from typing import List
13
+ from typing import NamedTuple
14
+ from typing import Optional
15
+ from typing import Tuple
16
+ from typing import Union
19
17
 
20
18
  import numpy as np
21
- from numpy.typing import ArrayLike, NDArray
19
+ from numpy.typing import ArrayLike
20
+ from numpy.typing import NDArray
22
21
 
23
22
  from pytcl.containers.kd_tree import KDTree
24
23
 
@@ -211,9 +210,7 @@ class MeasurementSet:
211
210
  MeasurementSet
212
211
  Measurements at the specified time.
213
212
  """
214
- measurements = [
215
- m for m in self._measurements if abs(m.time - time) <= tolerance
216
- ]
213
+ measurements = [m for m in self._measurements if abs(m.time - time) <= tolerance]
217
214
  return MeasurementSet(measurements)
218
215
 
219
216
  def in_time_window(self, start: float, end: float) -> MeasurementSet:
@@ -354,9 +351,7 @@ class MeasurementSet:
354
351
  return np.zeros((0, 0))
355
352
  return np.array([m.value for m in self._measurements])
356
353
 
357
- def values_at_time(
358
- self, time: float, tolerance: float = 1e-9
359
- ) -> NDArray[np.float64]:
354
+ def values_at_time(self, time: float, tolerance: float = 1e-9) -> NDArray[np.float64]:
360
355
  """
361
356
  Extract measurement values at a specific time.
362
357
 
pytcl/containers/rtree.py CHANGED
@@ -13,10 +13,14 @@ References
13
13
  Method for Points and Rectangles," ACM SIGMOD, 1990.
14
14
  """
15
15
 
16
- from typing import List, NamedTuple, Optional, Tuple
16
+ from typing import List
17
+ from typing import NamedTuple
18
+ from typing import Optional
19
+ from typing import Tuple
17
20
 
18
21
  import numpy as np
19
- from numpy.typing import ArrayLike, NDArray
22
+ from numpy.typing import ArrayLike
23
+ from numpy.typing import NDArray
20
24
 
21
25
 
22
26
  class BoundingBox(NamedTuple):
@@ -281,9 +285,7 @@ class RTree:
281
285
 
282
286
  # Simple split: sort by center x-coordinate and split in half
283
287
  if node.is_leaf:
284
- sorted_entries = sorted(
285
- entries, key=lambda e: e[0].center[0] if e[0] else 0
286
- )
288
+ sorted_entries = sorted(entries, key=lambda e: e[0].center[0] if e[0] else 0)
287
289
  else:
288
290
  sorted_entries = sorted(
289
291
  entries,
@@ -481,8 +483,7 @@ class RTree:
481
483
  else:
482
484
  # Sort children by distance and search closest first
483
485
  child_dists = [
484
- (min_dist_to_box(query, c.bbox) if c.bbox else np.inf, c)
485
- for c in node.children
486
+ (min_dist_to_box(query, c.bbox) if c.bbox else np.inf, c) for c in node.children
486
487
  ]
487
488
  child_dists.sort(key=lambda x: x[0])
488
489
  for _, child in child_dists:
@@ -7,22 +7,22 @@ with filtering, querying, and batch operations.
7
7
 
8
8
  from __future__ import annotations
9
9
 
10
- from typing import (
11
- TYPE_CHECKING,
12
- Callable,
13
- Iterable,
14
- Iterator,
15
- List,
16
- NamedTuple,
17
- Optional,
18
- Tuple,
19
- Union,
20
- )
10
+ from typing import TYPE_CHECKING
11
+ from typing import Callable
12
+ from typing import Iterable
13
+ from typing import Iterator
14
+ from typing import List
15
+ from typing import NamedTuple
16
+ from typing import Optional
17
+ from typing import Tuple
18
+ from typing import Union
21
19
 
22
20
  import numpy as np
23
- from numpy.typing import ArrayLike, NDArray
21
+ from numpy.typing import ArrayLike
22
+ from numpy.typing import NDArray
24
23
 
25
- from pytcl.trackers.multi_target import Track, TrackStatus
24
+ from pytcl.trackers.multi_target import Track
25
+ from pytcl.trackers.multi_target import TrackStatus
26
26
 
27
27
  if TYPE_CHECKING:
28
28
  from pytcl.trackers.multi_target import MultiTargetTracker
@@ -11,10 +11,15 @@ References
11
11
  neighbor search in general metric spaces," SODA 1993.
12
12
  """
13
13
 
14
- from typing import Callable, List, NamedTuple, Optional, Tuple
14
+ from typing import Callable
15
+ from typing import List
16
+ from typing import NamedTuple
17
+ from typing import Optional
18
+ from typing import Tuple
15
19
 
16
20
  import numpy as np
17
- from numpy.typing import ArrayLike, NDArray
21
+ from numpy.typing import ArrayLike
22
+ from numpy.typing import NDArray
18
23
 
19
24
 
20
25
  class VPTreeResult(NamedTuple):
@@ -15,89 +15,84 @@ systems commonly used in tracking applications:
15
15
  """
16
16
 
17
17
  # Import submodules for easy access
18
- from pytcl.coordinate_systems import conversions, jacobians, projections, rotations
18
+ from pytcl.coordinate_systems import conversions
19
+ from pytcl.coordinate_systems import jacobians
20
+ from pytcl.coordinate_systems import projections
21
+ from pytcl.coordinate_systems import rotations
19
22
 
20
23
  # Geodetic conversions
21
24
  # Spherical/polar conversions
22
- from pytcl.coordinate_systems.conversions import (
23
- cart2cyl,
24
- cart2pol,
25
- cart2ruv,
26
- cart2sphere,
27
- cyl2cart,
28
- ecef2enu,
29
- ecef2geodetic,
30
- ecef2ned,
31
- enu2ecef,
32
- enu2ned,
33
- geocentric_radius,
34
- geodetic2ecef,
35
- geodetic2enu,
36
- meridional_radius,
37
- ned2ecef,
38
- ned2enu,
39
- pol2cart,
40
- prime_vertical_radius,
41
- ruv2cart,
42
- sphere2cart,
43
- )
25
+ from pytcl.coordinate_systems.conversions import cart2cyl
26
+ from pytcl.coordinate_systems.conversions import cart2pol
27
+ from pytcl.coordinate_systems.conversions import cart2ruv
28
+ from pytcl.coordinate_systems.conversions import cart2sphere
29
+ from pytcl.coordinate_systems.conversions import cyl2cart
30
+ from pytcl.coordinate_systems.conversions import ecef2enu
31
+ from pytcl.coordinate_systems.conversions import ecef2geodetic
32
+ from pytcl.coordinate_systems.conversions import ecef2ned
33
+ from pytcl.coordinate_systems.conversions import enu2ecef
34
+ from pytcl.coordinate_systems.conversions import enu2ned
35
+ from pytcl.coordinate_systems.conversions import geocentric_radius
36
+ from pytcl.coordinate_systems.conversions import geodetic2ecef
37
+ from pytcl.coordinate_systems.conversions import geodetic2enu
38
+ from pytcl.coordinate_systems.conversions import meridional_radius
39
+ from pytcl.coordinate_systems.conversions import ned2ecef
40
+ from pytcl.coordinate_systems.conversions import ned2enu
41
+ from pytcl.coordinate_systems.conversions import pol2cart
42
+ from pytcl.coordinate_systems.conversions import prime_vertical_radius
43
+ from pytcl.coordinate_systems.conversions import ruv2cart
44
+ from pytcl.coordinate_systems.conversions import sphere2cart
44
45
 
45
46
  # Jacobians
46
- from pytcl.coordinate_systems.jacobians import (
47
- cross_covariance_transform,
48
- enu_jacobian,
49
- geodetic_jacobian,
50
- ned_jacobian,
51
- numerical_jacobian,
52
- polar_jacobian,
53
- polar_jacobian_inv,
54
- ruv_jacobian,
55
- spherical_jacobian,
56
- spherical_jacobian_inv,
57
- )
47
+ from pytcl.coordinate_systems.jacobians import cross_covariance_transform
48
+ from pytcl.coordinate_systems.jacobians import enu_jacobian
49
+ from pytcl.coordinate_systems.jacobians import geodetic_jacobian
50
+ from pytcl.coordinate_systems.jacobians import ned_jacobian
51
+ from pytcl.coordinate_systems.jacobians import numerical_jacobian
52
+ from pytcl.coordinate_systems.jacobians import polar_jacobian
53
+ from pytcl.coordinate_systems.jacobians import polar_jacobian_inv
54
+ from pytcl.coordinate_systems.jacobians import ruv_jacobian
55
+ from pytcl.coordinate_systems.jacobians import spherical_jacobian
56
+ from pytcl.coordinate_systems.jacobians import spherical_jacobian_inv
58
57
 
59
58
  # Projections
60
- from pytcl.coordinate_systems.projections import (
61
- azimuthal_equidistant,
62
- azimuthal_equidistant_inverse,
63
- geodetic2utm,
64
- lambert_conformal_conic,
65
- lambert_conformal_conic_inverse,
66
- mercator,
67
- mercator_inverse,
68
- polar_stereographic,
69
- stereographic,
70
- stereographic_inverse,
71
- transverse_mercator,
72
- transverse_mercator_inverse,
73
- utm2geodetic,
74
- utm_central_meridian,
75
- utm_zone,
76
- )
59
+ from pytcl.coordinate_systems.projections import azimuthal_equidistant
60
+ from pytcl.coordinate_systems.projections import azimuthal_equidistant_inverse
61
+ from pytcl.coordinate_systems.projections import geodetic2utm
62
+ from pytcl.coordinate_systems.projections import lambert_conformal_conic
63
+ from pytcl.coordinate_systems.projections import lambert_conformal_conic_inverse
64
+ from pytcl.coordinate_systems.projections import mercator
65
+ from pytcl.coordinate_systems.projections import mercator_inverse
66
+ from pytcl.coordinate_systems.projections import polar_stereographic
67
+ from pytcl.coordinate_systems.projections import stereographic
68
+ from pytcl.coordinate_systems.projections import stereographic_inverse
69
+ from pytcl.coordinate_systems.projections import transverse_mercator
70
+ from pytcl.coordinate_systems.projections import transverse_mercator_inverse
71
+ from pytcl.coordinate_systems.projections import utm2geodetic
72
+ from pytcl.coordinate_systems.projections import utm_central_meridian
73
+ from pytcl.coordinate_systems.projections import utm_zone
77
74
 
78
75
  # Rotation operations
79
- from pytcl.coordinate_systems.rotations import (
80
- axisangle2rotmat,
81
- dcm_rate,
82
- euler2quat,
83
- euler2rotmat,
84
- is_rotation_matrix,
85
- quat2euler,
86
- quat2rotmat,
87
- quat_conjugate,
88
- quat_inverse,
89
- quat_multiply,
90
- quat_rotate,
91
- rodrigues2rotmat,
92
- rotmat2axisangle,
93
- rotmat2euler,
94
- rotmat2quat,
95
- rotmat2rodrigues,
96
- rotx,
97
- roty,
98
- rotz,
99
- slerp,
100
- )
76
+ from pytcl.coordinate_systems.rotations import axisangle2rotmat
77
+ from pytcl.coordinate_systems.rotations import dcm_rate
78
+ from pytcl.coordinate_systems.rotations import euler2quat
79
+ from pytcl.coordinate_systems.rotations import euler2rotmat
80
+ from pytcl.coordinate_systems.rotations import is_rotation_matrix
81
+ from pytcl.coordinate_systems.rotations import quat2euler
82
+ from pytcl.coordinate_systems.rotations import quat2rotmat
83
+ from pytcl.coordinate_systems.rotations import quat_conjugate
84
+ from pytcl.coordinate_systems.rotations import quat_inverse
85
+ from pytcl.coordinate_systems.rotations import quat_multiply
86
+ from pytcl.coordinate_systems.rotations import quat_rotate
87
+ from pytcl.coordinate_systems.rotations import rodrigues2rotmat
88
+ from pytcl.coordinate_systems.rotations import rotmat2axisangle
89
+ from pytcl.coordinate_systems.rotations import rotmat2euler
90
+ from pytcl.coordinate_systems.rotations import rotmat2quat
91
+ from pytcl.coordinate_systems.rotations import rotmat2rodrigues
92
+ from pytcl.coordinate_systems.rotations import rotx
93
+ from pytcl.coordinate_systems.rotations import roty
94
+ from pytcl.coordinate_systems.rotations import rotz
95
+ from pytcl.coordinate_systems.rotations import slerp
101
96
 
102
97
  # Re-export commonly used functions at the top level
103
98
 
@@ -8,30 +8,26 @@ This module provides:
8
8
  - Direction cosine representations (r-u-v)
9
9
  """
10
10
 
11
- from pytcl.coordinate_systems.conversions.geodetic import (
12
- ecef2enu,
13
- ecef2geodetic,
14
- ecef2ned,
15
- enu2ecef,
16
- enu2ned,
17
- geocentric_radius,
18
- geodetic2ecef,
19
- geodetic2enu,
20
- meridional_radius,
21
- ned2ecef,
22
- ned2enu,
23
- prime_vertical_radius,
24
- )
25
- from pytcl.coordinate_systems.conversions.spherical import (
26
- cart2cyl,
27
- cart2pol,
28
- cart2ruv,
29
- cart2sphere,
30
- cyl2cart,
31
- pol2cart,
32
- ruv2cart,
33
- sphere2cart,
34
- )
11
+ from pytcl.coordinate_systems.conversions.geodetic import ecef2enu
12
+ from pytcl.coordinate_systems.conversions.geodetic import ecef2geodetic
13
+ from pytcl.coordinate_systems.conversions.geodetic import ecef2ned
14
+ from pytcl.coordinate_systems.conversions.geodetic import enu2ecef
15
+ from pytcl.coordinate_systems.conversions.geodetic import enu2ned
16
+ from pytcl.coordinate_systems.conversions.geodetic import geocentric_radius
17
+ from pytcl.coordinate_systems.conversions.geodetic import geodetic2ecef
18
+ from pytcl.coordinate_systems.conversions.geodetic import geodetic2enu
19
+ from pytcl.coordinate_systems.conversions.geodetic import meridional_radius
20
+ from pytcl.coordinate_systems.conversions.geodetic import ned2ecef
21
+ from pytcl.coordinate_systems.conversions.geodetic import ned2enu
22
+ from pytcl.coordinate_systems.conversions.geodetic import prime_vertical_radius
23
+ from pytcl.coordinate_systems.conversions.spherical import cart2cyl
24
+ from pytcl.coordinate_systems.conversions.spherical import cart2pol
25
+ from pytcl.coordinate_systems.conversions.spherical import cart2ruv
26
+ from pytcl.coordinate_systems.conversions.spherical import cart2sphere
27
+ from pytcl.coordinate_systems.conversions.spherical import cyl2cart
28
+ from pytcl.coordinate_systems.conversions.spherical import pol2cart
29
+ from pytcl.coordinate_systems.conversions.spherical import ruv2cart
30
+ from pytcl.coordinate_systems.conversions.spherical import sphere2cart
35
31
 
36
32
  __all__ = [
37
33
  # Spherical/polar
@@ -6,10 +6,12 @@ longitude, altitude) and Earth-centered coordinate systems (ECEF), as well
6
6
  as local tangent plane coordinates (ENU, NED).
7
7
  """
8
8
 
9
- from typing import Optional, Tuple
9
+ from typing import Optional
10
+ from typing import Tuple
10
11
 
11
12
  import numpy as np
12
- from numpy.typing import ArrayLike, NDArray
13
+ from numpy.typing import ArrayLike
14
+ from numpy.typing import NDArray
13
15
 
14
16
  from pytcl.core.constants import WGS84
15
17
 
@@ -147,9 +149,7 @@ def ecef2geodetic(
147
149
  # Bowring's iterative method
148
150
  # Initial estimate
149
151
  theta = np.arctan2(z * a, p * b)
150
- lat = np.arctan2(
151
- z + ep2 * b * np.sin(theta) ** 3, p - e2 * a * np.cos(theta) ** 3
152
- )
152
+ lat = np.arctan2(z + ep2 * b * np.sin(theta) ** 3, p - e2 * a * np.cos(theta) ** 3)
153
153
 
154
154
  # Iterate for improved accuracy
155
155
  for _ in range(5):
@@ -378,18 +378,8 @@ def enu2ecef(
378
378
  cos_lon = np.cos(lon_ref)
379
379
 
380
380
  # ECEF = R^T @ ENU + ECEF_ref
381
- x = (
382
- -sin_lon * east
383
- - sin_lat * cos_lon * north
384
- + cos_lat * cos_lon * up
385
- + ecef_ref[0]
386
- )
387
- y = (
388
- cos_lon * east
389
- - sin_lat * sin_lon * north
390
- + cos_lat * sin_lon * up
391
- + ecef_ref[1]
392
- )
381
+ x = -sin_lon * east - sin_lat * cos_lon * north + cos_lat * cos_lon * up + ecef_ref[0]
382
+ y = cos_lon * east - sin_lat * sin_lon * north + cos_lat * sin_lon * up + ecef_ref[1]
393
383
  z = cos_lat * north + sin_lat * up + ecef_ref[2]
394
384
 
395
385
  if x.size == 1:
@@ -5,10 +5,12 @@ This module provides functions for converting between Cartesian and
5
5
  spherical/polar coordinate systems, following tracking conventions.
6
6
  """
7
7
 
8
- from typing import Literal, Tuple
8
+ from typing import Literal
9
+ from typing import Tuple
9
10
 
10
11
  import numpy as np
11
- from numpy.typing import ArrayLike, NDArray
12
+ from numpy.typing import ArrayLike
13
+ from numpy.typing import NDArray
12
14
 
13
15
 
14
16
  def cart2sphere(