nrl-tracker 1.7.0__py3-none-any.whl → 1.7.3__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 (76) hide show
  1. {nrl_tracker-1.7.0.dist-info → nrl_tracker-1.7.3.dist-info}/METADATA +43 -3
  2. {nrl_tracker-1.7.0.dist-info → nrl_tracker-1.7.3.dist-info}/RECORD +76 -76
  3. pytcl/__init__.py +2 -2
  4. pytcl/assignment_algorithms/__init__.py +15 -15
  5. pytcl/assignment_algorithms/gating.py +10 -10
  6. pytcl/assignment_algorithms/jpda.py +40 -40
  7. pytcl/assignment_algorithms/nd_assignment.py +5 -4
  8. pytcl/assignment_algorithms/network_flow.py +18 -8
  9. pytcl/assignment_algorithms/three_dimensional/assignment.py +3 -3
  10. pytcl/astronomical/__init__.py +9 -9
  11. pytcl/astronomical/ephemerides.py +14 -11
  12. pytcl/astronomical/reference_frames.py +8 -4
  13. pytcl/astronomical/relativity.py +6 -5
  14. pytcl/astronomical/special_orbits.py +9 -13
  15. pytcl/atmosphere/__init__.py +6 -6
  16. pytcl/atmosphere/nrlmsise00.py +153 -152
  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 +31 -7
  27. pytcl/coordinate_systems/jacobians/jacobians.py +2 -2
  28. pytcl/coordinate_systems/projections/__init__.py +1 -1
  29. pytcl/coordinate_systems/projections/projections.py +2 -2
  30. pytcl/coordinate_systems/rotations/rotations.py +10 -6
  31. pytcl/core/validation.py +3 -3
  32. pytcl/dynamic_estimation/__init__.py +16 -16
  33. pytcl/dynamic_estimation/gaussian_sum_filter.py +20 -38
  34. pytcl/dynamic_estimation/imm.py +14 -14
  35. pytcl/dynamic_estimation/kalman/__init__.py +1 -1
  36. pytcl/dynamic_estimation/kalman/constrained.py +35 -23
  37. pytcl/dynamic_estimation/kalman/extended.py +8 -8
  38. pytcl/dynamic_estimation/kalman/h_infinity.py +2 -2
  39. pytcl/dynamic_estimation/kalman/square_root.py +8 -2
  40. pytcl/dynamic_estimation/kalman/sr_ukf.py +3 -3
  41. pytcl/dynamic_estimation/kalman/ud_filter.py +11 -5
  42. pytcl/dynamic_estimation/kalman/unscented.py +8 -6
  43. pytcl/dynamic_estimation/particle_filters/bootstrap.py +15 -15
  44. pytcl/dynamic_estimation/rbpf.py +36 -40
  45. pytcl/gravity/spherical_harmonics.py +3 -3
  46. pytcl/gravity/tides.py +6 -6
  47. pytcl/logging_config.py +3 -3
  48. pytcl/magnetism/emm.py +10 -3
  49. pytcl/magnetism/wmm.py +4 -4
  50. pytcl/mathematical_functions/combinatorics/combinatorics.py +5 -5
  51. pytcl/mathematical_functions/geometry/geometry.py +5 -5
  52. pytcl/mathematical_functions/numerical_integration/quadrature.py +6 -6
  53. pytcl/mathematical_functions/signal_processing/detection.py +24 -24
  54. pytcl/mathematical_functions/signal_processing/filters.py +14 -14
  55. pytcl/mathematical_functions/signal_processing/matched_filter.py +12 -12
  56. pytcl/mathematical_functions/special_functions/bessel.py +15 -3
  57. pytcl/mathematical_functions/special_functions/debye.py +5 -1
  58. pytcl/mathematical_functions/special_functions/error_functions.py +3 -1
  59. pytcl/mathematical_functions/special_functions/gamma_functions.py +4 -4
  60. pytcl/mathematical_functions/special_functions/hypergeometric.py +6 -4
  61. pytcl/mathematical_functions/transforms/fourier.py +8 -8
  62. pytcl/mathematical_functions/transforms/stft.py +12 -12
  63. pytcl/mathematical_functions/transforms/wavelets.py +9 -9
  64. pytcl/navigation/geodesy.py +3 -3
  65. pytcl/navigation/great_circle.py +5 -5
  66. pytcl/plotting/coordinates.py +7 -7
  67. pytcl/plotting/tracks.py +2 -2
  68. pytcl/static_estimation/maximum_likelihood.py +16 -14
  69. pytcl/static_estimation/robust.py +5 -5
  70. pytcl/terrain/loaders.py +5 -5
  71. pytcl/trackers/hypothesis.py +1 -1
  72. pytcl/trackers/mht.py +9 -9
  73. pytcl/trackers/multi_target.py +1 -1
  74. {nrl_tracker-1.7.0.dist-info → nrl_tracker-1.7.3.dist-info}/LICENSE +0 -0
  75. {nrl_tracker-1.7.0.dist-info → nrl_tracker-1.7.3.dist-info}/WHEEL +0 -0
  76. {nrl_tracker-1.7.0.dist-info → nrl_tracker-1.7.3.dist-info}/top_level.txt +0 -0
