nrl-tracker 1.9.2__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: nrl-tracker
3
- Version: 1.9.2
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,7 +71,7 @@ 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.2-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)
@@ -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,4 +1,4 @@
1
- pytcl/__init__.py,sha256=7ROietZU-pUiPRpioyeMjjZ6XybbmjRs1qRR_KoXioQ,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
@@ -56,7 +56,7 @@ pytcl/core/array_utils.py,sha256=SsgEiAoRCWxAVKq1aa5-nPdOi-2AB6XNObu0IaGClUk,139
56
56
  pytcl/core/constants.py,sha256=cwkCjzCU7zG2ZsFcbqwslN632v7Lw50L85s-5q892mo,9988
57
57
  pytcl/core/exceptions.py,sha256=6ImMiwL86BdmTt-Rc8fXLXxKUGQ-PcQQyxIvKKzw-n0,24324
58
58
  pytcl/core/maturity.py,sha256=Sut19NfH1-6f3Qd2QSC6OAqvDcVHJDwf5-F_-oEAMJA,11596
59
- pytcl/core/optional_deps.py,sha256=Xe7BG18SWsmzBD3zGa440U_QWKkfATBKhUfLOxhXZuU,15799
59
+ pytcl/core/optional_deps.py,sha256=a3UK_DM2s0XQE4Lwp0agq9L0qjupl_d8o4csCYbi440,16396
60
60
  pytcl/core/validation.py,sha256=4ay21cZVAil8udymwej7QnVQfNyjzi_5A8O1y-d-Lyw,23492
61
61
  pytcl/dynamic_estimation/__init__.py,sha256=zxmkZIXVfHPv5AHYpQV5nwsI0PA3m-Vw7W0gkJE7j98,5191
62
62
  pytcl/dynamic_estimation/gaussian_sum_filter.py,sha256=3Ks5-sGo3IF9p_dsIzk5u2zaXS2ZAkJFAg1mdxo8vj8,15343
@@ -90,6 +90,13 @@ pytcl/dynamic_models/process_noise/__init__.py,sha256=ZRYgV40qmBkPwU3yTbIMvxorr4
90
90
  pytcl/dynamic_models/process_noise/coordinated_turn.py,sha256=0PciDXtXHjgQdaYf7qpQqIZ7qoMV4uO_kE7wjpiBe64,6483
91
91
  pytcl/dynamic_models/process_noise/polynomial.py,sha256=w5ZW5Ouw6QpVtev_mnuCmZoj6_O6ovb2L_ENKDhHYIc,7742
92
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
93
100
  pytcl/gravity/__init__.py,sha256=5xNdQSrrkt7-1-JPOYqR38CqvNJ7qKlPyMK36DGm6-I,3693
94
101
  pytcl/gravity/clenshaw.py,sha256=O7yYfjHMigR1RQHR_gZe3UuMIe_WsGrXFSLzn7PLfIE,16985
95
102
  pytcl/gravity/egm.py,sha256=LAeNbaQ7eZakk0ciwLec0_8q41MrBFouVLpDsETis6o,19683
@@ -165,8 +172,8 @@ pytcl/trackers/mht.py,sha256=osEOXMaCeTt1eVn_E08dLRhEvBroVmf8b81zO5Zp1lU,20720
165
172
  pytcl/trackers/multi_target.py,sha256=RDITa0xnbgtVYAMj5XXp4lljo5lZ2zAAc02KZlOjxbQ,10526
166
173
  pytcl/trackers/single_target.py,sha256=Yy3FwaNTArMWcaod-0HVeiioNV4xLWxNDn_7ZPVqQYs,6562
167
174
  pytcl/transponders/__init__.py,sha256=5fL4u3lKCYgPLo5uFeuZbtRZkJPABntuKYGUvVgMMEI,41
