nrl-tracker 1.9.1__py3-none-any.whl → 1.10.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. {nrl_tracker-1.9.1.dist-info → nrl_tracker-1.10.0.dist-info}/METADATA +49 -4
  2. {nrl_tracker-1.9.1.dist-info → nrl_tracker-1.10.0.dist-info}/RECORD +68 -60
  3. pytcl/__init__.py +2 -2
  4. pytcl/assignment_algorithms/gating.py +18 -0
  5. pytcl/assignment_algorithms/jpda.py +56 -0
  6. pytcl/assignment_algorithms/nd_assignment.py +65 -0
  7. pytcl/assignment_algorithms/network_flow.py +40 -0
  8. pytcl/astronomical/ephemerides.py +18 -0
  9. pytcl/astronomical/orbital_mechanics.py +131 -0
  10. pytcl/atmosphere/ionosphere.py +44 -0
  11. pytcl/atmosphere/models.py +29 -0
  12. pytcl/clustering/dbscan.py +9 -0
  13. pytcl/clustering/gaussian_mixture.py +20 -0
  14. pytcl/clustering/hierarchical.py +29 -0
  15. pytcl/clustering/kmeans.py +9 -0
  16. pytcl/coordinate_systems/conversions/geodetic.py +46 -0
  17. pytcl/coordinate_systems/conversions/spherical.py +35 -0
  18. pytcl/coordinate_systems/rotations/rotations.py +147 -0
  19. pytcl/core/__init__.py +16 -0
  20. pytcl/core/maturity.py +346 -0
  21. pytcl/core/optional_deps.py +20 -0
  22. pytcl/dynamic_estimation/gaussian_sum_filter.py +55 -0
  23. pytcl/dynamic_estimation/imm.py +29 -0
  24. pytcl/dynamic_estimation/information_filter.py +64 -0
  25. pytcl/dynamic_estimation/kalman/extended.py +56 -0
  26. pytcl/dynamic_estimation/kalman/linear.py +69 -0
  27. pytcl/dynamic_estimation/kalman/unscented.py +81 -0
  28. pytcl/dynamic_estimation/particle_filters/bootstrap.py +146 -0
  29. pytcl/dynamic_estimation/rbpf.py +51 -0
  30. pytcl/dynamic_estimation/smoothers.py +58 -0
  31. pytcl/dynamic_models/continuous_time/dynamics.py +104 -0
  32. pytcl/dynamic_models/discrete_time/coordinated_turn.py +6 -0
  33. pytcl/dynamic_models/discrete_time/singer.py +12 -0
  34. pytcl/dynamic_models/process_noise/coordinated_turn.py +46 -0
  35. pytcl/dynamic_models/process_noise/polynomial.py +6 -0
  36. pytcl/dynamic_models/process_noise/singer.py +52 -0
  37. pytcl/gpu/__init__.py +153 -0
  38. pytcl/gpu/ekf.py +425 -0
  39. pytcl/gpu/kalman.py +543 -0
  40. pytcl/gpu/matrix_utils.py +486 -0
  41. pytcl/gpu/particle_filter.py +568 -0
  42. pytcl/gpu/ukf.py +476 -0
  43. pytcl/gpu/utils.py +582 -0
  44. pytcl/gravity/clenshaw.py +60 -0
  45. pytcl/gravity/egm.py +47 -0
  46. pytcl/gravity/models.py +34 -0
  47. pytcl/gravity/spherical_harmonics.py +73 -0
  48. pytcl/gravity/tides.py +34 -0
  49. pytcl/mathematical_functions/numerical_integration/quadrature.py +85 -0
  50. pytcl/mathematical_functions/special_functions/bessel.py +55 -0
  51. pytcl/mathematical_functions/special_functions/elliptic.py +42 -0
  52. pytcl/mathematical_functions/special_functions/error_functions.py +49 -0
  53. pytcl/mathematical_functions/special_functions/gamma_functions.py +43 -0
  54. pytcl/mathematical_functions/special_functions/lambert_w.py +5 -0
  55. pytcl/mathematical_functions/special_functions/marcum_q.py +16 -0
  56. pytcl/navigation/geodesy.py +101 -2
  57. pytcl/navigation/great_circle.py +71 -0
  58. pytcl/navigation/rhumb.py +74 -0
  59. pytcl/performance_evaluation/estimation_metrics.py +70 -0
  60. pytcl/performance_evaluation/track_metrics.py +30 -0
  61. pytcl/static_estimation/maximum_likelihood.py +54 -0
  62. pytcl/static_estimation/robust.py +57 -0
  63. pytcl/terrain/dem.py +69 -0
  64. pytcl/terrain/visibility.py +65 -0
  65. pytcl/trackers/hypothesis.py +65 -0
  66. {nrl_tracker-1.9.1.dist-info → nrl_tracker-1.10.0.dist-info}/LICENSE +0 -0
  67. {nrl_tracker-1.9.1.dist-info → nrl_tracker-1.10.0.dist-info}/WHEEL +0 -0
  68. {nrl_tracker-1.9.1.dist-info → nrl_tracker-1.10.0.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: nrl-tracker
3
- Version: 1.9.1
3
+ Version: 1.10.0
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
@@ -41,6 +41,8 @@ Requires-Dist: pytest>=7.0.0; extra == "dev"
41
41
  Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
42
42
  Requires-Dist: pytest-xdist>=3.0.0; extra == "dev"
43
43
  Requires-Dist: pytest-benchmark>=4.0.0; extra == "dev"
44
+ Requires-Dist: pytest-timeout>=2.0.0; extra == "dev"
45
+ Requires-Dist: nbval>=0.10.0; extra == "dev"
44
46
  Requires-Dist: hypothesis>=6.0.0; extra == "dev"
45
47
  Requires-Dist: black>=23.0.0; extra == "dev"
46
48
  Requires-Dist: isort>=5.12.0; extra == "dev"
@@ -51,9 +53,15 @@ Requires-Dist: sphinx>=6.0.0; extra == "dev"
51
53
  Requires-Dist: sphinx-rtd-theme>=1.2.0; extra == "dev"
52
54
  Requires-Dist: myst-parser>=1.0.0; extra == "dev"
53
55
  Requires-Dist: nbsphinx>=0.9.0; extra == "dev"
56
+ Requires-Dist: jupyter>=1.0.0; extra == "dev"
57
+ Requires-Dist: ipykernel>=6.0.0; extra == "dev"
54
58
  Provides-Extra: geodesy
55
59
  Requires-Dist: pyproj>=3.4.0; extra == "geodesy"
56
60
  Requires-Dist: geographiclib>=2.0; extra == "geodesy"
61
+ Provides-Extra: gpu
62
+ Requires-Dist: cupy-cuda12x>=12.0.0; extra == "gpu"
63
+ Provides-Extra: gpu-apple
64
+ Requires-Dist: mlx>=0.5.0; extra == "gpu-apple"
57
65
  Provides-Extra: optimization
58
66
  Requires-Dist: cvxpy>=1.3.0; extra == "optimization"
59
67
  Provides-Extra: signal
@@ -63,17 +71,17 @@ Requires-Dist: plotly>=5.15.0; extra == "visualization"
63
71
 
64
72
  # Tracker Component Library (Python)
65
73
 
66
- [![PyPI version](https://img.shields.io/badge/pypi-v1.9.0-blue.svg)](https://pypi.org/project/nrl-tracker/)
74
+ [![PyPI version](https://img.shields.io/badge/pypi-v1.10.0-blue.svg)](https://pypi.org/project/nrl-tracker/)
67
75
  [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
68
76
  [![License: Public Domain](https://img.shields.io/badge/License-Public%20Domain-brightgreen.svg)](https://en.wikipedia.org/wiki/Public_domain)
69
77
  [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
70
- [![Tests](https://img.shields.io/badge/tests-1988%20passing-success.svg)](https://github.com/nedonatelli/TCL)
78
+ [![Tests](https://img.shields.io/badge/tests-2133%20passing-success.svg)](https://github.com/nedonatelli/TCL)
71
79
  [![MATLAB Parity](https://img.shields.io/badge/MATLAB%20Parity-100%25-brightgreen.svg)](docs/gap_analysis.rst)
72
80
  [![Type Checking](https://img.shields.io/badge/mypy--strict-passing-brightgreen.svg)](mypy.ini)
73
81
 
74
82
  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.
75
83
 
76
- **1,070+ functions** | **153 modules** | **1,988 tests** | **100% MATLAB parity**
84
+ **1,070+ functions** | **153 modules** | **2,133 tests** | **100% MATLAB parity**
77
85
 
78
86
  ## Overview
79
87
 
@@ -90,6 +98,7 @@ The Tracker Component Library provides building blocks for developing target tra
90
98
  - **Navigation**: Geodetic calculations, INS mechanization, GNSS utilities, INS/GNSS integration
91
99
  - **Geophysical Models**: Gravity (WGS84, EGM96/2008), magnetism (WMM, IGRF), atmosphere, tides, terrain
92
100
  - **Signal Processing**: Digital filters, matched filtering, CFAR detection, transforms (FFT, STFT, wavelets)
101
+ - **GPU Acceleration**: CuPy (NVIDIA CUDA) and MLX (Apple Silicon) backends for batch Kalman filtering and particle filters
93
102
 
94
103
  ## Installation
95
104
 
@@ -111,6 +120,12 @@ pip install nrl-tracker[geodesy]
111
120
  # For visualization
112
121
  pip install nrl-tracker[visualization]
113
122
 
123
+ # For GPU acceleration (NVIDIA CUDA)
124
+ pip install nrl-tracker[gpu]
125
+
126
+ # For GPU acceleration (Apple Silicon M1/M2/M3)
127
+ pip install nrl-tracker[gpu-apple]
128
+
114
129
  # For development
115
130
  pip install nrl-tracker[dev]
116
131
 
@@ -183,6 +198,35 @@ assignment, total_cost = hungarian(cost_matrix)
183
198
  print(f"Optimal assignment: {assignment}, Total cost: {total_cost}")
184
199
  ```
185
200
 
201
+ ### GPU Acceleration
202
+
203
+ The library supports GPU acceleration for batch processing of multiple tracks:
204
+
205
+ ```python
206
+ from pytcl.gpu import is_gpu_available, get_backend, to_gpu, to_cpu
207
+
208
+ # Check GPU availability (auto-detects CUDA or Apple Silicon)
209
+ if is_gpu_available():
210
+ print(f"GPU available, using {get_backend()} backend")
211
+
212
+ # Transfer data to GPU
213
+ x_gpu = to_gpu(states) # (n_tracks, state_dim)
214
+ P_gpu = to_gpu(covariances) # (n_tracks, state_dim, state_dim)
215
+
216
+ # Use batch Kalman filter operations
217
+ from pytcl.gpu import batch_kf_predict
218
+ x_pred, P_pred = batch_kf_predict(x_gpu, P_gpu, F, Q)
219
+
220
+ # Transfer results back to CPU
221
+ x_pred_cpu = to_cpu(x_pred)
222
+ ```
223
+
224
+ **Supported backends:**
225
+ - **NVIDIA CUDA**: Via CuPy (`pip install nrl-tracker[gpu]`)
226
+ - **Apple Silicon**: Via MLX (`pip install nrl-tracker[gpu-apple]`)
227
+
228
+ The backend is automatically selected based on your platform.
229
+
186
230
  ## Module Structure
187
231
 
188
232
  ```
@@ -202,6 +246,7 @@ pytcl/
202
246
  ├── gravity/ # Gravity models
203
247
  ├── magnetism/ # Magnetic field models
204
248
  ├── terrain/ # Terrain elevation models
249
+ ├── gpu/ # GPU acceleration (CuPy/MLX)
205
250
  └── misc/ # Utilities, visualization
206
251
  ```
207
252
 
@@ -1,12 +1,12 @@
1
- pytcl/__init__.py,sha256=9dJwbOB9i-NLj_XEO6d0V6mq9jAl7dlgoNPL9NMR78s,2030
1
+ pytcl/__init__.py,sha256=DEk9yoH37UzqAZycMHTVEm6GgrN3uhXfObXQs3o28kI,2032
2
2
  pytcl/logging_config.py,sha256=UJaYufQgNuIjpsOMTPo3ewz1XCHPk8a08jTHyP7uoI4,8956
3
3
  pytcl/assignment_algorithms/__init__.py,sha256=kUWhmyLhZcs5GiUQA5_v7KA3qETGsvqV6wU8r7paO-k,2976
4
4
  pytcl/assignment_algorithms/data_association.py,sha256=tsRxWJZk9aAPmE99BKXGouEpFfZrjPjb4HXvgxFUHhU,11405
5
5
  pytcl/assignment_algorithms/dijkstra_min_cost.py,sha256=z-Wk1HXRNKieBsRFqR8_UB8QvG5QkK3evazr8wzTpl0,5429
6
- pytcl/assignment_algorithms/gating.py,sha256=AXWn-F_EOGI6qrBc4PN5eFM-ZZGu1WOMi5b5ZsxValU,10910
7
- pytcl/assignment_algorithms/jpda.py,sha256=8-HoO2VygxJ8FFSCCOIOfbhMAn87jU7PqVvd7lQ3GEY,19797
8
- pytcl/assignment_algorithms/nd_assignment.py,sha256=RBRoXoJnUY0lB9Vb_dwvQtwh6oI31KfeDqpaNrTNXzk,11344
9
- pytcl/assignment_algorithms/network_flow.py,sha256=yxEtoNe0-paXgNmeH2e3qcdRr_8ZvAg2L62QtqZZKMI,13221
6
+ pytcl/assignment_algorithms/gating.py,sha256=JaRaFcFqjfdsTbbTP6k_GY2zemDSR02l5yInWHpb05Y,11439
7
+ pytcl/assignment_algorithms/jpda.py,sha256=rOY_v1vesL6EJySwD0kRDTfe7wHoDFLITg_lJLM-bX4,21731
8
+ pytcl/assignment_algorithms/nd_assignment.py,sha256=qYTFZryqfnHXz1I1Kg2vTvEJIYla4JknedhKPXphdiQ,13269
9
+ pytcl/assignment_algorithms/network_flow.py,sha256=pPD63Z0-HOBv5XIqKUedt1KzTkcs0KG41DNojFZocDI,14459
10
10
  pytcl/assignment_algorithms/network_simplex.py,sha256=Qi10PsIYcTc6MZ-9GPl6ivaLaGA9F5-B7ltBbmasRNM,5566
11
11
  pytcl/assignment_algorithms/three_dimensional/__init__.py,sha256=1Q40OUlUQoo7YKEucwdrSNo3D4A0Zibvkr8z4TpueBg,526
12
12
  pytcl/assignment_algorithms/three_dimensional/assignment.py,sha256=OGcjg3Yr1tYriWYBJ5k6jiRMpOHDISK8FJDY0nTQxxw,19244
@@ -14,9 +14,9 @@ pytcl/assignment_algorithms/two_dimensional/__init__.py,sha256=4Evsn__9hTfI2i8m8
14
14
  pytcl/assignment_algorithms/two_dimensional/assignment.py,sha256=eh87MBb-uiUSI1MXj4HrreRKB6Z8rxAyDkNQ8-u4SbM,11848
15
15
  pytcl/assignment_algorithms/two_dimensional/kbest.py,sha256=yiTToLuP7xWxQlQ8E-fpgXg-5iu0nnXcJXStjUB0nOE,17284
16
16
  pytcl/astronomical/__init__.py,sha256=v0nUgEy5ReHXzpNb1JdwWXv4AtcFksotEOccQnOyVfI,9667
17
- pytcl/astronomical/ephemerides.py,sha256=dJNq2Z_qmgM4rpFbH2zZl5kXWtvPjwPLGkP_eDUF7KA,16859
17
+ pytcl/astronomical/ephemerides.py,sha256=cZ_qedKAG7BfIinjfGyH48pRwiVfn7bQ_4qyICa9-GA,17401
18
18
  pytcl/astronomical/lambert.py,sha256=Lc8FT1JmpI9WSXsG2s5vIRkSoBSV7r5hd3o2bGh2Ojo,15607
19
- pytcl/astronomical/orbital_mechanics.py,sha256=8GssRanwTowCl6PJYqmB_SDnNznLUq5gkPa3j6iEo3U,19965
19
+ pytcl/astronomical/orbital_mechanics.py,sha256=alC8r9SToqVpBeo6EJ6alHdoJ6hJ6wshZF_xA1qPYJQ,23003
20
20
  pytcl/astronomical/reference_frames.py,sha256=MBqprzBpEvdq3ngRL-_pp-Vnj7AqbuXhjUfGQ98znfc,35616
21
21
  pytcl/astronomical/relativity.py,sha256=vSay4am_ElkiGRwuu_4rwo5C10eN8hm86jy43xmaEt4,15933
22
22
  pytcl/astronomical/sgp4.py,sha256=iNZrqMRUzR-LFeZiluzlNmkwxeYbIyF2F1cygyeEZVE,21546
@@ -24,14 +24,14 @@ pytcl/astronomical/special_orbits.py,sha256=N54c_wAD7XKk_diDOw2QjUSkmYECMyWQDq2P
24
24
  pytcl/astronomical/time_systems.py,sha256=Jg0Zaq60hc4Ts1aQtb5bK4KSZhz-uQse8gYC89Y0-TA,15243
25
25
  pytcl/astronomical/tle.py,sha256=t3e2-0f3Wiz77q-pC2jfpohkrDfoYOEHacpNgWMNLAk,14638
26
26
  pytcl/atmosphere/__init__.py,sha256=Joa6PBEfKun0Moii6BOzyVYG8AOFyvucKdVuY62ArQc,1685
27
- pytcl/atmosphere/ionosphere.py,sha256=1qC3hY-27pD0XcLBjU735deKYmmi6qnj2fDG1zNbTqg,14681
28
- pytcl/atmosphere/models.py,sha256=pMLv8D7qoFqLZrlbTHLJJULOdDdhPskJ1m7KVKLV63E,9584
27
+ pytcl/atmosphere/ionosphere.py,sha256=tt_Qu1IvqZxah2P_QaWxpwroSgtDNU-6RrqtxMRZScY,16092
28
+ pytcl/atmosphere/models.py,sha256=ZAwa6rsSe9RaQyVjiJ2i2K_D9ZyJ0MymhSsltnsiAK8,10358
29
29
  pytcl/atmosphere/nrlmsise00.py,sha256=jcmAC00G3X0CzfK4eWkvq2tPxHXzMqC8GBHNbFZRq4w,25868
30
30
  pytcl/clustering/__init__.py,sha256=bYdhC_XJEt6KUUni9bIPxaddXNEGmIJQvGkA14rK4J8,1697
31
- pytcl/clustering/dbscan.py,sha256=WgzYz_f5nDh0T1RPClX9b3xSvFPmLxY6QaI2NCtxJg4,7389
32
- pytcl/clustering/gaussian_mixture.py,sha256=UAI2_WG2RASA0N2PIZ0EZgqYZ3yly7oJBSJWSJnm_bE,22904
33
- pytcl/clustering/hierarchical.py,sha256=K7z6bZR4QSDMva9kaqEOjdktl8unMK1wyCJm3cFN8pQ,14292
34
- pytcl/clustering/kmeans.py,sha256=GNvgaGP53LKr4-fh-UajxbjCi0jWCCLJba23EGcQq4I,10712
31
+ pytcl/clustering/dbscan.py,sha256=paEua1ocHfnEM1rh972osfKPerziSw04vRkRmNApb1U,7681
32
+ pytcl/clustering/gaussian_mixture.py,sha256=U-mIRLkpyZbWt9Egx3CZrpDCmci9588YMVff0JM8ge0,23778
33
+ pytcl/clustering/hierarchical.py,sha256=MDBIcJtZHYruSsM_seAR9bNWKB63EDh1nIf6qAn43lE,15195
34
+ pytcl/clustering/kmeans.py,sha256=_r08KVvqHL1UnYE4rHBAJ1OKA97q-PWl2OOsTi6kKqk,10963
35
35
  pytcl/containers/__init__.py,sha256=i-o_KDjhbPWc9yAlgN1R5igmyWK3CVKIB-V7Qnr-fLg,2746
36
36
  pytcl/containers/base.py,sha256=oKD8vAH09qAEOG3uhtoTgJ9UU_hQhl6keSIlGEVucrs,7762
37
37
  pytcl/containers/cluster_set.py,sha256=uhfOIpXlYoI1U75TWcLMHjezVavnIZhVEGQHKCDmKo4,22774
@@ -43,58 +43,66 @@ pytcl/containers/track_list.py,sha256=6q9Qgcwm-8H_JqtOCsMssF27av4XaSkhfDl-MWb1AB
43
43
  pytcl/containers/vptree.py,sha256=-7znAilGCNpN7SN8TxVhNFIOyP-s9oJa9Vp4FJWehcg,8720
44
44
  pytcl/coordinate_systems/__init__.py,sha256=jwYhu_-9AvOeP9WLG9PYtyDwfe0GjxNZ9-xCqiLymW4,3909
45
45
  pytcl/coordinate_systems/conversions/__init__.py,sha256=PkNevB78vBw0BkalydJBbQO91AyiMJxKRrgJNt4HsYc,1100
46
- pytcl/coordinate_systems/conversions/geodetic.py,sha256=rRRf4MWBkGj3VTN1WRW3lrlw4Yf9a4HH3UCgNOGjbJ0,23460
47
- pytcl/coordinate_systems/conversions/spherical.py,sha256=q7k9l5mJbVzVdNj9Gcq4ibFxax8z_mVpJfITRBzx630,10812
46
+ pytcl/coordinate_systems/conversions/geodetic.py,sha256=CarrTBW9rTC-CZ4E4YGxA8QjlpauuXJ2ZScnzc4QvK8,25001
47
+ pytcl/coordinate_systems/conversions/spherical.py,sha256=GwuS1k0aUQ3AG1zZJouioMjxSIuEPRZMk-arvUCTh2k,11563
48
48
  pytcl/coordinate_systems/jacobians/__init__.py,sha256=CRGB8GzvGT_sr4Ynm51S7gSX8grqt1pO1Pq1MWmHPTs,890
49
49
  pytcl/coordinate_systems/jacobians/jacobians.py,sha256=0gpbelZPN4HDtvS1ymc3RIhOfxCVTKpRc-jDJXdM6pQ,11747
50
50
  pytcl/coordinate_systems/projections/__init__.py,sha256=TmBiffO5cmazAhsfPIVBaaqnravVSO3JxjGb0MXkucc,2404
51
51
  pytcl/coordinate_systems/projections/projections.py,sha256=y_kwcu_zp0HHiKR-wp3v3AvRcY61bleDi1SxwbrnWB0,33179
52
52
  pytcl/coordinate_systems/rotations/__init__.py,sha256=nqAz4iJd2hEOX_r7Tz4cE524sShyxdbtcQ5m56RrDLg,1047
53
- pytcl/coordinate_systems/rotations/rotations.py,sha256=2KK6Lgpfmjac3qfOMvHku_BcwGOgkRC13BZbSCUvfwQ,18314
54
- pytcl/core/__init__.py,sha256=RNsMJw_rydDqNaoxHunANCooxtdc_lclVVfsy7EIK1U,2854
53
+ pytcl/coordinate_systems/rotations/rotations.py,sha256=-VheczqsqF-qHF46HVKYTe0oS76MTmqyXQV3EO2JAJs,22258
54
+ pytcl/core/__init__.py,sha256=Rm02KyEP5jCgcaS6N6F-Bs2nLgW-EO1cjCD0NqAg664,3236
55
55
  pytcl/core/array_utils.py,sha256=SsgEiAoRCWxAVKq1aa5-nPdOi-2AB6XNObu0IaGClUk,13983
56
56
  pytcl/core/constants.py,sha256=cwkCjzCU7zG2ZsFcbqwslN632v7Lw50L85s-5q892mo,9988
57
57
  pytcl/core/exceptions.py,sha256=6ImMiwL86BdmTt-Rc8fXLXxKUGQ-PcQQyxIvKKzw-n0,24324
58
- pytcl/core/optional_deps.py,sha256=Xe7BG18SWsmzBD3zGa440U_QWKkfATBKhUfLOxhXZuU,15799
58
+ pytcl/core/maturity.py,sha256=Sut19NfH1-6f3Qd2QSC6OAqvDcVHJDwf5-F_-oEAMJA,11596
59
+ pytcl/core/optional_deps.py,sha256=a3UK_DM2s0XQE4Lwp0agq9L0qjupl_d8o4csCYbi440,16396
59
60
  pytcl/core/validation.py,sha256=4ay21cZVAil8udymwej7QnVQfNyjzi_5A8O1y-d-Lyw,23492
60
61
  pytcl/dynamic_estimation/__init__.py,sha256=zxmkZIXVfHPv5AHYpQV5nwsI0PA3m-Vw7W0gkJE7j98,5191
61
- pytcl/dynamic_estimation/gaussian_sum_filter.py,sha256=rxUy_WapTL_pkGimD01DqYE7fElLS_DljnX2yg95Uts,13620
62
- pytcl/dynamic_estimation/imm.py,sha256=RLSFPTMDsudxSf9Mh6Q5qD852tq9lRoCTvFCGphezhs,22152
63
- pytcl/dynamic_estimation/information_filter.py,sha256=x7iQwO_iJT1dCSvDws5LqD3yAtjw9QVGUfMPcXn1IA4,17349
64
- pytcl/dynamic_estimation/rbpf.py,sha256=CaKSD2TC1sxICnHuN1W2v2S7P-Kxi4lxdy4KRq2We3w,17898
65
- pytcl/dynamic_estimation/smoothers.py,sha256=x2j-nR--EI5JNZvMywPeDHcrfW8b5PYK0DCU4Rmig_g,18914
62
+ pytcl/dynamic_estimation/gaussian_sum_filter.py,sha256=3Ks5-sGo3IF9p_dsIzk5u2zaXS2ZAkJFAg1mdxo8vj8,15343
63
+ pytcl/dynamic_estimation/imm.py,sha256=Iq8hpnak9NQxcrtIoYgFYReul3sjo8o3QOvr9vXXUEU,23258
64
+ pytcl/dynamic_estimation/information_filter.py,sha256=DIziISqxbhfmLaeK5T6zROhncTZQKm4d3077nfs5u6o,19254
65
+ pytcl/dynamic_estimation/rbpf.py,sha256=gaJz0fDCFf-VAIQHlqrpFGv5LsBQMlr0DfptSv4JpQw,19819
66
+ pytcl/dynamic_estimation/smoothers.py,sha256=QVThB1E8Tj8UFHMRJ4tNMq509SvvBHECQRlMSM5fjRg,21259
66
67
  pytcl/dynamic_estimation/batch_estimation/__init__.py,sha256=JQ0s76Enov5a7plA4EnUua4t-7etikQrwr5z4WIjUeo,46
67
68
  pytcl/dynamic_estimation/kalman/__init__.py,sha256=lR-OacfZ5mqnAboEbOel5w_WS_Gmz-1q0l4meKfQsGs,3163
68
69
  pytcl/dynamic_estimation/kalman/constrained.py,sha256=Zidzz6_9OvwUyQppEltdmYTMvEeqRKFRkVMwx1TASuw,10960
69
- pytcl/dynamic_estimation/kalman/extended.py,sha256=fxi2-oq8qxnxZqPmjB8-Am03z6_F_R90wwFcOIEk_dg,10459
70
+ pytcl/dynamic_estimation/kalman/extended.py,sha256=Yxc4Ve2aBtrkoelfMTFmzcXZefVZM0p0Z_a9n2IM1gQ,12032
70
71
  pytcl/dynamic_estimation/kalman/h_infinity.py,sha256=rtbYiryJbxzko-CIdNJSHuWXU2wI9T52YGBYq3o92sE,16563
71
- pytcl/dynamic_estimation/kalman/linear.py,sha256=1Zgg9gZya0Vxs9im7sPUqLj0Luo463vS-RSa6GCReFI,12248
72
+ pytcl/dynamic_estimation/kalman/linear.py,sha256=gLFoCHjWtNHus_Nh4fTu67n_Xiv9QFVAuO5vO8MJICo,14673
72
73
  pytcl/dynamic_estimation/kalman/matrix_utils.py,sha256=couRVm0VKbhj9ctHcI-wcq8rj2MOapaSRVGuVdze3fQ,12426
73
74
  pytcl/dynamic_estimation/kalman/square_root.py,sha256=RlDepNt7eJ1qbQkZElqfhcX2oJET09P9Q_P8Bv7LcJo,8199
74
75
  pytcl/dynamic_estimation/kalman/sr_ukf.py,sha256=Vys5uC58HSZSTLc9xfmWCjw_XnZZfD4MpFBXBX0OVzU,8912
75
76
  pytcl/dynamic_estimation/kalman/types.py,sha256=5sMEWAvd9kkE3EG9daYcG8uV70MBx_awC5u6KJkmiZw,2202
76
77
  pytcl/dynamic_estimation/kalman/ud_filter.py,sha256=j56gw-piKJaMtoHWRkr2MiBjOC9tGSguIgFregOMJOs,10269
77
- pytcl/dynamic_estimation/kalman/unscented.py,sha256=G3Ks6fa_Z-MxUdOEiiHqQ1wYJzOgfuipiP32at6Mv8o,15505
78
+ pytcl/dynamic_estimation/kalman/unscented.py,sha256=I88b2XVAoiKlOnmNrI4vc3hAbHMc_sILmqXu2t4JktQ,17777
78
79
  pytcl/dynamic_estimation/measurement_update/__init__.py,sha256=8rlyJwVpxf0fZj-AFo1hlewvryZRhUzcy3F8uMe6I8c,48
79
80
  pytcl/dynamic_estimation/particle_filters/__init__.py,sha256=-DRF5rVF2749suLlArmkTvVkqeMcV_mIx0eLeTj6wNU,906
80
- pytcl/dynamic_estimation/particle_filters/bootstrap.py,sha256=6KSLZROxfrldExpDL1GaGhd75IXO5KA8iC-kmhuUBkg,13531
81
+ pytcl/dynamic_estimation/particle_filters/bootstrap.py,sha256=MZlBTO7lYQprireUS52O1dxtL4srrPylFT3BoIU8Jrw,18187
81
82
  pytcl/dynamic_models/__init__.py,sha256=Cd8MyyYuB8gMnepkPA-HSwTaKFPThnqoKOhdjVOsXWg,2783
82
83
  pytcl/dynamic_models/continuous_time/__init__.py,sha256=dAkfEddLkfMvDalK9v2GRBvaZV1KgqYpFBLOnoiFClw,1023
83
- pytcl/dynamic_models/continuous_time/dynamics.py,sha256=CDwqn-66eUwXA5xfIjaG6A4EDBqtOyQ3aWarJr9QH4g,12858
84
+ pytcl/dynamic_models/continuous_time/dynamics.py,sha256=X4mmskbj_ngDTWC3eiBuSauqMDFUBXGsNNlB6Q5AuKQ,15718
84
85
  pytcl/dynamic_models/discrete_time/__init__.py,sha256=1cdYeVIe-kgogiHzeCv1eYMctSimh8t1nIE6Z1N4im4,949
85
- pytcl/dynamic_models/discrete_time/coordinated_turn.py,sha256=jrSGCKiAdXaFIJBLzRyAv0xxxpOHOBnAtDHyu7VYsm8,7206
86
+ pytcl/dynamic_models/discrete_time/coordinated_turn.py,sha256=h83OUxUeYHdoS2tXcOYtaUe_9tAIe3z1fCJ7-z6yPCw,7322
86
87
  pytcl/dynamic_models/discrete_time/polynomial.py,sha256=zv5V-AbuaXlIj36n-YkOEyC74jV2vczxpCW09P0kmi0,5529
87
- pytcl/dynamic_models/discrete_time/singer.py,sha256=wZS3Nad-YyPZp8Mle8Sf5GgW0-t4TxMRcnbc42HtQnA,3861
88
+ pytcl/dynamic_models/discrete_time/singer.py,sha256=o0nR1MJjVi6Qjd5oLsy4vFUgfMKjG3UbE_FIi2qxl8s,4051
88
89
  pytcl/dynamic_models/process_noise/__init__.py,sha256=ZRYgV40qmBkPwU3yTbIMvxorr4nVz0_FEP2oCeVjXoM,933
89
- pytcl/dynamic_models/process_noise/coordinated_turn.py,sha256=w7bHUImLPL5m3KYenfNgAnHPCRtAyYESbsFc6lQKXRg,4768
90
- pytcl/dynamic_models/process_noise/polynomial.py,sha256=natfpsdN3qM9VzPeXF_nBpsbRI74S1WkkRCaaem6EQo,7620
91
- pytcl/dynamic_models/process_noise/singer.py,sha256=lsJDT6xOvcS_qQKFtgHX0L7Ukpy4D7HgvPT8Q3I0ibU,3901
90
+ pytcl/dynamic_models/process_noise/coordinated_turn.py,sha256=0PciDXtXHjgQdaYf7qpQqIZ7qoMV4uO_kE7wjpiBe64,6483
91
+ pytcl/dynamic_models/process_noise/polynomial.py,sha256=w5ZW5Ouw6QpVtev_mnuCmZoj6_O6ovb2L_ENKDhHYIc,7742
92
+ pytcl/dynamic_models/process_noise/singer.py,sha256=ozAdzH4s0wGlBaxajdyZvSnK8_CumgsUZDKeMW-TxDs,5735
93
+ pytcl/gpu/__init__.py,sha256=B3t8UrMg7_1k79eeJMJqPLlb4dG8xHfttsaIDqCDk2g,4268
94
+ pytcl/gpu/ekf.py,sha256=Lern6c0lP9LdfL4vHM1PWvXLHl1tniNZPXq7Mw81R5A,12138
95
+ pytcl/gpu/kalman.py,sha256=8swMqLsnXjdl9-0vOg6wEqxtVHQRHcV4bXjHL8RwUmk,16417
96
+ pytcl/gpu/matrix_utils.py,sha256=FKlcZKEbWSPHUgRjsFpcvN2LgcXZncMIWmOo8GAXp2Q,12394
97
+ pytcl/gpu/particle_filter.py,sha256=uBK9ItCgGRfZ7WtWQIky-t3pl1oM1Fi1hZ6fmHTr4kc,16957
98
+ pytcl/gpu/ukf.py,sha256=NzSWOKBBpyNFKiTwj9fpDIWmO9-1-vpmFXLdkXrxM1E,13070
99
+ pytcl/gpu/utils.py,sha256=HAwC2cYh2UFr5hJBeabvdK3AxhJJNN9I2MFJel2FIjU,14790
92
100
  pytcl/gravity/__init__.py,sha256=5xNdQSrrkt7-1-JPOYqR38CqvNJ7qKlPyMK36DGm6-I,3693
93
- pytcl/gravity/clenshaw.py,sha256=1BdxzU8IfGGd68H_U35soIJkiOHphY35e9mLElhPTOg,15364
94
- pytcl/gravity/egm.py,sha256=47I8nyXNhXUKPkufXahs4JGsBcqhM-9z2xGz0X4JPmU,18422
95
- pytcl/gravity/models.py,sha256=rdY3Do4M1eRFO74gu3xy-bBn7tox3zM49wYbfnsIQWw,11159
96
- pytcl/gravity/spherical_harmonics.py,sha256=FV_cFp0lx6uGw-dxNFRpehaAn28QImX9z7PFdyRbEJI,16549
97
- pytcl/gravity/tides.py,sha256=nu9_L12aBd2EpmTMh3UulmYCUxQ9wC4kOpdSIn7f0Z8,27785
101
+ pytcl/gravity/clenshaw.py,sha256=O7yYfjHMigR1RQHR_gZe3UuMIe_WsGrXFSLzn7PLfIE,16985
102
+ pytcl/gravity/egm.py,sha256=LAeNbaQ7eZakk0ciwLec0_8q41MrBFouVLpDsETis6o,19683
103
+ pytcl/gravity/models.py,sha256=WqBwaOhQdGMx7MsYGYYNbwQLj8rgV-I_VhKZLFvmfso,11990
104
+ pytcl/gravity/spherical_harmonics.py,sha256=bRUFVLgPQEJ8M5a_cJrJ-d5s5xTCmOs4fwRvdYaACuw,18522
105
+ pytcl/gravity/tides.py,sha256=NjsiXSiI7f-0qGr7G7YJVpIOVGzDxagz2S2vf_aRq68,28681
98
106
  pytcl/magnetism/__init__.py,sha256=pBASOzCPHNnYqUH_XDEblhGtjz50vY9uW2KS25A0zQQ,2701
99
107
  pytcl/magnetism/emm.py,sha256=iIdxSL0uGGIf8nfA-c_SmHvg9_J7HwRA2-qbQIUW6IE,22380
100
108
  pytcl/magnetism/igrf.py,sha256=3g0PsH8IdbwQQS28OR5XWD-g-QxvfUva7jOkKToxndQ,13384
@@ -111,21 +119,21 @@ pytcl/mathematical_functions/geometry/geometry.py,sha256=iLKqTlLEGm8IScEDHEWOBQz
111
119
  pytcl/mathematical_functions/interpolation/__init__.py,sha256=lK4Rs0Ds_fzf9q0n6id5epdN0U8V7yD87dS-w1hvN8I,741
112
120
  pytcl/mathematical_functions/interpolation/interpolation.py,sha256=2cXMDgWBjWDGHnK1K_lawFlJL8oPl5AQGf9MNgsESfo,12610
113
121
  pytcl/mathematical_functions/numerical_integration/__init__.py,sha256=iXiHzyV_KIhCv7tXErXlN1_fUEACN6yN3CYDHRA7esw,974
114
- pytcl/mathematical_functions/numerical_integration/quadrature.py,sha256=3MwNCjdMfopgtJjXWxn-q9VyawI1IArkNBXqa_kRMj4,15716
122
+ pytcl/mathematical_functions/numerical_integration/quadrature.py,sha256=F5y8UQltTiAyIj_lGuuRYnSf465Rm_DNHMeq-E8bj-8,17732
115
123
  pytcl/mathematical_functions/polynomials/__init__.py,sha256=WJWZcoQhnvy5f59-kncMTgD9mCtgwfDgULvDYYHS5ys,43
116
124
  pytcl/mathematical_functions/signal_processing/__init__.py,sha256=_SzzBVtxmSvP8FKeogRdNmFo8FOVDDoexVOqd-lE7do,2325
117
125
  pytcl/mathematical_functions/signal_processing/detection.py,sha256=vLToMHdPkhom6ouo1oN0QqBYjEGv7SQENqTD0DOv1XY,30934
118
126
  pytcl/mathematical_functions/signal_processing/filters.py,sha256=xiB8VSFqTFkBCAom0yIWw7pK3Zjm6l-VZ_DAtwJMxFA,23676
119
127
  pytcl/mathematical_functions/signal_processing/matched_filter.py,sha256=El7XcUbunmXA7s-btXX_R4fgNx8d6QNa86GJETg4zAQ,23134
120
128
  pytcl/mathematical_functions/special_functions/__init__.py,sha256=AJBCKj32daQxdahUQckW0bWowzOoapxni2eZnVXERdg,3859
121
- pytcl/mathematical_functions/special_functions/bessel.py,sha256=Xe62y2vrDwdJy3fR4U8_e8TAgisXIWJ94J7wu_xk0kI,14603
129
+ pytcl/mathematical_functions/special_functions/bessel.py,sha256=kRRPafQMXmooBglEteccjb6Hct1LLq3Oze4JfLQ-AmY,15459
122
130
  pytcl/mathematical_functions/special_functions/debye.py,sha256=eH7Y5qq5j-AMKKx7y8uMS_l_pb6z9_3SG6Igvnc1Fdg,9626
123
- pytcl/mathematical_functions/special_functions/elliptic.py,sha256=WyzBkrfZufIR5dUmCKGcxp6KNpVDrU89NGLDyRrZOqQ,7418
124
- pytcl/mathematical_functions/special_functions/error_functions.py,sha256=24-XRcAW-KF6ixEU5V7iB7brD8UVPPQ0b4Zz8gscRdw,6321
125
- pytcl/mathematical_functions/special_functions/gamma_functions.py,sha256=XB7NHVgKzOEVKpUScqvG3L220bvwIRuUnm_ayO7lJRk,10243
131
+ pytcl/mathematical_functions/special_functions/elliptic.py,sha256=mF3hVrErlK376pw-QZDoq_R6y8gnJAZAK5Kmuq8_0n4,8131
132
+ pytcl/mathematical_functions/special_functions/error_functions.py,sha256=6i5HqQfYdcz0UNhLnHpoMCnWzzZypjckSHTC5ISrcHA,6990
133
+ pytcl/mathematical_functions/special_functions/gamma_functions.py,sha256=riTiy1cqYFtJrzscw0vgTkCaPBCPDGN8Ge6qWAD1zBg,11086
126
134
  pytcl/mathematical_functions/special_functions/hypergeometric.py,sha256=mCBf5NPl0mOkwvIwAUp-sbXshin5HyGsdqEeGbYt3wQ,11428
127
- pytcl/mathematical_functions/special_functions/lambert_w.py,sha256=ivRc4KH5Lwoxb_yijrJEwG0ITa0hhcYF7_gCfVBBNW4,6855
128
- pytcl/mathematical_functions/special_functions/marcum_q.py,sha256=OZ5QjIB1e_XvRG8A-3dbZ13YXHtdk2EYVEPaqtgVr14,9580
135
+ pytcl/mathematical_functions/special_functions/lambert_w.py,sha256=flLSf_7IY5sRXzd2aGgyXfJTRCjekgtvguBV3MhB9GE,6943
136
+ pytcl/mathematical_functions/special_functions/marcum_q.py,sha256=ASQ2vVfhmx4iEvtZTyiQ60-Hy8Qxl_4XgJzYufayJaQ,9910
129
137
  pytcl/mathematical_functions/statistics/__init__.py,sha256=dfypStgmnFmOrnWcm-3CEvLinONHraFgx9O66_37bqw,1278
130
138
  pytcl/mathematical_functions/statistics/distributions.py,sha256=icfFIIKCEFzkpFHuYGWL197nm8wvS7UPJlr9kd_uEgw,19373
131
139
  pytcl/mathematical_functions/statistics/estimators.py,sha256=TLnYXSwk5MzBakZrzDBupbOB3ONmJI7q1-oB2xuSVQM,10831
@@ -135,14 +143,14 @@ pytcl/mathematical_functions/transforms/stft.py,sha256=olDzNH02Nta5GoeEdsdX1tTVK
135
143
  pytcl/mathematical_functions/transforms/wavelets.py,sha256=lR71JX5vX_OXl1g9H89OGiimM_oqfU-WfGYJF3uD2z8,21887
136
144
  pytcl/misc/__init__.py,sha256=SCHf_lQVfdl2gwUluHBiIloTF8HRH8EkgYfbNr7zOug,33
137
145
  pytcl/navigation/__init__.py,sha256=k1_x_FnnPrIzGeNu7zejPtPubIhweBgCfwqlZJEMw0I,6042
138
- pytcl/navigation/geodesy.py,sha256=zrpFhPFLr3N1byeE1pxXh-SmPixjuuoGK3_izEnAAdw,19719
139
- pytcl/navigation/great_circle.py,sha256=u8iqMV6RNsAyzATzjJU11QFGA2pGEaiFJRakQwxTTs0,23326
146
+ pytcl/navigation/geodesy.py,sha256=NH4Txv_VtUdBk6LkQqnSnPfRnG4WnoGF7zGwB-mIbJA,23140
147
+ pytcl/navigation/great_circle.py,sha256=K7CLS8k1P4uN9jpq4Nzc6jk_bSmo-ppb3vyUJbwYjVg,25503
140
148
  pytcl/navigation/ins.py,sha256=OIi8_RjrgEYl0MFpJEFMjIlpgX8DYGTEhdLEvqG-ABU,31151
141
149
  pytcl/navigation/ins_gnss.py,sha256=euKF5JGgwmVBsw3jBf7_wa2z1BpZeVbSNmBuwzhGS6c,30157
142
- pytcl/navigation/rhumb.py,sha256=lr1c3iEXfoOSfIyyXSRWv6He5TlaxEHbJy-dhqM1gRw,18224
150
+ pytcl/navigation/rhumb.py,sha256=lEr3LJqowT-WsdSA4E-V7BFmaqxoI7OpJa05pl_-uGg,20562
143
151
  pytcl/performance_evaluation/__init__.py,sha256=tM2pnBfDb2XbnLt4Y5MQ6w6XBwFy_5bf_y0toZmxx88,1859
144
- pytcl/performance_evaluation/estimation_metrics.py,sha256=X1ZCpp8m6DV14N2wbMvlRwfORRKga8DgKmG3dROyJqA,12351
145
- pytcl/performance_evaluation/track_metrics.py,sha256=Nd3royJkAelZV-Qggl8i72e7WocCxWomgliArvVAEkc,13342
152
+ pytcl/performance_evaluation/estimation_metrics.py,sha256=5dNzgMYTWt0bdGfIWgmc8diWA5SgivLvaSt_OahUhfk,14593
153
+ pytcl/performance_evaluation/track_metrics.py,sha256=4AJyU8mqczKnuOTi3eD8WqC56Xp2xxE-pwupM5WwBsE,14396
146
154
  pytcl/physical_values/__init__.py,sha256=SGbg6b0d4dWebE3baW4OlJshL00grG5E4wABw6jxl20,44
147
155
  pytcl/plotting/__init__.py,sha256=YtYnKYHL5lN6EaT_bwwR3h89NW0HSMToIWHhHBxcidY,3126
148
156
  pytcl/plotting/coordinates.py,sha256=kk1UO5aRPCUt206QS4COgtaExZI1Mjhi4P6falQCQLI,17247
@@ -152,20 +160,20 @@ pytcl/plotting/tracks.py,sha256=RoQyjpMcPm16mQqj4RvDOzPgD6UpHCOid6hxAN3kGC0,2317
152
160
  pytcl/scheduling/__init__.py,sha256=jTqMSKcsCrWU_Fh6WaT6BW5WatNHyyEYjFbsv6X18Oc,39
153
161
  pytcl/static_estimation/__init__.py,sha256=sSEhqq35jq_MpRLnBtWjKXwGZ9dqIw71iwji-TNwXmc,2222
154
162
  pytcl/static_estimation/least_squares.py,sha256=8ouOyRGC7K-W8fynZMWlc2-KAFojvTbuzcqi5uS_sVA,13432
155
- pytcl/static_estimation/maximum_likelihood.py,sha256=nt1WShfZ0PlT_eA4gu2WcLiz9zZO9r90m_1PhWqDDgY,21821
156
- pytcl/static_estimation/robust.py,sha256=mpDUcc3-8F42SVGxXMv20huzekoGWattAa4px9tAZNM,18623
163
+ pytcl/static_estimation/maximum_likelihood.py,sha256=82tjFEEecNmTLrOrFKldEpkDrn4xC980qHZTZoOy3UY,23393
164
+ pytcl/static_estimation/robust.py,sha256=E9mmXcL1PycmyWvUnmLUbpErNvIbpu_XNAMGECmcMmU,20091
157
165
  pytcl/terrain/__init__.py,sha256=e7plNQI5Y_jpZ24r82AgqdX0ChmmyYoeT7HReclnGXc,3228
158
- pytcl/terrain/dem.py,sha256=rg2o0h0ZDrfxvtYhnE2A5tdzRnCmqcihu4w1uNJdH3Y,20814
166
+ pytcl/terrain/dem.py,sha256=3r1qV_FXaQDqEfUYJYSMrNNefd9hXRk8OGFkk3A3k9k,22881
159
167
  pytcl/terrain/loaders.py,sha256=3BbeFTaZ0I5bOlRFUcnP2eGQn-JyR2QDaUbIorDWdsg,27220
160
- pytcl/terrain/visibility.py,sha256=nIJr9AVk7C8GCpJV4UDvUjhmAieycWD8BLepAMUBMIQ,22739
168
+ pytcl/terrain/visibility.py,sha256=03pGWQGE4LY-DQFdqxPTHS-ZCYS9rJQNyAFnuQKe-3I,24992
161
169
  pytcl/trackers/__init__.py,sha256=Gw79xlSIUzdPV8bN1slNWUlGxE3d-NsVmbMygkYVV20,1151
162
- pytcl/trackers/hypothesis.py,sha256=ubK-q89cYayahSHIw5sVYD1fpRUEB0XvC6rQnI1WACA,17361
170
+ pytcl/trackers/hypothesis.py,sha256=cmcLWdSTbAoapl0EhsYcYBos7RXLzgHBfFVUUUh3Hmo,20210
163
171
  pytcl/trackers/mht.py,sha256=osEOXMaCeTt1eVn_E08dLRhEvBroVmf8b81zO5Zp1lU,20720
164
172
  pytcl/trackers/multi_target.py,sha256=RDITa0xnbgtVYAMj5XXp4lljo5lZ2zAAc02KZlOjxbQ,10526
165
173
  pytcl/trackers/single_target.py,sha256=Yy3FwaNTArMWcaod-0HVeiioNV4xLWxNDn_7ZPVqQYs,6562
166
174
  pytcl/transponders/__init__.py,sha256=5fL4u3lKCYgPLo5uFeuZbtRZkJPABntuKYGUvVgMMEI,41
167
- nrl_tracker-1.9.1.dist-info/LICENSE,sha256=rB5G4WppIIUzMOYr2N6uyYlNJ00hRJqE5tie6BMvYuE,1612
168
- nrl_tracker-1.9.1.dist-info/METADATA,sha256=DESL1GY4i_xV4n_gc4OdBfSMeCiNoh32058vSgQFu2M,12452
169
- nrl_tracker-1.9.1.dist-info/WHEEL,sha256=pL8R0wFFS65tNSRnaOVrsw9EOkOqxLrlUPenUYnJKNo,91
170
- nrl_tracker-1.9.1.dist-info/top_level.txt,sha256=17megxcrTPBWwPZTh6jTkwTKxX7No-ZqRpyvElnnO-s,6
171
- nrl_tracker-1.9.1.dist-info/RECORD,,
175
+ nrl_tracker-1.10.0.dist-info/LICENSE,sha256=rB5G4WppIIUzMOYr2N6uyYlNJ00hRJqE5tie6BMvYuE,1612
176
+ nrl_tracker-1.10.0.dist-info/METADATA,sha256=WUCa_SI-MIoBVkEmPW-VCR8B25wWtet0OSKMQpBMTAc,14038
177
+ nrl_tracker-1.10.0.dist-info/WHEEL,sha256=pL8R0wFFS65tNSRnaOVrsw9EOkOqxLrlUPenUYnJKNo,91
178
+ nrl_tracker-1.10.0.dist-info/top_level.txt,sha256=17megxcrTPBWwPZTh6jTkwTKxX7No-ZqRpyvElnnO-s,6
179
+ nrl_tracker-1.10.0.dist-info/RECORD,,
pytcl/__init__.py CHANGED
@@ -6,7 +6,7 @@ systems, dynamic models, estimation algorithms, and mathematical functions.
6
6
 
7
7
  This is a Python port of the U.S. Naval Research Laboratory's Tracker Component
8
8
  Library originally written in MATLAB.
9
- **Current Version:** 1.9.1 (January 4, 2026)
9
+ **Current Version:** 1.10.0 (January 4, 2026)
10
10
  **Status:** Production-ready, 2,133 tests passing, 76% line coverage
11
11
  Examples
12
12
  --------
@@ -21,7 +21,7 @@ References
21
21
  no. 5, pp. 18-27, May 2017.
22
22
  """
23
23
 
24
- __version__ = "1.9.1"
24
+ __version__ = "1.10.0"
25
25
  __author__ = "Python Port Contributors"
26
26
  __original_author__ = "David F. Crouse, Naval Research Laboratory"
27
27
 
@@ -322,6 +322,24 @@ def compute_gate_volume(
322
322
  V = c_m * sqrt(det(S)) * gamma^(m/2)
323
323
 
324
324
  where c_m is the volume of the unit hypersphere in m dimensions.
325
+
326
+ Examples
327
+ --------
328
+ Compute gate volume for a 2D measurement with 99% gate probability:
329
+
330
+ >>> import numpy as np
331
+ >>> from scipy.stats import chi2
332
+ >>> S = np.array([[4.0, 0.0], [0.0, 1.0]]) # innovation covariance
333
+ >>> gate_prob = 0.99
334
+ >>> threshold = chi2.ppf(gate_prob, df=2)
335
+ >>> volume = compute_gate_volume(S, threshold)
336
+ >>> volume > 0
337
+ True
338
+
339
+ See Also
340
+ --------
341
+ ellipsoidal_gate : Test if measurement passes gate.
342
+ mahalanobis_distance : Compute distance used in gating.
325
343
  """
326
344
  S = np.asarray(innovation_covariance, dtype=np.float64)
327
345
  m = S.shape[0]
@@ -136,6 +136,22 @@ def compute_likelihood_matrix(
136
136
  Likelihood values, shape (n_tracks, n_meas).
137
137
  gated : ndarray[Any]
138
138
  Boolean gating matrix, shape (n_tracks, n_meas).
139
+
140
+ Examples
141
+ --------
142
+ >>> import numpy as np
143
+ >>> # Two tracks, two measurements
144
+ >>> states = [np.array([0.0, 1.0]), np.array([5.0, 0.0])]
145
+ >>> covs = [np.eye(2) * 0.5, np.eye(2) * 0.5]
146
+ >>> measurements = np.array([[0.1], [5.2]])
147
+ >>> H = np.array([[1, 0]])
148
+ >>> R = np.array([[0.1]])
149
+ >>> L, gated = compute_likelihood_matrix(states, covs, measurements, H, R)
150
+ >>> L.shape
151
+ (2, 2)
152
+ >>> # Track 0 should have high likelihood for measurement 0
153
+ >>> L[0, 0] > L[0, 1]
154
+ True
139
155
  """
140
156
  n_tracks = len(track_states)
141
157
  n_meas = len(measurements)
@@ -191,6 +207,23 @@ def jpda_probabilities(
191
207
  Association probability matrix, shape (n_tracks, n_meas + 1).
192
208
  beta[i, j] = P(measurement j is from track i) for j < n_meas.
193
209
  beta[i, n_meas] = P(track i has no measurement).
210
+
211
+ Examples
212
+ --------
213
+ >>> import numpy as np
214
+ >>> # Likelihood matrix: 2 tracks, 2 measurements
215
+ >>> # Track 0 has high likelihood for meas 0
216
+ >>> # Track 1 has high likelihood for meas 1
217
+ >>> likelihood = np.array([[0.9, 0.1],
218
+ ... [0.1, 0.8]])
219
+ >>> gated = np.array([[True, True],
220
+ ... [True, True]])
221
+ >>> beta = jpda_probabilities(likelihood, gated, detection_prob=0.9)
222
+ >>> beta.shape # 2 tracks, 3 columns (2 meas + 1 miss)
223
+ (2, 3)
224
+ >>> # Track 0 most likely associated with measurement 0
225
+ >>> np.argmax(beta[0, :2])
226
+ 0
194
227
  """
195
228
  n_tracks, n_meas = likelihood_matrix.shape
196
229
 
@@ -591,6 +624,29 @@ def jpda(
591
624
  -------
592
625
  result : JPDAResult
593
626
  Association probabilities and related information.
627
+
628
+ Examples
629
+ --------
630
+ Compute association probabilities for 2 tracks and 3 measurements:
631
+
632
+ >>> import numpy as np
633
+ >>> # Two tracks with [x, vx] state
634
+ >>> states = [np.array([0.0, 1.0]), np.array([10.0, -0.5])]
635
+ >>> covariances = [np.eye(2) * 0.5, np.eye(2) * 0.5]
636
+ >>> # Three position measurements
637
+ >>> measurements = np.array([[0.1], [9.8], [5.0]])
638
+ >>> H = np.array([[1, 0]]) # measure position only
639
+ >>> R = np.array([[0.1]])
640
+ >>> result = jpda(states, covariances, measurements, H, R)
641
+ >>> result.association_probs.shape # (2 tracks, 4 columns: 3 meas + miss)
642
+ (2, 4)
643
+ >>> # Track 0 should have high prob for measurement 0
644
+ >>> result.association_probs[0, 0] > 0.5
645
+ True
646
+
647
+ See Also
648
+ --------
649
+ jpda_update : JPDA with state update.
594
650
  """
595
651
  # Convert inputs
596
652
  track_states = [np.asarray(x, dtype=np.float64).flatten() for x in track_states]
@@ -67,6 +67,20 @@ def validate_cost_tensor(cost_tensor: NDArray[np.float64]) -> Tuple[int, ...]:
67
67
  ------
68
68
  ValueError
69
69
  If tensor has fewer than 2 dimensions.
70
+
71
+ Examples
72
+ --------
73
+ >>> import numpy as np
74
+ >>> cost = np.random.rand(3, 4, 5)
75
+ >>> dims = validate_cost_tensor(cost)
76
+ >>> dims
77
+ (3, 4, 5)
78
+ >>> # 1D tensor should raise error
79
+ >>> try:
80
+ ... validate_cost_tensor(np.array([1, 2, 3]))
81
+ ... except ValueError:
82
+ ... print("Caught expected error")
83
+ Caught expected error
70
84
  """
71
85
  if cost_tensor.ndim < 2:
72
86
  raise ValueError(
@@ -98,6 +112,21 @@ def greedy_assignment_nd(
98
112
  AssignmentNDResult
99
113
  Assignments, total cost, and algorithm info.
100
114
 
115
+ Examples
116
+ --------
117
+ >>> import numpy as np
118
+ >>> # 3D cost tensor: 3 measurements x 2 tracks x 2 hypotheses
119
+ >>> cost = np.array([
120
+ ... [[1.0, 5.0], [3.0, 2.0]], # meas 0
121
+ ... [[4.0, 1.0], [2.0, 6.0]], # meas 1
122
+ ... [[2.0, 3.0], [5.0, 1.0]], # meas 2
123
+ ... ])
124
+ >>> result = greedy_assignment_nd(cost)
125
+ >>> result.cost # Total cost of greedy solution
126
+ 4.0
127
+ >>> len(result.assignments) # Number of assignments made
128
+ 2
129
+
101
130
  Notes
102
131
  -----
103
132
  Greedy assignment is fast O(n log n) but not optimal. Used as
@@ -178,6 +207,18 @@ def relaxation_assignment_nd(
178
207
  AssignmentNDResult
179
208
  Assignments, total cost, convergence info, and optimality gap.
180
209
 
210
+ Examples
211
+ --------
212
+ >>> import numpy as np
213
+ >>> # 3x3x3 assignment problem
214
+ >>> np.random.seed(42)
215
+ >>> cost = np.random.rand(3, 3, 3)
216
+ >>> result = relaxation_assignment_nd(cost, max_iterations=50)
217
+ >>> result.converged
218
+ True
219
+ >>> result.assignments.shape[1] # 3D assignments
220
+ 3
221
+
181
222
  Notes
182
223
  -----
183
224
  The relaxation approach:
@@ -297,6 +338,18 @@ def auction_assignment_nd(
297
338
  AssignmentNDResult
298
339
  Assignments, total cost, convergence info, gap estimate.
299
340
 
341
+ Examples
342
+ --------
343
+ >>> import numpy as np
344
+ >>> # 4D assignment: sensors x measurements x tracks x hypotheses
345
+ >>> np.random.seed(123)
346
+ >>> cost = np.random.rand(2, 3, 3, 2) * 10
347
+ >>> result = auction_assignment_nd(cost, max_iterations=50, epsilon=0.1)
348
+ >>> len(result.assignments) > 0
349
+ True
350
+ >>> result.n_iterations <= 50
351
+ True
352
+
300
353
  Notes
301
354
  -----
302
355
  The algorithm maintains a "price" for each index and allows bidding
@@ -368,6 +421,18 @@ def detect_dimension_conflicts(
368
421
  -------
369
422
  has_conflicts : bool
370
423
  True if any index appears more than once in any dimension.
424
+
425
+ Examples
426
+ --------
427
+ >>> import numpy as np
428
+ >>> # Valid assignment: no index repeated in any dimension
429
+ >>> assignments = np.array([[0, 0], [1, 1]])
430
+ >>> detect_dimension_conflicts(assignments, (3, 3))
431
+ False
432
+ >>> # Invalid: index 0 used twice in first dimension
433
+ >>> assignments = np.array([[0, 0], [0, 1]])
434
+ >>> detect_dimension_conflicts(assignments, (3, 3))
435
+ True
371
436
  """
372
437
  n_dims = len(dims)
373
438
 
@@ -104,6 +104,20 @@ def assignment_to_flow_network(
104
104
  Positive = supply, negative = demand.
105
105
  node_names : ndarray
106
106
  Names of nodes for reference.
107
+
108
+ Examples
109
+ --------
110
+ >>> import numpy as np
111
+ >>> # 2 workers, 3 tasks
112
+ >>> cost = np.array([[1.0, 2.0, 3.0],
113
+ ... [4.0, 5.0, 6.0]])
114
+ >>> edges, supplies, names = assignment_to_flow_network(cost)
115
+ >>> len(edges) # source->workers + workers->tasks + tasks->sink
116
+ 11
117
+ >>> supplies[0] # source supplies 2 (num workers)
118
+ 2.0
119
+ >>> names[0]
120
+ 'source'
107
121
  """
108
122
  m, n = cost_matrix.shape
109
123
 
@@ -187,6 +201,20 @@ def min_cost_flow_successive_shortest_paths(
187
201
  MinCostFlowResult
188
202
  Solution with flow values, cost, status, and iterations.
189
203
 
204
+ Examples
205
+ --------
206
+ >>> import numpy as np
207
+ >>> from pytcl.assignment_algorithms.network_flow import (
208
+ ... FlowEdge, assignment_to_flow_network
209
+ ... )
210
+ >>> cost = np.array([[1.0, 5.0], [4.0, 2.0]])
211
+ >>> edges, supplies, _ = assignment_to_flow_network(cost)
212
+ >>> result = min_cost_flow_successive_shortest_paths(edges, supplies)
213
+ >>> result.status == FlowStatus.OPTIMAL
214
+ True
215
+ >>> result.cost # Optimal is 1+2=3 (diagonal)
216
+ 3.0
217
+
190
218
  Notes
191
219
  -----
192
220
  This is a simplified implementation using Bellman-Ford for shortest
@@ -445,6 +473,18 @@ def min_cost_assignment_via_flow(
445
473
  total_cost : float
446
474
  Total assignment cost.
447
475
 
476
+ Examples
477
+ --------
478
+ >>> import numpy as np
479
+ >>> cost = np.array([[1.0, 5.0, 9.0],
480
+ ... [3.0, 2.0, 8.0],
481
+ ... [7.0, 6.0, 4.0]])
482
+ >>> assignment, total_cost = min_cost_assignment_via_flow(cost)
483
+ >>> total_cost # Optimal assignment: (0,0), (1,1), (2,2) = 1+2+4 = 7
484
+ 7.0
485
+ >>> len(assignment)
486
+ 3
487
+
448
488
  Notes
449
489
  -----
450
490
  Phase 1B: Dijkstra-based optimization provides O(K*E log V) vs