nrl-tracker 0.22.3__tar.gz → 0.22.4__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 (199) hide show
  1. {nrl_tracker-0.22.3/nrl_tracker.egg-info → nrl_tracker-0.22.4}/PKG-INFO +1 -1
  2. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4/nrl_tracker.egg-info}/PKG-INFO +1 -1
  3. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pyproject.toml +1 -1
  4. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/__init__.py +1 -1
  5. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/assignment_algorithms/gating.py +3 -3
  6. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/assignment_algorithms/jpda.py +12 -4
  7. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/assignment_algorithms/two_dimensional/kbest.py +3 -1
  8. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/astronomical/ephemerides.py +17 -9
  9. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/astronomical/lambert.py +14 -4
  10. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/astronomical/orbital_mechanics.py +3 -1
  11. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/astronomical/reference_frames.py +3 -1
  12. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/astronomical/relativity.py +8 -2
  13. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/atmosphere/models.py +3 -1
  14. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/clustering/gaussian_mixture.py +8 -4
  15. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/clustering/hierarchical.py +5 -1
  16. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/clustering/kmeans.py +3 -1
  17. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/containers/cluster_set.py +9 -3
  18. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/containers/measurement_set.py +6 -2
  19. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/containers/rtree.py +5 -2
  20. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/coordinate_systems/conversions/geodetic.py +15 -3
  21. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/coordinate_systems/projections/projections.py +38 -11
  22. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/coordinate_systems/rotations/rotations.py +3 -1
  23. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/core/array_utils.py +4 -1
  24. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/core/constants.py +3 -1
  25. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/core/validation.py +17 -6
  26. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/dynamic_estimation/imm.py +9 -3
  27. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/dynamic_estimation/kalman/square_root.py +6 -2
  28. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/dynamic_estimation/particle_filters/bootstrap.py +6 -2
  29. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/dynamic_estimation/smoothers.py +3 -1
  30. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/dynamic_models/process_noise/polynomial.py +6 -2
  31. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/gravity/clenshaw.py +6 -2
  32. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/gravity/egm.py +3 -1
  33. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/gravity/models.py +3 -1
  34. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/gravity/spherical_harmonics.py +10 -4
  35. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/gravity/tides.py +16 -7
  36. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/magnetism/emm.py +12 -3
  37. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/magnetism/wmm.py +9 -2
  38. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/mathematical_functions/basic_matrix/decompositions.py +3 -1
  39. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/mathematical_functions/combinatorics/combinatorics.py +3 -1
  40. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/mathematical_functions/geometry/geometry.py +12 -4
  41. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/mathematical_functions/interpolation/interpolation.py +3 -1
  42. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/mathematical_functions/signal_processing/detection.py +6 -3
  43. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/mathematical_functions/signal_processing/filters.py +6 -2
  44. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/mathematical_functions/signal_processing/matched_filter.py +4 -2
  45. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/mathematical_functions/special_functions/elliptic.py +3 -1
  46. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/mathematical_functions/special_functions/gamma_functions.py +3 -1
  47. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/mathematical_functions/special_functions/lambert_w.py +3 -1
  48. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/mathematical_functions/statistics/distributions.py +36 -12
  49. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/mathematical_functions/statistics/estimators.py +3 -1
  50. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/mathematical_functions/transforms/stft.py +9 -3
  51. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/mathematical_functions/transforms/wavelets.py +18 -6
  52. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/navigation/geodesy.py +31 -9
  53. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/navigation/great_circle.py +12 -4
  54. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/navigation/ins.py +8 -2
  55. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/navigation/ins_gnss.py +25 -7
  56. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/navigation/rhumb.py +10 -3
  57. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/performance_evaluation/track_metrics.py +3 -1
  58. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/plotting/coordinates.py +17 -5
  59. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/plotting/metrics.py +9 -3
  60. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/plotting/tracks.py +11 -3
  61. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/static_estimation/least_squares.py +2 -1
  62. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/static_estimation/maximum_likelihood.py +3 -3
  63. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/terrain/dem.py +8 -2
  64. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/terrain/loaders.py +13 -5
  65. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/terrain/visibility.py +7 -2
  66. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/trackers/hypothesis.py +7 -2
  67. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/trackers/mht.py +15 -5
  68. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/tests/conftest.py +3 -1
  69. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/tests/test_astronomical.py +3 -1
  70. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/tests/test_coordinate_systems.py +3 -1
  71. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/tests/test_coverage_boost.py +3 -1
  72. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/tests/test_coverage_boost_2.py +9 -3
  73. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/tests/test_egm.py +54 -18
  74. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/tests/test_emm.py +42 -14
  75. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/tests/test_ephemerides.py +6 -2
  76. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/tests/test_gaussian_mixtures.py +2 -1
  77. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/tests/test_great_circle.py +3 -1
  78. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/tests/test_ins.py +3 -1
  79. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/tests/test_ins_gnss.py +9 -3
  80. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/tests/test_projections.py +3 -1
  81. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/tests/test_relativity.py +9 -3
  82. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/tests/test_smoothers.py +12 -4
  83. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/tests/test_static_estimation.py +9 -3
  84. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/tests/test_tides.py +12 -4
  85. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/tests/test_trackers.py +12 -4
  86. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/tests/test_v030_comprehensive.py +9 -3
  87. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/tests/test_v030_features.py +3 -1
  88. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/CONTRIBUTING.md +0 -0
  89. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/LICENSE +0 -0
  90. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/MANIFEST.in +0 -0
  91. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/README.md +0 -0
  92. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/nrl_tracker.egg-info/SOURCES.txt +0 -0
  93. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/nrl_tracker.egg-info/dependency_links.txt +0 -0
  94. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/nrl_tracker.egg-info/requires.txt +0 -0
  95. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/nrl_tracker.egg-info/top_level.txt +0 -0
  96. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/assignment_algorithms/__init__.py +0 -0
  97. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/assignment_algorithms/data_association.py +0 -0
  98. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/assignment_algorithms/three_dimensional/__init__.py +0 -0
  99. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/assignment_algorithms/three_dimensional/assignment.py +0 -0
  100. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/assignment_algorithms/two_dimensional/__init__.py +0 -0
  101. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/assignment_algorithms/two_dimensional/assignment.py +0 -0
  102. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/astronomical/__init__.py +0 -0
  103. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/astronomical/time_systems.py +0 -0
  104. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/atmosphere/__init__.py +0 -0
  105. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/clustering/__init__.py +0 -0
  106. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/clustering/dbscan.py +0 -0
  107. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/containers/__init__.py +0 -0
  108. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/containers/covertree.py +0 -0
  109. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/containers/kd_tree.py +0 -0
  110. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/containers/track_list.py +0 -0
  111. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/containers/vptree.py +0 -0
  112. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/coordinate_systems/__init__.py +0 -0
  113. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/coordinate_systems/conversions/__init__.py +0 -0
  114. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/coordinate_systems/conversions/spherical.py +0 -0
  115. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/coordinate_systems/jacobians/__init__.py +0 -0
  116. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/coordinate_systems/jacobians/jacobians.py +0 -0
  117. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/coordinate_systems/projections/__init__.py +0 -0
  118. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/coordinate_systems/rotations/__init__.py +0 -0
  119. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/core/__init__.py +0 -0
  120. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/dynamic_estimation/__init__.py +0 -0
  121. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/dynamic_estimation/batch_estimation/__init__.py +0 -0
  122. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/dynamic_estimation/information_filter.py +0 -0
  123. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/dynamic_estimation/kalman/__init__.py +0 -0
  124. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/dynamic_estimation/kalman/extended.py +0 -0
  125. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/dynamic_estimation/kalman/linear.py +0 -0
  126. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/dynamic_estimation/kalman/unscented.py +0 -0
  127. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/dynamic_estimation/measurement_update/__init__.py +0 -0
  128. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/dynamic_estimation/particle_filters/__init__.py +0 -0
  129. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/dynamic_models/__init__.py +0 -0
  130. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/dynamic_models/continuous_time/__init__.py +0 -0
  131. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/dynamic_models/continuous_time/dynamics.py +0 -0
  132. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/dynamic_models/discrete_time/__init__.py +0 -0
  133. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/dynamic_models/discrete_time/coordinated_turn.py +0 -0
  134. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/dynamic_models/discrete_time/polynomial.py +0 -0
  135. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/dynamic_models/discrete_time/singer.py +0 -0
  136. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/dynamic_models/process_noise/__init__.py +0 -0
  137. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/dynamic_models/process_noise/coordinated_turn.py +0 -0
  138. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/dynamic_models/process_noise/singer.py +0 -0
  139. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/gravity/__init__.py +0 -0
  140. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/magnetism/__init__.py +0 -0
  141. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/magnetism/igrf.py +0 -0
  142. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/mathematical_functions/__init__.py +0 -0
  143. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/mathematical_functions/basic_matrix/__init__.py +0 -0
  144. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/mathematical_functions/basic_matrix/special_matrices.py +0 -0
  145. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/mathematical_functions/combinatorics/__init__.py +0 -0
  146. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/mathematical_functions/continuous_optimization/__init__.py +0 -0
  147. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/mathematical_functions/geometry/__init__.py +0 -0
  148. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/mathematical_functions/interpolation/__init__.py +0 -0
  149. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/mathematical_functions/numerical_integration/__init__.py +0 -0
  150. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/mathematical_functions/numerical_integration/quadrature.py +0 -0
  151. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/mathematical_functions/polynomials/__init__.py +0 -0
  152. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/mathematical_functions/signal_processing/__init__.py +0 -0
  153. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/mathematical_functions/special_functions/__init__.py +0 -0
  154. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/mathematical_functions/special_functions/bessel.py +0 -0
  155. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/mathematical_functions/special_functions/debye.py +0 -0
  156. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/mathematical_functions/special_functions/error_functions.py +0 -0
  157. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/mathematical_functions/special_functions/hypergeometric.py +0 -0
  158. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/mathematical_functions/special_functions/marcum_q.py +0 -0
  159. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/mathematical_functions/statistics/__init__.py +0 -0
  160. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/mathematical_functions/transforms/__init__.py +0 -0
  161. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/mathematical_functions/transforms/fourier.py +0 -0
  162. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/misc/__init__.py +0 -0
  163. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/navigation/__init__.py +0 -0
  164. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/performance_evaluation/__init__.py +0 -0
  165. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/performance_evaluation/estimation_metrics.py +0 -0
  166. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/physical_values/__init__.py +0 -0
  167. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/plotting/__init__.py +0 -0
  168. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/plotting/ellipses.py +0 -0
  169. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/scheduling/__init__.py +0 -0
  170. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/static_estimation/__init__.py +0 -0
  171. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/static_estimation/robust.py +0 -0
  172. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/terrain/__init__.py +0 -0
  173. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/trackers/__init__.py +0 -0
  174. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/trackers/multi_target.py +0 -0
  175. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/trackers/single_target.py +0 -0
  176. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/pytcl/transponders/__init__.py +0 -0
  177. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/setup.cfg +0 -0
  178. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/tests/__init__.py +0 -0
  179. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/tests/test_additional_trees.py +0 -0
  180. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/tests/test_assignment_algorithms.py +0 -0
  181. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/tests/test_clustering.py +0 -0
  182. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/tests/test_dynamic_models.py +0 -0
  183. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/tests/test_geophysical.py +0 -0
  184. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/tests/test_kalman_filters.py +0 -0
  185. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/tests/test_mathematical_functions.py +0 -0
  186. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/tests/test_maximum_likelihood.py +0 -0
  187. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/tests/test_mht.py +0 -0
  188. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/tests/test_performance_evaluation.py +0 -0
  189. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/tests/test_phase6_specialized.py +0 -0
  190. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/tests/test_plotting.py +0 -0
  191. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/tests/test_rhumb.py +0 -0
  192. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/tests/test_signal_processing.py +0 -0
  193. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/tests/test_spatial_structures.py +0 -0
  194. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/tests/test_special_functions_phase12.py +0 -0
  195. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/tests/test_terrain.py +0 -0
  196. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/tests/test_terrain_loaders.py +0 -0
  197. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/tests/test_tracking_containers.py +0 -0
  198. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/tests/test_transforms.py +0 -0
  199. {nrl_tracker-0.22.3 → nrl_tracker-0.22.4}/tests/unit/test_core.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: nrl-tracker
