nrl-tracker 1.6.0__py3-none-any.whl → 1.7.1__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 (75) hide show
  1. {nrl_tracker-1.6.0.dist-info → nrl_tracker-1.7.1.dist-info}/METADATA +14 -10
  2. {nrl_tracker-1.6.0.dist-info → nrl_tracker-1.7.1.dist-info}/RECORD +75 -68
  3. pytcl/__init__.py +2 -2
  4. pytcl/assignment_algorithms/__init__.py +28 -0
  5. pytcl/assignment_algorithms/gating.py +10 -10
  6. pytcl/assignment_algorithms/jpda.py +40 -40
  7. pytcl/assignment_algorithms/nd_assignment.py +379 -0
  8. pytcl/assignment_algorithms/network_flow.py +371 -0
  9. pytcl/assignment_algorithms/three_dimensional/assignment.py +3 -3
  10. pytcl/astronomical/__init__.py +35 -0
  11. pytcl/astronomical/ephemerides.py +14 -11
  12. pytcl/astronomical/reference_frames.py +110 -4
  13. pytcl/astronomical/relativity.py +6 -5
  14. pytcl/astronomical/special_orbits.py +532 -0
  15. pytcl/atmosphere/__init__.py +11 -0
  16. pytcl/atmosphere/nrlmsise00.py +809 -0
  17. pytcl/clustering/dbscan.py +2 -2
  18. pytcl/clustering/gaussian_mixture.py +3 -3
  19. pytcl/clustering/hierarchical.py +15 -15
  20. pytcl/clustering/kmeans.py +4 -4
  21. pytcl/containers/base.py +3 -3
  22. pytcl/containers/cluster_set.py +12 -2
  23. pytcl/containers/covertree.py +5 -3
  24. pytcl/containers/rtree.py +1 -1
  25. pytcl/containers/vptree.py +4 -2
  26. pytcl/coordinate_systems/conversions/geodetic.py +272 -5
  27. pytcl/coordinate_systems/jacobians/jacobians.py +2 -2
  28. pytcl/coordinate_systems/projections/projections.py +2 -2
  29. pytcl/coordinate_systems/rotations/rotations.py +10 -6
  30. pytcl/core/validation.py +3 -3
  31. pytcl/dynamic_estimation/__init__.py +26 -0
  32. pytcl/dynamic_estimation/gaussian_sum_filter.py +434 -0
  33. pytcl/dynamic_estimation/imm.py +14 -14
  34. pytcl/dynamic_estimation/kalman/__init__.py +12 -0
  35. pytcl/dynamic_estimation/kalman/constrained.py +382 -0
  36. pytcl/dynamic_estimation/kalman/extended.py +8 -8
  37. pytcl/dynamic_estimation/kalman/h_infinity.py +2 -2
  38. pytcl/dynamic_estimation/kalman/square_root.py +8 -2
  39. pytcl/dynamic_estimation/kalman/sr_ukf.py +3 -3
  40. pytcl/dynamic_estimation/kalman/ud_filter.py +11 -5
  41. pytcl/dynamic_estimation/kalman/unscented.py +8 -6
  42. pytcl/dynamic_estimation/particle_filters/bootstrap.py +15 -15
  43. pytcl/dynamic_estimation/rbpf.py +589 -0
  44. pytcl/gravity/spherical_harmonics.py +3 -3
  45. pytcl/gravity/tides.py +6 -6
  46. pytcl/logging_config.py +3 -3
  47. pytcl/magnetism/emm.py +10 -3
  48. pytcl/magnetism/wmm.py +4 -4
  49. pytcl/mathematical_functions/combinatorics/combinatorics.py +5 -5
  50. pytcl/mathematical_functions/geometry/geometry.py +5 -5
  51. pytcl/mathematical_functions/numerical_integration/quadrature.py +6 -6
  52. pytcl/mathematical_functions/signal_processing/detection.py +24 -24
  53. pytcl/mathematical_functions/signal_processing/filters.py +14 -14
  54. pytcl/mathematical_functions/signal_processing/matched_filter.py +12 -12
  55. pytcl/mathematical_functions/special_functions/bessel.py +15 -3
  56. pytcl/mathematical_functions/special_functions/debye.py +5 -1
  57. pytcl/mathematical_functions/special_functions/error_functions.py +3 -1
  58. pytcl/mathematical_functions/special_functions/gamma_functions.py +4 -4
  59. pytcl/mathematical_functions/special_functions/hypergeometric.py +6 -4
  60. pytcl/mathematical_functions/transforms/fourier.py +8 -8
  61. pytcl/mathematical_functions/transforms/stft.py +12 -12
  62. pytcl/mathematical_functions/transforms/wavelets.py +9 -9
  63. pytcl/navigation/geodesy.py +3 -3
  64. pytcl/navigation/great_circle.py +5 -5
  65. pytcl/plotting/coordinates.py +7 -7
  66. pytcl/plotting/tracks.py +2 -2
  67. pytcl/static_estimation/maximum_likelihood.py +16 -14
  68. pytcl/static_estimation/robust.py +5 -5
  69. pytcl/terrain/loaders.py +5 -5
  70. pytcl/trackers/hypothesis.py +1 -1
  71. pytcl/trackers/mht.py +9 -9
  72. pytcl/trackers/multi_target.py +1 -1
  73. {nrl_tracker-1.6.0.dist-info → nrl_tracker-1.7.1.dist-info}/LICENSE +0 -0
  74. {nrl_tracker-1.6.0.dist-info → nrl_tracker-1.7.1.dist-info}/WHEEL +0 -0
  75. {nrl_tracker-1.6.0.dist-info → nrl_tracker-1.7.1.dist-info}/top_level.txt +0 -0
