nrl-tracker 1.9.0__py3-none-any.whl → 1.9.2__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.0.dist-info → nrl_tracker-1.9.2.dist-info}/METADATA +4 -4
- {nrl_tracker-1.9.0.dist-info → nrl_tracker-1.9.2.dist-info}/RECORD +61 -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 +1 -1
- 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/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.0.dist-info → nrl_tracker-1.9.2.dist-info}/LICENSE +0 -0
- {nrl_tracker-1.9.0.dist-info → nrl_tracker-1.9.2.dist-info}/WHEEL +0 -0
- {nrl_tracker-1.9.0.dist-info → nrl_tracker-1.9.2.dist-info}/top_level.txt +0 -0
pytcl/terrain/visibility.py
CHANGED
|
@@ -160,6 +160,20 @@ def line_of_sight(
|
|
|
160
160
|
The refraction coefficient models atmospheric bending of radio waves.
|
|
161
161
|
A typical value for radio frequencies is 0.13 (4/3 Earth model).
|
|
162
162
|
For optical line of sight, use 0.
|
|
163
|
+
|
|
164
|
+
Examples
|
|
165
|
+
--------
|
|
166
|
+
>>> import numpy as np
|
|
167
|
+
>>> from pytcl.terrain.dem import create_flat_dem
|
|
168
|
+
>>> dem = create_flat_dem(
|
|
169
|
+
... np.radians(35), np.radians(36),
|
|
170
|
+
... np.radians(-120), np.radians(-119), elevation=100)
|
|
171
|
+
>>> result = line_of_sight(
|
|
172
|
+
... dem,
|
|
173
|
+
... np.radians(35.3), np.radians(-119.7), 10,
|
|
174
|
+
... np.radians(35.7), np.radians(-119.3), 10)
|
|
175
|
+
>>> result.visible # Clear LOS over flat terrain
|
|
176
|
+
True
|
|
163
177
|
"""
|
|
164
178
|
# Effective Earth radius for refraction
|
|
165
179
|
if refraction_coeff > 0:
|
|
@@ -296,6 +310,19 @@ def viewshed(
|
|
|
296
310
|
-------
|
|
297
311
|
ViewshedResult
|
|
298
312
|
Viewshed computation result with visibility grid.
|
|
313
|
+
|
|
314
|
+
Examples
|
|
315
|
+
--------
|
|
316
|
+
>>> import numpy as np
|
|
317
|
+
>>> from pytcl.terrain.dem import create_flat_dem
|
|
318
|
+
>>> dem = create_flat_dem(
|
|
319
|
+
... np.radians(35), np.radians(36),
|
|
320
|
+
... np.radians(-120), np.radians(-119), elevation=100)
|
|
321
|
+
>>> result = viewshed(
|
|
322
|
+
... dem, np.radians(35.5), np.radians(-119.5), 20,
|
|
323
|
+
... max_range=10000, n_radials=36, samples_per_radial=10)
|
|
324
|
+
>>> result.visible.any() # Some cells visible
|
|
325
|
+
True
|
|
299
326
|
"""
|
|
300
327
|
# Convert max range to angular distance
|
|
301
328
|
max_angular_range = max_range / earth_radius
|
|
@@ -428,6 +455,19 @@ def compute_horizon(
|
|
|
428
455
|
-------
|
|
429
456
|
list of HorizonPoint
|
|
430
457
|
Horizon points for each azimuth direction.
|
|
458
|
+
|
|
459
|
+
Examples
|
|
460
|
+
--------
|
|
461
|
+
>>> import numpy as np
|
|
462
|
+
>>> from pytcl.terrain.dem import create_flat_dem
|
|
463
|
+
>>> dem = create_flat_dem(
|
|
464
|
+
... np.radians(35), np.radians(36),
|
|
465
|
+
... np.radians(-120), np.radians(-119), elevation=100)
|
|
466
|
+
>>> horizon = compute_horizon(
|
|
467
|
+
... dem, np.radians(35.5), np.radians(-119.5), 10,
|
|
468
|
+
... n_azimuths=8, max_range=10000, samples_per_radial=10)
|
|
469
|
+
>>> len(horizon)
|
|
470
|
+
8
|
|
431
471
|
"""
|
|
432
472
|
max_angular_range = max_range / earth_radius
|
|
433
473
|
|
|
@@ -534,6 +574,18 @@ def terrain_masking_angle(
|
|
|
534
574
|
-------
|
|
535
575
|
float
|
|
536
576
|
Masking angle in radians above horizontal.
|
|
577
|
+
|
|
578
|
+
Examples
|
|
579
|
+
--------
|
|
580
|
+
>>> import numpy as np
|
|
581
|
+
>>> from pytcl.terrain.dem import create_flat_dem
|
|
582
|
+
>>> dem = create_flat_dem(
|
|
583
|
+
... np.radians(35), np.radians(36),
|
|
584
|
+
... np.radians(-120), np.radians(-119), elevation=100)
|
|
585
|
+
>>> angle = terrain_masking_angle(
|
|
586
|
+
... dem, np.radians(35.5), np.radians(-119.5), 10, azimuth=0)
|
|
587
|
+
>>> -np.pi/2 <= angle <= np.pi/2 # Valid angle range
|
|
588
|
+
True
|
|
537
589
|
"""
|
|
538
590
|
max_angular_range = max_range / earth_radius
|
|
539
591
|
|
|
@@ -628,6 +680,19 @@ def radar_coverage_map(
|
|
|
628
680
|
-------
|
|
629
681
|
ViewshedResult
|
|
630
682
|
Radar coverage map.
|
|
683
|
+
|
|
684
|
+
Examples
|
|
685
|
+
--------
|
|
686
|
+
>>> import numpy as np
|
|
687
|
+
>>> from pytcl.terrain.dem import create_flat_dem
|
|
688
|
+
>>> dem = create_flat_dem(
|
|
689
|
+
... np.radians(35), np.radians(36),
|
|
690
|
+
... np.radians(-120), np.radians(-119), elevation=100)
|
|
691
|
+
>>> coverage = radar_coverage_map(
|
|
692
|
+
... dem, np.radians(35.5), np.radians(-119.5), 30,
|
|
693
|
+
... max_range=20000, n_radials=36, samples_per_radial=20)
|
|
694
|
+
>>> coverage.visible.any() # Some coverage exists
|
|
695
|
+
True
|
|
631
696
|
"""
|
|
632
697
|
# Compute basic viewshed with refraction
|
|
633
698
|
result = viewshed(
|
pytcl/trackers/hypothesis.py
CHANGED
|
@@ -208,6 +208,29 @@ def compute_association_likelihood(
|
|
|
208
208
|
-------
|
|
209
209
|
likelihood : float
|
|
210
210
|
Joint likelihood of the association.
|
|
211
|
+
|
|
212
|
+
Examples
|
|
213
|
+
--------
|
|
214
|
+
>>> import numpy as np
|
|
215
|
+
>>> # 2 tracks, 2 measurements
|
|
216
|
+
>>> likelihood_matrix = np.array([[0.9, 0.1],
|
|
217
|
+
... [0.1, 0.8]])
|
|
218
|
+
>>> # Association: track 0 -> meas 0, track 1 -> meas 1
|
|
219
|
+
>>> association = {0: 0, 1: 1}
|
|
220
|
+
>>> lik = compute_association_likelihood(
|
|
221
|
+
... association, likelihood_matrix,
|
|
222
|
+
... detection_prob=0.9, clutter_density=1e-6, n_meas=2
|
|
223
|
+
... )
|
|
224
|
+
>>> lik > 0
|
|
225
|
+
True
|
|
226
|
+
>>> # Association with missed detection
|
|
227
|
+
>>> assoc_miss = {0: 0, 1: -1} # track 1 misses
|
|
228
|
+
>>> lik_miss = compute_association_likelihood(
|
|
229
|
+
... assoc_miss, likelihood_matrix,
|
|
230
|
+
... detection_prob=0.9, clutter_density=1e-6, n_meas=2
|
|
231
|
+
... )
|
|
232
|
+
>>> lik > lik_miss # Full detection more likely
|
|
233
|
+
True
|
|
211
234
|
"""
|
|
212
235
|
likelihood = 1.0
|
|
213
236
|
|
|
@@ -259,6 +282,31 @@ def n_scan_prune(
|
|
|
259
282
|
committed_track_ids : set
|
|
260
283
|
Track IDs that are now committed (survived N-scan).
|
|
261
284
|
|
|
285
|
+
Examples
|
|
286
|
+
--------
|
|
287
|
+
>>> import numpy as np
|
|
288
|
+
>>> from pytcl.trackers.hypothesis import (
|
|
289
|
+
... Hypothesis, MHTTrack, MHTTrackStatus, n_scan_prune
|
|
290
|
+
... )
|
|
291
|
+
>>> # Two hypotheses, tracks with different creation scans
|
|
292
|
+
>>> track1 = MHTTrack(id=0, state=np.zeros(2), covariance=np.eye(2),
|
|
293
|
+
... score=1.0, status=MHTTrackStatus.CONFIRMED,
|
|
294
|
+
... history=[0], parent_id=-1, scan_created=0,
|
|
295
|
+
... n_hits=3, n_misses=0)
|
|
296
|
+
>>> track2 = MHTTrack(id=1, state=np.zeros(2), covariance=np.eye(2),
|
|
297
|
+
... score=0.5, status=MHTTrackStatus.TENTATIVE,
|
|
298
|
+
... history=[1], parent_id=-1, scan_created=2,
|
|
299
|
+
... n_hits=1, n_misses=0)
|
|
300
|
+
>>> tracks = {0: track1, 1: track2}
|
|
301
|
+
>>> hyp1 = Hypothesis(id=0, probability=0.8, track_ids=[0],
|
|
302
|
+
... scan_created=0, parent_id=-1)
|
|
303
|
+
>>> hyp2 = Hypothesis(id=1, probability=0.2, track_ids=[1],
|
|
304
|
+
... scan_created=2, parent_id=-1)
|
|
305
|
+
>>> pruned, committed = n_scan_prune([hyp1, hyp2], tracks, n_scan=2,
|
|
306
|
+
... current_scan=3)
|
|
307
|
+
>>> len(pruned) >= 1
|
|
308
|
+
True
|
|
309
|
+
|
|
262
310
|
Notes
|
|
263
311
|
-----
|
|
264
312
|
N-scan pruning works by:
|
|
@@ -338,6 +386,23 @@ def prune_hypotheses_by_probability(
|
|
|
338
386
|
-------
|
|
339
387
|
pruned : list of Hypothesis
|
|
340
388
|
Pruned and renormalized hypotheses.
|
|
389
|
+
|
|
390
|
+
Examples
|
|
391
|
+
--------
|
|
392
|
+
>>> from pytcl.trackers.hypothesis import Hypothesis, prune_hypotheses_by_probability
|
|
393
|
+
>>> # 5 hypotheses with varying probabilities
|
|
394
|
+
>>> hyps = [
|
|
395
|
+
... Hypothesis(id=0, probability=0.5, track_ids=[0], scan_created=0, parent_id=-1),
|
|
396
|
+
... Hypothesis(id=1, probability=0.3, track_ids=[1], scan_created=0, parent_id=-1),
|
|
397
|
+
... Hypothesis(id=2, probability=0.1, track_ids=[2], scan_created=0, parent_id=-1),
|
|
398
|
+
... Hypothesis(id=3, probability=0.05, track_ids=[3], scan_created=0, parent_id=-1),
|
|
399
|
+
... Hypothesis(id=4, probability=1e-8, track_ids=[4], scan_created=0, parent_id=-1),
|
|
400
|
+
... ]
|
|
401
|
+
>>> pruned = prune_hypotheses_by_probability(hyps, max_hypotheses=3)
|
|
402
|
+
>>> len(pruned) # Only top 3 kept
|
|
403
|
+
3
|
|
404
|
+
>>> sum(h.probability for h in pruned) # Renormalized to 1
|
|
405
|
+
1.0
|
|
341
406
|
"""
|
|
342
407
|
if not hypotheses:
|
|
343
408
|
return []
|
|
File without changes
|
|
File without changes
|
|
File without changes
|