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.
- {nrl_tracker-1.7.0.dist-info → nrl_tracker-1.7.3.dist-info}/METADATA +43 -3
- {nrl_tracker-1.7.0.dist-info → nrl_tracker-1.7.3.dist-info}/RECORD +76 -76
- pytcl/__init__.py +2 -2
- pytcl/assignment_algorithms/__init__.py +15 -15
- pytcl/assignment_algorithms/gating.py +10 -10
- pytcl/assignment_algorithms/jpda.py +40 -40
- pytcl/assignment_algorithms/nd_assignment.py +5 -4
- pytcl/assignment_algorithms/network_flow.py +18 -8
- pytcl/assignment_algorithms/three_dimensional/assignment.py +3 -3
- pytcl/astronomical/__init__.py +9 -9
- pytcl/astronomical/ephemerides.py +14 -11
- pytcl/astronomical/reference_frames.py +8 -4
- pytcl/astronomical/relativity.py +6 -5
- pytcl/astronomical/special_orbits.py +9 -13
- pytcl/atmosphere/__init__.py +6 -6
- pytcl/atmosphere/nrlmsise00.py +153 -152
- pytcl/clustering/dbscan.py +2 -2
- pytcl/clustering/gaussian_mixture.py +3 -3
- pytcl/clustering/hierarchical.py +15 -15
- pytcl/clustering/kmeans.py +4 -4
- pytcl/containers/base.py +3 -3
- pytcl/containers/cluster_set.py +12 -2
- pytcl/containers/covertree.py +5 -3
- pytcl/containers/rtree.py +1 -1
- pytcl/containers/vptree.py +4 -2
- pytcl/coordinate_systems/conversions/geodetic.py +31 -7
- pytcl/coordinate_systems/jacobians/jacobians.py +2 -2
- pytcl/coordinate_systems/projections/__init__.py +1 -1
- pytcl/coordinate_systems/projections/projections.py +2 -2
- pytcl/coordinate_systems/rotations/rotations.py +10 -6
- pytcl/core/validation.py +3 -3
- pytcl/dynamic_estimation/__init__.py +16 -16
- pytcl/dynamic_estimation/gaussian_sum_filter.py +20 -38
- pytcl/dynamic_estimation/imm.py +14 -14
- pytcl/dynamic_estimation/kalman/__init__.py +1 -1
- pytcl/dynamic_estimation/kalman/constrained.py +35 -23
- pytcl/dynamic_estimation/kalman/extended.py +8 -8
- pytcl/dynamic_estimation/kalman/h_infinity.py +2 -2
- pytcl/dynamic_estimation/kalman/square_root.py +8 -2
- pytcl/dynamic_estimation/kalman/sr_ukf.py +3 -3
- pytcl/dynamic_estimation/kalman/ud_filter.py +11 -5
- pytcl/dynamic_estimation/kalman/unscented.py +8 -6
- pytcl/dynamic_estimation/particle_filters/bootstrap.py +15 -15
- pytcl/dynamic_estimation/rbpf.py +36 -40
- pytcl/gravity/spherical_harmonics.py +3 -3
- pytcl/gravity/tides.py +6 -6
- pytcl/logging_config.py +3 -3
- pytcl/magnetism/emm.py +10 -3
- pytcl/magnetism/wmm.py +4 -4
- pytcl/mathematical_functions/combinatorics/combinatorics.py +5 -5
- pytcl/mathematical_functions/geometry/geometry.py +5 -5
- pytcl/mathematical_functions/numerical_integration/quadrature.py +6 -6
- pytcl/mathematical_functions/signal_processing/detection.py +24 -24
- pytcl/mathematical_functions/signal_processing/filters.py +14 -14
- pytcl/mathematical_functions/signal_processing/matched_filter.py +12 -12
- pytcl/mathematical_functions/special_functions/bessel.py +15 -3
- pytcl/mathematical_functions/special_functions/debye.py +5 -1
- pytcl/mathematical_functions/special_functions/error_functions.py +3 -1
- pytcl/mathematical_functions/special_functions/gamma_functions.py +4 -4
- pytcl/mathematical_functions/special_functions/hypergeometric.py +6 -4
- pytcl/mathematical_functions/transforms/fourier.py +8 -8
- pytcl/mathematical_functions/transforms/stft.py +12 -12
- pytcl/mathematical_functions/transforms/wavelets.py +9 -9
- pytcl/navigation/geodesy.py +3 -3
- pytcl/navigation/great_circle.py +5 -5
- pytcl/plotting/coordinates.py +7 -7
- pytcl/plotting/tracks.py +2 -2
- pytcl/static_estimation/maximum_likelihood.py +16 -14
- pytcl/static_estimation/robust.py +5 -5
- pytcl/terrain/loaders.py +5 -5
- pytcl/trackers/hypothesis.py +1 -1
- pytcl/trackers/mht.py +9 -9
- pytcl/trackers/multi_target.py +1 -1
- {nrl_tracker-1.7.0.dist-info → nrl_tracker-1.7.3.dist-info}/LICENSE +0 -0
- {nrl_tracker-1.7.0.dist-info → nrl_tracker-1.7.3.dist-info}/WHEEL +0 -0
- {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(
|
|
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(
|
|
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
|
|
pytcl/navigation/geodesy.py
CHANGED
|
@@ -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 {
|
pytcl/navigation/great_circle.py
CHANGED
|
@@ -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 {
|
pytcl/plotting/coordinates.py
CHANGED
|
@@ -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",
|