pytcl/magnetism/wmm.py CHANGED
@@ -13,7 +13,7 @@ References
13
13
  """
14
14
 
15
15
  from functools import lru_cache
16
- from typing import NamedTuple, Optional, Tuple
16
+ from typing import Any, NamedTuple, Optional, Tuple
17
17
 
18
18
  import numpy as np
19
19
  from numpy.typing import NDArray
@@ -482,7 +482,7 @@ def _magnetic_field_spherical_cached(
482
482
 
483
483
 
484
484
  # Registry to hold coefficient sets by id
485
- _coefficient_registry: dict = {}
485
+ _coefficient_registry: dict[str, Any] = {}
486
486
 
487
487
 
488
488
  def _register_coefficients(coeffs: "MagneticCoefficients") -> int:
@@ -579,7 +579,7 @@ def _compute_magnetic_field_spherical_impl(
579
579
  # =============================================================================
580
580
 
581
581
 
582
- def get_magnetic_cache_info() -> dict:
582
+ def get_magnetic_cache_info() -> dict[str, Any]:
583
583
  """
584
584
  Get information about the magnetic field computation cache.
585
585
 
@@ -630,7 +630,7 @@ def clear_magnetic_cache() -> None:
630
630
 
631
631
  def configure_magnetic_cache(
632
632
  maxsize: Optional[int] = None,
633
- precision: Optional[dict] = None,
633
+ precision: Optional[dict[str, Any]] = None,
634
634
  ) -> None:
635
635
  """
636
636
  Configure the magnetic field computation cache.
@@ -7,7 +7,7 @@ related operations commonly used in assignment problems and data association.
7
7
 
8
8
  import itertools
9
9
  from functools import lru_cache
10
- from typing import Iterator, List, Optional, Tuple
10
+ from typing import Any, Iterator, List, Optional, Tuple
11
11
 
12
12
  from numpy.typing import ArrayLike
13
13
 
@@ -108,7 +108,7 @@ def n_permute_k(n: int, k: int) -> int:
108
108
  def permutations(
109
109
  items: ArrayLike,
110
110
  k: Optional[int] = None,
111
- ) -> Iterator[Tuple]:
111
+ ) -> Iterator[tuple[Any, ...]]:
112
112
  """
113
113
  Generate all k-permutations of items.
114
114
 
@@ -136,7 +136,7 @@ def permutations(
136
136
  def combinations(
137
137
  items: ArrayLike,
138
138
  k: int,
139
- ) -> Iterator[Tuple]:
139
+ ) -> Iterator[tuple[Any, ...]]:
140
140
  """
141
141
  Generate all k-combinations of items.
142
142
 
@@ -164,7 +164,7 @@ def combinations(
164
164
  def combinations_with_replacement(
165
165
  items: ArrayLike,
166
166
  k: int,
167
- ) -> Iterator[Tuple]:
167
+ ) -> Iterator[tuple[Any, ...]]:
168
168
  """
