nrl-tracker 0.22.3__tar.gz → 0.22.5__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.
- {nrl_tracker-0.22.3/nrl_tracker.egg-info → nrl_tracker-0.22.5}/PKG-INFO +4 -4
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/README.md +3 -3
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5/nrl_tracker.egg-info}/PKG-INFO +4 -4
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pyproject.toml +1 -1
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/__init__.py +1 -1
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/assignment_algorithms/gating.py +3 -3
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/assignment_algorithms/jpda.py +12 -4
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/assignment_algorithms/two_dimensional/kbest.py +3 -1
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/astronomical/ephemerides.py +17 -9
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/astronomical/lambert.py +14 -4
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/astronomical/orbital_mechanics.py +3 -1
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/astronomical/reference_frames.py +3 -1
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/astronomical/relativity.py +8 -2
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/atmosphere/models.py +3 -1
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/clustering/gaussian_mixture.py +8 -4
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/clustering/hierarchical.py +5 -1
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/clustering/kmeans.py +3 -1
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/containers/cluster_set.py +9 -3
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/containers/measurement_set.py +6 -2
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/containers/rtree.py +5 -2
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/coordinate_systems/conversions/geodetic.py +15 -3
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/coordinate_systems/projections/projections.py +38 -11
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/coordinate_systems/rotations/rotations.py +3 -1
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/core/array_utils.py +4 -1
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/core/constants.py +3 -1
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/core/validation.py +17 -6
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/dynamic_estimation/imm.py +9 -3
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/dynamic_estimation/kalman/square_root.py +6 -2
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/dynamic_estimation/particle_filters/bootstrap.py +6 -2
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/dynamic_estimation/smoothers.py +3 -1
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/dynamic_models/process_noise/polynomial.py +6 -2
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/gravity/clenshaw.py +6 -2
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/gravity/egm.py +3 -1
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/gravity/models.py +3 -1
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/gravity/spherical_harmonics.py +10 -4
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/gravity/tides.py +16 -7
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/magnetism/emm.py +12 -3
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/magnetism/wmm.py +9 -2
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/mathematical_functions/basic_matrix/decompositions.py +3 -1
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/mathematical_functions/combinatorics/combinatorics.py +3 -1
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/mathematical_functions/geometry/geometry.py +12 -4
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/mathematical_functions/interpolation/interpolation.py +3 -1
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/mathematical_functions/signal_processing/detection.py +6 -3
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/mathematical_functions/signal_processing/filters.py +6 -2
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/mathematical_functions/signal_processing/matched_filter.py +4 -2
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/mathematical_functions/special_functions/elliptic.py +3 -1
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/mathematical_functions/special_functions/gamma_functions.py +3 -1
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/mathematical_functions/special_functions/lambert_w.py +3 -1
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/mathematical_functions/statistics/distributions.py +36 -12
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/mathematical_functions/statistics/estimators.py +3 -1
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/mathematical_functions/transforms/stft.py +9 -3
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/mathematical_functions/transforms/wavelets.py +18 -6
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/navigation/geodesy.py +31 -9
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/navigation/great_circle.py +12 -4
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/navigation/ins.py +8 -2
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/navigation/ins_gnss.py +25 -7
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/navigation/rhumb.py +10 -3
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/performance_evaluation/track_metrics.py +3 -1
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/plotting/coordinates.py +17 -5
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/plotting/metrics.py +9 -3
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/plotting/tracks.py +11 -3
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/static_estimation/least_squares.py +2 -1
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/static_estimation/maximum_likelihood.py +3 -3
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/terrain/dem.py +8 -2
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/terrain/loaders.py +13 -5
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/terrain/visibility.py +7 -2
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/trackers/hypothesis.py +7 -2
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/trackers/mht.py +15 -5
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/tests/conftest.py +3 -1
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/tests/test_astronomical.py +3 -1
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/tests/test_coordinate_systems.py +3 -1
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/tests/test_coverage_boost.py +3 -1
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/tests/test_coverage_boost_2.py +9 -3
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/tests/test_egm.py +54 -18
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/tests/test_emm.py +42 -14
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/tests/test_ephemerides.py +6 -2
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/tests/test_gaussian_mixtures.py +2 -1
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/tests/test_great_circle.py +3 -1
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/tests/test_ins.py +3 -1
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/tests/test_ins_gnss.py +9 -3
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/tests/test_projections.py +3 -1
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/tests/test_relativity.py +9 -3
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/tests/test_smoothers.py +12 -4
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/tests/test_static_estimation.py +9 -3
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/tests/test_tides.py +12 -4
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/tests/test_trackers.py +12 -4
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/tests/test_v030_comprehensive.py +9 -3
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/tests/test_v030_features.py +3 -1
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/CONTRIBUTING.md +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/LICENSE +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/MANIFEST.in +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/nrl_tracker.egg-info/SOURCES.txt +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/nrl_tracker.egg-info/dependency_links.txt +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/nrl_tracker.egg-info/requires.txt +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/nrl_tracker.egg-info/top_level.txt +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/assignment_algorithms/__init__.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/assignment_algorithms/data_association.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/assignment_algorithms/three_dimensional/__init__.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/assignment_algorithms/three_dimensional/assignment.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/assignment_algorithms/two_dimensional/__init__.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/assignment_algorithms/two_dimensional/assignment.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/astronomical/__init__.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/astronomical/time_systems.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/atmosphere/__init__.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/clustering/__init__.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/clustering/dbscan.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/containers/__init__.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/containers/covertree.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/containers/kd_tree.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/containers/track_list.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/containers/vptree.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/coordinate_systems/__init__.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/coordinate_systems/conversions/__init__.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/coordinate_systems/conversions/spherical.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/coordinate_systems/jacobians/__init__.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/coordinate_systems/jacobians/jacobians.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/coordinate_systems/projections/__init__.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/coordinate_systems/rotations/__init__.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/core/__init__.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/dynamic_estimation/__init__.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/dynamic_estimation/batch_estimation/__init__.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/dynamic_estimation/information_filter.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/dynamic_estimation/kalman/__init__.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/dynamic_estimation/kalman/extended.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/dynamic_estimation/kalman/linear.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/dynamic_estimation/kalman/unscented.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/dynamic_estimation/measurement_update/__init__.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/dynamic_estimation/particle_filters/__init__.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/dynamic_models/__init__.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/dynamic_models/continuous_time/__init__.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/dynamic_models/continuous_time/dynamics.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/dynamic_models/discrete_time/__init__.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/dynamic_models/discrete_time/coordinated_turn.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/dynamic_models/discrete_time/polynomial.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/dynamic_models/discrete_time/singer.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/dynamic_models/process_noise/__init__.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/dynamic_models/process_noise/coordinated_turn.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/dynamic_models/process_noise/singer.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/gravity/__init__.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/magnetism/__init__.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/magnetism/igrf.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/mathematical_functions/__init__.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/mathematical_functions/basic_matrix/__init__.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/mathematical_functions/basic_matrix/special_matrices.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/mathematical_functions/combinatorics/__init__.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/mathematical_functions/continuous_optimization/__init__.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/mathematical_functions/geometry/__init__.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/mathematical_functions/interpolation/__init__.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/mathematical_functions/numerical_integration/__init__.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/mathematical_functions/numerical_integration/quadrature.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/mathematical_functions/polynomials/__init__.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/mathematical_functions/signal_processing/__init__.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/mathematical_functions/special_functions/__init__.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/mathematical_functions/special_functions/bessel.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/mathematical_functions/special_functions/debye.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/mathematical_functions/special_functions/error_functions.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/mathematical_functions/special_functions/hypergeometric.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/mathematical_functions/special_functions/marcum_q.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/mathematical_functions/statistics/__init__.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/mathematical_functions/transforms/__init__.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/mathematical_functions/transforms/fourier.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/misc/__init__.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/navigation/__init__.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/performance_evaluation/__init__.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/performance_evaluation/estimation_metrics.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/physical_values/__init__.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/plotting/__init__.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/plotting/ellipses.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/scheduling/__init__.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/static_estimation/__init__.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/static_estimation/robust.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/terrain/__init__.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/trackers/__init__.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/trackers/multi_target.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/trackers/single_target.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/transponders/__init__.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/setup.cfg +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/tests/__init__.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/tests/test_additional_trees.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/tests/test_assignment_algorithms.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/tests/test_clustering.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/tests/test_dynamic_models.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/tests/test_geophysical.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/tests/test_kalman_filters.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/tests/test_mathematical_functions.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/tests/test_maximum_likelihood.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/tests/test_mht.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/tests/test_performance_evaluation.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/tests/test_phase6_specialized.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/tests/test_plotting.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/tests/test_rhumb.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/tests/test_signal_processing.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/tests/test_spatial_structures.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/tests/test_special_functions_phase12.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/tests/test_terrain.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/tests/test_terrain_loaders.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/tests/test_tracking_containers.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/tests/test_transforms.py +0 -0
- {nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/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
|
+
Version: 0.22.5
|
|
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
|
|
@@ -60,15 +60,15 @@ Requires-Dist: nrl-tracker[astronomy,dev,geodesy,optimization,signal,visualizati
|
|
|
60
60
|
|
|
61
61
|
# Tracker Component Library (Python)
|
|
62
62
|
|
|
63
|
-
[](https://pypi.org/project/nrl-tracker/)
|
|
64
64
|
[](https://www.python.org/downloads/)
|
|
65
65
|
[](https://en.wikipedia.org/wiki/Public_domain)
|
|
66
66
|
[](https://github.com/psf/black)
|
|
67
|
-
[](https://github.com/nedonatelli/TCL)
|
|
68
68
|
|
|
69
69
|
A Python port of the [U.S. Naval Research Laboratory's Tracker Component Library](https://github.com/USNavalResearchLaboratory/TrackerComponentLibrary), a comprehensive collection of algorithms for target tracking, estimation, coordinate systems, and related mathematical functions.
|
|
70
70
|
|
|
71
|
-
**800+ functions** | **144 modules** | **1,
|
|
71
|
+
**800+ functions** | **144 modules** | **1,598 tests** | **15+ algorithm categories**
|
|
72
72
|
|
|
73
73
|
## Overview
|
|
74
74
|
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
# Tracker Component Library (Python)
|
|
2
2
|
|
|
3
|
-
[](https://pypi.org/project/nrl-tracker/)
|
|
4
4
|
[](https://www.python.org/downloads/)
|
|
5
5
|
[](https://en.wikipedia.org/wiki/Public_domain)
|
|
6
6
|
[](https://github.com/psf/black)
|
|
7
|
-
[](https://github.com/nedonatelli/TCL)
|
|
8
8
|
|
|
9
9
|
A Python port of the [U.S. Naval Research Laboratory's Tracker Component Library](https://github.com/USNavalResearchLaboratory/TrackerComponentLibrary), a comprehensive collection of algorithms for target tracking, estimation, coordinate systems, and related mathematical functions.
|
|
10
10
|
|
|
11
|
-
**800+ functions** | **144 modules** | **1,
|
|
11
|
+
**800+ functions** | **144 modules** | **1,598 tests** | **15+ algorithm categories**
|
|
12
12
|
|
|
13
13
|
## Overview
|
|
14
14
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: nrl-tracker
|
|
3
|
-
Version: 0.22.
|
|
3
|
+
Version: 0.22.5
|
|
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
|
|
@@ -60,15 +60,15 @@ Requires-Dist: nrl-tracker[astronomy,dev,geodesy,optimization,signal,visualizati
|
|
|
60
60
|
|
|
61
61
|
# Tracker Component Library (Python)
|
|
62
62
|
|
|
63
|
-
[](https://pypi.org/project/nrl-tracker/)
|
|
64
64
|
[](https://www.python.org/downloads/)
|
|
65
65
|
[](https://en.wikipedia.org/wiki/Public_domain)
|
|
66
66
|
[](https://github.com/psf/black)
|
|
67
|
-
[](https://github.com/nedonatelli/TCL)
|
|
68
68
|
|
|
69
69
|
A Python port of the [U.S. Naval Research Laboratory's Tracker Component Library](https://github.com/USNavalResearchLaboratory/TrackerComponentLibrary), a comprehensive collection of algorithms for target tracking, estimation, coordinate systems, and related mathematical functions.
|
|
70
70
|
|
|
71
|
-
**800+ functions** | **144 modules** | **1,
|
|
71
|
+
**800+ functions** | **144 modules** | **1,598 tests** | **15+ algorithm categories**
|
|
72
72
|
|
|
73
73
|
## Overview
|
|
74
74
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "nrl-tracker"
|
|
7
|
-
version = "0.22.
|
|
7
|
+
version = "0.22.5"
|
|
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 = [
|
|
@@ -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] * (
|
|
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 =
|
|
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(
|
|
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(
|
|
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(
|
|
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:
|
{nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/assignment_algorithms/two_dimensional/kbest.py
RENAMED
|
@@ -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 + [
|
|
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}, "
|
|
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. "
|
|
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 =
|
|
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[
|
|
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(
|
|
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[
|
|
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(
|
|
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 =
|
|
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(
|
|
338
|
+
psi = np.arccos(
|
|
339
|
+
x * lambda_param + y * np.sqrt(1 - lambda_param * lambda_param)
|
|
340
|
+
)
|
|
333
341
|
else:
|
|
334
|
-
psi = np.arccosh(
|
|
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(
|
|
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 =
|
|
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(
|
|
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,
|
|
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)) ** (
|
|
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)
|
|
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)
|
|
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)
|
|
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)
|
|
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
|
-
(
|
|
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 (
|
|
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] = {
|
|
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(
|
|
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(
|
|
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 = [
|
|
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(
|
|
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(
|
|
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)
|
|
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(
|
|
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 =
|
|
380
|
-
|
|
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:
|
{nrl_tracker-0.22.3 → nrl_tracker-0.22.5}/pytcl/coordinate_systems/projections/projections.py
RENAMED
|
@@ -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(
|
|
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(
|
|
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(
|
|
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)
|
|
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)
|
|
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)
|
|
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) / (
|
|
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) / (
|
|
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(
|
|
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
|
-
(
|
|
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
|
-
(
|
|
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]]) / (
|
|
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
|
|