nrl-tracker 0.20.0__py3-none-any.whl → 0.21.0__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: nrl-tracker
3
- Version: 0.20.0
3
+ Version: 0.21.0
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
@@ -88,17 +88,21 @@ pytcl/mathematical_functions/geometry/geometry.py,sha256=l63wQnhCtJwVHZOJeONX1qy
88
88
  pytcl/mathematical_functions/interpolation/__init__.py,sha256=HDhP7ZsgUrXFBNJ_eCZEdp5gizWJ-BxvkQSCMnvBg3A,677
89
89
  pytcl/mathematical_functions/interpolation/interpolation.py,sha256=2cXMDgWBjWDGHnK1K_lawFlJL8oPl5AQGf9MNgsESfo,12610
90
90
  pytcl/mathematical_functions/numerical_integration/__init__.py,sha256=iXiHzyV_KIhCv7tXErXlN1_fUEACN6yN3CYDHRA7esw,974
91
- pytcl/mathematical_functions/numerical_integration/quadrature.py,sha256=ErxG_HLfM2LjKStguK_2wEhodln63v1FVubetAS5GL0,14748
91
+ pytcl/mathematical_functions/numerical_integration/quadrature.py,sha256=ZRMKs0vbcgFDe1Sr8sjyEOkALLmJU4zKRJjoPEcXrUc,15670
92
92
  pytcl/mathematical_functions/polynomials/__init__.py,sha256=WJWZcoQhnvy5f59-kncMTgD9mCtgwfDgULvDYYHS5ys,43
93
93
  pytcl/mathematical_functions/signal_processing/__init__.py,sha256=_SzzBVtxmSvP8FKeogRdNmFo8FOVDDoexVOqd-lE7do,2325
94
94
  pytcl/mathematical_functions/signal_processing/detection.py,sha256=9F0xdy3hMat1czSWAQYMExn0kY5DBRpyBneAfjjHUVI,30377
95
95
  pytcl/mathematical_functions/signal_processing/filters.py,sha256=8Ojf4h4rfiucBXqUmB1odvHH41Gf3rPwmWCMKb-qzWk,23435
96
96
  pytcl/mathematical_functions/signal_processing/matched_filter.py,sha256=AahJZRZk2IIXzRL7www0n8bc0XoKabaLOe8yYNSjuDY,22893
97
- pytcl/mathematical_functions/special_functions/__init__.py,sha256=fXACpf-y1Jdq7UmVjwETUVhN_mkATT1I4tKbT1FW-C0,2017
98
- pytcl/mathematical_functions/special_functions/bessel.py,sha256=0sVwL1pPqNYiVkjXqacnkHoPBkiomk0D7IDu6-bKtEs,8139
97
+ pytcl/mathematical_functions/special_functions/__init__.py,sha256=qDPGfee1i1NkVi9LXJKnsWXL3CWHkPQINrkwqLqB8YU,3796
98
+ pytcl/mathematical_functions/special_functions/bessel.py,sha256=M0mwLQBaUXEHA8wyKReJ2D66I1v1XR7y-txAipd-WDs,14377
99
+ pytcl/mathematical_functions/special_functions/debye.py,sha256=Nchjwkl1vzSL1L7nQpslb-lvT49LgTfdTIQMeSNn4vQ,6689
99
100
  pytcl/mathematical_functions/special_functions/elliptic.py,sha256=WyzBkrfZufIR5dUmCKGcxp6KNpVDrU89NGLDyRrZOqQ,7418
100
101
  pytcl/mathematical_functions/special_functions/error_functions.py,sha256=a3SS8FYAMRv1KdCmebOZL95yjvVt9gZRF2XOjHvQ9M8,6253
101
102
  pytcl/mathematical_functions/special_functions/gamma_functions.py,sha256=xXN_9SCokH10HjE8PpaPKHYVK_RZRHRAbZgR2mZYIAA,10191
