nrl-tracker 1.9.1__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.
Files changed (60) hide show
  1. {nrl_tracker-1.9.1.dist-info → nrl_tracker-1.9.2.dist-info}/METADATA +4 -4
  2. {nrl_tracker-1.9.1.dist-info → nrl_tracker-1.9.2.dist-info}/RECORD +60 -59
  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/dynamic_estimation/gaussian_sum_filter.py +55 -0
  22. pytcl/dynamic_estimation/imm.py +29 -0
  23. pytcl/dynamic_estimation/information_filter.py +64 -0
  24. pytcl/dynamic_estimation/kalman/extended.py +56 -0
  25. pytcl/dynamic_estimation/kalman/linear.py +69 -0
  26. pytcl/dynamic_estimation/kalman/unscented.py +81 -0
  27. pytcl/dynamic_estimation/particle_filters/bootstrap.py +146 -0
  28. pytcl/dynamic_estimation/rbpf.py +51 -0
  29. pytcl/dynamic_estimation/smoothers.py +58 -0
  30. pytcl/dynamic_models/continuous_time/dynamics.py +104 -0
  31. pytcl/dynamic_models/discrete_time/coordinated_turn.py +6 -0
  32. pytcl/dynamic_models/discrete_time/singer.py +12 -0
  33. pytcl/dynamic_models/process_noise/coordinated_turn.py +46 -0
  34. pytcl/dynamic_models/process_noise/polynomial.py +6 -0
  35. pytcl/dynamic_models/process_noise/singer.py +52 -0
  36. pytcl/gravity/clenshaw.py +60 -0
  37. pytcl/gravity/egm.py +47 -0
  38. pytcl/gravity/models.py +34 -0
  39. pytcl/gravity/spherical_harmonics.py +73 -0
  40. pytcl/gravity/tides.py +34 -0
  41. pytcl/mathematical_functions/numerical_integration/quadrature.py +85 -0
  42. pytcl/mathematical_functions/special_functions/bessel.py +55 -0
  43. pytcl/mathematical_functions/special_functions/elliptic.py +42 -0
  44. pytcl/mathematical_functions/special_functions/error_functions.py +49 -0
  45. pytcl/mathematical_functions/special_functions/gamma_functions.py +43 -0
  46. pytcl/mathematical_functions/special_functions/lambert_w.py +5 -0
  47. pytcl/mathematical_functions/special_functions/marcum_q.py +16 -0
  48. pytcl/navigation/geodesy.py +101 -2
  49. pytcl/navigation/great_circle.py +71 -0
  50. pytcl/navigation/rhumb.py +74 -0
  51. pytcl/performance_evaluation/estimation_metrics.py +70 -0
  52. pytcl/performance_evaluation/track_metrics.py +30 -0
  53. pytcl/static_estimation/maximum_likelihood.py +54 -0
  54. pytcl/static_estimation/robust.py +57 -0
  55. pytcl/terrain/dem.py +69 -0
  56. pytcl/terrain/visibility.py +65 -0
  57. pytcl/trackers/hypothesis.py +65 -0
  58. {nrl_tracker-1.9.1.dist-info → nrl_tracker-1.9.2.dist-info}/LICENSE +0 -0
  59. {nrl_tracker-1.9.1.dist-info → nrl_tracker-1.9.2.dist-info}/WHEEL +0 -0
  60. {nrl_tracker-1.9.1.dist-info → nrl_tracker-1.9.2.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.9.2
4
4
  Summary: Python port of the U.S. Naval Research Laboratory's Tracker Component Library for target tracking algorithms
5
5
  Author: Original: David F. Crouse, Naval Research Laboratory
6
6
  Maintainer: Python Port Contributors
@@ -63,17 +63,17 @@ Requires-Dist: plotly>=5.15.0; extra == "visualization"
63
63
 
64
64
  # Tracker Component Library (Python)
65
65
 
66
- [![PyPI version](https://img.shields.io/badge/pypi-v1.9.0-blue.svg)](https://pypi.org/project/nrl-tracker/)
66
+ [![PyPI version](https://img.shields.io/badge/pypi-v1.9.2-blue.svg)](https://pypi.org/project/nrl-tracker/)
67
67
  [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
68
68
  [![License: Public Domain](https://img.shields.io/badge/License-Public%20Domain-brightgreen.svg)](https://en.wikipedia.org/wiki/Public_domain)
69
69
  [![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)
70
+ [![Tests](https://img.shields.io/badge/tests-2133%20passing-success.svg)](https://github.com/nedonatelli/TCL)
71
71
  [![MATLAB Parity](https://img.shields.io/badge/MATLAB%20Parity-100%25-brightgreen.svg)](docs/gap_analysis.rst)
72
72
  [![Type Checking](https://img.shields.io/badge/mypy--strict-passing-brightgreen.svg)](mypy.ini)
73
73
 
74
74
  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
75
 
76
- **1,070+ functions** | **153 modules** | **1,988 tests** | **100% MATLAB parity**
76
+ **1,070+ functions** | **153 modules** | **2,133 tests** | **100% MATLAB parity**
77
77
 
78
78
  ## Overview
79
79
 
@@ -1,12 +1,12 @@
1
- pytcl/__init__.py,sha256=9dJwbOB9i-NLj_XEO6d0V6mq9jAl7dlgoNPL9NMR78s,2030
1
+ pytcl/__init__.py,sha256=7ROietZU-pUiPRpioyeMjjZ6XybbmjRs1qRR_KoXioQ,2030
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,59 @@ 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/maturity.py,sha256=Sut19NfH1-6f3Qd2QSC6OAqvDcVHJDwf5-F_-oEAMJA,11596
58
59
  pytcl/core/optional_deps.py,sha256=Xe7BG18SWsmzBD3zGa440U_QWKkfATBKhUfLOxhXZuU,15799
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
92
93
  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
94
+ pytcl/gravity/clenshaw.py,sha256=O7yYfjHMigR1RQHR_gZe3UuMIe_WsGrXFSLzn7PLfIE,16985
95
+ pytcl/gravity/egm.py,sha256=LAeNbaQ7eZakk0ciwLec0_8q41MrBFouVLpDsETis6o,19683
96
+ pytcl/gravity/models.py,sha256=WqBwaOhQdGMx7MsYGYYNbwQLj8rgV-I_VhKZLFvmfso,11990
97
+ pytcl/gravity/spherical_harmonics.py,sha256=bRUFVLgPQEJ8M5a_cJrJ-d5s5xTCmOs4fwRvdYaACuw,18522
98
+ pytcl/gravity/tides.py,sha256=NjsiXSiI7f-0qGr7G7YJVpIOVGzDxagz2S2vf_aRq68,28681
98
99
  pytcl/magnetism/__init__.py,sha256=pBASOzCPHNnYqUH_XDEblhGtjz50vY9uW2KS25A0zQQ,2701
99
100
  pytcl/magnetism/emm.py,sha256=iIdxSL0uGGIf8nfA-c_SmHvg9_J7HwRA2-qbQIUW6IE,22380
100
101
  pytcl/magnetism/igrf.py,sha256=3g0PsH8IdbwQQS28OR5XWD-g-QxvfUva7jOkKToxndQ,13384
@@ -111,21 +112,21 @@ pytcl/mathematical_functions/geometry/geometry.py,sha256=iLKqTlLEGm8IScEDHEWOBQz
111
112
  pytcl/mathematical_functions/interpolation/__init__.py,sha256=lK4Rs0Ds_fzf9q0n6id5epdN0U8V7yD87dS-w1hvN8I,741
112
113
  pytcl/mathematical_functions/interpolation/interpolation.py,sha256=2cXMDgWBjWDGHnK1K_lawFlJL8oPl5AQGf9MNgsESfo,12610
113
114
  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
115
+ pytcl/mathematical_functions/numerical_integration/quadrature.py,sha256=F5y8UQltTiAyIj_lGuuRYnSf465Rm_DNHMeq-E8bj-8,17732
115
116
  pytcl/mathematical_functions/polynomials/__init__.py,sha256=WJWZcoQhnvy5f59-kncMTgD9mCtgwfDgULvDYYHS5ys,43
116
117
  pytcl/mathematical_functions/signal_processing/__init__.py,sha256=_SzzBVtxmSvP8FKeogRdNmFo8FOVDDoexVOqd-lE7do,2325
117
118
  pytcl/mathematical_functions/signal_processing/detection.py,sha256=vLToMHdPkhom6ouo1oN0QqBYjEGv7SQENqTD0DOv1XY,30934
118
119
  pytcl/mathematical_functions/signal_processing/filters.py,sha256=xiB8VSFqTFkBCAom0yIWw7pK3Zjm6l-VZ_DAtwJMxFA,23676
119
120
  pytcl/mathematical_functions/signal_processing/matched_filter.py,sha256=El7XcUbunmXA7s-btXX_R4fgNx8d6QNa86GJETg4zAQ,23134
120
121
  pytcl/mathematical_functions/special_functions/__init__.py,sha256=AJBCKj32daQxdahUQckW0bWowzOoapxni2eZnVXERdg,3859
121
- pytcl/mathematical_functions/special_functions/bessel.py,sha256=Xe62y2vrDwdJy3fR4U8_e8TAgisXIWJ94J7wu_xk0kI,14603
122
+ pytcl/mathematical_functions/special_functions/bessel.py,sha256=kRRPafQMXmooBglEteccjb6Hct1LLq3Oze4JfLQ-AmY,15459
122
123
  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
124
+ pytcl/mathematical_functions/special_functions/elliptic.py,sha256=mF3hVrErlK376pw-QZDoq_R6y8gnJAZAK5Kmuq8_0n4,8131
125
+ pytcl/mathematical_functions/special_functions/error_functions.py,sha256=6i5HqQfYdcz0UNhLnHpoMCnWzzZypjckSHTC5ISrcHA,6990
126
+ pytcl/mathematical_functions/special_functions/gamma_functions.py,sha256=riTiy1cqYFtJrzscw0vgTkCaPBCPDGN8Ge6qWAD1zBg,11086
126
127
  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
128
+ pytcl/mathematical_functions/special_functions/lambert_w.py,sha256=flLSf_7IY5sRXzd2aGgyXfJTRCjekgtvguBV3MhB9GE,6943
129
+ pytcl/mathematical_functions/special_functions/marcum_q.py,sha256=ASQ2vVfhmx4iEvtZTyiQ60-Hy8Qxl_4XgJzYufayJaQ,9910
129
130
  pytcl/mathematical_functions/statistics/__init__.py,sha256=dfypStgmnFmOrnWcm-3CEvLinONHraFgx9O66_37bqw,1278
130
131
  pytcl/mathematical_functions/statistics/distributions.py,sha256=icfFIIKCEFzkpFHuYGWL197nm8wvS7UPJlr9kd_uEgw,19373
131
132
  pytcl/mathematical_functions/statistics/estimators.py,sha256=TLnYXSwk5MzBakZrzDBupbOB3ONmJI7q1-oB2xuSVQM,10831
@@ -135,14 +136,14 @@ pytcl/mathematical_functions/transforms/stft.py,sha256=olDzNH02Nta5GoeEdsdX1tTVK
135
136
  pytcl/mathematical_functions/transforms/wavelets.py,sha256=lR71JX5vX_OXl1g9H89OGiimM_oqfU-WfGYJF3uD2z8,21887
136
137
  pytcl/misc/__init__.py,sha256=SCHf_lQVfdl2gwUluHBiIloTF8HRH8EkgYfbNr7zOug,33
137
138
  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
139
+ pytcl/navigation/geodesy.py,sha256=NH4Txv_VtUdBk6LkQqnSnPfRnG4WnoGF7zGwB-mIbJA,23140
140
+ pytcl/navigation/great_circle.py,sha256=K7CLS8k1P4uN9jpq4Nzc6jk_bSmo-ppb3vyUJbwYjVg,25503
140
141
  pytcl/navigation/ins.py,sha256=OIi8_RjrgEYl0MFpJEFMjIlpgX8DYGTEhdLEvqG-ABU,31151
141
142
  pytcl/navigation/ins_gnss.py,sha256=euKF5JGgwmVBsw3jBf7_wa2z1BpZeVbSNmBuwzhGS6c,30157
142
- pytcl/navigation/rhumb.py,sha256=lr1c3iEXfoOSfIyyXSRWv6He5TlaxEHbJy-dhqM1gRw,18224
143
+ pytcl/navigation/rhumb.py,sha256=lEr3LJqowT-WsdSA4E-V7BFmaqxoI7OpJa05pl_-uGg,20562
143
144
  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
145
+ pytcl/performance_evaluation/estimation_metrics.py,sha256=5dNzgMYTWt0bdGfIWgmc8diWA5SgivLvaSt_OahUhfk,14593
146
+ pytcl/performance_evaluation/track_metrics.py,sha256=4AJyU8mqczKnuOTi3eD8WqC56Xp2xxE-pwupM5WwBsE,14396
146
147
  pytcl/physical_values/__init__.py,sha256=SGbg6b0d4dWebE3baW4OlJshL00grG5E4wABw6jxl20,44
147
148
  pytcl/plotting/__init__.py,sha256=YtYnKYHL5lN6EaT_bwwR3h89NW0HSMToIWHhHBxcidY,3126
148
149
  pytcl/plotting/coordinates.py,sha256=kk1UO5aRPCUt206QS4COgtaExZI1Mjhi4P6falQCQLI,17247
@@ -152,20 +153,20 @@ pytcl/plotting/tracks.py,sha256=RoQyjpMcPm16mQqj4RvDOzPgD6UpHCOid6hxAN3kGC0,2317
152
153
  pytcl/scheduling/__init__.py,sha256=jTqMSKcsCrWU_Fh6WaT6BW5WatNHyyEYjFbsv6X18Oc,39
153
154
  pytcl/static_estimation/__init__.py,sha256=sSEhqq35jq_MpRLnBtWjKXwGZ9dqIw71iwji-TNwXmc,2222
154
155
  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
156
+ pytcl/static_estimation/maximum_likelihood.py,sha256=82tjFEEecNmTLrOrFKldEpkDrn4xC980qHZTZoOy3UY,23393
157
+ pytcl/static_estimation/robust.py,sha256=E9mmXcL1PycmyWvUnmLUbpErNvIbpu_XNAMGECmcMmU,20091
157
158
  pytcl/terrain/__init__.py,sha256=e7plNQI5Y_jpZ24r82AgqdX0ChmmyYoeT7HReclnGXc,3228
158
- pytcl/terrain/dem.py,sha256=rg2o0h0ZDrfxvtYhnE2A5tdzRnCmqcihu4w1uNJdH3Y,20814
159
+ pytcl/terrain/dem.py,sha256=3r1qV_FXaQDqEfUYJYSMrNNefd9hXRk8OGFkk3A3k9k,22881
159
160
  pytcl/terrain/loaders.py,sha256=3BbeFTaZ0I5bOlRFUcnP2eGQn-JyR2QDaUbIorDWdsg,27220
160
- pytcl/terrain/visibility.py,sha256=nIJr9AVk7C8GCpJV4UDvUjhmAieycWD8BLepAMUBMIQ,22739
161
+ pytcl/terrain/visibility.py,sha256=03pGWQGE4LY-DQFdqxPTHS-ZCYS9rJQNyAFnuQKe-3I,24992
161
162
  pytcl/trackers/__init__.py,sha256=Gw79xlSIUzdPV8bN1slNWUlGxE3d-NsVmbMygkYVV20,1151
162
- pytcl/trackers/hypothesis.py,sha256=ubK-q89cYayahSHIw5sVYD1fpRUEB0XvC6rQnI1WACA,17361
163
+ pytcl/trackers/hypothesis.py,sha256=cmcLWdSTbAoapl0EhsYcYBos7RXLzgHBfFVUUUh3Hmo,20210
163
164
  pytcl/trackers/mht.py,sha256=osEOXMaCeTt1eVn_E08dLRhEvBroVmf8b81zO5Zp1lU,20720
164
165
  pytcl/trackers/multi_target.py,sha256=RDITa0xnbgtVYAMj5XXp4lljo5lZ2zAAc02KZlOjxbQ,10526
165
166
  pytcl/trackers/single_target.py,sha256=Yy3FwaNTArMWcaod-0HVeiioNV4xLWxNDn_7ZPVqQYs,6562
166
167
  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,,
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,,
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.9.2 (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.9.2"
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
@@ -446,6 +446,12 @@ def sun_position(
446
446
  velocity : ndarray, shape (3,)
447
447
  Sun velocity in AU/day
448
448
 
449
+ Examples
450
+ --------
451
+ >>> r, v = sun_position(2451545.0) # J2000.0 # doctest: +SKIP
452
+ >>> np.linalg.norm(r) # Distance from SSB # doctest: +SKIP
453
+ 0.00...
454
+
449
455
  See Also
450
456
  --------
451
457
  DEEphemeris.sun_position : Full ephemeris class with caching
@@ -473,6 +479,12 @@ def moon_position(
473
479
  velocity : ndarray, shape (3,)
474
480
  Moon velocity in AU/day
475
481
 
482
+ Examples
483
+ --------
484
+ >>> r, v = moon_position(2451545.0, 'earth_centered') # doctest: +SKIP
485
+ >>> np.linalg.norm(r) * 149597870.7 # Distance in km # doctest: +SKIP
486
+ 402...
487
+
476
488
  See Also
477
489
  --------
478
490
  DEEphemeris.moon_position : Full ephemeris class with caching
@@ -533,5 +545,11 @@ def barycenter_position(
533
545
  velocity : ndarray, shape (3,)
534
546
  Velocity in AU/day
535
547
 
548
+ Examples
549
+ --------
550
+ >>> r, v = barycenter_position('mars', 2451545.0) # doctest: +SKIP
551
+ >>> np.linalg.norm(r) # Mars distance from SSB # doctest: +SKIP
552
+ 1.4...
553
+
536
554
  """
537
555
  return _get_default_ephemeris().barycenter_position(body, jd)