nrl-tracker 1.7.1__tar.gz → 1.7.3__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-1.7.1/nrl_tracker.egg-info → nrl_tracker-1.7.3}/PKG-INFO +42 -3
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/README.md +41 -2
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3/nrl_tracker.egg-info}/PKG-INFO +42 -3
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pyproject.toml +1 -1
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/__init__.py +1 -1
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/astronomical/__init__.py +3 -3
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/coordinate_systems/projections/__init__.py +1 -1
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/tests/conftest.py +3 -1
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/tests/test_assignment_algorithms.py +1 -1
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/tests/test_astronomical.py +3 -1
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/tests/test_coordinate_systems.py +6 -2
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/tests/test_coverage_boost.py +3 -1
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/tests/test_coverage_boost_2.py +9 -3
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/tests/test_egm.py +54 -18
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/tests/test_emm.py +42 -14
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/tests/test_ephemerides.py +6 -2
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/tests/test_gaussian_mixtures.py +2 -1
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/tests/test_gaussian_sum_filter.py +3 -1
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/tests/test_great_circle.py +3 -1
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/tests/test_ins.py +3 -1
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/tests/test_ins_gnss.py +9 -3
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/tests/test_nd_assignment.py +9 -3
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/tests/test_nrlmsise00.py +114 -19
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/tests/test_projections.py +3 -1
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/tests/test_rbpf.py +46 -15
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/tests/test_relativity.py +9 -3
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/tests/test_smoothers.py +12 -4
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/tests/test_special_functions_phase12.py +1 -1
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/tests/test_static_estimation.py +9 -3
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/tests/test_tides.py +12 -4
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/tests/test_trackers.py +12 -4
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/tests/test_v030_comprehensive.py +9 -3
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/tests/test_v030_features.py +3 -1
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/CONTRIBUTING.md +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/LICENSE +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/MANIFEST.in +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/nrl_tracker.egg-info/SOURCES.txt +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/nrl_tracker.egg-info/dependency_links.txt +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/nrl_tracker.egg-info/requires.txt +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/nrl_tracker.egg-info/top_level.txt +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/assignment_algorithms/__init__.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/assignment_algorithms/data_association.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/assignment_algorithms/gating.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/assignment_algorithms/jpda.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/assignment_algorithms/nd_assignment.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/assignment_algorithms/network_flow.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/assignment_algorithms/three_dimensional/__init__.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/assignment_algorithms/three_dimensional/assignment.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/assignment_algorithms/two_dimensional/__init__.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/assignment_algorithms/two_dimensional/assignment.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/assignment_algorithms/two_dimensional/kbest.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/astronomical/ephemerides.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/astronomical/lambert.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/astronomical/orbital_mechanics.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/astronomical/reference_frames.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/astronomical/relativity.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/astronomical/sgp4.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/astronomical/special_orbits.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/astronomical/time_systems.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/astronomical/tle.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/atmosphere/__init__.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/atmosphere/ionosphere.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/atmosphere/models.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/atmosphere/nrlmsise00.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/clustering/__init__.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/clustering/dbscan.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/clustering/gaussian_mixture.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/clustering/hierarchical.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/clustering/kmeans.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/containers/__init__.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/containers/base.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/containers/cluster_set.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/containers/covertree.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/containers/kd_tree.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/containers/measurement_set.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/containers/rtree.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/containers/track_list.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/containers/vptree.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/coordinate_systems/__init__.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/coordinate_systems/conversions/__init__.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/coordinate_systems/conversions/geodetic.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/coordinate_systems/conversions/spherical.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/coordinate_systems/jacobians/__init__.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/coordinate_systems/jacobians/jacobians.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/coordinate_systems/projections/projections.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/coordinate_systems/rotations/__init__.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/coordinate_systems/rotations/rotations.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/core/__init__.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/core/array_utils.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/core/constants.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/core/validation.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/dynamic_estimation/__init__.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/dynamic_estimation/batch_estimation/__init__.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/dynamic_estimation/gaussian_sum_filter.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/dynamic_estimation/imm.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/dynamic_estimation/information_filter.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/dynamic_estimation/kalman/__init__.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/dynamic_estimation/kalman/constrained.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/dynamic_estimation/kalman/extended.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/dynamic_estimation/kalman/h_infinity.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/dynamic_estimation/kalman/linear.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/dynamic_estimation/kalman/square_root.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/dynamic_estimation/kalman/sr_ukf.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/dynamic_estimation/kalman/ud_filter.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/dynamic_estimation/kalman/unscented.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/dynamic_estimation/measurement_update/__init__.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/dynamic_estimation/particle_filters/__init__.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/dynamic_estimation/particle_filters/bootstrap.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/dynamic_estimation/rbpf.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/dynamic_estimation/smoothers.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/dynamic_models/__init__.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/dynamic_models/continuous_time/__init__.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/dynamic_models/continuous_time/dynamics.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/dynamic_models/discrete_time/__init__.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/dynamic_models/discrete_time/coordinated_turn.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/dynamic_models/discrete_time/polynomial.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/dynamic_models/discrete_time/singer.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/dynamic_models/process_noise/__init__.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/dynamic_models/process_noise/coordinated_turn.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/dynamic_models/process_noise/polynomial.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/dynamic_models/process_noise/singer.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/gravity/__init__.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/gravity/clenshaw.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/gravity/egm.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/gravity/models.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/gravity/spherical_harmonics.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/gravity/tides.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/logging_config.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/magnetism/__init__.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/magnetism/emm.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/magnetism/igrf.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/magnetism/wmm.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/mathematical_functions/__init__.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/mathematical_functions/basic_matrix/__init__.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/mathematical_functions/basic_matrix/decompositions.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/mathematical_functions/basic_matrix/special_matrices.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/mathematical_functions/combinatorics/__init__.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/mathematical_functions/combinatorics/combinatorics.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/mathematical_functions/continuous_optimization/__init__.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/mathematical_functions/geometry/__init__.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/mathematical_functions/geometry/geometry.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/mathematical_functions/interpolation/__init__.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/mathematical_functions/interpolation/interpolation.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/mathematical_functions/numerical_integration/__init__.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/mathematical_functions/numerical_integration/quadrature.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/mathematical_functions/polynomials/__init__.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/mathematical_functions/signal_processing/__init__.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/mathematical_functions/signal_processing/detection.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/mathematical_functions/signal_processing/filters.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/mathematical_functions/signal_processing/matched_filter.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/mathematical_functions/special_functions/__init__.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/mathematical_functions/special_functions/bessel.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/mathematical_functions/special_functions/debye.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/mathematical_functions/special_functions/elliptic.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/mathematical_functions/special_functions/error_functions.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/mathematical_functions/special_functions/gamma_functions.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/mathematical_functions/special_functions/hypergeometric.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/mathematical_functions/special_functions/lambert_w.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/mathematical_functions/special_functions/marcum_q.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/mathematical_functions/statistics/__init__.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/mathematical_functions/statistics/distributions.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/mathematical_functions/statistics/estimators.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/mathematical_functions/transforms/__init__.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/mathematical_functions/transforms/fourier.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/mathematical_functions/transforms/stft.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/mathematical_functions/transforms/wavelets.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/misc/__init__.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/navigation/__init__.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/navigation/geodesy.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/navigation/great_circle.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/navigation/ins.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/navigation/ins_gnss.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/navigation/rhumb.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/performance_evaluation/__init__.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/performance_evaluation/estimation_metrics.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/performance_evaluation/track_metrics.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/physical_values/__init__.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/plotting/__init__.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/plotting/coordinates.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/plotting/ellipses.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/plotting/metrics.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/plotting/tracks.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/scheduling/__init__.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/static_estimation/__init__.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/static_estimation/least_squares.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/static_estimation/maximum_likelihood.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/static_estimation/robust.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/terrain/__init__.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/terrain/dem.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/terrain/loaders.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/terrain/visibility.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/trackers/__init__.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/trackers/hypothesis.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/trackers/mht.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/trackers/multi_target.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/trackers/single_target.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/pytcl/transponders/__init__.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/setup.cfg +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/tests/__init__.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/tests/test_additional_trees.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/tests/test_clustering.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/tests/test_constrained_ekf.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/tests/test_dynamic_models.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/tests/test_geophysical.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/tests/test_h_infinity.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/tests/test_kalman_filters.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/tests/test_mathematical_functions.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/tests/test_maximum_likelihood.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/tests/test_mht.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/tests/test_network_flow.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/tests/test_performance_evaluation.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/tests/test_phase6_specialized.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/tests/test_plotting.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/tests/test_rhumb.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/tests/test_sgp4.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/tests/test_signal_processing.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/tests/test_spatial_containers_parametrized.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/tests/test_spatial_structures.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/tests/test_special_orbits.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/tests/test_terrain.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/tests/test_terrain_loaders.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/tests/test_tod_mod.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/tests/test_tracking_containers.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/tests/test_transforms.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/tests/test_validation.py +0 -0
- {nrl_tracker-1.7.1 → nrl_tracker-1.7.3}/tests/unit/test_core.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: nrl-tracker
|
|
3
|
-
Version: 1.7.
|
|
3
|
+
Version: 1.7.3
|
|
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
|
|
@@ -63,7 +63,7 @@ Requires-Dist: nrl-tracker[astronomy,dev,geodesy,optimization,signal,visualizati
|
|
|
63
63
|
|
|
64
64
|
# Tracker Component Library (Python)
|
|
65
65
|
|
|
66
|
-
[](https://pypi.org/project/nrl-tracker/)
|
|
67
67
|
[](https://www.python.org/downloads/)
|
|
68
68
|
[](https://en.wikipedia.org/wiki/Public_domain)
|
|
69
69
|
[](https://github.com/psf/black)
|
|
@@ -209,7 +209,46 @@ pytcl/
|
|
|
209
209
|
|
|
210
210
|
- [API Reference](https://pytcl.readthedocs.io/en/latest/api/)
|
|
211
211
|
- [User Guides](https://pytcl.readthedocs.io/en/latest/user_guide/)
|
|
212
|
-
- [Examples](examples/)
|
|
212
|
+
- [Examples](examples/) - 29 validated example scripts
|
|
213
|
+
- [Tutorials](docs/tutorials/) - 10 interactive tutorial modules
|
|
214
|
+
|
|
215
|
+
## Examples & Tutorials
|
|
216
|
+
|
|
217
|
+
The library includes 39 runnable code examples demonstrating all major features:
|
|
218
|
+
|
|
219
|
+
### Examples (29 files in `/examples/`)
|
|
220
|
+
|
|
221
|
+
Comprehensive demonstrations of library functionality:
|
|
222
|
+
- **Tracking & Estimation**: Kalman filters, particle filters, smoothers
|
|
223
|
+
- **Assignment**: Hungarian algorithm, k-best assignments, 3D assignment
|
|
224
|
+
- **Coordinates**: Frame conversions, transformations, geodetic calculations
|
|
225
|
+
- **Dynamics**: State models, motion models, dynamic systems
|
|
226
|
+
- **Filtering**: Uncertainty visualization, multi-target tracking
|
|
227
|
+
- **Astronomy**: Ephemerides, orbital mechanics, relativistic corrections
|
|
228
|
+
- **Navigation**: INS/GNSS integration, geophysical modeling
|
|
229
|
+
- **Signal Processing**: Detection, filtering, transforms
|
|
230
|
+
- **Terrain & Atmosphere**: Elevation models, atmospheric properties
|
|
231
|
+
|
|
232
|
+
**Status**: ✅ All 29 examples validated and passing (100% execution success)
|
|
233
|
+
|
|
234
|
+
### Tutorials (10 modules in `/docs/tutorials/`)
|
|
235
|
+
|
|
236
|
+
Interactive learning modules with visualizations:
|
|
237
|
+
- Assignment algorithms and 3D assignment problems
|
|
238
|
+
- Atmospheric and geophysical models
|
|
239
|
+
- Dynamical systems and reference frames
|
|
240
|
+
- Filtering and smoothing techniques
|
|
241
|
+
- Sensor fusion and advanced filtering
|
|
242
|
+
- Special functions and mathematical tools
|
|
243
|
+
|
|
244
|
+
**Status**: ✅ All 10 tutorials validated and passing (100% execution success)
|
|
245
|
+
|
|
246
|
+
## Documentation
|
|
247
|
+
|
|
248
|
+
- [API Reference](https://pytcl.readthedocs.io/en/latest/api/)
|
|
249
|
+
- [User Guides](https://pytcl.readthedocs.io/en/latest/user_guide/)
|
|
250
|
+
- [Examples](examples/) - 29 validated example scripts
|
|
251
|
+
- [Tutorials](docs/tutorials/) - 10 interactive tutorial modules
|
|
213
252
|
|
|
214
253
|
## Comparison with Original MATLAB Library
|
|
215
254
|
|
|
@@ -1,6 +1,6 @@
|
|
|
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)
|
|
@@ -146,7 +146,46 @@ pytcl/
|
|
|
146
146
|
|
|
147
147
|
- [API Reference](https://pytcl.readthedocs.io/en/latest/api/)
|
|
148
148
|
- [User Guides](https://pytcl.readthedocs.io/en/latest/user_guide/)
|
|
149
|
-
- [Examples](examples/)
|
|
149
|
+
- [Examples](examples/) - 29 validated example scripts
|
|
150
|
+
- [Tutorials](docs/tutorials/) - 10 interactive tutorial modules
|
|
151
|
+
|
|
152
|
+
## Examples & Tutorials
|
|
153
|
+
|
|
154
|
+
The library includes 39 runnable code examples demonstrating all major features:
|
|
155
|
+
|
|
156
|
+
### Examples (29 files in `/examples/`)
|
|
157
|
+
|
|
158
|
+
Comprehensive demonstrations of library functionality:
|
|
159
|
+
- **Tracking & Estimation**: Kalman filters, particle filters, smoothers
|
|
160
|
+
- **Assignment**: Hungarian algorithm, k-best assignments, 3D assignment
|
|
161
|
+
- **Coordinates**: Frame conversions, transformations, geodetic calculations
|
|
162
|
+
- **Dynamics**: State models, motion models, dynamic systems
|
|
163
|
+
- **Filtering**: Uncertainty visualization, multi-target tracking
|
|
164
|
+
- **Astronomy**: Ephemerides, orbital mechanics, relativistic corrections
|
|
165
|
+
- **Navigation**: INS/GNSS integration, geophysical modeling
|
|
166
|
+
- **Signal Processing**: Detection, filtering, transforms
|
|
167
|
+
- **Terrain & Atmosphere**: Elevation models, atmospheric properties
|
|
168
|
+
|
|
169
|
+
**Status**: ✅ All 29 examples validated and passing (100% execution success)
|
|
170
|
+
|
|
171
|
+
### Tutorials (10 modules in `/docs/tutorials/`)
|
|
172
|
+
|
|
173
|
+
Interactive learning modules with visualizations:
|
|
174
|
+
- Assignment algorithms and 3D assignment problems
|
|
175
|
+
- Atmospheric and geophysical models
|
|
176
|
+
- Dynamical systems and reference frames
|
|
177
|
+
- Filtering and smoothing techniques
|
|
178
|
+
- Sensor fusion and advanced filtering
|
|
179
|
+
- Special functions and mathematical tools
|
|
180
|
+
|
|
181
|
+
**Status**: ✅ All 10 tutorials validated and passing (100% execution success)
|
|
182
|
+
|
|
183
|
+
## Documentation
|
|
184
|
+
|
|
185
|
+
- [API Reference](https://pytcl.readthedocs.io/en/latest/api/)
|
|
186
|
+
- [User Guides](https://pytcl.readthedocs.io/en/latest/user_guide/)
|
|
187
|
+
- [Examples](examples/) - 29 validated example scripts
|
|
188
|
+
- [Tutorials](docs/tutorials/) - 10 interactive tutorial modules
|
|
150
189
|
|
|
151
190
|
## Comparison with Original MATLAB Library
|
|
152
191
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: nrl-tracker
|
|
3
|
-
Version: 1.7.
|
|
3
|
+
Version: 1.7.3
|
|
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
|
|
@@ -63,7 +63,7 @@ Requires-Dist: nrl-tracker[astronomy,dev,geodesy,optimization,signal,visualizati
|
|
|
63
63
|
|
|
64
64
|
# Tracker Component Library (Python)
|
|
65
65
|
|
|
66
|
-
[](https://pypi.org/project/nrl-tracker/)
|
|
67
67
|
[](https://www.python.org/downloads/)
|
|
68
68
|
[](https://en.wikipedia.org/wiki/Public_domain)
|
|
69
69
|
[](https://github.com/psf/black)
|
|
@@ -209,7 +209,46 @@ pytcl/
|
|
|
209
209
|
|
|
210
210
|
- [API Reference](https://pytcl.readthedocs.io/en/latest/api/)
|
|
211
211
|
- [User Guides](https://pytcl.readthedocs.io/en/latest/user_guide/)
|
|
212
|
-
- [Examples](examples/)
|
|
212
|
+
- [Examples](examples/) - 29 validated example scripts
|
|
213
|
+
- [Tutorials](docs/tutorials/) - 10 interactive tutorial modules
|
|
214
|
+
|
|
215
|
+
## Examples & Tutorials
|
|
216
|
+
|
|
217
|
+
The library includes 39 runnable code examples demonstrating all major features:
|
|
218
|
+
|
|
219
|
+
### Examples (29 files in `/examples/`)
|
|
220
|
+
|
|
221
|
+
Comprehensive demonstrations of library functionality:
|
|
222
|
+
- **Tracking & Estimation**: Kalman filters, particle filters, smoothers
|
|
223
|
+
- **Assignment**: Hungarian algorithm, k-best assignments, 3D assignment
|
|
224
|
+
- **Coordinates**: Frame conversions, transformations, geodetic calculations
|
|
225
|
+
- **Dynamics**: State models, motion models, dynamic systems
|
|
226
|
+
- **Filtering**: Uncertainty visualization, multi-target tracking
|
|
227
|
+
- **Astronomy**: Ephemerides, orbital mechanics, relativistic corrections
|
|
228
|
+
- **Navigation**: INS/GNSS integration, geophysical modeling
|
|
229
|
+
- **Signal Processing**: Detection, filtering, transforms
|
|
230
|
+
- **Terrain & Atmosphere**: Elevation models, atmospheric properties
|
|
231
|
+
|
|
232
|
+
**Status**: ✅ All 29 examples validated and passing (100% execution success)
|
|
233
|
+
|
|
234
|
+
### Tutorials (10 modules in `/docs/tutorials/`)
|
|
235
|
+
|
|
236
|
+
Interactive learning modules with visualizations:
|
|
237
|
+
- Assignment algorithms and 3D assignment problems
|
|
238
|
+
- Atmospheric and geophysical models
|
|
239
|
+
- Dynamical systems and reference frames
|
|
240
|
+
- Filtering and smoothing techniques
|
|
241
|
+
- Sensor fusion and advanced filtering
|
|
242
|
+
- Special functions and mathematical tools
|
|
243
|
+
|
|
244
|
+
**Status**: ✅ All 10 tutorials validated and passing (100% execution success)
|
|
245
|
+
|
|
246
|
+
## Documentation
|
|
247
|
+
|
|
248
|
+
- [API Reference](https://pytcl.readthedocs.io/en/latest/api/)
|
|
249
|
+
- [User Guides](https://pytcl.readthedocs.io/en/latest/user_guide/)
|
|
250
|
+
- [Examples](examples/) - 29 validated example scripts
|
|
251
|
+
- [Tutorials](docs/tutorials/) - 10 interactive tutorial modules
|
|
213
252
|
|
|
214
253
|
## Comparison with Original MATLAB Library
|
|
215
254
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "nrl-tracker"
|
|
7
|
-
version = "1.7.
|
|
7
|
+
version = "1.7.3"
|
|
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 = [
|
|
@@ -77,10 +77,10 @@ from pytcl.astronomical.orbital_mechanics import (
|
|
|
77
77
|
vis_viva,
|
|
78
78
|
)
|
|
79
79
|
from pytcl.astronomical.reference_frames import (
|
|
80
|
-
earth_rotation_angle, # Time utilities; Precession; Nutation
|
|
80
|
+
earth_rotation_angle, # Time utilities; Precession; Nutation
|
|
81
81
|
)
|
|
82
|
+
from pytcl.astronomical.reference_frames import ecef_to_eci # Time utilities
|
|
82
83
|
from pytcl.astronomical.reference_frames import (
|
|
83
|
-
ecef_to_eci,
|
|
84
84
|
eci_to_ecef,
|
|
85
85
|
ecliptic_to_equatorial,
|
|
86
86
|
equation_of_equinoxes,
|
|
@@ -116,7 +116,7 @@ from pytcl.astronomical.reference_frames import (
|
|
|
116
116
|
true_obliquity,
|
|
117
117
|
)
|
|
118
118
|
from pytcl.astronomical.relativity import (
|
|
119
|
-
C_LIGHT, # Physical constants; Schwarzschild metric; Time dilation
|
|
119
|
+
C_LIGHT, # Physical constants; Schwarzschild metric; Time dilation
|
|
120
120
|
)
|
|
121
121
|
from pytcl.astronomical.relativity import (
|
|
122
122
|
G_GRAV,
|
|
@@ -27,7 +27,7 @@ Examples
|
|
|
27
27
|
"""
|
|
28
28
|
|
|
29
29
|
from pytcl.coordinate_systems.projections.projections import (
|
|
30
|
-
WGS84_A, # Constants; Result types
|
|
30
|
+
WGS84_A, # Constants; Result types
|
|
31
31
|
)
|
|
32
32
|
from pytcl.coordinate_systems.projections.projections import (
|
|
33
33
|
WGS84_B,
|
|
@@ -82,7 +82,9 @@ class NumpyTestCase:
|
|
|
82
82
|
|
|
83
83
|
def assert_shape(self, arr, expected_shape):
|
|
84
84
|
"""Assert array has expected shape."""
|
|
85
|
-
assert
|
|
85
|
+
assert (
|
|
86
|
+
arr.shape == expected_shape
|
|
87
|
+
), f"Expected shape {expected_shape}, got {arr.shape}"
|
|
86
88
|
|
|
87
89
|
def assert_symmetric(self, arr, rtol=1e-10):
|
|
88
90
|
"""Assert matrix is symmetric."""
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import numpy as np
|
|
4
4
|
from numpy.testing import assert_allclose
|
|
5
5
|
|
|
6
|
-
from pytcl.assignment_algorithms import ( # 2D Assignment
|
|
6
|
+
from pytcl.assignment_algorithms import ( # 2D Assignment
|
|
7
7
|
Assignment3DResult,
|
|
8
8
|
AssignmentResult,
|
|
9
9
|
AssociationResult,
|
|
@@ -150,7 +150,9 @@ class TestOrbitalElementConversions:
|
|
|
150
150
|
|
|
151
151
|
def test_roundtrip_elements_state(self):
|
|
152
152
|
"""Test elements -> state -> elements roundtrip."""
|
|
153
|
-
elements_orig = OrbitalElements(
|
|
153
|
+
elements_orig = OrbitalElements(
|
|
154
|
+
a=8000, e=0.2, i=0.5, raan=0.3, omega=0.8, nu=1.0
|
|
155
|
+
)
|
|
154
156
|
state = orbital_elements_to_state(elements_orig)
|
|
155
157
|
elements_back = state_to_orbital_elements(state)
|
|
156
158
|
|
|
@@ -403,7 +403,9 @@ class TestSlerp:
|
|
|
403
403
|
|
|
404
404
|
# Should be 45 deg rotation about z
|
|
405
405
|
expected_angle = angle / 2
|
|
406
|
-
expected = np.array(
|
|
406
|
+
expected = np.array(
|
|
407
|
+
[np.cos(expected_angle / 2), 0, 0, np.sin(expected_angle / 2)]
|
|
408
|
+
)
|
|
407
409
|
np.testing.assert_allclose(result, expected, atol=1e-10)
|
|
408
410
|
|
|
409
411
|
|
|
@@ -1315,4 +1317,6 @@ class TestSEZConversions:
|
|
|
1315
1317
|
# For northward target, the magnitude should be large and east component small
|
|
1316
1318
|
total_distance = np.linalg.norm(sez)
|
|
1317
1319
|
assert total_distance > 100000, "Distance should be significant"
|
|
1318
|
-
assert abs(sez[1]) < abs(
|
|
1320
|
+
assert abs(sez[1]) < abs(
|
|
1321
|
+
sez[0]
|
|
1322
|
+
), "East component should be smaller than meridional"
|
|
@@ -438,7 +438,9 @@ class TestCoordinatedTurnProcessNoise:
|
|
|
438
438
|
T = 0.1
|
|
439
439
|
sigma_a = 1.0
|
|
440
440
|
sigma_omega = 0.01
|
|
441
|
-
Q = q_coord_turn_2d(
|
|
441
|
+
Q = q_coord_turn_2d(
|
|
442
|
+
T, sigma_a, sigma_omega, state_type="position_velocity_omega"
|
|
443
|
+
)
|
|
442
444
|
assert Q.shape == (5, 5)
|
|
443
445
|
np.testing.assert_allclose(Q, Q.T)
|
|
444
446
|
|
|
@@ -121,7 +121,9 @@ class TestParticleFilters:
|
|
|
121
121
|
def likelihood_func(z, x):
|
|
122
122
|
return gaussian_likelihood(z, x, R)
|
|
123
123
|
|
|
124
|
-
new_weights, log_lik = bootstrap_pf_update(
|
|
124
|
+
new_weights, log_lik = bootstrap_pf_update(
|
|
125
|
+
particles, weights, z, likelihood_func
|
|
126
|
+
)
|
|
125
127
|
|
|
126
128
|
assert new_weights.shape == weights.shape
|
|
127
129
|
assert np.isclose(np.sum(new_weights), 1.0)
|
|
@@ -325,7 +327,9 @@ class TestParticleFilters:
|
|
|
325
327
|
|
|
326
328
|
mean = particle_mean(particles, weights)
|
|
327
329
|
|
|
328
|
-
expected =
|
|
330
|
+
expected = (
|
|
331
|
+
0.5 * np.array([0, 0]) + 0.3 * np.array([1, 1]) + 0.2 * np.array([2, 2])
|
|
332
|
+
)
|
|
329
333
|
assert np.allclose(mean, expected)
|
|
330
334
|
|
|
331
335
|
def test_particle_covariance(self):
|
|
@@ -991,7 +995,9 @@ class TestNavigationCoverage:
|
|
|
991
995
|
tdoa12 = 0.0
|
|
992
996
|
tdoa13 = 0.0
|
|
993
997
|
|
|
994
|
-
result1, result2 = great_circle_tdoa_loc(
|
|
998
|
+
result1, result2 = great_circle_tdoa_loc(
|
|
999
|
+
lat1, lon1, lat2, lon2, lat3, lon3, tdoa12, tdoa13
|
|
1000
|
+
)
|
|
995
1001
|
|
|
996
1002
|
# Should return at least one solution
|
|
997
1003
|
assert result1 is not None or result2 is not None
|
|
@@ -98,7 +98,9 @@ class TestClenshawSumOrderDerivative:
|
|
|
98
98
|
cos_theta = 0.5
|
|
99
99
|
sin_theta = np.sqrt(1 - cos_theta**2)
|
|
100
100
|
|
|
101
|
-
result = clenshaw_sum_order_derivative(
|
|
101
|
+
result = clenshaw_sum_order_derivative(
|
|
102
|
+
0, cos_theta, sin_theta, coef.C, coef.S, 10
|
|
103
|
+
)
|
|
102
104
|
|
|
103
105
|
assert isinstance(result, tuple)
|
|
104
106
|
assert len(result) == 4
|
|
@@ -140,8 +142,12 @@ class TestClenshawPotential:
|
|
|
140
142
|
lat = np.radians(30)
|
|
141
143
|
lon = 0
|
|
142
144
|
|
|
143
|
-
V_close = clenshaw_potential(
|
|
144
|
-
|
|
145
|
+
V_close = clenshaw_potential(
|
|
146
|
+
lat, lon, coef.R, coef.C, coef.S, coef.R, coef.GM, 10
|
|
147
|
+
)
|
|
148
|
+
V_far = clenshaw_potential(
|
|
149
|
+
lat, lon, coef.R * 1.1, coef.C, coef.S, coef.R, coef.GM, 10
|
|
150
|
+
)
|
|
145
151
|
|
|
146
152
|
# Potential magnitude should decrease with distance
|
|
147
153
|
assert abs(V_far) < abs(V_close)
|
|
@@ -152,8 +158,12 @@ class TestClenshawPotential:
|
|
|
152
158
|
lon = 0
|
|
153
159
|
r = coef.R
|
|
154
160
|
|
|
155
|
-
V_north = clenshaw_potential(
|
|
156
|
-
|
|
161
|
+
V_north = clenshaw_potential(
|
|
162
|
+
np.radians(45), lon, r, coef.C, coef.S, coef.R, coef.GM, 10
|
|
163
|
+
)
|
|
164
|
+
V_south = clenshaw_potential(
|
|
165
|
+
np.radians(-45), lon, r, coef.C, coef.S, coef.R, coef.GM, 10
|
|
166
|
+
)
|
|
157
167
|
|
|
158
168
|
# For Earth's gravity field (with small asymmetries), should be close
|
|
159
169
|
# The potential is dominated by the central term, so relative difference is small
|
|
@@ -185,7 +195,9 @@ class TestClenshawGravity:
|
|
|
185
195
|
lon = np.radians(0)
|
|
186
196
|
r = coef.R
|
|
187
197
|
|
|
188
|
-
g_r, g_lat, g_lon = clenshaw_gravity(
|
|
198
|
+
g_r, g_lat, g_lon = clenshaw_gravity(
|
|
199
|
+
lat, lon, r, coef.C, coef.S, coef.R, coef.GM, 10
|
|
200
|
+
)
|
|
189
201
|
|
|
190
202
|
# Full gravity includes the central term GM/r^2 which is about 9.8 m/s^2
|
|
191
203
|
# The sign depends on convention - we compute -dV/dr
|
|
@@ -245,7 +257,9 @@ class TestAssociatedLegendreScaled:
|
|
|
245
257
|
for m in range(n + 1):
|
|
246
258
|
# exp is indexed by degree only (1D array)
|
|
247
259
|
P_reconstructed = P_scaled[n, m] * (10.0 ** exp[n])
|
|
248
|
-
assert_allclose(
|
|
260
|
+
assert_allclose(
|
|
261
|
+
P_reconstructed, P_unscaled[n, m], rtol=1e-8, atol=1e-12
|
|
262
|
+
)
|
|
249
263
|
|
|
250
264
|
def test_no_overflow_high_degree(self):
|
|
251
265
|
"""High degree computation doesn't overflow."""
|
|
@@ -306,7 +320,9 @@ class TestGeoidHeight:
|
|
|
306
320
|
# Test several locations
|
|
307
321
|
for lat in [0, 45, -45, 90]:
|
|
308
322
|
for lon in [0, 90, -90, 180]:
|
|
309
|
-
N = geoid_height(
|
|
323
|
+
N = geoid_height(
|
|
324
|
+
np.radians(lat), np.radians(lon), coefficients=coef, n_max=36
|
|
325
|
+
)
|
|
310
326
|
assert not np.isnan(N)
|
|
311
327
|
assert not np.isinf(N)
|
|
312
328
|
|
|
@@ -332,7 +348,9 @@ class TestGeoidHeights:
|
|
|
332
348
|
lon = np.radians(-75)
|
|
333
349
|
|
|
334
350
|
N_single = geoid_height(lat, lon, coefficients=coef, n_max=10)
|
|
335
|
-
N_batch = geoid_heights(
|
|
351
|
+
N_batch = geoid_heights(
|
|
352
|
+
np.array([lat]), np.array([lon]), coefficients=coef, n_max=10
|
|
353
|
+
)
|
|
336
354
|
|
|
337
355
|
assert_allclose(N_batch[0], N_single)
|
|
338
356
|
|
|
@@ -362,7 +380,9 @@ class TestGravityDisturbance:
|
|
|
362
380
|
np.radians(30), np.radians(60), h=0.0, coefficients=coef, n_max=10
|
|
363
381
|
)
|
|
364
382
|
|
|
365
|
-
expected_mag = np.sqrt(
|
|
383
|
+
expected_mag = np.sqrt(
|
|
384
|
+
result.delta_g_r**2 + result.delta_g_lat**2 + result.delta_g_lon**2
|
|
385
|
+
)
|
|
366
386
|
assert_allclose(result.magnitude, expected_mag)
|
|
367
387
|
|
|
368
388
|
def test_disturbance_decreases_with_altitude(self):
|
|
@@ -372,7 +392,9 @@ class TestGravityDisturbance:
|
|
|
372
392
|
lon = np.radians(0)
|
|
373
393
|
|
|
374
394
|
result_0 = gravity_disturbance(lat, lon, h=0.0, coefficients=coef, n_max=20)
|
|
375
|
-
result_10km = gravity_disturbance(
|
|
395
|
+
result_10km = gravity_disturbance(
|
|
396
|
+
lat, lon, h=10000.0, coefficients=coef, n_max=20
|
|
397
|
+
)
|
|
376
398
|
|
|
377
399
|
# Disturbance magnitude should decrease with altitude
|
|
378
400
|
assert result_10km.magnitude < result_0.magnitude
|
|
@@ -385,7 +407,9 @@ class TestGravityAnomaly:
|
|
|
385
407
|
"""gravity_anomaly returns a float."""
|
|
386
408
|
coef = create_test_coefficients(n_max=10)
|
|
387
409
|
|
|
388
|
-
anom = gravity_anomaly(
|
|
410
|
+
anom = gravity_anomaly(
|
|
411
|
+
np.radians(45), np.radians(-75), h=0.0, coefficients=coef, n_max=10
|
|
412
|
+
)
|
|
389
413
|
|
|
390
414
|
assert isinstance(anom, float)
|
|
391
415
|
assert not np.isnan(anom)
|
|
@@ -394,7 +418,9 @@ class TestGravityAnomaly:
|
|
|
394
418
|
"""Gravity anomaly computation produces finite values."""
|
|
395
419
|
coef = create_test_coefficients(n_max=36)
|
|
396
420
|
|
|
397
|
-
anom = gravity_anomaly(
|
|
421
|
+
anom = gravity_anomaly(
|
|
422
|
+
np.radians(45), np.radians(0), h=0.0, coefficients=coef, n_max=36
|
|
423
|
+
)
|
|
398
424
|
|
|
399
425
|
# Note: With test coefficients (including full J2), values are large
|
|
400
426
|
# because J2 represents the equatorial bulge which is part of the
|
|
@@ -423,7 +449,9 @@ class TestDeflectionOfVertical:
|
|
|
423
449
|
"""Deflection values are finite."""
|
|
424
450
|
coef = create_test_coefficients(n_max=36)
|
|
425
451
|
|
|
426
|
-
xi, eta = deflection_of_vertical(
|
|
452
|
+
xi, eta = deflection_of_vertical(
|
|
453
|
+
np.radians(45), np.radians(0), coefficients=coef, n_max=36
|
|
454
|
+
)
|
|
427
455
|
|
|
428
456
|
# Note: Test coefficients include full J2, so deflections are larger
|
|
429
457
|
# than real-world values which are typically < 60 arcseconds.
|
|
@@ -493,12 +521,16 @@ class TestClenshawVsNaive:
|
|
|
493
521
|
r = coef.R
|
|
494
522
|
|
|
495
523
|
# Compute potential using Clenshaw
|
|
496
|
-
V_clenshaw = clenshaw_potential(
|
|
524
|
+
V_clenshaw = clenshaw_potential(
|
|
525
|
+
lat, lon, r, coef.C, coef.S, coef.R, coef.GM, 10
|
|
526
|
+
)
|
|
497
527
|
|
|
498
528
|
# Compute using naive spherical harmonic sum
|
|
499
529
|
# spherical_harmonic_sum takes (lat, lon, r, C, S, R, GM, n_max)
|
|
500
530
|
# and returns (V, dV_r, dV_lat)
|
|
501
|
-
V_naive, _, _ = spherical_harmonic_sum(
|
|
531
|
+
V_naive, _, _ = spherical_harmonic_sum(
|
|
532
|
+
lat, lon, r, coef.C, coef.S, coef.R, coef.GM, 10
|
|
533
|
+
)
|
|
502
534
|
|
|
503
535
|
# Should match to reasonable precision
|
|
504
536
|
# (Clenshaw and naive may have different numerical properties)
|
|
@@ -546,8 +578,12 @@ class TestEdgeCases:
|
|
|
546
578
|
"""Negative longitude works correctly."""
|
|
547
579
|
coef = create_test_coefficients(n_max=20)
|
|
548
580
|
|
|
549
|
-
N_pos = geoid_height(
|
|
550
|
-
|
|
581
|
+
N_pos = geoid_height(
|
|
582
|
+
np.radians(45), np.radians(90), coefficients=coef, n_max=20
|
|
583
|
+
)
|
|
584
|
+
N_neg = geoid_height(
|
|
585
|
+
np.radians(45), np.radians(-270), coefficients=coef, n_max=20
|
|
586
|
+
)
|
|
551
587
|
|
|
552
588
|
# 90° and -270° are the same longitude
|
|
553
589
|
assert_allclose(N_pos, N_neg, rtol=1e-10)
|
|
@@ -130,31 +130,41 @@ class TestEMMFunction:
|
|
|
130
130
|
|
|
131
131
|
def test_total_intensity_reasonable(self, test_coefficients):
|
|
132
132
|
"""Total field intensity should be in expected range."""
|
|
133
|
-
result = emm(
|
|
133
|
+
result = emm(
|
|
134
|
+
np.radians(45), np.radians(0), 0, 2020.0, coefficients=test_coefficients
|
|
135
|
+
)
|
|
134
136
|
# Field intensity typically 25,000-65,000 nT at mid-latitudes
|
|
135
137
|
# but can exceed this at high latitudes, allow up to 100,000 nT
|
|
136
138
|
assert 20000 < result.F < 100000
|
|
137
139
|
|
|
138
140
|
def test_horizontal_intensity_formula(self, test_coefficients):
|
|
139
141
|
"""H = sqrt(X^2 + Y^2)."""
|
|
140
|
-
result = emm(
|
|
142
|
+
result = emm(
|
|
143
|
+
np.radians(40), np.radians(-75), 0, 2020.0, coefficients=test_coefficients
|
|
144
|
+
)
|
|
141
145
|
H_calc = np.sqrt(result.X**2 + result.Y**2)
|
|
142
146
|
assert_allclose(result.H, H_calc, rtol=1e-10)
|
|
143
147
|
|
|
144
148
|
def test_total_intensity_formula(self, test_coefficients):
|
|
145
149
|
"""F = sqrt(H^2 + Z^2)."""
|
|
146
|
-
result = emm(
|
|
150
|
+
result = emm(
|
|
151
|
+
np.radians(40), np.radians(-75), 0, 2020.0, coefficients=test_coefficients
|
|
152
|
+
)
|
|
147
153
|
F_calc = np.sqrt(result.H**2 + result.Z**2)
|
|
148
154
|
assert_allclose(result.F, F_calc, rtol=1e-10)
|
|
149
155
|
|
|
150
156
|
def test_declination_range(self, test_coefficients):
|
|
151
157
|
"""Declination should be within -180 to 180 degrees."""
|
|
152
|
-
result = emm(
|
|
158
|
+
result = emm(
|
|
159
|
+
np.radians(45), np.radians(-75), 0, 2020.0, coefficients=test_coefficients
|
|
160
|
+
)
|
|
153
161
|
assert -np.pi <= result.D <= np.pi
|
|
154
162
|
|
|
155
163
|
def test_inclination_range(self, test_coefficients):
|
|
156
164
|
"""Inclination should be within -90 to 90 degrees."""
|
|
157
|
-
result = emm(
|
|
165
|
+
result = emm(
|
|
166
|
+
np.radians(45), np.radians(-75), 0, 2020.0, coefficients=test_coefficients
|
|
167
|
+
)
|
|
158
168
|
assert -np.pi / 2 <= result.I <= np.pi / 2
|
|
159
169
|
|
|
160
170
|
|
|
@@ -219,7 +229,9 @@ class TestWMMHR:
|
|
|
219
229
|
|
|
220
230
|
def test_wmmhr_returns_result(self, test_coefficients):
|
|
221
231
|
"""WMMHR returns MagneticResult."""
|
|
222
|
-
result = wmmhr(
|
|
232
|
+
result = wmmhr(
|
|
233
|
+
np.radians(45), np.radians(-75), 0, 2025.0, coefficients=test_coefficients
|
|
234
|
+
)
|
|
223
235
|
assert hasattr(result, "F")
|
|
224
236
|
assert hasattr(result, "D")
|
|
225
237
|
assert hasattr(result, "I")
|
|
@@ -259,7 +271,9 @@ class TestConvenienceFunctions:
|
|
|
259
271
|
|
|
260
272
|
def test_emm_declination(self, test_coefficients):
|
|
261
273
|
"""emm_declination returns correct value."""
|
|
262
|
-
result = emm(
|
|
274
|
+
result = emm(
|
|
275
|
+
np.radians(40), np.radians(-105), 0, 2020.0, coefficients=test_coefficients
|
|
276
|
+
)
|
|
263
277
|
D = emm_declination(
|
|
264
278
|
np.radians(40), np.radians(-105), 0, 2020.0, coefficients=test_coefficients
|
|
265
279
|
)
|
|
@@ -267,7 +281,9 @@ class TestConvenienceFunctions:
|
|
|
267
281
|
|
|
268
282
|
def test_emm_inclination(self, test_coefficients):
|
|
269
283
|
"""emm_inclination returns correct value."""
|
|
270
|
-
result = emm(
|
|
284
|
+
result = emm(
|
|
285
|
+
np.radians(40), np.radians(-105), 0, 2020.0, coefficients=test_coefficients
|
|
286
|
+
)
|
|
271
287
|
incl = emm_inclination(
|
|
272
288
|
np.radians(40), np.radians(-105), 0, 2020.0, coefficients=test_coefficients
|
|
273
289
|
)
|
|
@@ -275,7 +291,9 @@ class TestConvenienceFunctions:
|
|
|
275
291
|
|
|
276
292
|
def test_emm_intensity(self, test_coefficients):
|
|
277
293
|
"""emm_intensity returns correct value."""
|
|
278
|
-
result = emm(
|
|
294
|
+
result = emm(
|
|
295
|
+
np.radians(40), np.radians(-105), 0, 2020.0, coefficients=test_coefficients
|
|
296
|
+
)
|
|
279
297
|
F = emm_intensity(
|
|
280
298
|
np.radians(40), np.radians(-105), 0, 2020.0, coefficients=test_coefficients
|
|
281
299
|
)
|
|
@@ -313,8 +331,12 @@ class TestSecularVariation:
|
|
|
313
331
|
|
|
314
332
|
def test_field_changes_with_time(self, test_coefficients):
|
|
315
333
|
"""Field should change slightly between years."""
|
|
316
|
-
result_2020 = emm(
|
|
317
|
-
|
|
334
|
+
result_2020 = emm(
|
|
335
|
+
np.radians(45), np.radians(0), 0, 2020.0, coefficients=test_coefficients
|
|
336
|
+
)
|
|
337
|
+
result_2022 = emm(
|
|
338
|
+
np.radians(45), np.radians(0), 0, 2022.0, coefficients=test_coefficients
|
|
339
|
+
)
|
|
318
340
|
# Small but non-zero change expected
|
|
319
341
|
# Secular variation is ~50-100 nT/year at mid-latitudes
|
|
320
342
|
assert result_2020.F != result_2022.F
|
|
@@ -389,7 +411,9 @@ class TestHighDegreeEvaluation:
|
|
|
389
411
|
def test_higher_degree_coefficients(self):
|
|
390
412
|
"""Test with higher degree coefficients (n_max=50)."""
|
|
391
413
|
coef = create_emm_test_coefficients(n_max=50)
|
|
392
|
-
result = emm(
|
|
414
|
+
result = emm(
|
|
415
|
+
np.radians(40), np.radians(-105), 0, 2020.0, coefficients=coef, n_max=50
|
|
416
|
+
)
|
|
393
417
|
assert not np.isnan(result.F)
|
|
394
418
|
assert result.F > 0
|
|
395
419
|
|
|
@@ -398,8 +422,12 @@ class TestHighDegreeEvaluation:
|
|
|
398
422
|
coef = create_emm_test_coefficients(n_max=50)
|
|
399
423
|
|
|
400
424
|
# Evaluate at different n_max values
|
|
401
|
-
result_12 = emm(
|
|
402
|
-
|
|
425
|
+
result_12 = emm(
|
|
426
|
+
np.radians(40), np.radians(-105), 0, 2020.0, coefficients=coef, n_max=12
|
|
427
|
+
)
|
|
428
|
+
result_50 = emm(
|
|
429
|
+
np.radians(40), np.radians(-105), 0, 2020.0, coefficients=coef, n_max=50
|
|
430
|
+
)
|
|
403
431
|
|
|
404
432
|
# Both should be valid
|
|
405
433
|
assert result_12.F > 0
|
|
@@ -155,7 +155,9 @@ class TestMoonPosition:
|
|
|
155
155
|
def test_moon_position_earth_centered(self):
|
|
156
156
|
"""Test Moon position relative to Earth."""
|
|
157
157
|
jd = 2451545.0
|
|
158
|
-
r_earth_centered, v_earth_centered = self.eph.moon_position(
|
|
158
|
+
r_earth_centered, v_earth_centered = self.eph.moon_position(
|
|
159
|
+
jd, frame="earth_centered"
|
|
160
|
+
)
|
|
159
161
|
|
|
160
162
|
# Moon is about 385,000 km = 0.00257 AU from Earth
|
|
161
163
|
distance = np.linalg.norm(r_earth_centered)
|
|
@@ -163,7 +165,9 @@ class TestMoonPosition:
|
|
|
163
165
|
distance_km = distance * au_to_km
|
|
164
166
|
|
|
165
167
|
# Should be roughly 380,000-390,000 km
|
|
166
|
-
assert
|
|
168
|
+
assert (
|
|
169
|
+
370000 < distance_km < 400000
|
|
170
|
+
), f"Moon distance {distance_km:.0f} km is unexpected"
|
|
167
171
|
|
|
168
172
|
def test_moon_position_frames_consistency(self):
|
|
169
173
|
"""Test that Moon positions are consistent across frames."""
|