103
+ pytcl/mathematical_functions/special_functions/hypergeometric.py,sha256=gKn_tXboEst7pVDiW15IbKFAANM4XVqKtDc1dmWL-2A,9768
104
+ pytcl/mathematical_functions/special_functions/lambert_w.py,sha256=ivRc4KH5Lwoxb_yijrJEwG0ITa0hhcYF7_gCfVBBNW4,6855
105
+ pytcl/mathematical_functions/special_functions/marcum_q.py,sha256=OZ5QjIB1e_XvRG8A-3dbZ13YXHtdk2EYVEPaqtgVr14,9580
102
106
  pytcl/mathematical_functions/statistics/__init__.py,sha256=dfypStgmnFmOrnWcm-3CEvLinONHraFgx9O66_37bqw,1278
103
107
  pytcl/mathematical_functions/statistics/distributions.py,sha256=icfFIIKCEFzkpFHuYGWL197nm8wvS7UPJlr9kd_uEgw,19373
104
108
  pytcl/mathematical_functions/statistics/estimators.py,sha256=TLnYXSwk5MzBakZrzDBupbOB3ONmJI7q1-oB2xuSVQM,10831
@@ -137,8 +141,8 @@ pytcl/trackers/mht.py,sha256=7mwhMmja3ri2wnx7W1wueDGn2r3ArwAxJDPUJ7IZAkQ,20617
137
141
  pytcl/trackers/multi_target.py,sha256=7ZL8V25TO_rEMtQm2eYkScesDQHC9qXZVHLHyVbxy3M,10529
138
142
  pytcl/trackers/single_target.py,sha256=Yy3FwaNTArMWcaod-0HVeiioNV4xLWxNDn_7ZPVqQYs,6562
139
143
  pytcl/transponders/__init__.py,sha256=5fL4u3lKCYgPLo5uFeuZbtRZkJPABntuKYGUvVgMMEI,41
140
- nrl_tracker-0.20.0.dist-info/LICENSE,sha256=rB5G4WppIIUzMOYr2N6uyYlNJ00hRJqE5tie6BMvYuE,1612
141
- nrl_tracker-0.20.0.dist-info/METADATA,sha256=5ObdsLBjNtHmUoVDxkzrARr4ITlJz4nyzm-ysPNZOvs,9699
142
- nrl_tracker-0.20.0.dist-info/WHEEL,sha256=pL8R0wFFS65tNSRnaOVrsw9EOkOqxLrlUPenUYnJKNo,91
143
- nrl_tracker-0.20.0.dist-info/top_level.txt,sha256=17megxcrTPBWwPZTh6jTkwTKxX7No-ZqRpyvElnnO-s,6
144
- nrl_tracker-0.20.0.dist-info/RECORD,,
144
+ nrl_tracker-0.21.0.dist-info/LICENSE,sha256=rB5G4WppIIUzMOYr2N6uyYlNJ00hRJqE5tie6BMvYuE,1612
145
+ nrl_tracker-0.21.0.dist-info/METADATA,sha256=eDRPYJpt_3_IysLZ1cPPhRikpdZmtCd_1EF8Fmfyq6M,9699
146
+ nrl_tracker-0.21.0.dist-info/WHEEL,sha256=pL8R0wFFS65tNSRnaOVrsw9EOkOqxLrlUPenUYnJKNo,91
147
+ nrl_tracker-0.21.0.dist-info/top_level.txt,sha256=17megxcrTPBWwPZTh6jTkwTKxX7No-ZqRpyvElnnO-s,6
148
+ nrl_tracker-0.21.0.dist-info/RECORD,,
@@ -336,7 +336,8 @@ def romberg(
336
336
  f: Callable[[float], float],
337
337
  a: float,
338
338
  b: float,
339
- **kwargs,
339
+ tol: float = 1e-8,
340
+ max_steps: int = 20,
340
341
  ) -> float:
341
342
  """
342
343
  Romberg integration.
@@ -351,19 +352,47 @@ def romberg(
351
352
  Lower limit.
352
353
  b : float
353
354
  Upper limit.
354
- **kwargs
355
- Additional arguments passed to scipy.integrate.romberg.
355
+ tol : float, optional
356
+ Desired tolerance. Default is 1e-8.
357
+ max_steps : int, optional
358
+ Maximum number of extrapolation steps. Default is 20.
356
359
 
357
360
  Returns
358
361
  -------
359
362
  result : float
360
363
  Estimated integral value.
361
364
 
362
- See Also
363
- --------
364
- scipy.integrate.romberg : Underlying implementation.
365
+ Notes
366
+ -----
367
+ This is a native implementation that does not depend on scipy.integrate.romberg,
368
+ which was deprecated in scipy 1.12 and removed in scipy 1.15.
365
369
  """
366
- return float(integrate.romberg(f, a, b, **kwargs))
370
+ # Romberg table
371
+ R = np.zeros((max_steps, max_steps), dtype=np.float64)
372
+
373
+ h = b - a
374
+ R[0, 0] = 0.5 * h * (f(a) + f(b))
375
+
376
+ for i in range(1, max_steps):
377
+ h = h / 2.0
378
+
379
+ # Composite trapezoidal rule with 2^i intervals
380
+ n_new = 2 ** (i - 1)
381
+ total = 0.0
382
+ for k in range(1, n_new + 1):
383
+ total += f(a + (2 * k - 1) * h)
384
+ R[i, 0] = 0.5 * R[i - 1, 0] + h * total
385
+
386
+ # Richardson extrapolation
387
+ for j in range(1, i + 1):
388
+ factor = 4**j
389
+ R[i, j] = (factor * R[i, j - 1] - R[i - 1, j - 1]) / (factor - 1)
390
+
391
+ # Check convergence
392
+ if i > 0 and abs(R[i, i] - R[i - 1, i - 1]) < tol:
393
+ return float(R[i, i])
394
+
395
+ return float(R[max_steps - 1, max_steps - 1])
367
396
 
368
397
 