@@ -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
 
@@ -22,7 +22,7 @@ References
22
22
  Speech, and Signal Processing, 32(2), 236-243.
23
23
  """
24
24
 
25
- from typing import NamedTuple, Optional, Union
25
+ from typing import Any, NamedTuple, Optional, Union
26
26
 
27
27
  import numpy as np
28
28
  from numpy.typing import ArrayLike, NDArray
@@ -77,7 +77,7 @@ class Spectrogram(NamedTuple):
77
77
 
78
78
 
79
79
  def get_window(
80
- window: Union[str, tuple, ArrayLike],
80
+ window: Union[str, tuple[str, Any], ArrayLike],
81
81
  length: int,
82
82
  fftbins: bool = True,
83
83
  ) -> NDArray[np.floating]:
@@ -174,7 +174,7 @@ def window_bandwidth(
174
174
  def stft(
175
175
  x: ArrayLike,
176
176
  fs: float = 1.0,
177
- window: Union[str, tuple, ArrayLike] = "hann",
177
+ window: Union[str, tuple[str, Any], ArrayLike] = "hann",
178
178
  nperseg: int = 256,
179
179
  noverlap: Optional[int] = None,
180
180
  nfft: Optional[int] = None,
@@ -264,13 +264,13 @@ def stft(
264
264
  def istft(
265
265
  Zxx: ArrayLike,
266
266
  fs: float = 1.0,
267
- window: Union[str, tuple, ArrayLike] = "hann",
267
+ window: Union[str, tuple[str, Any], ArrayLike] = "hann",
268
268
  nperseg: Optional[int] = None,
269
269
  noverlap: Optional[int] = None,
270
270
  nfft: Optional[int] = None,
271
271
  input_onesided: bool = True,
272
272
  boundary: bool = True,
273
- ) -> tuple:
273
+ ) -> tuple[NDArray[np.floating], NDArray[np.floating]]:
274
274
  """
275
275
  Compute the inverse Short-Time Fourier Transform.
276
276
 