169
169
  Generate all k-combinations with replacement.
170
170
 
@@ -263,7 +263,7 @@ def permutation_unrank(rank: int, n: int) -> List[int]:
263
263
  return perm
264
264
 
265
265
 
266
- def next_permutation(perm: ArrayLike) -> Optional[List]:
266
+ def next_permutation(perm: ArrayLike) -> Optional[List[Any]]:
267
267
  """
268
268
  Generate the next permutation in lexicographic order.
269
269
 
@@ -5,7 +5,7 @@ This module provides geometric functions for points, lines, planes,
5
5
  polygons, and related operations used in tracking applications.
6
6
  """
7
7
 
8
- from typing import Optional, Tuple
8
+ from typing import Any, Optional, Tuple
9
9
 
10
10
  import numpy as np
11
11
  from numpy.typing import ArrayLike, NDArray
@@ -527,12 +527,12 @@ def minimum_bounding_circle(
527
527
  """
528
528
  points = np.asarray(points, dtype=np.float64)
529
529
 
530
- def circle_from_two_points(p1, p2):
530
+ def circle_from_two_points(p1: Any, p2: Any) -> tuple[Any, Any]:
531
531
  center = (p1 + p2) / 2
532
532
  radius = np.linalg.norm(p1 - center)
533
533
  return center, radius
534
534
 
535
- def circle_from_three_points(p1, p2, p3):
535
+ def circle_from_three_points(p1: Any, p2: Any, p3: Any) -> tuple[Any, Any]:
536
536
  ax, ay = p1
537
537
  bx, by = p2
538
538
  cx, cy = p3
@@ -565,10 +565,10 @@ def minimum_bounding_circle(
565
565
  radius = np.linalg.norm(p1 - center)
566
566
  return center, radius
567
567
 
568
- def is_inside(c, r, p):
568
+ def is_inside(c: Any, r: Any, p: Any) -> Any:
569
569
  return np.linalg.norm(p - c) <= r + 1e-10
570
570
 
571
- def welzl(P, R):
571
+ def welzl(P: Any, R: Any) -> tuple[Any, Any]:
572
572
  if len(P) == 0 or len(R) == 3:
573
573
  if len(R) == 0:
574
574
  return np.array([0.0, 0.0]), 0.0
@@ -5,7 +5,7 @@ This module provides Gaussian quadrature rules and numerical integration
5
5
  functions commonly used in state estimation and filtering.
6
6
  """
7
7
 
8
- from typing import Callable, Literal, Optional, Tuple
8
+ from typing import Any, Callable, Literal, Optional, Tuple
9
9
 
10
10
  import numpy as np
11
11
  import scipy.integrate as integrate
@@ -158,7 +158,7 @@ def quad(
158
158
  f: Callable[[float], float],
159
159
  a: float,
160
160
  b: float,
161
- **kwargs,
161
+ **kwargs: Any,
162
162
  ) -> Tuple[float, float]:
163
163
  """
164
164
  Adaptive quadrature integration.
@@ -203,7 +203,7 @@ def dblquad(
203
203
  b: float,
204
204
  gfun: Callable[[float], float],
205
205
  hfun: Callable[[float], float],
206
- **kwargs,
206
+ **kwargs: Any,
207
207
  ) -> Tuple[float, float]:
208
208
  """
209
209
  Double integration.
@@ -248,7 +248,7 @@ def tplquad(
248
248
  hfun: Callable[[float], float],
249
249
  qfun: Callable[[float, float], float],
250
250
  rfun: Callable[[float, float], float],
251
- **kwargs,
251
+ **kwargs: Any,
252
252
  ) -> Tuple[float, float]:
253
253
  """
254
254
  Triple integration.
@@ -290,11 +290,11 @@ def tplquad(
290
290
 
291
291
 
292
292
  def fixed_quad(
293
- f: Callable[[NDArray], NDArray],
293
+ f: Callable[[np.ndarray[Any, Any]], np.ndarray[Any, Any]],
294
294
  a: float,
295
295
  b: float,
296
296
  n: int = 5,
297
- ) -> Tuple[float, None]:
297
+ ) -> tuple[float, None]:
298
298
  """
299
299
  Fixed-order Gaussian quadrature.
300
300
 
@@ -24,7 +24,7 @@ References
24
24
  Systems, 19(4), 608-621.
25
25
  """
26
26
 
27
- from typing import NamedTuple, Optional
27
+ from typing import Any, NamedTuple, Optional
28
28
 
29
29
  import numpy as np
30
30
  from numba import njit, prange
@@ -214,12 +214,12 @@ def detection_probability(
214
214
 
215
215
  @njit(cache=True, fastmath=True)
216
216
  def _cfar_ca_kernel(
217
- signal: np.ndarray,
217
+ signal: np.ndarray[Any, Any],
218
218
  guard_cells: int,
219
219
  ref_cells: int,
220
220
  alpha: float,
221
- noise_estimate: np.ndarray,
222
- threshold: np.ndarray,
221
+ noise_estimate: np.ndarray[Any, Any],
222
+ threshold: np.ndarray[Any, Any],
223
223
  ) -> None:
224
224
  """JIT-compiled CA-CFAR kernel."""
225
225
  n = len(signal)
@@ -252,12 +252,12 @@ def _cfar_ca_kernel(
252
252
 
253
253
  @njit(cache=True, fastmath=True)
254
254
  def _cfar_go_kernel(
255
- signal: np.ndarray,
255
+ signal: np.ndarray[Any, Any],
256
256
  guard_cells: int,
257
257
  ref_cells: int,
258
258
  alpha: float,
259
- noise_estimate: np.ndarray,
260
- threshold: np.ndarray,
259
+ noise_estimate: np.ndarray[Any, Any],
260
+ threshold: np.ndarray[Any, Any],
261
261
  ) -> None:
262
262
  """JIT-compiled GO-CFAR kernel."""
263
263
  n = len(signal)
@@ -290,12 +290,12 @@ def _cfar_go_kernel(
290
290
 
291
291
  @njit(cache=True, fastmath=True)
292
292
  def _cfar_so_kernel(
293
- signal: np.ndarray,
293
+ signal: np.ndarray[Any, Any],
294
294
  guard_cells: int,
295
295
  ref_cells: int,
296
296
  alpha: float,
297
- noise_estimate: np.ndarray,
298
- threshold: np.ndarray,
297
+ noise_estimate: np.ndarray[Any, Any],
298
+ threshold: np.ndarray[Any, Any],
299
299
  ) -> None:
300
300
  """JIT-compiled SO-CFAR kernel."""
301
301
  n = len(signal)
@@ -331,13 +331,13 @@ def _cfar_so_kernel(
331
331
 
332
332
  @njit(cache=True, fastmath=True)
333
333
  def _cfar_os_kernel(
334
- signal: np.ndarray,
334
+ signal: np.ndarray[Any, Any],
335
335
  guard_cells: int,
336
336
  ref_cells: int,
337
337
  k: int,
338
338
  alpha: float,
339
- noise_estimate: np.ndarray,
340
- threshold: np.ndarray,
339
+ noise_estimate: np.ndarray[Any, Any],
340
+ threshold: np.ndarray[Any, Any],
341
341
  ) -> None:
342
342
  """JIT-compiled OS-CFAR kernel."""
343
343
  n = len(signal)
@@ -378,14 +378,14 @@ def _cfar_os_kernel(
378
378
 
379
379
  @njit(cache=True, fastmath=True, parallel=True)
380
380
  def _cfar_2d_ca_kernel(
381
- image: np.ndarray,
381
+ image: np.ndarray[Any, Any],
382
382
  guard_rows: int,
383
383
  guard_cols: int,
384
384
  ref_rows: int,
385
385
  ref_cols: int,
386
386
  alpha: float,
387
- noise_estimate: np.ndarray,
388
- threshold: np.ndarray,
387
+ noise_estimate: np.ndarray[Any, Any],
388
+ threshold: np.ndarray[Any, Any],
389
389
  ) -> None:
390
390
  """JIT-compiled 2D CA-CFAR kernel with parallel execution."""
391
391
  n_rows, n_cols = image.shape
@@ -426,14 +426,14 @@ def _cfar_2d_ca_kernel(
426
426
 
427
427
  @njit(cache=True, fastmath=True, parallel=True)
428
428
  def _cfar_2d_go_kernel(
429
- image: np.ndarray,
429
+ image: np.ndarray[Any, Any],
430
430
  guard_rows: int,
431
431
  guard_cols: int,
432
432
  ref_rows: int,
433
433
  ref_cols: int,
434
434
  alpha: float,
435
- noise_estimate: np.ndarray,
436
- threshold: np.ndarray,
435
+ noise_estimate: np.ndarray[Any, Any],
436
+ threshold: np.ndarray[Any, Any],
437
437
  ) -> None:
438
438
  """JIT-compiled 2D GO-CFAR kernel with parallel execution."""
439
439
  n_rows, n_cols = image.shape
@@ -478,14 +478,14 @@ def _cfar_2d_go_kernel(
478
478
 
479
479
  @njit(cache=True, fastmath=True, parallel=True)
480
480
  def _cfar_2d_so_kernel(
481
- image: np.ndarray,
481
+ image: np.ndarray[Any, Any],
482
482
  guard_rows: int,
483
483
  guard_cols: int,
484
484
  ref_rows: int,
485
485
  ref_cols: int,
486
486
  alpha: float,
487
- noise_estimate: np.ndarray,
488
- threshold: np.ndarray,
487
+ noise_estimate: np.ndarray[Any, Any],
488
+ threshold: np.ndarray[Any, Any],
489
489
  ) -> None:
490
490
  """JIT-compiled 2D SO-CFAR kernel with parallel execution."""
491
491
  n_rows, n_cols = image.shape
@@ -830,8 +830,8 @@ def cfar_os(
830
830
 
831
831
  def cfar_2d(
832
832
  image: ArrayLike,
833
- guard_cells: tuple,
834
- ref_cells: tuple,
833
+ guard_cells: tuple[int, int],
834
+ ref_cells: tuple[int, int],
835
835
  pfa: float = 1e-6,
836
836
  method: str = "ca",
837
837
  alpha: Optional[float] = None,
@@ -24,7 +24,7 @@ References
24
24
  Wiley-Interscience.
25
25
  """
26
26
 
27
- from typing import NamedTuple, Optional, Union
27
+ from typing import Any, NamedTuple, Optional, Union
28
28
 
29
29
  import numpy as np
30
30
  from numpy.typing import ArrayLike, NDArray
@@ -80,7 +80,7 @@ class FrequencyResponse(NamedTuple):
80
80
 
81
81
  def butter_design(
82
82
  order: int,
83
- cutoff: Union[float, tuple],
83
+ cutoff: Union[float, tuple[float, ...]],
84
84
  fs: float,
85
85
  btype: str = "low",
86
86
  output: str = "sos",
@@ -141,7 +141,7 @@ def butter_design(
141
141
  def cheby1_design(
142
142
  order: int,
143
143
  ripple: float,
144
- cutoff: Union[float, tuple],
144
+ cutoff: Union[float, tuple[float, ...]],
145
145
  fs: float,
146
146
  btype: str = "low",
147
147
  output: str = "sos",
@@ -198,7 +198,7 @@ def cheby1_design(
198
198
  def cheby2_design(
199
199
  order: int,
200
200
  attenuation: float,
201
- cutoff: Union[float, tuple],
201
+ cutoff: Union[float, tuple[float, ...]],
202
202
  fs: float,
203
203
  btype: str = "low",
204
204
  output: str = "sos",
@@ -255,7 +255,7 @@ def ellip_design(
255
255
  order: int,
256
256
  passband_ripple: float,
257
257
  stopband_attenuation: float,
258
- cutoff: Union[float, tuple],
258
+ cutoff: Union[float, tuple[float, ...]],
259
259
  fs: float,
260
260
  btype: str = "low",
261
261
  output: str = "sos",
@@ -317,7 +317,7 @@ def ellip_design(
317
317
 
318
318
  def bessel_design(
319
319
  order: int,
320
- cutoff: Union[float, tuple],
320
+ cutoff: Union[float, tuple[float, ...]],
321
321
  fs: float,
322
322
  btype: str = "low",
323
323
  norm: str = "phase",
@@ -383,7 +383,7 @@ def bessel_design(
383
383
 
384
384
  def fir_design(
385
385
  numtaps: int,
386
- cutoff: Union[float, tuple],
386
+ cutoff: Union[float, tuple[float, ...]],
387
387
  fs: float,
388
388
  window: str = "hamming",
389
389
  pass_zero: Union[bool, str] = True,
@@ -499,10 +499,10 @@ def fir_design_remez(
499
499
 
500
500
 
501
501
  def apply_filter(
502
- coeffs: Union[FilterCoefficients, tuple, NDArray],
502
+ coeffs: Union[FilterCoefficients, tuple[Any, ...], NDArray[Any]],
503
503
  x: ArrayLike,
504
504
  zi: Optional[ArrayLike] = None,
505
- ) -> Union[NDArray[np.floating], tuple]:
505
+ ) -> Union[NDArray[np.floating], tuple[NDArray[np.floating], Any]]:
506
506
  """
507
507
  Apply a digital filter to a signal.
508
508
 
@@ -559,7 +559,7 @@ def apply_filter(
559
559
 
560
560
 
561
561
  def filtfilt(
562
- coeffs: Union[FilterCoefficients, tuple, NDArray],
562
+ coeffs: Union[FilterCoefficients, tuple[Any, ...], NDArray[Any]],
563
563
  x: ArrayLike,
564
564
  padtype: str = "odd",
565
565
  padlen: Optional[int] = None,
@@ -627,7 +627,7 @@ def filtfilt(
627
627
 
628
628
 
629
629
  def frequency_response(
630
- coeffs: Union[FilterCoefficients, tuple, NDArray],
630
+ coeffs: Union[FilterCoefficients, tuple[Any, ...], NDArray[Any]],
631
631
  fs: float,
632
632
  n_points: int = 512,
633
633
  whole: bool = False,
@@ -684,10 +684,10 @@ def frequency_response(
684
684
 
685
685
 
686
686
  def group_delay(
687
- coeffs: Union[FilterCoefficients, tuple, NDArray],
687
+ coeffs: Union[FilterCoefficients, tuple[Any, ...], NDArray[Any]],
688
688
  fs: float,
689
689
  n_points: int = 512,
690
- ) -> tuple:
690
+ ) -> tuple[NDArray[np.floating], NDArray[np.floating]]:
691
691
  """
692
692
  Compute the group delay of a digital filter.
693
693
 
@@ -793,7 +793,7 @@ def filter_order(
793
793
  return int(order)
794
794
 
795
795
 
796
- def sos_to_zpk(sos: ArrayLike) -> tuple:
796
+ def sos_to_zpk(sos: ArrayLike) -> tuple[NDArray[Any], NDArray[Any], Any]:
797
797
  """
798
798
  Convert second-order sections to zeros, poles, gain.
799
799
 
@@ -21,7 +21,7 @@ References
21
21
  IRE Transactions on Information Theory, 6(3), 311-329.
22
22
  """
23
23
 
24
- from typing import NamedTuple, Optional
24
+ from typing import Any, NamedTuple, Optional
25
25
 
26
26
  import numpy as np
27
27
  from numba import njit, prange
@@ -553,11 +553,11 @@ def generate_nlfm_chirp(
553
553
 
554
554
  @njit(cache=True, fastmath=True, parallel=True)
555
555
  def _ambiguity_function_kernel(
556
- signal: np.ndarray,
557
- delays: np.ndarray,
558
- dopplers: np.ndarray,
556
+ signal: np.ndarray[Any, Any],
557
+ delays: np.ndarray[Any, Any],
558
+ dopplers: np.ndarray[Any, Any],
559
559
  fs: float,
560
- af: np.ndarray,
560
+ af: np.ndarray[Any, Any],
561
561
  ) -> None:
562
562
  """JIT-compiled kernel for ambiguity function computation."""
563
563
  n_signal = len(signal)
@@ -600,12 +600,12 @@ def _ambiguity_function_kernel(
600
600
 
601
601
  @njit(cache=True, fastmath=True, parallel=True)
602
602
  def _cross_ambiguity_kernel(
603
- signal1: np.ndarray,
604
- signal2: np.ndarray,
605
- delays: np.ndarray,
606
- dopplers: np.ndarray,
603
+ signal1: np.ndarray[Any, Any],
604
+ signal2: np.ndarray[Any, Any],
605
+ delays: np.ndarray[Any, Any],
606
+ dopplers: np.ndarray[Any, Any],
607
607
  fs: float,
608
- caf: np.ndarray,
608
+ caf: np.ndarray[Any, Any],
609
609
  ) -> None:
610
610
  """JIT-compiled kernel for cross-ambiguity function computation."""
611
611
  n_signal = len(signal1)
@@ -653,7 +653,7 @@ def ambiguity_function(
653
653
  max_doppler: Optional[float] = None,
654
654
  n_delay: int = 256,
655
655
  n_doppler: int = 256,
656
- ) -> tuple:
656
+ ) -> tuple[NDArray[np.floating], NDArray[np.floating], NDArray[np.complexfloating]]:
657
657
  """
658
658
  Compute the ambiguity function of a signal.
659
659
 
@@ -722,7 +722,7 @@ def cross_ambiguity(
722
722
  max_doppler: Optional[float] = None,
723
723
  n_delay: int = 256,
724
724
  n_doppler: int = 256,
725
- ) -> tuple:
725
+ ) -> tuple[NDArray[np.floating], NDArray[np.floating], NDArray[np.complexfloating]]:
726
726
  """
727
727
  Compute the cross-ambiguity function between two signals.
728
728
 
@@ -5,7 +5,7 @@ This module provides Bessel functions commonly used in signal processing,
5
5
  antenna theory, and scattering problems in tracking applications.
6
6
  """
7
7
 
8
- from typing import Union
8
+ from typing import Any, Union
9
9
 
10
10
  import numpy as np
11
11
  import scipy.special as sp
@@ -315,7 +315,14 @@ def spherical_kn(
315
315
  return np.asarray(sp.spherical_kn(n, x, derivative=derivative), dtype=np.float64)
316
316
 
317
317
 
318
- def airy(x: ArrayLike) -> tuple:
318
+ def airy(
319
+ x: ArrayLike,
320
+ ) -> tuple[
321
+ np.ndarray[Any, Any],
322
+ np.ndarray[Any, Any],
323
+ np.ndarray[Any, Any],
324
+ np.ndarray[Any, Any],
325
+ ]:
319
326
  """
320
327
  Airy functions and their derivatives.
321
328
 
@@ -554,7 +561,12 @@ def bessel_zeros(
554
561
 
555
562
  def kelvin(
556
563
  x: ArrayLike,
557
- ) -> tuple:
564
+ ) -> tuple[
565
+ np.ndarray[Any, Any],
566
+ np.ndarray[Any, Any],
567
+ np.ndarray[Any, Any],
568
+ np.ndarray[Any, Any],
569
+ ]:
558
570
  """
559
571
  Kelvin functions ber, bei, ker, kei.
560
572
 
@@ -11,6 +11,8 @@ core, providing ~10-50x speedup for batch computations compared to
11
11
  scipy.integrate.quad.
12
12
  """
13
13
 
14
+ from typing import Any
15
+
14
16
  import numpy as np
15
17
  from numba import njit, prange
16
18
  from numpy.typing import ArrayLike, NDArray
@@ -90,7 +92,9 @@ def _debye_small_x(x: float, n: int) -> float:
90
92
 
91
93
 
92
94
  @njit(cache=True, fastmath=True, parallel=True)
93
- def _debye_batch(n: int, x_arr: np.ndarray, zeta_n_plus_1: float) -> np.ndarray:
95
+ def _debye_batch(
96
+ n: int, x_arr: np.ndarray[Any, Any], zeta_n_plus_1: float
97
+ ) -> np.ndarray[Any, Any]:
94
98
  """
95
99
  Batch computation of Debye function for array input.
96
100
 
@@ -5,6 +5,8 @@ This module provides error functions and their variants, commonly used
5
5
  in probability theory and statistical analysis.
6
6
  """
7
7
 
8
+ from typing import Any
9
+
8
10
  import numpy as np
9
11
  import scipy.special as sp
10
12
  from numpy.typing import ArrayLike, NDArray
@@ -216,7 +218,7 @@ def dawsn(x: ArrayLike) -> NDArray[np.floating]:
216
218
  return np.asarray(sp.dawsn(x), dtype=np.float64)
217
219
 
218
220
 
219
- def fresnel(x: ArrayLike) -> tuple:
221
+ def fresnel(x: ArrayLike) -> tuple[np.ndarray[Any, Any], np.ndarray[Any, Any]]:
220
222
  """
221
223
  Fresnel integrals.
222
224
 
@@ -318,7 +318,7 @@ def betaincinv(a: ArrayLike, b: ArrayLike, y: ArrayLike) -> NDArray[np.floating]
318
318
  return np.asarray(sp.betaincinv(a, b, y), dtype=np.float64)
319
319
 
320
320
 
321
- def factorial(n: ArrayLike, exact: bool = False) -> NDArray:
321
+ def factorial(n: ArrayLike, exact: bool = False) -> NDArray[np.floating]:
322
322
  """
323
323
  Factorial function.
324
324
 
@@ -351,7 +351,7 @@ def factorial(n: ArrayLike, exact: bool = False) -> NDArray:
351
351
  return np.asarray(sp.factorial(n, exact=exact), dtype=np.float64)
352
352
 
353
353
 
354
- def factorial2(n: ArrayLike, exact: bool = False) -> NDArray:
354
+ def factorial2(n: ArrayLike, exact: bool = False) -> NDArray[np.floating]:
355
355
  """
356
356
  Double factorial.
357
357
 
@@ -388,7 +388,7 @@ def comb(
388
388
  k: ArrayLike,
389
389
  exact: bool = False,
390
390
  repetition: bool = False,
391
- ) -> NDArray:
391
+ ) -> NDArray[np.floating]:
392
392
  """
393
393
  Binomial coefficient (combinations).
394
394
 
@@ -426,7 +426,7 @@ def comb(
426
426
  )
427
427
 
428
428
 
429
- def perm(n: ArrayLike, k: ArrayLike, exact: bool = False) -> NDArray:
429
+ def perm(n: ArrayLike, k: ArrayLike, exact: bool = False) -> NDArray[np.floating]:
430
430
  """
431
431
  Permutation coefficient.
432
432
 
@@ -11,6 +11,8 @@ the series summation loop, providing significant speedup for the general
11
11
  case (p > 2 or q > 1).
12
12
  """
13
13
 
14
+ from typing import Any
15
+
14
16
  import numpy as np
15
17
  import scipy.special as sp
16
18
  from numba import njit
@@ -19,12 +21,12 @@ from numpy.typing import ArrayLike, NDArray
19
21
 
20
22
  @njit(cache=True, fastmath=True)
21
23
  def _hypergeometric_series(
22
- a: np.ndarray,
23
- b: np.ndarray,
24
- z: np.ndarray,
24
+ a: np.ndarray[Any, Any],
25
+ b: np.ndarray[Any, Any],
26
+ z: np.ndarray[Any, Any],
25
27
  max_terms: int,
26
28
  tol: float,
27
- ) -> np.ndarray:
29
+ ) -> np.ndarray[Any, Any]:
28
30
  """
29
31
  Numba-optimized series summation for generalized hypergeometric function.
30
32
 
@@ -247,8 +247,8 @@ def irfft(
247
247
 
248
248
  def fft2(
249
249
  x: ArrayLike,
250
- s: Optional[tuple] = None,
251
- axes: tuple = (-2, -1),
250
+ s: Optional[tuple[int, ...]] = None,
251
+ axes: tuple[int, ...] = (-2, -1),
252
252
  norm: Optional[str] = None,
253
253
  ) -> NDArray[np.complexfloating]:
254
254
  """
@@ -284,8 +284,8 @@ def fft2(
284
284
 
285
285
  def ifft2(
286
286
  X: ArrayLike,
287
- s: Optional[tuple] = None,
288
- axes: tuple = (-2, -1),
287
+ s: Optional[tuple[int, ...]] = None,
288
+ axes: tuple[int, ...] = (-2, -1),
289
289
  norm: Optional[str] = None,
290
290
  ) -> NDArray[np.complexfloating]:
291
291
  """
@@ -313,8 +313,8 @@ def ifft2(
313
313
 
314
314
  def fftshift(
315
315
  x: ArrayLike,
316
- axes: Optional[Union[int, tuple]] = None,
317
- ) -> NDArray:
316
+ axes: Optional[Union[int, tuple[int, ...]]] = None,
317
+ ) -> NDArray[np.floating]:
318
318
  """
319
319
  Shift the zero-frequency component to the center of the spectrum.
320
320
 
@@ -345,8 +345,8 @@ def fftshift(
345
345
 
346
346
  def ifftshift(
347
347
  x: ArrayLike,
348
- axes: Optional[Union[int, tuple]] = None,
349
- ) -> NDArray:
348
+ axes: Optional[Union[int, tuple[int, ...]]] = None,
349
+ ) -> NDArray[np.floating]:
350
350
  """
351
351
  Inverse of fftshift. Shift zero-frequency back to beginning.
352
352