369
398
  def simpson(
@@ -7,19 +7,38 @@ physics, signal processing, and statistical applications:
7
7
  - Gamma and beta functions
8
8
  - Error functions
9
9
  - Elliptic integrals
10
+ - Marcum Q function (radar detection)
11
+ - Hypergeometric functions
12
+ - Lambert W function
13
+ - Debye functions (thermodynamics)
10
14
  """
11
15
 
12
16
  from pytcl.mathematical_functions.special_functions.bessel import (
13
17
  airy,
18
+ bessel_deriv,
19
+ bessel_ratio,
20
+ bessel_zeros,
14
21
  besselh,
15
22
  besseli,
16
23
  besselj,
17
24
  besselk,
18
25
  bessely,
26
+ kelvin,
19
27
  spherical_in,
20
28
  spherical_jn,
21
29
  spherical_kn,
22
30
  spherical_yn,
31
+ struve_h,
32
+ struve_l,
33
+ )
34
+ from pytcl.mathematical_functions.special_functions.debye import (
35
+ debye,
36
+ debye_1,
37
+ debye_2,
38
+ debye_3,
39
+ debye_4,
40
+ debye_entropy,
41
+ debye_heat_capacity,
23
42
  )
24
43
  from pytcl.mathematical_functions.special_functions.elliptic import ( # noqa: E501
25
44
  ellipe,
@@ -62,6 +81,32 @@ from pytcl.mathematical_functions.special_functions.gamma_functions import ( #
62
81
  perm,
63
82
  polygamma,
64
83
  )
84
+ from pytcl.mathematical_functions.special_functions.hypergeometric import (
85
+ falling_factorial,
86
+ generalized_hypergeometric,
87
+ hyp0f1,
88
+ hyp1f1,
89
+ hyp1f1_regularized,
90
+ hyp2f1,
91
+ hyperu,
92
+ pochhammer,
93
+ )
94
+ from pytcl.mathematical_functions.special_functions.lambert_w import (
95
+ lambert_w,
96
+ lambert_w_real,
97
+ omega_constant,
98
+ solve_exponential_equation,
99
+ time_delay_equation,
100
+ wright_omega,
101
+ )
102
+ from pytcl.mathematical_functions.special_functions.marcum_q import (
103
+ log_marcum_q,
104
+ marcum_q,
105
+ marcum_q1,
106
+ marcum_q_inv,
107
+ nuttall_q,
108
+ swerling_detection_probability,
109
+ )
65
110
 
66
111
  __all__ = [
67
112
  # Bessel functions
@@ -75,6 +120,12 @@ __all__ = [
75
120
  "spherical_in",
76
121
  "spherical_kn",
77
122
  "airy",
123
+ "bessel_ratio",
124
+ "bessel_deriv",
125
+ "bessel_zeros",
126
+ "struve_h",
127
+ "struve_l",
128
+ "kelvin",
78
129
  # Gamma functions
79
130
  "gamma",
80
131
  "gammaln",
@@ -113,4 +164,35 @@ __all__ = [
113
164
  "elliprg",
114
165
  "elliprj",
115
166
  "elliprc",
167
+ # Marcum Q function (radar detection)
168
+ "marcum_q",
169
+ "marcum_q1",
170
+ "log_marcum_q",
171
+ "marcum_q_inv",
172
+ "nuttall_q",
173
+ "swerling_detection_probability",
174
+ # Lambert W function
175
+ "lambert_w",
176
+ "lambert_w_real",
177
+ "omega_constant",
178
+ "wright_omega",
179
+ "solve_exponential_equation",
180
+ "time_delay_equation",
181
+ # Debye functions
182
+ "debye",
183
+ "debye_1",
184
+ "debye_2",
185
+ "debye_3",
186
+ "debye_4",
187
+ "debye_heat_capacity",
188
+ "debye_entropy",
189
+ # Hypergeometric functions
190
+ "hyp0f1",
191
+ "hyp1f1",
192
+ "hyp2f1",
193
+ "hyperu",
194
+ "hyp1f1_regularized",
195
+ "pochhammer",
196
+ "falling_factorial",
197
+ "generalized_hypergeometric",
116
198
  ]
@@ -345,6 +345,260 @@ def airy(x: ArrayLike) -> tuple:
345
345
  return tuple(np.asarray(r, dtype=np.float64) for r in result)
346
346
 
347
347
 
348
+ def bessel_ratio(
349
+ n: Union[int, float],
350
+ x: ArrayLike,
351
+ kind: str = "j",
352
+ ) -> NDArray[np.floating]:
353
+ """
354
+ Ratio of Bessel functions J_{n+1}(x) / J_n(x) or I_{n+1}(x) / I_n(x).
355
+
356
+ Parameters
357
+ ----------
358
+ n : int or float
359
+ Order of the Bessel function in the denominator.
360
+ x : array_like
361
+ Argument of the Bessel function.
362
+ kind : str, optional
363
+ Type of Bessel function: 'j' for J_n, 'i' for I_n. Default is 'j'.
364
+
365
+ Returns
366
+ -------
367
+ ratio : ndarray
368
+ Values of J_{n+1}(x) / J_n(x) or I_{n+1}(x) / I_n(x).
369
+
370
+ Notes
371
+ -----
372
+ Uses the recurrence relation for numerical stability:
373
+ J_{n+1}(x) / J_n(x) = 2n/x - 1/(J_n(x)/J_{n-1}(x))
374
+
375
+ Examples
376
+ --------
377
+ >>> bessel_ratio(0, 1) # J_1(1) / J_0(1)
378
+ 0.5767...
379
+ """
380
+ x = np.asarray(x, dtype=np.float64)
381
+
382
+ if kind.lower() == "j":
383
+ num = sp.jv(n + 1, x)
384
+ den = sp.jv(n, x)
385
+ elif kind.lower() == "i":
386
+ num = sp.iv(n + 1, x)
387
+ den = sp.iv(n, x)
388
+ else:
389
+ raise ValueError(f"kind must be 'j' or 'i', got '{kind}'")
390
+
391
+ # Handle zeros in denominator
392
+ with np.errstate(divide="ignore", invalid="ignore"):
393
+ ratio = np.where(den != 0, num / den, np.inf * np.sign(num))
394
+
395
+ return np.asarray(ratio, dtype=np.float64)
396
+
397
+
398
+ def bessel_deriv(
399
+ n: Union[int, float],
400
+ x: ArrayLike,
401
+ kind: str = "j",
402
+ ) -> NDArray[np.floating]:
403
+ """
404
+ Derivative of Bessel function d/dx[B_n(x)].
405
+
406
+ Parameters
407
+ ----------
408
+ n : int or float
409
+ Order of the Bessel function.
410
+ x : array_like
411
+ Argument of the Bessel function.
412
+ kind : str, optional
413
+ Type of Bessel function: 'j', 'y', 'i', or 'k'. Default is 'j'.
414
+
415
+ Returns
416
+ -------
417
+ deriv : ndarray
418
+ Values of dB_n(x)/dx.
419
+
420
+ Notes
421
+ -----
422
+ Uses the identity:
423
+ dJ_n/dx = (J_{n-1}(x) - J_{n+1}(x)) / 2
424
+ dY_n/dx = (Y_{n-1}(x) - Y_{n+1}(x)) / 2
425
+ dI_n/dx = (I_{n-1}(x) + I_{n+1}(x)) / 2
426
+ dK_n/dx = -(K_{n-1}(x) + K_{n+1}(x)) / 2
427
+
428
+ Examples
429
+ --------
430
+ >>> bessel_deriv(0, 1, kind='j') # -J_1(1)
431
+ -0.4400...
432
+ """
433
+ x = np.asarray(x, dtype=np.float64)
434
+
435
+ kind = kind.lower()
436
+ if kind == "j":
437
+ deriv = (sp.jv(n - 1, x) - sp.jv(n + 1, x)) / 2
438
+ elif kind == "y":
439
+ deriv = (sp.yv(n - 1, x) - sp.yv(n + 1, x)) / 2
440
+ elif kind == "i":
441
+ deriv = (sp.iv(n - 1, x) + sp.iv(n + 1, x)) / 2
442
+ elif kind == "k":
443
+ deriv = -(sp.kv(n - 1, x) + sp.kv(n + 1, x)) / 2
444
+ else:
445
+ raise ValueError(f"kind must be 'j', 'y', 'i', or 'k', got '{kind}'")
446
+
447
+ return np.asarray(deriv, dtype=np.float64)
448
+
449
+
450
+ def struve_h(
451
+ n: Union[int, float],
452
+ x: ArrayLike,
453
+ ) -> NDArray[np.floating]:
454
+ """
455
+ Struve function H_n(x).
456
+
457
+ The Struve function is defined by the integral:
458
+ H_n(x) = (2/sqrt(pi)) * (x/2)^n * integral from 0 to pi/2 of
459
+ sin(x*cos(t)) * sin^(2n)(t) dt
460
+
461
+ Parameters
462
+ ----------
463
+ n : int or float
464
+ Order of the Struve function.
465
+ x : array_like
466
+ Argument of the function.
467
+
468
+ Returns
469
+ -------
470
+ H : ndarray
471
+ Values of H_n(x).
472
+
473
+ Notes
474
+ -----
475
+ Related to Bessel functions through:
476
+ H_0(x) is the particular solution of y'' + y'/x + y = 2/(pi*x)
477
+
478
+ Examples
479
+ --------
480
+ >>> struve_h(0, 1)
481
+ 0.5688...
482
+ """
483
+ return np.asarray(sp.struve(n, x), dtype=np.float64)
484
+
485
+
486
+ def struve_l(
487
+ n: Union[int, float],
488
+ x: ArrayLike,
489
+ ) -> NDArray[np.floating]:
490
+ """
491
+ Modified Struve function L_n(x).
492
+
493
+ The modified Struve function is related to the Struve function by:
494
+ L_n(x) = -i * exp(-i*n*pi/2) * H_n(i*x)
495
+
496
+ Parameters
497
+ ----------
498
+ n : int or float
499
+ Order of the modified Struve function.
500
+ x : array_like
501
+ Argument of the function.
502
+
503
+ Returns
504
+ -------
505
+ L : ndarray
506
+ Values of L_n(x).
507
+ """
508
+ return np.asarray(sp.modstruve(n, x), dtype=np.float64)
509
+
510
+
511
+ def bessel_zeros(
512
+ n: int,
513
+ nt: int,
514
+ kind: str = "j",
515
+ ) -> NDArray[np.floating]:
516
+ """
517
+ Zeros of Bessel functions.
518
+
519
+ Computes the first nt zeros of J_n(x), Y_n(x), or their derivatives.
520
+
521
+ Parameters
522
+ ----------
523
+ n : int
524
+ Order of the Bessel function.
525
+ nt : int
526
+ Number of zeros to compute.
527
+ kind : str, optional
528
+ Type: 'j' for J_n zeros, 'y' for Y_n zeros,
529
+ 'jp' for J_n' zeros, 'yp' for Y_n' zeros. Default is 'j'.
530
+
531
+ Returns
532
+ -------
533
+ zeros : ndarray
534
+ Array of zeros.
535
+
536
+ Examples
537
+ --------
538
+ >>> bessel_zeros(0, 3, kind='j') # First 3 zeros of J_0
539
+ array([2.404..., 5.520..., 8.653...])
540
+ """
541
+ kind = kind.lower()
542
+
543
+ if kind == "j":
544
+ return np.asarray(sp.jn_zeros(n, nt), dtype=np.float64)
545
+ elif kind == "y":
546
+ return np.asarray(sp.yn_zeros(n, nt), dtype=np.float64)
547
+ elif kind == "jp":
548
+ return np.asarray(sp.jnp_zeros(n, nt), dtype=np.float64)
549
+ elif kind == "yp":
550
+ return np.asarray(sp.ynp_zeros(n, nt), dtype=np.float64)
551
+ else:
552
+ raise ValueError(f"kind must be 'j', 'y', 'jp', or 'yp', got '{kind}'")
553
+
554
+
555
+ def kelvin(
556
+ x: ArrayLike,
557
+ ) -> tuple:
558
+ """
559
+ Kelvin functions ber, bei, ker, kei.
560
+
561
+ Kelvin functions are the real and imaginary parts of the
562
+ Bessel functions with argument x*exp(3*pi*i/4).
563
+
564
+ Parameters
565
+ ----------
566
+ x : array_like
567
+ Argument of the Kelvin functions.
568
+
569
+ Returns
570
+ -------
571
+ ber : ndarray
572
+ Kelvin function ber(x).
573
+ bei : ndarray
574
+ Kelvin function bei(x).
575
+ ker : ndarray
576
+ Kelvin function ker(x).
577
+ kei : ndarray
578
+ Kelvin function kei(x).
579
+
580
+ Notes
581
+ -----
582
+ ber(x) + i*bei(x) = J_0(x * exp(3*pi*i/4))
583
+ ker(x) + i*kei(x) = K_0(x * exp(pi*i/4))
584
+
585
+ Examples
586
+ --------
587
+ >>> ber, bei, ker, kei = kelvin(1)
588
+ >>> ber
589
+ 0.984...
590
+ """
591
+ x = np.asarray(x, dtype=np.float64)
592
+
593
+ # Use the individual scipy Kelvin functions for real-valued results
594
+ ber = np.asarray(sp.ber(x), dtype=np.float64)
595
+ bei = np.asarray(sp.bei(x), dtype=np.float64)
596
+ ker = np.asarray(sp.ker(x), dtype=np.float64)
597
+ kei = np.asarray(sp.kei(x), dtype=np.float64)
598
+
599
+ return ber, bei, ker, kei
600
+
601
+
348
602
  __all__ = [
349
603
  "besselj",
350
604
  "bessely",
@@ -356,4 +610,10 @@ __all__ = [
356
610
  "spherical_in",
357
611
  "spherical_kn",
358
612
  "airy",
613
+ "bessel_ratio",
614
+ "bessel_deriv",
615
+ "struve_h",
616
+ "struve_l",
617
+ "bessel_zeros",
618
+ "kelvin",
359
619
  ]