168
- nrl_tracker-1.9.2.dist-info/LICENSE,sha256=rB5G4WppIIUzMOYr2N6uyYlNJ00hRJqE5tie6BMvYuE,1612
169
- nrl_tracker-1.9.2.dist-info/METADATA,sha256=HPSMMmbYsxCQpku97YqiIiaTut7fd0LOxLUBKCoMV-Y,12452
170
- nrl_tracker-1.9.2.dist-info/WHEEL,sha256=pL8R0wFFS65tNSRnaOVrsw9EOkOqxLrlUPenUYnJKNo,91
171
- nrl_tracker-1.9.2.dist-info/top_level.txt,sha256=17megxcrTPBWwPZTh6jTkwTKxX7No-ZqRpyvElnnO-s,6
172
- nrl_tracker-1.9.2.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.2 (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.2"
24
+ __version__ = "1.10.0"
25
25
  __author__ = "Python Port Contributors"
26
26
  __original_author__ = "David F. Crouse, Naval Research Laboratory"
27
27
 
@@ -69,6 +69,10 @@ PACKAGE_EXTRAS: dict[str, tuple[str, str]] = {
69
69
  "pywavelets": ("signal", "pywavelets"),
70
70
  # Terrain data
71
71
  "netCDF4": ("terrain", "netCDF4"),
72
+ # GPU acceleration
73
+ "cupy": ("gpu", "cupy-cuda12x"),
74
+ # Apple Silicon GPU acceleration
75
+ "mlx": ("gpu-apple", "mlx"),
72
76
  }
73
77
 
74
78
  # Friendly names for features provided by each package
@@ -82,6 +86,8 @@ PACKAGE_FEATURES: dict[str, str] = {
82
86
  "pywt": "wavelet transforms",
83
87
  "pywavelets": "wavelet transforms",
84
88
  "netCDF4": "NetCDF file reading",
89
+ "cupy": "GPU acceleration",
90
+ "mlx": "Apple Silicon GPU acceleration",
85
91
  }
86
92
 
87
93
 
@@ -374,6 +380,16 @@ class _AvailabilityFlags:
374
380
  """True if netCDF4 is available."""
375
381
  return is_available("netCDF4")
376
382
 
383
+ @property
384
+ def HAS_CUPY(self) -> bool:
385
+ """True if cupy is available."""
386
+ return is_available("cupy")
387
+
388
+ @property
389
+ def HAS_MLX(self) -> bool:
390
+ """True if mlx is available (Apple Silicon)."""
391
+ return is_available("mlx")
392
+
377
393
 
378
394
  # Create singleton instance
379
395
  _flags = _AvailabilityFlags()
@@ -387,6 +403,8 @@ HAS_ASTROPY = property(lambda self: _flags.HAS_ASTROPY)
387
403
  HAS_PYPROJ = property(lambda self: _flags.HAS_PYPROJ)
388
404
  HAS_CVXPY = property(lambda self: _flags.HAS_CVXPY)
389
405
  HAS_NETCDF4 = property(lambda self: _flags.HAS_NETCDF4)
406
+ HAS_CUPY = property(lambda self: _flags.HAS_CUPY)
407
+ HAS_MLX = property(lambda self: _flags.HAS_MLX)
390
408
 
391
409
 
392
410
  # =============================================================================
@@ -525,6 +543,8 @@ __all__ = [
525
543
  "HAS_PYPROJ",
526
544
  "HAS_CVXPY",
527
545
  "HAS_NETCDF4",
546
+ "HAS_CUPY",
547
+ "HAS_MLX",
528
548
  # Internal (for testing)
529
549
  "_clear_cache",
530
550
  "_flags",
pytcl/gpu/__init__.py ADDED
@@ -0,0 +1,153 @@
1
+ """
2
+ GPU-accelerated algorithms for the Tracker Component Library.
3
+
4
+ This module provides GPU-accelerated implementations of key tracking algorithms
5
+ using CuPy (NVIDIA GPUs) or MLX (Apple Silicon). These implementations offer
6
+ significant speedups (5-15x) for batch processing of multiple tracks or large
7
+ particle sets.
8
+
9
+ The module automatically selects the best available backend:
10
+ - On Apple Silicon (M1/M2/M3): Uses MLX if installed
11
+ - On systems with NVIDIA GPUs: Uses CuPy if installed
12
+ - Falls back to CPU (numpy) if no GPU backend is available
13
+
14
+ The GPU implementations mirror the CPU API but accept GPU arrays and return
15
+ GPU arrays. Use the utility functions to seamlessly transfer data between
16
+ CPU and GPU.
17
+
18
+ Requirements
19
+ ------------
20
+ For NVIDIA GPUs:
21
+ - CUDA-capable GPU
22
+ - CuPy >= 12.0
23
+
24
+ For Apple Silicon:
25
+ - macOS with Apple Silicon (M1, M2, M3, etc.)
26
+ - MLX >= 0.5.0
27
+
28
+ Installation
29
+ ------------
30
+ For NVIDIA CUDA:
31
+ pip install pytcl[gpu]
32
+ # or directly:
33
+ pip install cupy-cuda12x # For CUDA 12.x
34
+
35
+ For Apple Silicon:
36
+ pip install pytcl[gpu-apple]
37
+ # or directly:
38
+ pip install mlx
39
+
40
+ Examples
41
+ --------
42
+ Basic usage with automatic backend selection:
43
+
44
+ >>> from pytcl.gpu import is_gpu_available, get_backend
45
+ >>> if is_gpu_available():
46
+ ... print(f"GPU available, using {get_backend()} backend")
47
+
48
+ Check platform:
49
+
50
+ >>> from pytcl.gpu import is_apple_silicon, is_mlx_available
51
+ >>> if is_apple_silicon():
52
+ ... print("Running on Apple Silicon")
53
+ >>> if is_mlx_available():
54
+ ... print("MLX acceleration available")
55
+
56
+ Batch processing example:
57
+
58
+ >>> from pytcl.gpu import batch_kf_predict, to_gpu, to_cpu
59
+ >>> # Move data to GPU (automatically uses best backend)
60
+ >>> x_gpu = to_gpu(x_batch) # (n_tracks, state_dim)
61
+ >>> P_gpu = to_gpu(P_batch) # (n_tracks, state_dim, state_dim)
62
+ >>> # Batch prediction
63
+ >>> x_pred, P_pred = batch_kf_predict(x_gpu, P_gpu, F, Q)
64
+ >>> # Move results back to CPU
65
+ >>> x_pred_cpu = to_cpu(x_pred)
66
+
67
+ See Also
68
+ --------
69
+ pytcl.dynamic_estimation.kalman : CPU Kalman filter implementations
70
+ pytcl.dynamic_estimation.particle_filters : CPU particle filter implementations
71
+ """
72
+
73
+ from pytcl.gpu.utils import (
74
+ get_array_module,
75
+ get_backend,
76
+ is_apple_silicon,
77
+ is_cupy_available,
78
+ is_gpu_available,
79
+ is_mlx_available,
80
+ to_cpu,
81
+ to_gpu,
82
+ )
83
+
84
+ __all__ = [
85
+ # Platform detection
86
+ "is_apple_silicon",
87
+ "is_mlx_available",
88
+ "is_cupy_available",
89
+ "get_backend",
90
+ # Availability check
91
+ "is_gpu_available",
92
+ # Utility functions
93
+ "get_array_module",
94
+ "to_gpu",
95
+ "to_cpu",
96
+ ]
97
+
98
+
99
+ # Lazy imports for GPU implementations (only loaded if CuPy is available)
100
+ def __getattr__(name: str):
101
+ """Lazy import GPU implementations."""
102
+ if name in ("CuPyKalmanFilter", "batch_kf_predict", "batch_kf_update"):
103
+ from pytcl.gpu.kalman import CuPyKalmanFilter, batch_kf_predict, batch_kf_update
104
+
105
+ globals()[name] = locals()[name]
106
+ return locals()[name]
107
+
108
+ if name in ("CuPyExtendedKalmanFilter", "batch_ekf_predict", "batch_ekf_update"):
109
+ from pytcl.gpu.ekf import (
110
+ CuPyExtendedKalmanFilter,
111
+ batch_ekf_predict,
112
+ batch_ekf_update,
113
+ )
114
+
115
+ globals()[name] = locals()[name]
116
+ return locals()[name]
117
+
118
+ if name in ("CuPyUnscentedKalmanFilter", "batch_ukf_predict", "batch_ukf_update"):
119
+ from pytcl.gpu.ukf import (
120
+ CuPyUnscentedKalmanFilter,
121
+ batch_ukf_predict,
122
+ batch_ukf_update,
123
+ )
124
+
125
+ globals()[name] = locals()[name]
126
+ return locals()[name]
127
+
128
+ if name in (
129
+ "CuPyParticleFilter",
130
+ "gpu_resample_systematic",
131
+ "gpu_resample_multinomial",
132
+ ):
133
+ from pytcl.gpu.particle_filter import (
134
+ CuPyParticleFilter,
135
+ gpu_resample_multinomial,
136
+ gpu_resample_systematic,
137
+ )
138
+
139
+ globals()[name] = locals()[name]
140
+ return locals()[name]
141
+
142
+ if name in ("gpu_cholesky", "gpu_qr", "gpu_solve", "MemoryPool"):
143
+ from pytcl.gpu.matrix_utils import (
144
+ MemoryPool,
145
+ gpu_cholesky,
146
+ gpu_qr,
147
+ gpu_solve,
148
+ )
149
+
150
+ globals()[name] = locals()[name]
151
+ return locals()[name]
152
+
153
+ raise AttributeError(f"module 'pytcl.gpu' has no attribute '{name}'")