3
- Version: 0.22.3
3
+ Version: 0.22.4
4
4
  Summary: Python port of the U.S. Naval Research Laboratory's Tracker Component Library for target tracking algorithms
5
5
  Author: Original: David F. Crouse, Naval Research Laboratory
6
6
  Maintainer: Python Port Contributors
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: nrl-tracker
3
- Version: 0.22.3
3
+ Version: 0.22.4
4
4
  Summary: Python port of the U.S. Naval Research Laboratory's Tracker Component Library for target tracking algorithms
5
5
  Author: Original: David F. Crouse, Naval Research Laboratory
6
6
  Maintainer: Python Port Contributors
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "nrl-tracker"
7
- version = "0.22.3"
7
+ version = "0.22.4"
8
8
  description = "Python port of the U.S. Naval Research Laboratory's Tracker Component Library for target tracking algorithms"
9
9
  readme = "README.md"
10
10
  authors = [
@@ -20,7 +20,7 @@ References
20
20
  no. 5, pp. 18-27, May 2017.
21
21
  """
22
22
 
23
- __version__ = "0.22.3"
23
+ __version__ = "0.22.4"
24
24
  __author__ = "Python Port Contributors"
25
25
  __original_author__ = "David F. Crouse, Naval Research Laboratory"
26
26
 
@@ -19,9 +19,9 @@ def _mahalanobis_distance_2d(
19
19
  S_inv: np.ndarray,
20
20
  ) -> float:
21
21
  """JIT-compiled Mahalanobis distance for 2D innovations."""
22
- return innovation[0] * (S_inv[0, 0] * innovation[0] + S_inv[0, 1] * innovation[1]) + innovation[
23
- 1
24
- ] * (S_inv[1, 0] * innovation[0] + S_inv[1, 1] * innovation[1])
22
+ return innovation[0] * (
23
+ S_inv[0, 0] * innovation[0] + S_inv[0, 1] * innovation[1]
24
+ ) + innovation[1] * (S_inv[1, 0] * innovation[0] + S_inv[1, 1] * innovation[1])
25
25
 
26
26
 
27
27
  @njit(cache=True, fastmath=True)
@@ -94,7 +94,9 @@ def compute_measurement_likelihood(
94
94
  return 0.0
95
95
 
96
96
  mahal_sq = innovation @ np.linalg.solve(innovation_cov, innovation)
97
- likelihood = detection_prob * np.exp(-0.5 * mahal_sq) / np.sqrt((2 * np.pi) ** m * det_S)
97
+ likelihood = (
98
+ detection_prob * np.exp(-0.5 * mahal_sq) / np.sqrt((2 * np.pi) ** m * det_S)
99
+ )
98
100
 
99
101
  return likelihood
100
102
 
@@ -208,7 +210,9 @@ def jpda_probabilities(
208
210
  if n_tracks <= 5 and n_meas <= 5:
209
211
  beta = _jpda_exact(likelihood_matrix, gated, detection_prob, clutter_density)
210
212
  else:
211
- beta = _jpda_approximate(likelihood_matrix, gated, detection_prob, clutter_density)
213
+ beta = _jpda_approximate(
214
+ likelihood_matrix, gated, detection_prob, clutter_density
215
+ )
212
216
 
213
217
  return beta
214
218
 
@@ -254,7 +258,9 @@ def _jpda_exact(
254
258
  if gated[track_idx, meas_idx] and track_idx not in used_tracks:
255
259
  current_assignment.append(track_idx)
256
260
  used_tracks.add(track_idx)
257
- yield from generate_hypotheses(meas_idx + 1, current_assignment, used_tracks)
261
+ yield from generate_hypotheses(
262
+ meas_idx + 1, current_assignment, used_tracks
263
+ )
258
264
  used_tracks.remove(track_idx)
259
265
  current_assignment.pop()
260
266
 
@@ -292,7 +298,9 @@ def _jpda_exact(
292
298
  hypothesis_probs = [p / total_prob for p in hypothesis_probs]
293
299
 
294
300
  # Compute marginal association probabilities
295
- for h_idx, (assignment, prob) in enumerate(zip(hypothesis_assignments, hypothesis_probs)):
301
+ for h_idx, (assignment, prob) in enumerate(
302
+ zip(hypothesis_assignments, hypothesis_probs)
303
+ ):
296
304
  detected_tracks = set()
297
305
  for j, track_idx in enumerate(assignment):
298
306
  if track_idx >= 0:
@@ -335,7 +335,9 @@ def _partition_solution(
335
335
 
336
336
  for i in range(start_idx, n_assigned):
337
337
  # Require assignments 0..i-1, forbid assignment i
338
- new_required = required + [(row_ind[j], col_ind[j]) for j in range(start_idx, i)]
338
+ new_required = required + [
339
+ (row_ind[j], col_ind[j]) for j in range(start_idx, i)
340
+ ]
339
341
  new_forbidden = forbidden + [(row_ind[i], col_ind[i])]
340
342
 
341
343
  # Solve constrained problem
@@ -137,14 +137,16 @@ class DEEphemeris:
137
137
  """
138
138
  if version not in self._VALID_VERSIONS:
139
139
  raise ValueError(
140
- f"Ephemeris version must be one of {self._VALID_VERSIONS}, " f"got '{version}'"
140
+ f"Ephemeris version must be one of {self._VALID_VERSIONS}, "
141
+ f"got '{version}'"
141
142
  )
142
143
 
143
144
  try:
144
145
  import jplephem
145
146
  except ImportError as e:
146
147
  raise ImportError(
147
- "jplephem is required for ephemeris access. " "Install with: pip install jplephem"
148
+ "jplephem is required for ephemeris access. "
149
+ "Install with: pip install jplephem"
148
150
  ) from e
149
151
 
150
152
  self.version = version
@@ -170,9 +172,7 @@ class DEEphemeris:
170
172
 
171
173
  # Try to construct kernel filename
172
174
  kernel_name = f"de{self.version[2:]}.bsp"
173
- kernel_url = (
174
- f"https://naif.jpl.nasa.gov/pub/naif/generic_kernels/spk/planets/{kernel_name}"
175
- )
175
+ kernel_url = f"https://naif.jpl.nasa.gov/pub/naif/generic_kernels/spk/planets/{kernel_name}"
176
176
 
177
177
  # Try to download if not exists
178
178
  kernel_path = os.path.expanduser(f"~/.jplephem/{kernel_name}")
@@ -296,7 +296,9 @@ class DEEphemeris:
296
296
 
297
297
  # Get Moon position relative to Earth
298
298
  moon_segment = self.kernel[3, 301]
299
- moon_rel_earth_pos, moon_rel_earth_vel = moon_segment.compute_and_differentiate(jd)
299
+ moon_rel_earth_pos, moon_rel_earth_vel = (
300
+ moon_segment.compute_and_differentiate(jd)
301
+ )
300
302
 
301
303
  # Moon position relative to SSB
302
304
  position = earth_pos + moon_rel_earth_pos
@@ -316,7 +318,9 @@ class DEEphemeris:
316
318
 
317
319
  def planet_position(
318
320
  self,
319
- planet: Literal["mercury", "venus", "mars", "jupiter", "saturn", "uranus", "neptune"],
321
+ planet: Literal[
322
+ "mercury", "venus", "mars", "jupiter", "saturn", "uranus", "neptune"
323
+ ],
320
324
  jd: float,
321
325
  frame: Literal["icrf", "ecliptic"] = "icrf",
322
326
  ) -> Tuple[np.ndarray, np.ndarray]:
@@ -373,7 +377,9 @@ class DEEphemeris:
373
377
 
374
378
  return position, velocity
375
379
 
376
- def barycenter_position(self, body: str, jd: float) -> Tuple[np.ndarray, np.ndarray]:
380
+ def barycenter_position(
381
+ self, body: str, jd: float
382
+ ) -> Tuple[np.ndarray, np.ndarray]:
377
383
  """Compute position of any body relative to Solar System Barycenter.
378
384
 
379
385
  Parameters
@@ -471,7 +477,9 @@ def moon_position(
471
477
 
472
478
 
473
479
  def planet_position(
474
- planet: Literal["mercury", "venus", "mars", "jupiter", "saturn", "uranus", "neptune"],
480
+ planet: Literal[
481
+ "mercury", "venus", "mars", "jupiter", "saturn", "uranus", "neptune"
482
+ ],
475
483
  jd: float,
476
484
  frame: Literal["icrf", "ecliptic"] = "icrf",
477
485
  ) -> Tuple[np.ndarray, np.ndarray]:
@@ -198,7 +198,9 @@ def lambert_universal(
198
198
  psi = (psi_low + psi_high) / 2
199
199
 
200
200
  else:
201
- raise ValueError(f"Lambert's problem did not converge after {max_iter} iterations")
201
+ raise ValueError(
202
+ f"Lambert's problem did not converge after {max_iter} iterations"
203
+ )
202
204
 
203
205
  # Compute f, g, f_dot, g_dot
204
206
  f = 1 - y / r1_mag
@@ -286,7 +288,11 @@ def lambert_izzo(
286
288
 
287
289
  # Cross product for angular momentum direction
288
290
  cross = np.cross(r1, r2)
289
- h_hat = cross / np.linalg.norm(cross) if np.linalg.norm(cross) > 1e-10 else np.array([0, 0, 1])
291
+ h_hat = (
292
+ cross / np.linalg.norm(cross)
293
+ if np.linalg.norm(cross) > 1e-10
294
+ else np.array([0, 0, 1])
295
+ )
290
296
 
291
297
  # Transfer angle
292
298
  cos_dnu = np.dot(r1_hat, r2_hat)
@@ -329,9 +335,13 @@ def lambert_izzo(
329
335
 
330
336
  # Time of flight equation
331
337
  if x < 1:
332
- psi = np.arccos(x * lambda_param + y * np.sqrt(1 - lambda_param * lambda_param))
338
+ psi = np.arccos(
339
+ x * lambda_param + y * np.sqrt(1 - lambda_param * lambda_param)
340
+ )
333
341
  else:
334
- psi = np.arccosh(x * lambda_param + y * np.sqrt(lambda_param * lambda_param - 1))
342
+ psi = np.arccosh(
343
+ x * lambda_param + y * np.sqrt(lambda_param * lambda_param - 1)
344
+ )
335
345
 
336
346
  T_x = (
337
347
  psi + multi_rev * np.pi - (x - lambda_param * y) * np.sqrt(abs(1 - x * x))
@@ -176,7 +176,9 @@ def mean_to_hyperbolic_anomaly(
176
176
  if abs(delta) < tol:
177
177
  return H
178
178
 
179
- raise ValueError(f"Hyperbolic Kepler's equation did not converge after {max_iter} iterations")
179
+ raise ValueError(
180
+ f"Hyperbolic Kepler's equation did not converge after {max_iter} iterations"
181
+ )
180
182
 
181
183
 
182
184
  def eccentric_to_true_anomaly(E: float, e: float) -> float:
@@ -292,7 +292,9 @@ def gmst_iau82(jd_ut1: float) -> float:
292
292
  T_u = (jd_0h - JD_J2000) / 36525.0
293
293
 
294
294
  # GMST at 0h UT1 (seconds)
295
- gmst_0h_sec = 24110.54841 + 8640184.812866 * T_u + 0.093104 * T_u**2 - 6.2e-6 * T_u**3
295
+ gmst_0h_sec = (
296
+ 24110.54841 + 8640184.812866 * T_u + 0.093104 * T_u**2 - 6.2e-6 * T_u**3
297
+ )
296
298
 
297
299
  # Add UT1 fraction
298
300
  ut1_fraction = (jd_ut1 - jd_0h) * 86400.0
@@ -323,7 +323,9 @@ def post_newtonian_acceleration(
323
323
  return a_newt + a_1pn
324
324
 
325
325
 
326
- def geodetic_precession(a: float, e: float, inclination: float, gm: float = GM_EARTH) -> float:
326
+ def geodetic_precession(
327
+ a: float, e: float, inclination: float, gm: float = GM_EARTH
328
+ ) -> float:
327
329
  """Compute geodetic (de Sitter) precession rate of orbital plane.
328
330
 
329
331
  The orbital plane of a satellite precesses due to frame-dragging effects
@@ -363,7 +365,11 @@ def geodetic_precession(a: float, e: float, inclination: float, gm: float = GM_E
363
365
 
364
366
 
365
367
  def lense_thirring_precession(
366
- a: float, e: float, inclination: float, angular_momentum: float, gm: float = GM_EARTH
368
+ a: float,
369
+ e: float,
370
+ inclination: float,
371
+ angular_momentum: float,
372
+ gm: float = GM_EARTH,
367
373
  ) -> float:
368
374
  """Compute Lense-Thirring (frame-dragging) precession of orbital node.
369
375
 
@@ -218,7 +218,9 @@ def isa_atmosphere(
218
218
  strat_mask = altitude > h_trop
219
219
  temperature[strat_mask] = T_trop + temperature_offset
220
220
  # Pressure at tropopause
221
- P_trop = P0 * ((T0 + temperature_offset) / (T_trop + temperature_offset)) ** (G0 / (R * L))
221
+ P_trop = P0 * ((T0 + temperature_offset) / (T_trop + temperature_offset)) ** (
222
+ G0 / (R * L)
223
+ )
222
224
  pressure[strat_mask] = P_trop * np.exp(
223
225
  -G0 * (altitude[strat_mask] - h_trop) / (R * (T_trop + temperature_offset))
224
226
  )
@@ -297,7 +297,8 @@ def prune_mixture(
297
297
  total_weight = sum(c.weight for c in surviving)
298
298
  if total_weight > 0:
299
299
  surviving = [
300
- GaussianComponent(c.weight / total_weight, c.mean, c.covariance) for c in surviving
300
+ GaussianComponent(c.weight / total_weight, c.mean, c.covariance)
301
+ for c in surviving
301
302
  ]
302
303
 
303
304
  return surviving
@@ -391,7 +392,8 @@ def reduce_mixture_runnalls(
391
392
  total_weight = sum(c.weight for c in working)
392
393
  if total_weight > 0:
393
394
  working = [
394
- GaussianComponent(c.weight / total_weight, c.mean, c.covariance) for c in working
395
+ GaussianComponent(c.weight / total_weight, c.mean, c.covariance)
396
+ for c in working
395
397
  ]
396
398
 
397
399
  return ReductionResult(working, n_original, len(working), total_cost)
@@ -531,7 +533,8 @@ def reduce_mixture_west(
531
533
  total_weight = sum(c.weight for c in working)
532
534
  if total_weight > 0:
533
535
  working = [
534
- GaussianComponent(c.weight / total_weight, c.mean, c.covariance) for c in working
536
+ GaussianComponent(c.weight / total_weight, c.mean, c.covariance)
537
+ for c in working
535
538
  ]
536
539
 
537
540
  return ReductionResult(working, n_original, len(working), total_cost)
@@ -602,7 +605,8 @@ class GaussianMixture:
602
605
  total = sum(c.weight for c in self.components)
603
606
  if total > 0:
604
607
  self.components = [
605
- GaussianComponent(c.weight / total, c.mean, c.covariance) for c in self.components
608
+ GaussianComponent(c.weight / total, c.mean, c.covariance)
609
+ for c in self.components
606
610
  ]
607
611
 
608
612
  @property
@@ -152,7 +152,11 @@ def _ward_linkage(
152
152
  """Ward's linkage: minimum variance merge."""
153
153
  total = size_i + size_j + size_k
154
154
  return np.sqrt(
155
- ((size_i + size_k) * dist_i**2 + (size_j + size_k) * dist_j**2 - size_k * dist_ij**2)
155
+ (
156
+ (size_i + size_k) * dist_i**2
157
+ + (size_j + size_k) * dist_j**2
158
+ - size_k * dist_ij**2
159
+ )
156
160
  / total
157
161
  )
158
162
 
@@ -250,7 +250,9 @@ def kmeans(
250
250
  raise ValueError(f"n_clusters ({n_clusters}) > n_samples ({n_samples})")
251
251
 
252
252
  # Check if initial centers are provided
253
- if isinstance(init, np.ndarray) or (isinstance(init, (list, tuple)) and len(init) > 0):
253
+ if isinstance(init, np.ndarray) or (
254
+ isinstance(init, (list, tuple)) and len(init) > 0
255
+ ):
254
256
  init_centers = np.asarray(init, dtype=np.float64)
255
257
  if init_centers.shape != (n_clusters, n_features):
256
258
  raise ValueError(
@@ -290,7 +290,9 @@ class ClusterSet:
290
290
  self._clusters = list(clusters)
291
291
 
292
292
  # Build lookups
293
- self._id_to_idx: Dict[int, int] = {c.id: i for i, c in enumerate(self._clusters)}
293
+ self._id_to_idx: Dict[int, int] = {
294
+ c.id: i for i, c in enumerate(self._clusters)
295
+ }
294
296
  self._track_to_cluster: Dict[int, int] = {}
295
297
  for cluster in self._clusters:
296
298
  for track_id in cluster.track_ids:
@@ -407,7 +409,9 @@ class ClusterSet:
407
409
  return self.get_cluster(cluster_id)
408
410
  return None
409
411
 
410
- def clusters_in_region(self, center: ArrayLike, radius: float) -> List[TrackCluster]:
412
+ def clusters_in_region(
413
+ self, center: ArrayLike, radius: float
414
+ ) -> List[TrackCluster]:
411
415
  """
412
416
  Get clusters with centroids within a spatial region.
413
417
 
@@ -556,7 +560,9 @@ class ClusterSet:
556
560
  """
557
561
  result = {}
558
562
  for cluster in self._clusters:
559
- stats = self.cluster_stats(cluster.id, tracks, state_indices, velocity_indices)
563
+ stats = self.cluster_stats(
564
+ cluster.id, tracks, state_indices, velocity_indices
565
+ )
560
566
  if stats is not None:
561
567
  result[cluster.id] = stats
562
568
  return result
@@ -203,7 +203,9 @@ class MeasurementSet:
203
203
  MeasurementSet
204
204
  Measurements at the specified time.
205
205
  """
206
- measurements = [m for m in self._measurements if abs(m.time - time) <= tolerance]
206
+ measurements = [
207
+ m for m in self._measurements if abs(m.time - time) <= tolerance
208
+ ]
207
209
  return MeasurementSet(measurements)
208
210
 
209
211
  def in_time_window(self, start: float, end: float) -> MeasurementSet:
@@ -344,7 +346,9 @@ class MeasurementSet:
344
346
  return np.zeros((0, 0))
345
347
  return np.array([m.value for m in self._measurements])
346
348
 
347
- def values_at_time(self, time: float, tolerance: float = 1e-9) -> NDArray[np.float64]:
349
+ def values_at_time(
350
+ self, time: float, tolerance: float = 1e-9
351
+ ) -> NDArray[np.float64]:
348
352
  """
349
353
  Extract measurement values at a specific time.
350
354
 
@@ -281,7 +281,9 @@ class RTree:
281
281
 
282
282
  # Simple split: sort by center x-coordinate and split in half
283
283
  if node.is_leaf:
284
- sorted_entries = sorted(entries, key=lambda e: e[0].center[0] if e[0] else 0)
284
+ sorted_entries = sorted(
285
+ entries, key=lambda e: e[0].center[0] if e[0] else 0
286
+ )
285
287
  else:
286
288
  sorted_entries = sorted(
287
289
  entries,
@@ -479,7 +481,8 @@ class RTree:
479
481
  else:
480
482
  # Sort children by distance and search closest first
481
483
  child_dists = [
482
- (min_dist_to_box(query, c.bbox) if c.bbox else np.inf, c) for c in node.children
484
+ (min_dist_to_box(query, c.bbox) if c.bbox else np.inf, c)
485
+ for c in node.children
483
486
  ]
484
487
  child_dists.sort(key=lambda x: x[0])
485
488
  for _, child in child_dists:
@@ -147,7 +147,9 @@ def ecef2geodetic(
147
147
  # Bowring's iterative method
148
148
  # Initial estimate
149
149
  theta = np.arctan2(z * a, p * b)
150
- lat = np.arctan2(z + ep2 * b * np.sin(theta) ** 3, p - e2 * a * np.cos(theta) ** 3)
150
+ lat = np.arctan2(
151
+ z + ep2 * b * np.sin(theta) ** 3, p - e2 * a * np.cos(theta) ** 3
152
+ )
151
153
 
152
154
  # Iterate for improved accuracy
153
155
  for _ in range(5):
@@ -376,8 +378,18 @@ def enu2ecef(
376
378
  cos_lon = np.cos(lon_ref)
377
379
 
378
380
  # ECEF = R^T @ ENU + ECEF_ref
379
- x = -sin_lon * east - sin_lat * cos_lon * north + cos_lat * cos_lon * up + ecef_ref[0]
380
- y = cos_lon * east - sin_lat * sin_lon * north + cos_lat * sin_lon * up + ecef_ref[1]
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
393
  z = cos_lat * north + sin_lat * up + ecef_ref[2]
382
394
 
383
395
  if x.size == 1:
@@ -140,7 +140,9 @@ def mercator(
140
140
 
141
141
  # Northing using isometric latitude
142
142
  sin_lat = np.sin(lat)
143
- y = a * np.log(np.tan(np.pi / 4 + lat / 2) * ((1 - e * sin_lat) / (1 + e * sin_lat)) ** (e / 2))
143
+ y = a * np.log(
144
+ np.tan(np.pi / 4 + lat / 2) * ((1 - e * sin_lat) / (1 + e * sin_lat)) ** (e / 2)
145
+ )
144
146
 
145
147
  # Scale factor
146
148
  cos_lat = np.cos(lat)
@@ -201,7 +203,9 @@ def mercator_inverse(
201
203
 
202
204
  for _ in range(max_iter):
203
205
  sin_lat = np.sin(lat)
204
- lat_new = np.pi / 2 - 2 * np.arctan(t * ((1 - e * sin_lat) / (1 + e * sin_lat)) ** (e / 2))
206
+ lat_new = np.pi / 2 - 2 * np.arctan(
207
+ t * ((1 - e * sin_lat) / (1 + e * sin_lat)) ** (e / 2)
208
+ )
205
209
  if abs(lat_new - lat) < tol:
206
210
  break
207
211
  lat = lat_new
@@ -579,7 +583,9 @@ def geodetic2utm(lat: float, lon: float, zone: Optional[int] = None) -> UTMResul
579
583
  northing = result.y + 10000000.0
580
584
  hemisphere = "S"
581
585
 
582
- return UTMResult(easting, northing, zone, hemisphere, result.scale, result.convergence)
586
+ return UTMResult(
587
+ easting, northing, zone, hemisphere, result.scale, result.convergence
588
+ )
583
589
 
584
590
 
585
591
  def utm2geodetic(
@@ -690,7 +696,8 @@ def stereographic(
690
696
  return (
691
697
  2
692
698
  * np.arctan(
693
- np.tan(np.pi / 4 + phi / 2) * ((1 - e * sin_phi) / (1 + e * sin_phi)) ** (e / 2)
699
+ np.tan(np.pi / 4 + phi / 2)
700
+ * ((1 - e * sin_phi) / (1 + e * sin_phi)) ** (e / 2)
694
701
  )
695
702
  - np.pi / 2
696
703
  )
@@ -778,7 +785,8 @@ def stereographic_inverse(
778
785
  chi0 = (
779
786
  2
780
787
  * np.arctan(
781
- np.tan(np.pi / 4 + lat0 / 2) * ((1 - e * sin_lat0) / (1 + e * sin_lat0)) ** (e / 2)
788
+ np.tan(np.pi / 4 + lat0 / 2)
789
+ * ((1 - e * sin_lat0) / (1 + e * sin_lat0)) ** (e / 2)
782
790
  )
783
791
  - np.pi / 2
784
792
  )
@@ -813,7 +821,8 @@ def stereographic_inverse(
813
821
  lat_new = (
814
822
  2
815
823
  * np.arctan(
816
- np.tan(np.pi / 4 + chi / 2) * ((1 + e * sin_lat) / (1 - e * sin_lat)) ** (e / 2)
824
+ np.tan(np.pi / 4 + chi / 2)
825
+ * ((1 + e * sin_lat) / (1 - e * sin_lat)) ** (e / 2)
817
826
  )
818
827
  - np.pi / 2
819
828
  )
@@ -945,7 +954,9 @@ def lambert_conformal_conic(
945
954
 
946
955
  def compute_t(phi: float) -> float:
947
956
  sin_phi = np.sin(phi)
948
- return np.tan(np.pi / 4 - phi / 2) / (((1 - e * sin_phi) / (1 + e * sin_phi)) ** (e / 2))
957
+ return np.tan(np.pi / 4 - phi / 2) / (
958
+ ((1 - e * sin_phi) / (1 + e * sin_phi)) ** (e / 2)
959
+ )
949
960
 
950
961
  m1 = compute_m(lat1)
951
962
  m2 = compute_m(lat2)
@@ -1034,7 +1045,9 @@ def lambert_conformal_conic_inverse(
1034
1045
 
1035
1046
  def compute_t(phi: float) -> float:
1036
1047
  sin_phi = np.sin(phi)
1037
- return np.tan(np.pi / 4 - phi / 2) / (((1 - e * sin_phi) / (1 + e * sin_phi)) ** (e / 2))
1048
+ return np.tan(np.pi / 4 - phi / 2) / (
1049
+ ((1 - e * sin_phi) / (1 + e * sin_phi)) ** (e / 2)
1050
+ )
1038
1051
 
1039
1052
  m1 = compute_m(lat1)
1040
1053
  m2 = compute_m(lat2)
@@ -1062,7 +1075,9 @@ def lambert_conformal_conic_inverse(
1062
1075
  lat = np.pi / 2 - 2 * np.arctan(t)
1063
1076
  for _ in range(max_iter):
1064
1077
  sin_lat = np.sin(lat)
1065
- lat_new = np.pi / 2 - 2 * np.arctan(t * ((1 - e * sin_lat) / (1 + e * sin_lat)) ** (e / 2))
1078
+ lat_new = np.pi / 2 - 2 * np.arctan(
1079
+ t * ((1 - e * sin_lat) / (1 + e * sin_lat)) ** (e / 2)
1080
+ )
1066
1081
  if abs(lat_new - lat) < tol:
1067
1082
  break
1068
1083
  lat = lat_new
@@ -1126,7 +1141,13 @@ def azimuthal_equidistant(
1126
1141
  """
1127
1142
  # Use spherical approximation with authalic radius
1128
1143
  R = a * np.sqrt(
1129
- (1 + (1 - e2) / (2 * np.sqrt(1 - e2)) * np.log((1 + np.sqrt(1 - e2)) / np.sqrt(e2))) / 2
1144
+ (
1145
+ 1
1146
+ + (1 - e2)
1147
+ / (2 * np.sqrt(1 - e2))
1148
+ * np.log((1 + np.sqrt(1 - e2)) / np.sqrt(e2))
1149
+ )
1150
+ / 2
1130
1151
  )
1131
1152
 
1132
1153
  sin_lat = np.sin(lat)
@@ -1196,7 +1217,13 @@ def azimuthal_equidistant_inverse(
1196
1217
  (latitude, longitude) in radians.
1197
1218
  """
1198
1219
  R = a * np.sqrt(
1199
- (1 + (1 - e2) / (2 * np.sqrt(1 - e2)) * np.log((1 + np.sqrt(1 - e2)) / np.sqrt(e2))) / 2
1220
+ (
1221
+ 1
1222
+ + (1 - e2)
1223
+ / (2 * np.sqrt(1 - e2))
1224
+ * np.log((1 + np.sqrt(1 - e2)) / np.sqrt(e2))
1225
+ )
1226
+ / 2
1200
1227
  )
1201
1228
 
1202
1229
  rho = np.sqrt(x**2 + y**2)
@@ -353,7 +353,9 @@ def rotmat2axisangle(
353
353
  return axis / np.linalg.norm(axis), float(angle)
354
354
 
355
355
  # General case
356
- axis = np.array([R[2, 1] - R[1, 2], R[0, 2] - R[2, 0], R[1, 0] - R[0, 1]]) / (2 * np.sin(angle))
356
+ axis = np.array([R[2, 1] - R[1, 2], R[0, 2] - R[2, 0], R[1, 0] - R[0, 1]]) / (
357
+ 2 * np.sin(angle)
358
+ )
357
359
 
358
360
  return axis, float(angle)
359
361
 
@@ -374,7 +374,10 @@ def normalize_vector(
374
374
  v: ArrayLike,
375
375
  axis: int | None = None,
376
376
  return_norm: bool = False,
377
- ) -> NDArray[np.floating[Any]] | tuple[NDArray[np.floating[Any]], NDArray[np.floating[Any]]]:
377
+ ) -> (
378
+ NDArray[np.floating[Any]]
379
+ | tuple[NDArray[np.floating[Any]], NDArray[np.floating[Any]]]
380
+ ):
378
381
  """
379
382
  Normalize vector(s) to unit length.
380
383
 
@@ -71,7 +71,9 @@ EARTH_ECCENTRICITY_SQ: Final[float] = 2 * EARTH_FLATTENING - EARTH_FLATTENING**2
71
71
  EARTH_ECCENTRICITY: Final[float] = math.sqrt(EARTH_ECCENTRICITY_SQ)
72
72
 
73
73
  #: Second eccentricity squared
74
- EARTH_ECCENTRICITY_PRIME_SQ: Final[float] = EARTH_ECCENTRICITY_SQ / (1 - EARTH_ECCENTRICITY_SQ)
74
+ EARTH_ECCENTRICITY_PRIME_SQ: Final[float] = EARTH_ECCENTRICITY_SQ / (
75
+ 1 - EARTH_ECCENTRICITY_SQ
76
+ )
75
77
 
76
78
  #: Earth rotation rate [rad/s] (IERS Conventions 2010)
77
79
  EARTH_ROTATION_RATE: Final[float] = 7.292115e-5