@@ -351,7 +351,7 @@ def istft(
351
351
  def spectrogram(
352
352
  x: ArrayLike,
353
353
  fs: float = 1.0,
354
- window: Union[str, tuple, ArrayLike] = "hann",
354
+ window: Union[str, tuple[str, Any], ArrayLike] = "hann",
355
355
  nperseg: int = 256,
356
356
  noverlap: Optional[int] = None,
357
357
  nfft: Optional[int] = None,
@@ -436,11 +436,11 @@ def spectrogram(
436
436
  def reassigned_spectrogram(
437
437
  x: ArrayLike,
438
438
  fs: float = 1.0,
439
- window: Union[str, tuple, ArrayLike] = "hann",
439
+ window: Union[str, tuple[str, Any], ArrayLike] = "hann",
440
440
  nperseg: int = 256,
441
441
  noverlap: Optional[int] = None,
442
442
  nfft: Optional[int] = None,
443
- ) -> tuple:
443
+ ) -> tuple[NDArray[np.floating], NDArray[np.floating], NDArray[np.floating]]:
444
444
  """
445
445
  Compute reassigned spectrogram for improved time-frequency resolution.
446
446
 
@@ -538,7 +538,7 @@ def mel_spectrogram(
538
538
  window: str = "hann",
539
539
  nperseg: int = 2048,
540
540
  noverlap: Optional[int] = None,
541
- ) -> tuple:
541
+ ) -> tuple[NDArray[np.floating], NDArray[np.floating], NDArray[np.floating]]:
542
542
  """
543
543
  Compute mel-scaled spectrogram.
544
544
 
@@ -611,15 +611,15 @@ def mel_spectrogram(
611
611
  # Mel frequency centers
612
612
  mel_freqs = _mel_frequencies(n_mels, fmin, fmax)
613
613
 
614
- return mel_freqs, spec_result.times, mel_spec
614
+ return (mel_freqs, spec_result.times, mel_spec)
615
615
 
616
616
 
617
- def _hz_to_mel(hz: Union[float, ArrayLike]) -> Union[float, NDArray]:
617
+ def _hz_to_mel(hz: Union[float, ArrayLike]) -> Union[float, NDArray[np.floating]]:
618
618
  """Convert frequency in Hz to mel scale."""
619
619
  return 2595.0 * np.log10(1.0 + np.asarray(hz) / 700.0)
620
620
 
621
621
 
622
- def _mel_to_hz(mel: Union[float, ArrayLike]) -> Union[float, NDArray]:
622
+ def _mel_to_hz(mel: Union[float, ArrayLike]) -> Union[float, NDArray[np.floating]]:
623
623
  """Convert mel scale to frequency in Hz."""
624
624
  return 700.0 * (10.0 ** (np.asarray(mel) / 2595.0) - 1.0)
625
625
 
@@ -20,7 +20,7 @@ References
20
20
  .. [2] Daubechies, I. (1992). Ten Lectures on Wavelets. SIAM.
21
21
  """
22
22
 
23
- from typing import Callable, List, NamedTuple, Optional, Union
23
+ from typing import Any, Callable, List, NamedTuple, Optional, Union
24
24
 
25
25
  import numpy as np
26
26
  from numpy.typing import ArrayLike, NDArray
@@ -262,7 +262,7 @@ def gaussian_wavelet(
262
262
  def cwt(
263
263
  signal: ArrayLike,
264
264
  scales: ArrayLike,
265
- wavelet: Union[str, Callable[[int], NDArray]] = "morlet",
265
+ wavelet: Union[str, Callable[[int], NDArray[np.floating]]] = "morlet",
266
266
  fs: float = 1.0,
267
267
  method: str = "fft",
268
268
  ) -> CWTResult:
@@ -312,16 +312,16 @@ def cwt(
312
312
  n = len(signal)
313
313
 
314
314
  # Determine wavelet function
315
- def _morlet_default(M: int) -> NDArray:
315
+ def _morlet_default(M: int) -> NDArray[np.floating]:
316
316
  return morlet_wavelet(M, w=5.0)
317
317
 
318
- def _ricker_default(M: int) -> NDArray:
318
+ def _ricker_default(M: int) -> NDArray[np.floating]:
319
319
  return ricker_wavelet(M, a=1.0)
320
320
 
321
- def _gaussian1_default(M: int) -> NDArray:
321
+ def _gaussian1_default(M: int) -> NDArray[np.floating]:
322
322
  return gaussian_wavelet(M, order=1)
323
323
 
324
- def _gaussian2_default(M: int) -> NDArray:
324
+ def _gaussian2_default(M: int) -> NDArray[np.floating]:
325
325
  return gaussian_wavelet(M, order=2)
326
326
 
327
327
  if callable(wavelet):
@@ -596,7 +596,7 @@ def dwt_single_level(
596
596
  signal: ArrayLike,
597
597
  wavelet: str = "db4",
598
598
  mode: str = "symmetric",
599
- ) -> tuple:
599
+ ) -> tuple[NDArray[np.floating], NDArray[np.floating]]:
600
600
  """
601
601
  Compute single-level DWT decomposition.
602
602
 
@@ -673,7 +673,7 @@ def wpt(
673
673
  wavelet: str = "db4",
674
674
  level: Optional[int] = None,
675
675
  mode: str = "symmetric",
676
- ) -> dict:
676
+ ) -> dict[str, NDArray[np.floating]]:
677
677
  """
678
678
  Compute the Wavelet Packet Transform.
679
679
 
@@ -748,7 +748,7 @@ def available_wavelets() -> List[str]:
748
748
  return pywt.wavelist()
749
749
 
750
750
 
751
- def wavelet_info(wavelet: str) -> dict:
751
+ def wavelet_info(wavelet: str) -> dict[str, Any]:
752
752
  """
753
753
  Get information about a wavelet.
754
754
 
@@ -10,7 +10,7 @@ This module provides geodetic utilities including:
10
10
 
11
11
  import logging
12
12
  from functools import lru_cache
13
- from typing import NamedTuple, Tuple
13
+ from typing import Any, NamedTuple, Tuple
14
14
 
15
15
  import numpy as np
16
16
  from numpy.typing import ArrayLike, NDArray
@@ -715,12 +715,12 @@ def clear_geodesy_cache() -> None:
715
715
  _logger.debug("Geodesy caches cleared")
716
716
 
717
717
 
718
- def get_geodesy_cache_info() -> dict:
718
+ def get_geodesy_cache_info() -> dict[str, Any]:
719
719
  """Get cache statistics for geodesy computations.
720
720
 
721
721
  Returns
722
722
  -------
723
- dict
723
+ dict[str, Any]
724
724
  Dictionary with cache statistics for inverse and direct geodetic caches.
725
725
  """
726
726
  return {
@@ -12,7 +12,7 @@ computing the shortest path on a sphere, including:
12
12
 
13
13
  import logging
14
14
  from functools import lru_cache
15
- from typing import NamedTuple, Optional, Tuple
15
+ from typing import Any, NamedTuple, Optional, Tuple
16
16
 
17
17
  import numpy as np
18
18
  from numpy.typing import NDArray
@@ -505,7 +505,7 @@ def great_circle_intersect(
505
505
  """
506
506
 
507
507
  # Convert to Cartesian unit vectors
508
- def to_cartesian(lat, lon):
508
+ def to_cartesian(lat: Any, lon: Any) -> NDArray[np.float64]:
509
509
  return np.array(
510
510
  [np.cos(lat) * np.cos(lon), np.cos(lat) * np.sin(lon), np.sin(lat)]
511
511
  )
@@ -661,7 +661,7 @@ def great_circle_tdoa_loc(
661
661
  delta_d12 = delta_r12 / radius
662
662
  delta_d13 = delta_r13 / radius
663
663
 
664
- def objective(lat, lon):
664
+ def objective(lat: Any, lon: Any) -> Any:
665
665
  """Objective function: difference between computed and observed TDOAs."""
666
666
  d1 = great_circle_distance(lat, lon, lat1, lon1, radius=1.0)
667
667
  d2 = great_circle_distance(lat, lon, lat2, lon2, radius=1.0)
@@ -836,12 +836,12 @@ def clear_great_circle_cache() -> None:
836
836
  _logger.debug("Great circle caches cleared")
837
837
 
838
838
 
839
- def get_cache_info() -> dict:
839
+ def get_cache_info() -> dict[str, Any]:
840
840
  """Get cache statistics for great circle computations.
841
841
 
842
842
  Returns
843
843
  -------
844
- dict
844
+ dict[str, Any]
845
845
  Dictionary with cache statistics for distance and azimuth caches.
846
846
  """
847
847
  return {
@@ -5,10 +5,10 @@ This module provides functions for visualizing coordinate systems,
5
5
  rotations, and transformations in 2D and 3D.
6
6
  """
7
7
 
8
- from typing import List, Optional, Tuple
8
+ from typing import Any, List, Optional, Tuple
9
9
 
10
10
  import numpy as np
11
- from numpy.typing import ArrayLike
11
+ from numpy.typing import ArrayLike, NDArray
12
12
 
13
13
  try:
14
14
  import plotly.graph_objects as go
@@ -180,17 +180,17 @@ def plot_euler_angles(
180
180
  angles = np.asarray(angles)
181
181
 
182
182
  # Create rotation matrices for each axis
183
- def rotx(a):
183
+ def rotx(a: Any) -> NDArray[np.float64]:
184
184
  return np.array(
185
185
  [[1, 0, 0], [0, np.cos(a), -np.sin(a)], [0, np.sin(a), np.cos(a)]]
186
186
  )
187
187
 
188
- def roty(a):
188
+ def roty(a: Any) -> NDArray[np.float64]:
189
189
  return np.array(
190
190
  [[np.cos(a), 0, np.sin(a)], [0, 1, 0], [-np.sin(a), 0, np.cos(a)]]
191
191
  )
192
192
 
193
- def rotz(a):
193
+ def rotz(a: Any) -> NDArray[np.float64]:
194
194
  return np.array(
195
195
  [[np.cos(a), -np.sin(a), 0], [np.sin(a), np.cos(a), 0], [0, 0, 1]]
196
196
  )
@@ -293,7 +293,7 @@ def plot_quaternion_interpolation(
293
293
  q_end = q_end / np.linalg.norm(q_end)
294
294
 
295
295
  # SLERP interpolation
296
- def quat_slerp(q1, q2, t):
296
+ def quat_slerp(q1: Any, q2: Any, t: Any) -> NDArray[np.float64]:
297
297
  dot = np.dot(q1, q2)
298
298
  if dot < 0:
299
299
  q2 = -q2
@@ -303,7 +303,7 @@ def plot_quaternion_interpolation(
303
303
  theta = np.arccos(dot)
304
304
  return (np.sin((1 - t) * theta) * q1 + np.sin(t * theta) * q2) / np.sin(theta)
305
305
 
306
- def quat_to_rotmat(q):
306
+ def quat_to_rotmat(q: Any) -> NDArray[np.float64]:
307
307
  w, x, y, z = q
308
308
  return np.array(
309
309
  [
pytcl/plotting/tracks.py CHANGED
@@ -196,7 +196,7 @@ def plot_tracking_result(
196
196
  covariances: Optional[List[ArrayLike]] = None,
197
197
  x_idx: int = 0,
198
198
  y_idx: int = 2,
199
- cov_xy_idx: tuple = (0, 2),
199
+ cov_xy_idx: tuple[int, int] = (0, 2),
200
200
  ellipse_interval: int = 5,
201
201
  n_std: float = 2.0,
202
202
  title: str = "Tracking Result",
@@ -596,7 +596,7 @@ def create_animated_tracking(
596
596
  covariances: Optional[List[ArrayLike]] = None,
597
597
  x_idx: int = 0,
598
598
  y_idx: int = 2,
599
- cov_xy_idx: tuple = (0, 2),
599
+ cov_xy_idx: tuple[int, int] = (0, 2),
600
600
  n_std: float = 2.0,
601
601
  frame_duration: int = 100,
602
602
  title: str = "Animated Tracking",