nrl-tracker 1.9.1__py3-none-any.whl → 1.10.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.
- {nrl_tracker-1.9.1.dist-info → nrl_tracker-1.10.0.dist-info}/METADATA +49 -4
- {nrl_tracker-1.9.1.dist-info → nrl_tracker-1.10.0.dist-info}/RECORD +68 -60
- pytcl/__init__.py +2 -2
- pytcl/assignment_algorithms/gating.py +18 -0
- pytcl/assignment_algorithms/jpda.py +56 -0
- pytcl/assignment_algorithms/nd_assignment.py +65 -0
- pytcl/assignment_algorithms/network_flow.py +40 -0
- pytcl/astronomical/ephemerides.py +18 -0
- pytcl/astronomical/orbital_mechanics.py +131 -0
- pytcl/atmosphere/ionosphere.py +44 -0
- pytcl/atmosphere/models.py +29 -0
- pytcl/clustering/dbscan.py +9 -0
- pytcl/clustering/gaussian_mixture.py +20 -0
- pytcl/clustering/hierarchical.py +29 -0
- pytcl/clustering/kmeans.py +9 -0
- pytcl/coordinate_systems/conversions/geodetic.py +46 -0
- pytcl/coordinate_systems/conversions/spherical.py +35 -0
- pytcl/coordinate_systems/rotations/rotations.py +147 -0
- pytcl/core/__init__.py +16 -0
- pytcl/core/maturity.py +346 -0
- pytcl/core/optional_deps.py +20 -0
- pytcl/dynamic_estimation/gaussian_sum_filter.py +55 -0
- pytcl/dynamic_estimation/imm.py +29 -0
- pytcl/dynamic_estimation/information_filter.py +64 -0
- pytcl/dynamic_estimation/kalman/extended.py +56 -0
- pytcl/dynamic_estimation/kalman/linear.py +69 -0
- pytcl/dynamic_estimation/kalman/unscented.py +81 -0
- pytcl/dynamic_estimation/particle_filters/bootstrap.py +146 -0
- pytcl/dynamic_estimation/rbpf.py +51 -0
- pytcl/dynamic_estimation/smoothers.py +58 -0
- pytcl/dynamic_models/continuous_time/dynamics.py +104 -0
- pytcl/dynamic_models/discrete_time/coordinated_turn.py +6 -0
- pytcl/dynamic_models/discrete_time/singer.py +12 -0
- pytcl/dynamic_models/process_noise/coordinated_turn.py +46 -0
- pytcl/dynamic_models/process_noise/polynomial.py +6 -0
- pytcl/dynamic_models/process_noise/singer.py +52 -0
- pytcl/gpu/__init__.py +153 -0
- pytcl/gpu/ekf.py +425 -0
- pytcl/gpu/kalman.py +543 -0
- pytcl/gpu/matrix_utils.py +486 -0
- pytcl/gpu/particle_filter.py +568 -0
- pytcl/gpu/ukf.py +476 -0
- pytcl/gpu/utils.py +582 -0
- pytcl/gravity/clenshaw.py +60 -0
- pytcl/gravity/egm.py +47 -0
- pytcl/gravity/models.py +34 -0
- pytcl/gravity/spherical_harmonics.py +73 -0
- pytcl/gravity/tides.py +34 -0
- pytcl/mathematical_functions/numerical_integration/quadrature.py +85 -0
- pytcl/mathematical_functions/special_functions/bessel.py +55 -0
- pytcl/mathematical_functions/special_functions/elliptic.py +42 -0
- pytcl/mathematical_functions/special_functions/error_functions.py +49 -0
- pytcl/mathematical_functions/special_functions/gamma_functions.py +43 -0
- pytcl/mathematical_functions/special_functions/lambert_w.py +5 -0
- pytcl/mathematical_functions/special_functions/marcum_q.py +16 -0
- pytcl/navigation/geodesy.py +101 -2
- pytcl/navigation/great_circle.py +71 -0
- pytcl/navigation/rhumb.py +74 -0
- pytcl/performance_evaluation/estimation_metrics.py +70 -0
- pytcl/performance_evaluation/track_metrics.py +30 -0
- pytcl/static_estimation/maximum_likelihood.py +54 -0
- pytcl/static_estimation/robust.py +57 -0
- pytcl/terrain/dem.py +69 -0
- pytcl/terrain/visibility.py +65 -0
- pytcl/trackers/hypothesis.py +65 -0
- {nrl_tracker-1.9.1.dist-info → nrl_tracker-1.10.0.dist-info}/LICENSE +0 -0
- {nrl_tracker-1.9.1.dist-info → nrl_tracker-1.10.0.dist-info}/WHEEL +0 -0
- {nrl_tracker-1.9.1.dist-info → nrl_tracker-1.10.0.dist-info}/top_level.txt +0 -0
pytcl/gravity/egm.py
CHANGED
|
@@ -131,6 +131,12 @@ def get_data_dir() -> Path:
|
|
|
131
131
|
-------
|
|
132
132
|
Path
|
|
133
133
|
Path to the data directory.
|
|
134
|
+
|
|
135
|
+
Examples
|
|
136
|
+
--------
|
|
137
|
+
>>> data_dir = get_data_dir()
|
|
138
|
+
>>> str(data_dir).endswith('.pytcl/data') or 'PYTCL_DATA_DIR' in dir()
|
|
139
|
+
True
|
|
134
140
|
"""
|
|
135
141
|
env_dir = os.environ.get("PYTCL_DATA_DIR")
|
|
136
142
|
if env_dir:
|
|
@@ -242,6 +248,16 @@ def create_test_coefficients(n_max: int = 36) -> EGMCoefficients:
|
|
|
242
248
|
-------
|
|
243
249
|
EGMCoefficients
|
|
244
250
|
Test coefficient set.
|
|
251
|
+
|
|
252
|
+
Examples
|
|
253
|
+
--------
|
|
254
|
+
>>> coef = create_test_coefficients(n_max=10)
|
|
255
|
+
>>> coef.n_max
|
|
256
|
+
10
|
|
257
|
+
>>> coef.C[0, 0] # Central term
|
|
258
|
+
1.0
|
|
259
|
+
>>> abs(coef.C[2, 0]) > 0 # J2 term present
|
|
260
|
+
True
|
|
245
261
|
"""
|
|
246
262
|
C = np.zeros((n_max + 1, n_max + 1))
|
|
247
263
|
S = np.zeros((n_max + 1, n_max + 1))
|
|
@@ -496,6 +512,16 @@ def geoid_heights(
|
|
|
496
512
|
-------
|
|
497
513
|
ndarray
|
|
498
514
|
Geoid heights in meters.
|
|
515
|
+
|
|
516
|
+
Examples
|
|
517
|
+
--------
|
|
518
|
+
>>> import numpy as np
|
|
519
|
+
>>> coef = create_test_coefficients(n_max=10)
|
|
520
|
+
>>> lats = np.array([0.0, np.pi/4]) # Equator and 45°N
|
|
521
|
+
>>> lons = np.array([0.0, np.pi/2]) # Prime meridian and 90°E
|
|
522
|
+
>>> heights = geoid_heights(lats, lons, coefficients=coef)
|
|
523
|
+
>>> len(heights)
|
|
524
|
+
2
|
|
499
525
|
"""
|
|
500
526
|
# Load coefficients once
|
|
501
527
|
if coefficients is None:
|
|
@@ -543,6 +569,13 @@ def gravity_disturbance(
|
|
|
543
569
|
-------
|
|
544
570
|
GravityDisturbance
|
|
545
571
|
Gravity disturbance components.
|
|
572
|
+
|
|
573
|
+
Examples
|
|
574
|
+
--------
|
|
575
|
+
>>> coef = create_test_coefficients(n_max=10)
|
|
576
|
+
>>> dist = gravity_disturbance(0, 0, h=0, coefficients=coef)
|
|
577
|
+
>>> isinstance(dist.magnitude, float)
|
|
578
|
+
True
|
|
546
579
|
"""
|
|
547
580
|
if coefficients is None:
|
|
548
581
|
coefficients = load_egm_coefficients(model, n_max)
|
|
@@ -613,6 +646,13 @@ def gravity_anomaly(
|
|
|
613
646
|
-------
|
|
614
647
|
float
|
|
615
648
|
Gravity anomaly in m/s^2 (typically reported in mGal = 1e-5 m/s^2).
|
|
649
|
+
|
|
650
|
+
Examples
|
|
651
|
+
--------
|
|
652
|
+
>>> coef = create_test_coefficients(n_max=10)
|
|
653
|
+
>>> anomaly = gravity_anomaly(0, 0, h=0, coefficients=coef)
|
|
654
|
+
>>> isinstance(anomaly, float)
|
|
655
|
+
True
|
|
616
656
|
"""
|
|
617
657
|
disturbance = gravity_disturbance(lat, lon, h, model, n_max, coefficients)
|
|
618
658
|
|
|
@@ -657,6 +697,13 @@ def deflection_of_vertical(
|
|
|
657
697
|
-----
|
|
658
698
|
Positive xi means the plumb line points more north than the normal.
|
|
659
699
|
Positive eta means the plumb line points more east than the normal.
|
|
700
|
+
|
|
701
|
+
Examples
|
|
702
|
+
--------
|
|
703
|
+
>>> coef = create_test_coefficients(n_max=10)
|
|
704
|
+
>>> xi, eta = deflection_of_vertical(0, 0, coefficients=coef)
|
|
705
|
+
>>> isinstance(xi, float) and isinstance(eta, float)
|
|
706
|
+
True
|
|
660
707
|
"""
|
|
661
708
|
if coefficients is None:
|
|
662
709
|
coefficients = load_egm_coefficients(model, n_max)
|
pytcl/gravity/models.py
CHANGED
|
@@ -267,6 +267,12 @@ def gravity_j2(
|
|
|
267
267
|
-------
|
|
268
268
|
result : GravityResult
|
|
269
269
|
Gravity components and magnitude.
|
|
270
|
+
|
|
271
|
+
Examples
|
|
272
|
+
--------
|
|
273
|
+
>>> result = gravity_j2(0, 0, 0) # At equator, sea level
|
|
274
|
+
>>> abs(result.magnitude - 9.78) < 0.01
|
|
275
|
+
True
|
|
270
276
|
"""
|
|
271
277
|
GM = constants.GM
|
|
272
278
|
a = constants.a
|
|
@@ -328,6 +334,12 @@ def geoid_height_j2(
|
|
|
328
334
|
N : float
|
|
329
335
|
Geoid height (geoid - ellipsoid) in meters.
|
|
330
336
|
|
|
337
|
+
Examples
|
|
338
|
+
--------
|
|
339
|
+
>>> N = geoid_height_j2(0) # At equator
|
|
340
|
+
>>> N > 0 # Equator bulges outward
|
|
341
|
+
True
|
|
342
|
+
|
|
331
343
|
Notes
|
|
332
344
|
-----
|
|
333
345
|
This is a simplified model. For accurate geoid heights,
|
|
@@ -371,6 +383,12 @@ def gravitational_potential(
|
|
|
371
383
|
-------
|
|
372
384
|
U : float
|
|
373
385
|
Gravitational potential (m^2/s^2).
|
|
386
|
+
|
|
387
|
+
Examples
|
|
388
|
+
--------
|
|
389
|
+
>>> U = gravitational_potential(0, 0, 6.4e6) # Near Earth surface
|
|
390
|
+
>>> U < 0 # Potential is negative
|
|
391
|
+
True
|
|
374
392
|
"""
|
|
375
393
|
GM = constants.GM
|
|
376
394
|
a = constants.a
|
|
@@ -415,6 +433,14 @@ def free_air_anomaly(
|
|
|
415
433
|
delta_g : float
|
|
416
434
|
Free-air anomaly in m/s^2 (or mGal if multiplied by 1e5).
|
|
417
435
|
|
|
436
|
+
Examples
|
|
437
|
+
--------
|
|
438
|
+
>>> import numpy as np
|
|
439
|
+
>>> # Observed gravity slightly higher than normal
|
|
440
|
+
>>> delta_g = free_air_anomaly(9.81, np.radians(45), 100)
|
|
441
|
+
>>> isinstance(delta_g, float)
|
|
442
|
+
True
|
|
443
|
+
|
|
418
444
|
Notes
|
|
419
445
|
-----
|
|
420
446
|
The free-air anomaly is the difference between observed gravity
|
|
@@ -452,6 +478,14 @@ def bouguer_anomaly(
|
|
|
452
478
|
delta_g : float
|
|
453
479
|
Bouguer anomaly in m/s^2.
|
|
454
480
|
|
|
481
|
+
Examples
|
|
482
|
+
--------
|
|
483
|
+
>>> import numpy as np
|
|
484
|
+
>>> # Bouguer anomaly at mountain location
|
|
485
|
+
>>> delta_g = bouguer_anomaly(9.81, np.radians(45), 1000)
|
|
486
|
+
>>> isinstance(delta_g, float)
|
|
487
|
+
True
|
|
488
|
+
|
|
455
489
|
Notes
|
|
456
490
|
-----
|
|
457
491
|
The Bouguer anomaly removes the gravitational effect of the
|
|
@@ -157,6 +157,16 @@ def associated_legendre_derivative(
|
|
|
157
157
|
-------
|
|
158
158
|
dP : ndarray
|
|
159
159
|
Array of shape (n_max+1, m_max+1) containing dP_n^m/dx.
|
|
160
|
+
|
|
161
|
+
Examples
|
|
162
|
+
--------
|
|
163
|
+
>>> import numpy as np
|
|
164
|
+
>>> x = np.cos(np.radians(45)) # cos of 45 degrees
|
|
165
|
+
>>> dP = associated_legendre_derivative(2, 2, x)
|
|
166
|
+
>>> dP.shape
|
|
167
|
+
(3, 3)
|
|
168
|
+
>>> abs(dP[0, 0]) < 1e-10 # dP_0^0/dx = 0
|
|
169
|
+
True
|
|
160
170
|
"""
|
|
161
171
|
if P is None:
|
|
162
172
|
P = associated_legendre(n_max, m_max, x, normalized)
|
|
@@ -255,6 +265,18 @@ def spherical_harmonic_sum(
|
|
|
255
265
|
V = \\frac{GM}{r} \\sum_{n=0}^{N} \\left(\\frac{R}{r}\\right)^n
|
|
256
266
|
\\sum_{m=0}^{n} \\bar{P}_n^m(\\sin\\phi)
|
|
257
267
|
(C_{nm}\\cos m\\lambda + S_{nm}\\sin m\\lambda)
|
|
268
|
+
|
|
269
|
+
Examples
|
|
270
|
+
--------
|
|
271
|
+
>>> import numpy as np
|
|
272
|
+
>>> # Simple monopole (degree 0 only)
|
|
273
|
+
>>> C = np.array([[1.0]])
|
|
274
|
+
>>> S = np.array([[0.0]])
|
|
275
|
+
>>> R = 6.378e6 # meters
|
|
276
|
+
>>> GM = 3.986e14 # m^3/s^2
|
|
277
|
+
>>> V, dV_r, dV_lat = spherical_harmonic_sum(0, 0, R, C, S, R, GM, n_max=0)
|
|
278
|
+
>>> abs(V - GM/R) / (GM/R) < 1e-10 # V = GM/r for degree 0
|
|
279
|
+
True
|
|
258
280
|
"""
|
|
259
281
|
if n_max is None:
|
|
260
282
|
n_max = C.shape[0] - 1
|
|
@@ -382,6 +404,18 @@ def gravity_acceleration(
|
|
|
382
404
|
Northward component of gravity.
|
|
383
405
|
g_lon : float
|
|
384
406
|
Eastward component of gravity.
|
|
407
|
+
|
|
408
|
+
Examples
|
|
409
|
+
--------
|
|
410
|
+
>>> import numpy as np
|
|
411
|
+
>>> # Simple monopole field
|
|
412
|
+
>>> C = np.array([[1.0]])
|
|
413
|
+
>>> S = np.array([[0.0]])
|
|
414
|
+
>>> R = 6.378e6
|
|
415
|
+
>>> GM = 3.986e14
|
|
416
|
+
>>> g_r, g_lat, g_lon = gravity_acceleration(0, 0, 0, C, S, R, GM, n_max=0)
|
|
417
|
+
>>> g_r < 0 # Gravity points inward (negative radial)
|
|
418
|
+
True
|
|
385
419
|
"""
|
|
386
420
|
# Approximate radial distance (simplified, ignoring ellipsoid flattening)
|
|
387
421
|
r = R + h
|
|
@@ -427,6 +461,18 @@ def legendre_scaling_factors(n_max: int) -> NDArray[np.floating]:
|
|
|
427
461
|
Clenshaw summation and the recursive computation of very high
|
|
428
462
|
degree and order normalised associated Legendre functions."
|
|
429
463
|
Journal of Geodesy 76.5 (2002): 279-299.
|
|
464
|
+
|
|
465
|
+
Examples
|
|
466
|
+
--------
|
|
467
|
+
>>> scale = legendre_scaling_factors(100)
|
|
468
|
+
>>> len(scale)
|
|
469
|
+
101
|
|
470
|
+
>>> scale[0] # No scaling for low degrees
|
|
471
|
+
1.0
|
|
472
|
+
|
|
473
|
+
>>> scale_high = legendre_scaling_factors(200)
|
|
474
|
+
>>> scale_high[200] < scale_high[0] # Higher degrees scaled down
|
|
475
|
+
True
|
|
430
476
|
"""
|
|
431
477
|
scale = np.ones(n_max + 1)
|
|
432
478
|
|
|
@@ -480,6 +526,16 @@ def associated_legendre_scaled(
|
|
|
480
526
|
|
|
481
527
|
For normal operations (n < 150), scale_exp is all zeros and
|
|
482
528
|
P_scaled equals the actual Legendre values.
|
|
529
|
+
|
|
530
|
+
Examples
|
|
531
|
+
--------
|
|
532
|
+
>>> import numpy as np
|
|
533
|
+
>>> x = np.cos(np.radians(45))
|
|
534
|
+
>>> P_scaled, scale_exp = associated_legendre_scaled(10, 10, x)
|
|
535
|
+
>>> P_scaled.shape
|
|
536
|
+
(11, 11)
|
|
537
|
+
>>> all(scale_exp == 0) # No scaling needed for n_max < 150
|
|
538
|
+
True
|
|
483
539
|
"""
|
|
484
540
|
if m_max > n_max:
|
|
485
541
|
raise ValueError("m_max must be <= n_max")
|
|
@@ -538,6 +594,15 @@ def clear_legendre_cache() -> None:
|
|
|
538
594
|
Call this function to clear the cached associated Legendre
|
|
539
595
|
polynomial arrays. Useful when memory is constrained or after
|
|
540
596
|
processing a batch with different colatitude values.
|
|
597
|
+
|
|
598
|
+
Examples
|
|
599
|
+
--------
|
|
600
|
+
>>> _ = associated_legendre(10, 10, 0.5) # Populate cache
|
|
601
|
+
>>> info = get_legendre_cache_info()
|
|
602
|
+
>>> clear_legendre_cache()
|
|
603
|
+
>>> info_after = get_legendre_cache_info()
|
|
604
|
+
>>> info_after.currsize
|
|
605
|
+
0
|
|
541
606
|
"""
|
|
542
607
|
_associated_legendre_cached.cache_clear()
|
|
543
608
|
_logger.debug("Legendre polynomial cache cleared")
|
|
@@ -550,6 +615,14 @@ def get_legendre_cache_info() -> Any:
|
|
|
550
615
|
-------
|
|
551
616
|
CacheInfo
|
|
552
617
|
Named tuple with hits, misses, maxsize, currsize.
|
|
618
|
+
|
|
619
|
+
Examples
|
|
620
|
+
--------
|
|
621
|
+
>>> clear_legendre_cache() # Start fresh
|
|
622
|
+
>>> _ = associated_legendre(5, 5, 0.5)
|
|
623
|
+
>>> info = get_legendre_cache_info()
|
|
624
|
+
>>> info.currsize >= 1 # At least one entry cached
|
|
625
|
+
True
|
|
553
626
|
"""
|
|
554
627
|
return _associated_legendre_cached.cache_info()
|
|
555
628
|
|
pytcl/gravity/tides.py
CHANGED
|
@@ -142,6 +142,15 @@ def julian_centuries_j2000(mjd: float) -> float:
|
|
|
142
142
|
-------
|
|
143
143
|
T : float
|
|
144
144
|
Julian centuries since J2000.0.
|
|
145
|
+
|
|
146
|
+
Examples
|
|
147
|
+
--------
|
|
148
|
+
>>> T = julian_centuries_j2000(51544.5) # J2000.0 epoch
|
|
149
|
+
>>> abs(T) < 1e-10 # Should be zero at J2000
|
|
150
|
+
True
|
|
151
|
+
>>> T = julian_centuries_j2000(51544.5 + 36525) # One century later
|
|
152
|
+
>>> abs(T - 1.0) < 1e-10
|
|
153
|
+
True
|
|
145
154
|
"""
|
|
146
155
|
# J2000.0 = JD 2451545.0 = MJD 51544.5
|
|
147
156
|
return (mjd - 51544.5) / 36525.0
|
|
@@ -172,6 +181,14 @@ def fundamental_arguments(T: float) -> Tuple[float, float, float, float, float]:
|
|
|
172
181
|
Notes
|
|
173
182
|
-----
|
|
174
183
|
Based on IERS Conventions (2010) expressions.
|
|
184
|
+
|
|
185
|
+
Examples
|
|
186
|
+
--------
|
|
187
|
+
>>> import numpy as np
|
|
188
|
+
>>> T = 0.0 # J2000.0
|
|
189
|
+
>>> l, lp, F, D, Om = fundamental_arguments(T)
|
|
190
|
+
>>> all(0 <= x < 2*np.pi for x in [l, lp, F, D, Om]) # All in [0, 2pi)
|
|
191
|
+
True
|
|
175
192
|
"""
|
|
176
193
|
# Convert degrees to radians
|
|
177
194
|
deg2rad = np.pi / 180.0
|
|
@@ -241,6 +258,15 @@ def moon_position_approximate(mjd: float) -> Tuple[float, float, float]:
|
|
|
241
258
|
Notes
|
|
242
259
|
-----
|
|
243
260
|
Low-precision formula adequate for tidal computations.
|
|
261
|
+
|
|
262
|
+
Examples
|
|
263
|
+
--------
|
|
264
|
+
>>> r, lat, lon = moon_position_approximate(58000)
|
|
265
|
+
>>> 350000e3 < r < 410000e3 # Distance in km range
|
|
266
|
+
True
|
|
267
|
+
>>> import numpy as np
|
|
268
|
+
>>> -np.pi/2 <= lat <= np.pi/2 # Valid latitude
|
|
269
|
+
True
|
|
244
270
|
"""
|
|
245
271
|
T = julian_centuries_j2000(mjd)
|
|
246
272
|
|
|
@@ -313,6 +339,14 @@ def sun_position_approximate(mjd: float) -> Tuple[float, float, float]:
|
|
|
313
339
|
Notes
|
|
314
340
|
-----
|
|
315
341
|
Low-precision formula adequate for tidal computations.
|
|
342
|
+
|
|
343
|
+
Examples
|
|
344
|
+
--------
|
|
345
|
+
>>> r, lat, lon = sun_position_approximate(58000)
|
|
346
|
+
>>> 1.47e11 < r < 1.52e11 # Distance ~1 AU
|
|
347
|
+
True
|
|
348
|
+
>>> lat == 0.0 # Sun on ecliptic
|
|
349
|
+
True
|
|
316
350
|
"""
|
|
317
351
|
T = julian_centuries_j2000(mjd)
|
|
318
352
|
|
|
@@ -71,6 +71,14 @@ def gauss_hermite(
|
|
|
71
71
|
w : ndarray
|
|
72
72
|
Quadrature weights of shape (n,).
|
|
73
73
|
|
|
74
|
+
Examples
|
|
75
|
+
--------
|
|
76
|
+
>>> x, w = gauss_hermite(5)
|
|
77
|
+
>>> # Compute E[X^2] for X ~ N(0, 1) (exact = 1)
|
|
78
|
+
>>> result = np.sum(w * (np.sqrt(2) * x)**2) / np.sqrt(np.pi)
|
|
79
|
+
>>> abs(result - 1.0) < 1e-10
|
|
80
|
+
True
|
|
81
|
+
|
|
74
82
|
Notes
|
|
75
83
|
-----
|
|
76
84
|
For computing E[f(X)] where X ~ N(μ, σ²):
|
|
@@ -105,6 +113,13 @@ def gauss_laguerre(
|
|
|
105
113
|
w : ndarray
|
|
106
114
|
Quadrature weights of shape (n,).
|
|
107
115
|
|
|
116
|
+
Examples
|
|
117
|
+
--------
|
|
118
|
+
>>> x, w = gauss_laguerre(5)
|
|
119
|
+
>>> # Integrate x * exp(-x) from 0 to inf (exact = 1)
|
|
120
|
+
>>> np.sum(w * x)
|
|
121
|
+
1.0
|
|
122
|
+
|
|
108
123
|
See Also
|
|
109
124
|
--------
|
|
110
125
|
numpy.polynomial.laguerre.laggauss : Equivalent function.
|
|
@@ -137,6 +152,12 @@ def gauss_chebyshev(
|
|
|
137
152
|
w : ndarray
|
|
138
153
|
Quadrature weights of shape (n,).
|
|
139
154
|
|
|
155
|
+
Examples
|
|
156
|
+
--------
|
|
157
|
+
>>> x, w = gauss_chebyshev(5, kind=1)
|
|
158
|
+
>>> x.shape
|
|
159
|
+
(5,)
|
|
160
|
+
|
|
140
161
|
See Also
|
|
141
162
|
--------
|
|
142
163
|
numpy.polynomial.chebyshev.chebgauss : Type 1 Chebyshev.
|
|
@@ -232,6 +253,13 @@ def dblquad(
|
|
|
232
253
|
error : float
|
|
233
254
|
Estimate of the absolute error.
|
|
234
255
|
|
|
256
|
+
Examples
|
|
257
|
+
--------
|
|
258
|
+
>>> # Integrate x*y over unit square
|
|
259
|
+
>>> result, error = dblquad(lambda y, x: x*y, 0, 1, lambda x: 0, lambda x: 1)
|
|
260
|
+
>>> result # Should be 0.25
|
|
261
|
+
0.25
|
|
262
|
+
|
|
235
263
|
See Also
|
|
236
264
|
--------
|
|
237
265
|
scipy.integrate.dblquad : Underlying implementation.
|
|
@@ -281,6 +309,18 @@ def tplquad(
|
|
|
281
309
|
error : float
|
|
282
310
|
Estimate of the absolute error.
|
|
283
311
|
|
|
312
|
+
Examples
|
|
313
|
+
--------
|
|
314
|
+
>>> # Integrate x*y*z over unit cube
|
|
315
|
+
>>> result, error = tplquad(
|
|
316
|
+
... lambda z, y, x: x*y*z,
|
|
317
|
+
... 0, 1,
|
|
318
|
+
... lambda x: 0, lambda x: 1,
|
|
319
|
+
... lambda x, y: 0, lambda x, y: 1
|
|
320
|
+
... )
|
|
321
|
+
>>> abs(result - 0.125) < 1e-6 # 1/8
|
|
322
|
+
True
|
|
323
|
+
|
|
284
324
|
See Also
|
|
285
325
|
--------
|
|
286
326
|
scipy.integrate.tplquad : Underlying implementation.
|
|
@@ -362,6 +402,13 @@ def romberg(
|
|
|
362
402
|
result : float
|
|
363
403
|
Estimated integral value.
|
|
364
404
|
|
|
405
|
+
Examples
|
|
406
|
+
--------
|
|
407
|
+
>>> # Integrate x^2 from 0 to 1 (exact = 1/3)
|
|
408
|
+
>>> result = romberg(lambda x: x**2, 0, 1)
|
|
409
|
+
>>> abs(result - 1/3) < 1e-8
|
|
410
|
+
True
|
|
411
|
+
|
|
365
412
|
Notes
|
|
366
413
|
-----
|
|
367
414
|
This is a native implementation that does not depend on scipy.integrate.romberg,
|
|
@@ -417,6 +464,15 @@ def simpson(
|
|
|
417
464
|
result : float
|
|
418
465
|
Estimated integral.
|
|
419
466
|
|
|
467
|
+
Examples
|
|
468
|
+
--------
|
|
469
|
+
>>> import numpy as np
|
|
470
|
+
>>> x = np.linspace(0, np.pi, 101)
|
|
471
|
+
>>> y = np.sin(x)
|
|
472
|
+
>>> result = simpson(y, x) # Should be ~2.0
|
|
473
|
+
>>> abs(result - 2.0) < 1e-5
|
|
474
|
+
True
|
|
475
|
+
|
|
420
476
|
See Also
|
|
421
477
|
--------
|
|
422
478
|
scipy.integrate.simpson : Underlying implementation.
|
|
@@ -446,6 +502,15 @@ def trapezoid(
|
|
|
446
502
|
result : float
|
|
447
503
|
Estimated integral.
|
|
448
504
|
|
|
505
|
+
Examples
|
|
506
|
+
--------
|
|
507
|
+
>>> import numpy as np
|
|
508
|
+
>>> x = np.linspace(0, 1, 11)
|
|
509
|
+
>>> y = x**2 # Integrate x^2 from 0 to 1
|
|
510
|
+
>>> result = trapezoid(y, x)
|
|
511
|
+
>>> abs(result - 1/3) < 0.01 # Approximation
|
|
512
|
+
True
|
|
513
|
+
|
|
449
514
|
See Also
|
|
450
515
|
--------
|
|
451
516
|
scipy.integrate.trapezoid : Underlying implementation.
|
|
@@ -534,6 +599,16 @@ def spherical_cubature(
|
|
|
534
599
|
References
|
|
535
600
|
----------
|
|
536
601
|
Arasaratnam & Haykin, "Cubature Kalman Filters", IEEE TAC, 2009.
|
|
602
|
+
|
|
603
|
+
Examples
|
|
604
|
+
--------
|
|
605
|
+
>>> points, weights = spherical_cubature(3)
|
|
606
|
+
>>> points.shape # 2*n = 6 points in 3D
|
|
607
|
+
(6, 3)
|
|
608
|
+
>>> weights.shape
|
|
609
|
+
(6,)
|
|
610
|
+
>>> np.sum(weights) # Weights sum to 1
|
|
611
|
+
1.0
|
|
537
612
|
"""
|
|
538
613
|
# Points at ±√n along each axis
|
|
539
614
|
sqrt_n = np.sqrt(n_dim)
|
|
@@ -592,6 +667,16 @@ def unscented_transform_points(
|
|
|
592
667
|
----------
|
|
593
668
|
Julier & Uhlmann, "Unscented Filtering and Nonlinear Estimation",
|
|
594
669
|
Proc. IEEE, 2004.
|
|
670
|
+
|
|
671
|
+
Examples
|
|
672
|
+
--------
|
|
673
|
+
>>> sigma_points, wm, wc = unscented_transform_points(3)
|
|
674
|
+
>>> sigma_points.shape # 2*n+1 = 7 points in 3D
|
|
675
|
+
(7, 3)
|
|
676
|
+
>>> wm.shape
|
|
677
|
+
(7,)
|
|
678
|
+
>>> np.abs(np.sum(wm) - 1.0) < 1e-10 # Mean weights sum to 1
|
|
679
|
+
True
|
|
595
680
|
"""
|
|
596
681
|
if kappa is None:
|
|
597
682
|
kappa = 3.0 - n_dim
|
|
@@ -72,6 +72,11 @@ def bessely(
|
|
|
72
72
|
-----
|
|
73
73
|
Y_n(x) is singular at x = 0.
|
|
74
74
|
|
|
75
|
+
Examples
|
|
76
|
+
--------
|
|
77
|
+
>>> bessely(0, 1)
|
|
78
|
+
0.088...
|
|
79
|
+
|
|
75
80
|
See Also
|
|
76
81
|
--------
|
|
77
82
|
scipy.special.yv : Bessel function of second kind of real order.
|
|
@@ -137,6 +142,13 @@ def besselk(
|
|
|
137
142
|
-----
|
|
138
143
|
K_n(x) is singular at x = 0.
|
|
139
144
|
|
|
145
|
+
Examples
|
|
146
|
+
--------
|
|
147
|
+
>>> besselk(0, 1)
|
|
148
|
+
0.421...
|
|
149
|
+
>>> besselk(1, 2)
|
|
150
|
+
0.139...
|
|
151
|
+
|
|
140
152
|
See Also
|
|
141
153
|
--------
|
|
142
154
|
scipy.special.kv : Modified Bessel function of second kind.
|
|
@@ -174,6 +186,14 @@ def besselh(
|
|
|
174
186
|
H^(1)_n(x) = J_n(x) + i*Y_n(x)
|
|
175
187
|
H^(2)_n(x) = J_n(x) - i*Y_n(x)
|
|
176
188
|
|
|
189
|
+
Examples
|
|
190
|
+
--------
|
|
191
|
+
>>> h = besselh(0, 1, 1) # H^(1)_0(1)
|
|
192
|
+
>>> h.real
|
|
193
|
+
0.765...
|
|
194
|
+
>>> h.imag
|
|
195
|
+
0.088...
|
|
196
|
+
|
|
177
197
|
See Also
|
|
178
198
|
--------
|
|
179
199
|
scipy.special.hankel1 : Hankel function of first kind.
|
|
@@ -215,6 +235,13 @@ def spherical_jn(
|
|
|
215
235
|
-----
|
|
216
236
|
j_n(x) = sqrt(pi / (2*x)) * J_{n+1/2}(x)
|
|
217
237
|
|
|
238
|
+
Examples
|
|
239
|
+
--------
|
|
240
|
+
>>> spherical_jn(0, 1) # sin(1)/1
|
|
241
|
+
0.841...
|
|
242
|
+
>>> spherical_jn(0, 1, derivative=True) # Derivative
|
|
243
|
+
0.301...
|
|
244
|
+
|
|
218
245
|
See Also
|
|
219
246
|
--------
|
|
220
247
|
scipy.special.spherical_jn : Spherical Bessel function of first kind.
|
|
@@ -246,6 +273,11 @@ def spherical_yn(
|
|
|
246
273
|
y : ndarray
|
|
247
274
|
Values of y_n(x) or y_n'(x).
|
|
248
275
|
|
|
276
|
+
Examples
|
|
277
|
+
--------
|
|
278
|
+
>>> spherical_yn(0, 1) # -cos(1)/1
|
|
279
|
+
-0.540...
|
|
280
|
+
|
|
249
281
|
See Also
|
|
250
282
|
--------
|
|
251
283
|
scipy.special.spherical_yn : Spherical Bessel function of second kind.
|
|
@@ -277,6 +309,11 @@ def spherical_in(
|
|
|
277
309
|
i : ndarray
|
|
278
310
|
Values of i_n(x) or i_n'(x).
|
|
279
311
|
|
|
312
|
+
Examples
|
|
313
|
+
--------
|
|
314
|
+
>>> spherical_in(0, 1) # sinh(1)/1
|
|
315
|
+
1.175...
|
|
316
|
+
|
|
280
317
|
See Also
|
|
281
318
|
--------
|
|
282
319
|
scipy.special.spherical_in : Modified spherical Bessel function of first kind.
|
|
@@ -308,6 +345,11 @@ def spherical_kn(
|
|
|
308
345
|
k : ndarray
|
|
309
346
|
Values of k_n(x) or k_n'(x).
|
|
310
347
|
|
|
348
|
+
Examples
|
|
349
|
+
--------
|
|
350
|
+
>>> spherical_kn(0, 1) # (pi/2) * exp(-1)
|
|
351
|
+
0.578...
|
|
352
|
+
|
|
311
353
|
See Also
|
|
312
354
|
--------
|
|
313
355
|
scipy.special.spherical_kn : Modified spherical Bessel function of second kind.
|
|
@@ -344,6 +386,14 @@ def airy(
|
|
|
344
386
|
Bip : ndarray
|
|
345
387
|
Derivative of Airy function Bi'(x).
|
|
346
388
|
|
|
389
|
+
Examples
|
|
390
|
+
--------
|
|
391
|
+
>>> Ai, Aip, Bi, Bip = airy(0)
|
|
392
|
+
>>> Ai
|
|
393
|
+
0.355...
|
|
394
|
+
>>> Bi
|
|
395
|
+
0.614...
|
|
396
|
+
|
|
347
397
|
See Also
|
|
348
398
|
--------
|
|
349
399
|
scipy.special.airy : Airy functions.
|
|
@@ -511,6 +561,11 @@ def struve_l(
|
|
|
511
561
|
-------
|
|
512
562
|
L : ndarray
|
|
513
563
|
Values of L_n(x).
|
|
564
|
+
|
|
565
|
+
Examples
|
|
566
|
+
--------
|
|
567
|
+
>>> struve_l(0, 1)
|
|
568
|
+
0.710...
|
|
514
569
|
"""
|
|
515
570
|
return np.asarray(sp.modstruve(n, x), dtype=np.float64)
|
|
516
571
|
|
|
@@ -61,6 +61,11 @@ def ellipkm1(p: ArrayLike) -> NDArray[np.floating]:
|
|
|
61
61
|
K : ndarray
|
|
62
62
|
Values of K(1 - p).
|
|
63
63
|
|
|
64
|
+
Examples
|
|
65
|
+
--------
|
|
66
|
+
>>> ellipkm1(0.1) # K(0.9)
|
|
67
|
+
2.578...
|
|
68
|
+
|
|
64
69
|
See Also
|
|
65
70
|
--------
|
|
66
71
|
scipy.special.ellipkm1 : Elliptic integral near m = 1.
|
|
@@ -117,6 +122,12 @@ def ellipeinc(phi: ArrayLike, m: ArrayLike) -> NDArray[np.floating]:
|
|
|
117
122
|
E : ndarray
|
|
118
123
|
Values of the incomplete elliptic integral of the second kind.
|
|
119
124
|
|
|
125
|
+
Examples
|
|
126
|
+
--------
|
|
127
|
+
>>> import numpy as np
|
|
128
|
+
>>> ellipeinc(np.pi/2, 0) # Same as ellipe(0) = π/2
|
|
129
|
+
1.5707...
|
|
130
|
+
|
|
120
131
|
See Also
|
|
121
132
|
--------
|
|
122
133
|
scipy.special.ellipeinc : Incomplete elliptic integral of second kind.
|
|
@@ -142,6 +153,12 @@ def ellipkinc(phi: ArrayLike, m: ArrayLike) -> NDArray[np.floating]:
|
|
|
142
153
|
F : ndarray
|
|
143
154
|
Values of the incomplete elliptic integral of the first kind.
|
|
144
155
|
|
|
156
|
+
Examples
|
|
157
|
+
--------
|
|
158
|
+
>>> import numpy as np
|
|
159
|
+
>>> ellipkinc(np.pi/2, 0) # Same as ellipk(0) = π/2
|
|
160
|
+
1.5707...
|
|
161
|
+
|
|
145
162
|
See Also
|
|
146
163
|
--------
|
|
147
164
|
scipy.special.ellipkinc : Incomplete elliptic integral of first kind.
|
|
@@ -170,6 +187,11 @@ def elliprd(x: ArrayLike, y: ArrayLike, z: ArrayLike) -> NDArray[np.floating]:
|
|
|
170
187
|
R_D : ndarray
|
|
171
188
|
Values of the Carlson R_D integral.
|
|
172
189
|
|
|
190
|
+
Examples
|
|
191
|
+
--------
|
|
192
|
+
>>> elliprd(1, 2, 3)
|
|
193
|
+
0.297...
|
|
194
|
+
|
|
173
195
|
See Also
|
|
174
196
|
--------
|
|
175
197
|
scipy.special.elliprd : Carlson R_D integral.
|
|
@@ -204,6 +226,11 @@ def elliprf(x: ArrayLike, y: ArrayLike, z: ArrayLike) -> NDArray[np.floating]:
|
|
|
204
226
|
The complete elliptic integral of the first kind is:
|
|
205
227
|
K(m) = R_F(0, 1-m, 1)
|
|
206
228
|
|
|
229
|
+
Examples
|
|
230
|
+
--------
|
|
231
|
+
>>> elliprf(1, 1, 1) # R_F(a, a, a) = 1/sqrt(a)
|
|
232
|
+
1.0
|
|
233
|
+
|
|
207
234
|
See Also
|
|
208
235
|
--------
|
|
209
236
|
scipy.special.elliprf : Carlson R_F integral.
|
|
@@ -236,6 +263,11 @@ def elliprg(x: ArrayLike, y: ArrayLike, z: ArrayLike) -> NDArray[np.floating]:
|
|
|
236
263
|
The complete elliptic integral of the second kind is:
|
|
237
264
|
E(m) = 2 * R_G(0, 1-m, 1)
|
|
238
265
|
|
|
266
|
+
Examples
|
|
267
|
+
--------
|
|
268
|
+
>>> elliprg(1, 1, 1) # R_G(a, a, a) = sqrt(a)
|
|
269
|
+
1.0
|
|
270
|
+
|
|
239
271
|
See Also
|
|
240
272
|
--------
|
|
241
273
|
scipy.special.elliprg : Carlson R_G integral.
|
|
@@ -272,6 +304,11 @@ def elliprj(
|
|
|
272
304
|
-----
|
|
273
305
|
The complete elliptic integral of the third kind can be computed using R_J.
|
|
274
306
|
|
|
307
|
+
Examples
|
|
308
|
+
--------
|
|
309
|
+
>>> elliprj(1, 2, 3, 4)
|
|
310
|
+
0.213...
|
|
311
|
+
|
|
275
312
|
See Also
|
|
276
313
|
--------
|
|
277
314
|
scipy.special.elliprj : Carlson R_J integral.
|
|
@@ -302,6 +339,11 @@ def elliprc(x: ArrayLike, y: ArrayLike) -> NDArray[np.floating]:
|
|
|
302
339
|
- R_C(x, y) = arctan(sqrt((x-y)/y)) / sqrt(x-y) for x > y
|
|
303
340
|
- R_C(x, y) = arctanh(sqrt((y-x)/y)) / sqrt(y-x) for x < y
|
|
304
341
|
|
|
342
|
+
Examples
|
|
343
|
+
--------
|
|
344
|
+
>>> elliprc(1, 1) # R_C(a, a) = 1/sqrt(a)
|
|
345
|
+
1.0
|
|
346
|
+
|
|
305
347
|
See Also
|
|
306
348
|
--------
|
|
307
349
|
scipy.special.elliprc : Carlson R_C integral.
|