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.
- {nrl_tracker-1.9.1.dist-info → nrl_tracker-1.10.0.dist-info}/METADATA +49 -4
- {nrl_tracker-1.9.1.dist-info → nrl_tracker-1.10.0.dist-info}/RECORD +68 -60
- pytcl/__init__.py +2 -2
- pytcl/assignment_algorithms/gating.py +18 -0
- pytcl/assignment_algorithms/jpda.py +56 -0
- pytcl/assignment_algorithms/nd_assignment.py +65 -0
- pytcl/assignment_algorithms/network_flow.py +40 -0
- pytcl/astronomical/ephemerides.py +18 -0
- pytcl/astronomical/orbital_mechanics.py +131 -0
- pytcl/atmosphere/ionosphere.py +44 -0
- pytcl/atmosphere/models.py +29 -0
- pytcl/clustering/dbscan.py +9 -0
- pytcl/clustering/gaussian_mixture.py +20 -0
- pytcl/clustering/hierarchical.py +29 -0
- pytcl/clustering/kmeans.py +9 -0
- pytcl/coordinate_systems/conversions/geodetic.py +46 -0
- pytcl/coordinate_systems/conversions/spherical.py +35 -0
- pytcl/coordinate_systems/rotations/rotations.py +147 -0
- pytcl/core/__init__.py +16 -0
- pytcl/core/maturity.py +346 -0
- pytcl/core/optional_deps.py +20 -0
- pytcl/dynamic_estimation/gaussian_sum_filter.py +55 -0
- pytcl/dynamic_estimation/imm.py +29 -0
- pytcl/dynamic_estimation/information_filter.py +64 -0
- pytcl/dynamic_estimation/kalman/extended.py +56 -0
- pytcl/dynamic_estimation/kalman/linear.py +69 -0
- pytcl/dynamic_estimation/kalman/unscented.py +81 -0
- pytcl/dynamic_estimation/particle_filters/bootstrap.py +146 -0
- pytcl/dynamic_estimation/rbpf.py +51 -0
- pytcl/dynamic_estimation/smoothers.py +58 -0
- pytcl/dynamic_models/continuous_time/dynamics.py +104 -0
- pytcl/dynamic_models/discrete_time/coordinated_turn.py +6 -0
- pytcl/dynamic_models/discrete_time/singer.py +12 -0
- pytcl/dynamic_models/process_noise/coordinated_turn.py +46 -0
- pytcl/dynamic_models/process_noise/polynomial.py +6 -0
- pytcl/dynamic_models/process_noise/singer.py +52 -0
- pytcl/gpu/__init__.py +153 -0
- pytcl/gpu/ekf.py +425 -0
- pytcl/gpu/kalman.py +543 -0
- pytcl/gpu/matrix_utils.py +486 -0
- pytcl/gpu/particle_filter.py +568 -0
- pytcl/gpu/ukf.py +476 -0
- pytcl/gpu/utils.py +582 -0
- pytcl/gravity/clenshaw.py +60 -0
- pytcl/gravity/egm.py +47 -0
- pytcl/gravity/models.py +34 -0
- pytcl/gravity/spherical_harmonics.py +73 -0
- pytcl/gravity/tides.py +34 -0
- pytcl/mathematical_functions/numerical_integration/quadrature.py +85 -0
- pytcl/mathematical_functions/special_functions/bessel.py +55 -0
- pytcl/mathematical_functions/special_functions/elliptic.py +42 -0
- pytcl/mathematical_functions/special_functions/error_functions.py +49 -0
- pytcl/mathematical_functions/special_functions/gamma_functions.py +43 -0
- pytcl/mathematical_functions/special_functions/lambert_w.py +5 -0
- pytcl/mathematical_functions/special_functions/marcum_q.py +16 -0
- pytcl/navigation/geodesy.py +101 -2
- pytcl/navigation/great_circle.py +71 -0
- pytcl/navigation/rhumb.py +74 -0
- pytcl/performance_evaluation/estimation_metrics.py +70 -0
- pytcl/performance_evaluation/track_metrics.py +30 -0
- pytcl/static_estimation/maximum_likelihood.py +54 -0
- pytcl/static_estimation/robust.py +57 -0
- pytcl/terrain/dem.py +69 -0
- pytcl/terrain/visibility.py +65 -0
- pytcl/trackers/hypothesis.py +65 -0
- {nrl_tracker-1.9.1.dist-info → nrl_tracker-1.10.0.dist-info}/LICENSE +0 -0
- {nrl_tracker-1.9.1.dist-info → nrl_tracker-1.10.0.dist-info}/WHEEL +0 -0
- {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.
|
|
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
|
-
[](https://pypi.org/project/nrl-tracker/)
|
|
67
75
|
[](https://www.python.org/downloads/)
|
|
68
76
|
[](https://en.wikipedia.org/wiki/Public_domain)
|
|
69
77
|
[](https://github.com/psf/black)
|
|
70
|
-
[](https://github.com/nedonatelli/TCL)
|
|
71
79
|
[](docs/gap_analysis.rst)
|
|
72
80
|
[](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** | **
|
|
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=
|
|
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=
|
|
7
|
-
pytcl/assignment_algorithms/jpda.py,sha256=
|
|
8
|
-
pytcl/assignment_algorithms/nd_assignment.py,sha256=
|
|
9
|
-
pytcl/assignment_algorithms/network_flow.py,sha256=
|
|
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=
|
|
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=
|
|
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=
|
|
28
|
-
pytcl/atmosphere/models.py,sha256=
|
|
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=
|
|
32
|
-
pytcl/clustering/gaussian_mixture.py,sha256=
|
|
33
|
-
pytcl/clustering/hierarchical.py,sha256=
|
|
34
|
-
pytcl/clustering/kmeans.py,sha256=
|
|
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=
|
|
47
|
-
pytcl/coordinate_systems/conversions/spherical.py,sha256=
|
|
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
|
|
54
|
-
pytcl/core/__init__.py,sha256=
|
|
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/
|
|
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=
|
|
62
|
-
pytcl/dynamic_estimation/imm.py,sha256=
|
|
63
|
-
pytcl/dynamic_estimation/information_filter.py,sha256=
|
|
64
|
-
pytcl/dynamic_estimation/rbpf.py,sha256=
|
|
65
|
-
pytcl/dynamic_estimation/smoothers.py,sha256=
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
90
|
-
pytcl/dynamic_models/process_noise/polynomial.py,sha256=
|
|
91
|
-
pytcl/dynamic_models/process_noise/singer.py,sha256=
|
|
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=
|
|
94
|
-
pytcl/gravity/egm.py,sha256=
|
|
95
|
-
pytcl/gravity/models.py,sha256=
|
|
96
|
-
pytcl/gravity/spherical_harmonics.py,sha256=
|
|
97
|
-
pytcl/gravity/tides.py,sha256=
|
|
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=
|
|
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=
|
|
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=
|
|
124
|
-
pytcl/mathematical_functions/special_functions/error_functions.py,sha256=
|
|
125
|
-
pytcl/mathematical_functions/special_functions/gamma_functions.py,sha256=
|
|
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=
|
|
128
|
-
pytcl/mathematical_functions/special_functions/marcum_q.py,sha256=
|
|
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=
|
|
139
|
-
pytcl/navigation/great_circle.py,sha256=
|
|
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=
|
|
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=
|
|
145
|
-
pytcl/performance_evaluation/track_metrics.py,sha256=
|
|
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=
|
|
156
|
-
pytcl/static_estimation/robust.py,sha256=
|
|
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=
|
|
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=
|
|
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=
|
|
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.
|
|
168
|
-
nrl_tracker-1.
|
|
169
|
-
nrl_tracker-1.
|
|
170
|
-
nrl_tracker-1.
|
|
171
|
-
nrl_tracker-1.
|
|
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
|
+
**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.
|
|
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
|