arepytools 1.7.6__tar.gz
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.
- arepytools-1.7.6/.gitignore +35 -0
- arepytools-1.7.6/LICENSE.txt +21 -0
- arepytools-1.7.6/PKG-INFO +64 -0
- arepytools-1.7.6/README.md +2 -0
- arepytools-1.7.6/arepytools/__init__.py +8 -0
- arepytools-1.7.6/arepytools/constants.py +109 -0
- arepytools-1.7.6/arepytools/geometry/__init__.py +6 -0
- arepytools-1.7.6/arepytools/geometry/_geodetic.py +107 -0
- arepytools-1.7.6/arepytools/geometry/_interpolator.py +210 -0
- arepytools-1.7.6/arepytools/geometry/anx_time.py +134 -0
- arepytools-1.7.6/arepytools/geometry/attitude_utils.py +88 -0
- arepytools-1.7.6/arepytools/geometry/conversions.py +120 -0
- arepytools-1.7.6/arepytools/geometry/curve.py +344 -0
- arepytools-1.7.6/arepytools/geometry/curve_protocols.py +113 -0
- arepytools-1.7.6/arepytools/geometry/direct_geocoding.py +1062 -0
- arepytools-1.7.6/arepytools/geometry/ellipsoid.py +233 -0
- arepytools-1.7.6/arepytools/geometry/generalsarattitude.py +528 -0
- arepytools-1.7.6/arepytools/geometry/generalsarorbit.py +831 -0
- arepytools-1.7.6/arepytools/geometry/geometric_functions.py +493 -0
- arepytools-1.7.6/arepytools/geometry/inverse_geocoding.py +315 -0
- arepytools-1.7.6/arepytools/geometry/inverse_geocoding_core.py +806 -0
- arepytools-1.7.6/arepytools/geometry/orbit.py +160 -0
- arepytools-1.7.6/arepytools/geometry/reference_frames.py +289 -0
- arepytools-1.7.6/arepytools/geometry/rotation.py +144 -0
- arepytools-1.7.6/arepytools/geometry/wgs84.py +22 -0
- arepytools-1.7.6/arepytools/io/__init__.py +59 -0
- arepytools-1.7.6/arepytools/io/channel.py +513 -0
- arepytools-1.7.6/arepytools/io/channel_iteration.py +147 -0
- arepytools-1.7.6/arepytools/io/create_orbit.py +35 -0
- arepytools-1.7.6/arepytools/io/debugio.py +65 -0
- arepytools-1.7.6/arepytools/io/io_support.py +683 -0
- arepytools-1.7.6/arepytools/io/manifest.py +100 -0
- arepytools-1.7.6/arepytools/io/metadata.py +2679 -0
- arepytools-1.7.6/arepytools/io/parsing/__init__.py +6 -0
- arepytools-1.7.6/arepytools/io/parsing/metadata_models/__init__.py +93 -0
- arepytools-1.7.6/arepytools/io/parsing/metadata_models/aresys_generic_metadata.py +222 -0
- arepytools-1.7.6/arepytools/io/parsing/metadata_models/aresys_types.py +3391 -0
- arepytools-1.7.6/arepytools/io/parsing/metadata_parsing.py +49 -0
- arepytools-1.7.6/arepytools/io/parsing/parsing.py +70 -0
- arepytools-1.7.6/arepytools/io/parsing/translate.py +1701 -0
- arepytools-1.7.6/arepytools/io/point_target_binary.py +406 -0
- arepytools-1.7.6/arepytools/io/point_target_file.py +299 -0
- arepytools-1.7.6/arepytools/io/point_target_models/__init__.py +25 -0
- arepytools-1.7.6/arepytools/io/point_target_models/aresys_point_target_models.py +181 -0
- arepytools-1.7.6/arepytools/io/productfolder.py +467 -0
- arepytools-1.7.6/arepytools/io/productfolder2.py +538 -0
- arepytools-1.7.6/arepytools/io/productfolder_layout.py +184 -0
- arepytools-1.7.6/arepytools/math/__init__.py +6 -0
- arepytools-1.7.6/arepytools/math/axis.py +434 -0
- arepytools-1.7.6/arepytools/math/genericpoly.py +155 -0
- arepytools-1.7.6/arepytools/timing/__init__.py +6 -0
- arepytools-1.7.6/arepytools/timing/conversions.py +54 -0
- arepytools-1.7.6/arepytools/timing/precisedatetime.py +863 -0
- arepytools-1.7.6/docs/source/_static/css/custom.css +9 -0
- arepytools-1.7.6/docs/source/_static/icons/aresys_logo.svg +16 -0
- arepytools-1.7.6/docs/source/changelog.rst +370 -0
- arepytools-1.7.6/docs/source/conf.py +227 -0
- arepytools-1.7.6/docs/source/index.rst +26 -0
- arepytools-1.7.6/docs/source/install.rst +21 -0
- arepytools-1.7.6/docs/source/reference/api/geometry.rst +28 -0
- arepytools-1.7.6/docs/source/reference/api/index.rst +11 -0
- arepytools-1.7.6/docs/source/reference/api/io.rst +24 -0
- arepytools-1.7.6/docs/source/reference/api/math.rst +6 -0
- arepytools-1.7.6/docs/source/reference/api/others.rst +4 -0
- arepytools-1.7.6/docs/source/reference/api/timing.rst +6 -0
- arepytools-1.7.6/docs/source/user_manual/index.rst +14 -0
- arepytools-1.7.6/docs/source/user_manual/input_output_module.rst +357 -0
- arepytools-1.7.6/docs/source/user_manual/new_code.txt +39 -0
- arepytools-1.7.6/docs/source/user_manual/new_code_orb.txt +98 -0
- arepytools-1.7.6/docs/source/user_manual/new_orbit_and_anx.rst +129 -0
- arepytools-1.7.6/docs/source/user_manual/old_code.txt +90 -0
- arepytools-1.7.6/docs/source/user_manual/old_code_orb.txt +73 -0
- arepytools-1.7.6/docs/source/user_manual/quickstart/index.rst +14 -0
- arepytools-1.7.6/docs/source/user_manual/quickstart/qs_general_sar_orbit.ipynb +240 -0
- arepytools-1.7.6/docs/source/user_manual/quickstart/qs_generic_poly.ipynb +147 -0
- arepytools-1.7.6/docs/source/user_manual/quickstart/qs_interpolated_orbit.ipynb +284 -0
- arepytools-1.7.6/docs/source/user_manual/quickstart/qs_precise_date_time.ipynb +116 -0
- arepytools-1.7.6/docs/source/user_manual/quickstart/qs_write_and_read_product_folder.ipynb +226 -0
- arepytools-1.7.6/pyproject.toml +100 -0
- arepytools-1.7.6/tests/__init__.py +6 -0
- arepytools-1.7.6/tests/geometry/__init__.py +6 -0
- arepytools-1.7.6/tests/geometry/test_anx_time.py +247 -0
- arepytools-1.7.6/tests/geometry/test_attitude_utils.py +171 -0
- arepytools-1.7.6/tests/geometry/test_conversions.py +54 -0
- arepytools-1.7.6/tests/geometry/test_curve.py +1056 -0
- arepytools-1.7.6/tests/geometry/test_direct_geocoding_attitude.py +1170 -0
- arepytools-1.7.6/tests/geometry/test_direct_geocoding_bistatic.py +1345 -0
- arepytools-1.7.6/tests/geometry/test_direct_geocoding_monostatic.py +1375 -0
- arepytools-1.7.6/tests/geometry/test_direct_geocoding_with_looks.py +168 -0
- arepytools-1.7.6/tests/geometry/test_ellipsoid.py +179 -0
- arepytools-1.7.6/tests/geometry/test_generalsarattitude.py +373 -0
- arepytools-1.7.6/tests/geometry/test_generalsarorbit.py +548 -0
- arepytools-1.7.6/tests/geometry/test_geodetic.py +67 -0
- arepytools-1.7.6/tests/geometry/test_geometric_functions.py +1337 -0
- arepytools-1.7.6/tests/geometry/test_inverse_geocoding_attitude.py +1039 -0
- arepytools-1.7.6/tests/geometry/test_inverse_geocoding_bistatic.py +2068 -0
- arepytools-1.7.6/tests/geometry/test_inverse_geocoding_monostatic.py +1472 -0
- arepytools-1.7.6/tests/geometry/test_orbit.py +436 -0
- arepytools-1.7.6/tests/geometry/test_reference_frames.py +215 -0
- arepytools-1.7.6/tests/geometry/test_rotation.py +264 -0
- arepytools-1.7.6/tests/io_/__init__.py +6 -0
- arepytools-1.7.6/tests/io_/parsing/__init__.py +6 -0
- arepytools-1.7.6/tests/io_/parsing/test_metadata_parsing.py +352 -0
- arepytools-1.7.6/tests/io_/parsing/test_translate.py +2114 -0
- arepytools-1.7.6/tests/io_/test_channel.py +189 -0
- arepytools-1.7.6/tests/io_/test_channel_iteration.py +341 -0
- arepytools-1.7.6/tests/io_/test_io_support.py +251 -0
- arepytools-1.7.6/tests/io_/test_manifest.py +81 -0
- arepytools-1.7.6/tests/io_/test_point_target_binary.py +297 -0
- arepytools-1.7.6/tests/io_/test_point_target_file.py +258 -0
- arepytools-1.7.6/tests/io_/test_product_folder_layout.py +168 -0
- arepytools-1.7.6/tests/io_/test_productfolder.py +382 -0
- arepytools-1.7.6/tests/io_/test_productfolder2.py +642 -0
- arepytools-1.7.6/tests/math_/__init__.py +6 -0
- arepytools-1.7.6/tests/math_/test_axis.py +306 -0
- arepytools-1.7.6/tests/math_/test_generic_poly.py +266 -0
- arepytools-1.7.6/tests/timing/__init__.py +6 -0
- arepytools-1.7.6/tests/timing/test_conversions.py +35 -0
- arepytools-1.7.6/tests/timing/test_precisedatetime.py +487 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Byte-compiled / optimized
|
|
2
|
+
__pycache__
|
|
3
|
+
*.py[co]
|
|
4
|
+
|
|
5
|
+
# Distribution / packaging
|
|
6
|
+
build/
|
|
7
|
+
_build/
|
|
8
|
+
dist/
|
|
9
|
+
*.egg-info/
|
|
10
|
+
.ipynb_checkpoints/
|
|
11
|
+
arepytools/meta.yaml
|
|
12
|
+
conda_build_dir
|
|
13
|
+
|
|
14
|
+
# Pyenv
|
|
15
|
+
.python-version
|
|
16
|
+
|
|
17
|
+
# VS Code project settings
|
|
18
|
+
.vscode
|
|
19
|
+
|
|
20
|
+
# PyCharm project settings
|
|
21
|
+
.idea
|
|
22
|
+
|
|
23
|
+
# Spyder project settings
|
|
24
|
+
.spyproject
|
|
25
|
+
|
|
26
|
+
# Environments
|
|
27
|
+
venv*
|
|
28
|
+
.venv
|
|
29
|
+
|
|
30
|
+
# Other
|
|
31
|
+
*.bak
|
|
32
|
+
.coverage
|
|
33
|
+
htmlcov
|
|
34
|
+
xsd/*xsd
|
|
35
|
+
.pdm*
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (C) Aresys S.r.l. <info@aresys.it>
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: arepytools
|
|
3
|
+
Version: 1.7.6
|
|
4
|
+
Summary: ArePyTools is the Aresys Python toolset for SAR data processing.
|
|
5
|
+
Author-email: "Aresys S.R.L." <info@aresys.it>
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (C) Aresys S.r.l. <info@aresys.it>
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
License-File: LICENSE.txt
|
|
28
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
29
|
+
Classifier: Operating System :: OS Independent
|
|
30
|
+
Classifier: Programming Language :: Python
|
|
31
|
+
Classifier: Programming Language :: Python :: 3
|
|
32
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
33
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
34
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
35
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
36
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
37
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
38
|
+
Classifier: Topic :: Utilities
|
|
39
|
+
Requires-Python: >=3.9
|
|
40
|
+
Requires-Dist: lxml
|
|
41
|
+
Requires-Dist: numpy>=1.20
|
|
42
|
+
Requires-Dist: python-dateutil
|
|
43
|
+
Requires-Dist: scipy
|
|
44
|
+
Requires-Dist: xsdata
|
|
45
|
+
Provides-Extra: bench
|
|
46
|
+
Requires-Dist: arepyextras-benchmark; extra == 'bench'
|
|
47
|
+
Provides-Extra: dev
|
|
48
|
+
Requires-Dist: nox; extra == 'dev'
|
|
49
|
+
Requires-Dist: pylint; extra == 'dev'
|
|
50
|
+
Requires-Dist: ruff; extra == 'dev'
|
|
51
|
+
Provides-Extra: doc
|
|
52
|
+
Requires-Dist: ipython; extra == 'doc'
|
|
53
|
+
Requires-Dist: nbsphinx; extra == 'doc'
|
|
54
|
+
Requires-Dist: pydata-sphinx-theme; extra == 'doc'
|
|
55
|
+
Requires-Dist: sphinx-copybutton; extra == 'doc'
|
|
56
|
+
Requires-Dist: sphinx-design; extra == 'doc'
|
|
57
|
+
Requires-Dist: sphinx<8.2; extra == 'doc'
|
|
58
|
+
Provides-Extra: test
|
|
59
|
+
Requires-Dist: coverage; extra == 'test'
|
|
60
|
+
Requires-Dist: unittest-xml-reporting; extra == 'test'
|
|
61
|
+
Description-Content-Type: text/markdown
|
|
62
|
+
|
|
63
|
+
# ArePyTools
|
|
64
|
+
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: Aresys S.r.l. <info@aresys.it>
|
|
2
|
+
# SPDX-License-Identifier: MIT
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
"""
|
|
6
|
+
**Deprecated** Constants module
|
|
7
|
+
-------------------------------
|
|
8
|
+
|
|
9
|
+
.. deprecated:: v1.7.0
|
|
10
|
+
Importing constants is deprecated.
|
|
11
|
+
Use scipy.constants.speed_of_light for LIGHT_SPEED.
|
|
12
|
+
|
|
13
|
+
Examples
|
|
14
|
+
--------
|
|
15
|
+
>>> import arepytools.constants as cst
|
|
16
|
+
>>> print(cst.LIGHT_SPEED)
|
|
17
|
+
299792458.0
|
|
18
|
+
"""
|
|
19
|
+
import warnings
|
|
20
|
+
|
|
21
|
+
import scipy
|
|
22
|
+
|
|
23
|
+
warnings.warn(
|
|
24
|
+
"arepytools.constants module is deprecated. Instead of importing LIGHT_SPEED use 'from scipy.constants import speed_of_light'",
|
|
25
|
+
DeprecationWarning,
|
|
26
|
+
stacklevel=2,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
SECONDS_IN_A_DAY = 86164.09054
|
|
30
|
+
"""
|
|
31
|
+
Number of seconds in a day
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
LIGHT_SPEED = scipy.constants.speed_of_light
|
|
35
|
+
"""
|
|
36
|
+
Speed of light in vacuum (m/s).
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
# Units of measure
|
|
40
|
+
SECOND_STR = "s"
|
|
41
|
+
"""
|
|
42
|
+
Second symbol.
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
HERTZ_STR = "Hz"
|
|
46
|
+
"""
|
|
47
|
+
Hertz symbol.
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
JOULE_STR = "j"
|
|
51
|
+
"""
|
|
52
|
+
Joule symbol.
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
DEGREE_STR = "deg"
|
|
56
|
+
"""
|
|
57
|
+
Degree symbol.
|
|
58
|
+
"""
|
|
59
|
+
|
|
60
|
+
RAD_STR = "rad"
|
|
61
|
+
"""
|
|
62
|
+
Radian symbol.
|
|
63
|
+
"""
|
|
64
|
+
|
|
65
|
+
UTC_STR = "Utc"
|
|
66
|
+
"""
|
|
67
|
+
Coordinated Universal Time abbreviation.
|
|
68
|
+
"""
|
|
69
|
+
|
|
70
|
+
METER_STR = "m"
|
|
71
|
+
"""
|
|
72
|
+
Meter symbol.
|
|
73
|
+
"""
|
|
74
|
+
|
|
75
|
+
# Metric prefixes
|
|
76
|
+
KILO = 1e3
|
|
77
|
+
"""
|
|
78
|
+
Number of units in one kilounit (kilounits-to-units conversion factor).
|
|
79
|
+
"""
|
|
80
|
+
|
|
81
|
+
MEGA = KILO**2
|
|
82
|
+
"""
|
|
83
|
+
Number of units in one megaunit (megaunits-to-units conversion factor).
|
|
84
|
+
"""
|
|
85
|
+
|
|
86
|
+
GIGA = KILO**3
|
|
87
|
+
"""
|
|
88
|
+
Number of units in one gigaunit (gigaunits-to-units conversion factor).
|
|
89
|
+
"""
|
|
90
|
+
|
|
91
|
+
MILLI = KILO**-1
|
|
92
|
+
"""
|
|
93
|
+
Number of units in one milliunit (milliunits-to-units conversion factor).
|
|
94
|
+
"""
|
|
95
|
+
|
|
96
|
+
MICRO = KILO**-2
|
|
97
|
+
"""
|
|
98
|
+
Number of units in one microunit (microunits-to-units conversion factor).
|
|
99
|
+
"""
|
|
100
|
+
|
|
101
|
+
NANO = KILO**-3
|
|
102
|
+
"""
|
|
103
|
+
Number of units in one nanounit (nanounits-to-units conversion factor).
|
|
104
|
+
"""
|
|
105
|
+
|
|
106
|
+
PICO = KILO**-4
|
|
107
|
+
"""
|
|
108
|
+
Number of units in one picounit (picounits-to-units conversion factor).
|
|
109
|
+
"""
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: Aresys S.r.l. <info@aresys.it>
|
|
2
|
+
# SPDX-License-Identifier: MIT
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
Geodetic module
|
|
6
|
+
---------------
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import numpy as np
|
|
10
|
+
import numpy.typing as npt
|
|
11
|
+
|
|
12
|
+
from arepytools.geometry.conversions import llh2xyz, xyz2llh
|
|
13
|
+
from arepytools.geometry.ellipsoid import WGS84
|
|
14
|
+
|
|
15
|
+
_semi_axis_ratio_sqr = WGS84.semi_axes_ratio_min_max**2
|
|
16
|
+
_major_semi_axis_sqr = WGS84.semi_major_axis**2
|
|
17
|
+
_minor_semi_axis_sqr = WGS84.semi_minor_axis**2
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _ze(x: float, y: float) -> float:
|
|
21
|
+
eps = 1.0e-21
|
|
22
|
+
|
|
23
|
+
return np.sqrt(_minor_semi_axis_sqr - _semi_axis_ratio_sqr * (x**2 + y**2)) + eps
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _ze_x(x: float, y: float) -> float:
|
|
27
|
+
return -WGS84.semi_axes_ratio_min_max * x / _ze(x, y)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _ze_xy(x: float, y: float) -> float:
|
|
31
|
+
# pylint: disable-next=arguments-out-of-order
|
|
32
|
+
return (_semi_axis_ratio_sqr * x) / _ze(x, y) ** 2 * _ze_x(y, x)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _ze_xx(x: float, y: float) -> float:
|
|
36
|
+
return -_semi_axis_ratio_sqr / _ze(x, y) + (_semi_axis_ratio_sqr * x) / _ze(x, y) ** 2 * _ze_x(x, y)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _compute_geodetic_jacobian(point: np.ndarray, sensor_position: np.ndarray) -> np.ndarray:
|
|
40
|
+
jac = np.empty(shape=(3, 3), dtype=float)
|
|
41
|
+
|
|
42
|
+
zed_diff = point[2] - sensor_position[2]
|
|
43
|
+
|
|
44
|
+
jac[0][0] = 2.0 * point[0] / _major_semi_axis_sqr
|
|
45
|
+
jac[0][1] = 2.0 * point[1] / _major_semi_axis_sqr
|
|
46
|
+
jac[0][2] = 2.0 * point[2] / _minor_semi_axis_sqr
|
|
47
|
+
jac[1][0] = 1.0 + zed_diff * _ze_xx(point[0], point[1])
|
|
48
|
+
jac[1][1] = zed_diff * _ze_xy(point[0], point[1])
|
|
49
|
+
jac[1][2] = _ze_x(point[0], point[1])
|
|
50
|
+
jac[2][0] = jac[1][1]
|
|
51
|
+
jac[2][1] = 1.0 + zed_diff * _ze_xx(point[1], point[0])
|
|
52
|
+
jac[2][2] = _ze_x(point[1], point[0])
|
|
53
|
+
|
|
54
|
+
return jac
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def _compute_geodetic_rhs(point: npt.NDArray[np.floating], sensor_position: npt.NDArray[np.floating]) -> np.ndarray:
|
|
58
|
+
rhs = np.empty(shape=(3,), dtype=float)
|
|
59
|
+
los = point - sensor_position
|
|
60
|
+
rhs[0] = (point[0] ** 2 + point[1] ** 2) / _major_semi_axis_sqr + point[2] ** 2 / _minor_semi_axis_sqr - 1
|
|
61
|
+
rhs[1] = los[0] + los[2] * _ze_x(point[0], point[1])
|
|
62
|
+
rhs[2] = los[1] + los[2] * _ze_x(point[1], point[0])
|
|
63
|
+
return rhs
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def compute_geodetic_point(sensor_positions: npt.ArrayLike) -> np.ndarray:
|
|
67
|
+
"""Compute the geodetic point that corresponds to a sensor position
|
|
68
|
+
|
|
69
|
+
:param sensor_position: sensor position array like with shape (3,) or (N, 3)
|
|
70
|
+
|
|
71
|
+
:return: geodetic point as a (3,) or (N, 3) numpy array
|
|
72
|
+
"""
|
|
73
|
+
sensor_positions = np.asarray(sensor_positions)
|
|
74
|
+
|
|
75
|
+
if sensor_positions.ndim > 2 or sensor_positions.shape[-1] != 3:
|
|
76
|
+
raise ValueError(f"sensor_positions has invalid shape: {sensor_positions.shape}, it should be (3,) or (N, 3)")
|
|
77
|
+
|
|
78
|
+
sensor_positions = sensor_positions.copy()
|
|
79
|
+
change_sign = sensor_positions[..., 2] < 0
|
|
80
|
+
sensor_positions[change_sign, 2] *= -1
|
|
81
|
+
|
|
82
|
+
geodetic_points = xyz2llh(sensor_positions.T)
|
|
83
|
+
geodetic_points[2, ...] = 0
|
|
84
|
+
geodetic_points = llh2xyz(geodetic_points).T.reshape(sensor_positions.shape)
|
|
85
|
+
|
|
86
|
+
for sensor_position, point in zip(
|
|
87
|
+
sensor_positions.reshape((-1, 3)),
|
|
88
|
+
geodetic_points.reshape((-1, 3)),
|
|
89
|
+
):
|
|
90
|
+
increment_norm_threshold = 1e-9
|
|
91
|
+
max_num_iterations = 10
|
|
92
|
+
for _ in range(max_num_iterations):
|
|
93
|
+
jacobian = _compute_geodetic_jacobian(point[:], sensor_position)
|
|
94
|
+
rhs = _compute_geodetic_rhs(point[:], sensor_position)
|
|
95
|
+
|
|
96
|
+
increment = -np.linalg.solve(jacobian, rhs)
|
|
97
|
+
|
|
98
|
+
increment_norm = np.linalg.norm(increment)
|
|
99
|
+
|
|
100
|
+
point[:] += increment
|
|
101
|
+
|
|
102
|
+
if increment_norm < increment_norm_threshold:
|
|
103
|
+
break
|
|
104
|
+
|
|
105
|
+
geodetic_points[change_sign, 2] *= -1
|
|
106
|
+
|
|
107
|
+
return geodetic_points
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: Aresys S.r.l. <info@aresys.it>
|
|
2
|
+
# SPDX-License-Identifier: MIT
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
Geometry interpolator module
|
|
6
|
+
----------------------------
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import numpy as np
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def check_eval_function_input(fun):
|
|
13
|
+
"""
|
|
14
|
+
Interpolator eval function input checker
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
def decorated_fun(self, *args_f, **kwargs_f):
|
|
18
|
+
if isinstance(args_f[0], (list, np.ndarray)):
|
|
19
|
+
interpolation_axis = np.asarray(args_f[0])
|
|
20
|
+
else:
|
|
21
|
+
interpolation_axis = np.full((1,), args_f[0])
|
|
22
|
+
return fun(self, interpolation_axis, *args_f[1:], **kwargs_f)
|
|
23
|
+
|
|
24
|
+
return decorated_fun
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class GeometryInterpolator:
|
|
28
|
+
"""
|
|
29
|
+
Internal class for handling interpolation in GeneralSarOrbit and in GeneralSarAttitude
|
|
30
|
+
It interpolates vector-valued functions defined on a given axis
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
_POLYNOMIAL_ORDER = 4
|
|
34
|
+
_DATA_POINTS_PER_POLY = _POLYNOMIAL_ORDER + 1
|
|
35
|
+
_POLY_CENTER_REL_INTERVAL_INDEX = _DATA_POINTS_PER_POLY // 2
|
|
36
|
+
|
|
37
|
+
@classmethod
|
|
38
|
+
def get_min_num_of_data_points(cls):
|
|
39
|
+
"""Return the minimum number of data points needed by the interpolator
|
|
40
|
+
|
|
41
|
+
:return: minimum number of data points"""
|
|
42
|
+
return cls._DATA_POINTS_PER_POLY
|
|
43
|
+
|
|
44
|
+
@classmethod
|
|
45
|
+
def get_polynomial_order(cls):
|
|
46
|
+
"""Return the order of the interpolation polynomial
|
|
47
|
+
|
|
48
|
+
:return: order of the interpolation polynomial
|
|
49
|
+
"""
|
|
50
|
+
return cls._POLYNOMIAL_ORDER
|
|
51
|
+
|
|
52
|
+
def __init__(self, data_axis, data):
|
|
53
|
+
"""Initialize the object as interpolator of the input data defined on the specified axis
|
|
54
|
+
|
|
55
|
+
:param data_axis: the axis of length N on which the data is defined
|
|
56
|
+
:param data: data defined as MxN array of M-dimensional values (e.g. state vectors or attitude angles)
|
|
57
|
+
"""
|
|
58
|
+
self._data_axis = data_axis
|
|
59
|
+
self._num_of_data_components = data.shape[0]
|
|
60
|
+
self._num_of_polynomials = self._data_axis.size - self._POLYNOMIAL_ORDER
|
|
61
|
+
|
|
62
|
+
# Matrix of polynomials
|
|
63
|
+
self._pos = np.ndarray((self._num_of_polynomials, self._num_of_data_components), dtype=np.poly1d)
|
|
64
|
+
self._vel = np.ndarray((self._num_of_polynomials, self._num_of_data_components), dtype=np.poly1d)
|
|
65
|
+
self._acc = np.ndarray((self._num_of_polynomials, self._num_of_data_components), dtype=np.poly1d)
|
|
66
|
+
# Relative azimuth axis [s]
|
|
67
|
+
relative_axis = self._data_axis.get_relative_array()
|
|
68
|
+
self._data_axis_array = self._data_axis.get_array()
|
|
69
|
+
for poly_index in range(self._num_of_polynomials):
|
|
70
|
+
# Each polynomial domain is defined by the poly_axis
|
|
71
|
+
poly_axis = relative_axis[poly_index : poly_index + self._DATA_POINTS_PER_POLY]
|
|
72
|
+
|
|
73
|
+
# Each polynomial relative axis starts at the start of the interval:
|
|
74
|
+
# P(t) = c0 + c1 * (t-poly_time_axis[0]) + ...
|
|
75
|
+
vandermonde_matrix = np.vander((poly_axis - poly_axis[0]).astype(float))
|
|
76
|
+
|
|
77
|
+
# Computation of polynomial coefficients
|
|
78
|
+
for component_index in range(self._num_of_data_components):
|
|
79
|
+
values = data[
|
|
80
|
+
component_index,
|
|
81
|
+
poly_index : poly_index + self._DATA_POINTS_PER_POLY,
|
|
82
|
+
]
|
|
83
|
+
coefficients = np.linalg.solve(vandermonde_matrix, values).tolist()
|
|
84
|
+
position = np.poly1d(coefficients)
|
|
85
|
+
self._pos[poly_index, component_index] = position
|
|
86
|
+
self._vel[poly_index, component_index] = np.polyder(position, 1)
|
|
87
|
+
self._acc[poly_index, component_index] = np.polyder(position, 2)
|
|
88
|
+
|
|
89
|
+
@check_eval_function_input
|
|
90
|
+
def eval(self, interpolation_axis, interval_indexes, components_to_interpolate=None):
|
|
91
|
+
"""Interpolate the data on the given interpolation axis
|
|
92
|
+
|
|
93
|
+
:param interpolation_axis: interpolation axis
|
|
94
|
+
:param interval_indexes: vector or single scalar or None. Denotes the intervals where the given interpolation
|
|
95
|
+
points are expected
|
|
96
|
+
:param components_to_interpolate: list of the components to interpolate, identified by their
|
|
97
|
+
index [optional]
|
|
98
|
+
|
|
99
|
+
:return: CxP array of interpolated values, where C is the number of interpolated components and P is the length
|
|
100
|
+
of the interpolation axis
|
|
101
|
+
"""
|
|
102
|
+
return self._eval(interpolation_axis, interval_indexes, self._pos, components_to_interpolate)
|
|
103
|
+
|
|
104
|
+
@check_eval_function_input
|
|
105
|
+
def eval_first_derivative(self, interpolation_axis, interval_indexes, components_to_interpolate=None):
|
|
106
|
+
"""Interpolate the first derivative of the data on the given interpolation axis
|
|
107
|
+
|
|
108
|
+
:param interpolation_axis: interpolation axis
|
|
109
|
+
:param interval_indexes: vector or single scalar or None. Denotes the interval where the given interpolation
|
|
110
|
+
points are expected
|
|
111
|
+
:param components_to_interpolate: list of the components to interpolate, identified by their index [optional]
|
|
112
|
+
|
|
113
|
+
:return: CxP array of interpolated values, where C is the number of interpolated components and P is the length
|
|
114
|
+
of the interpolation axis
|
|
115
|
+
"""
|
|
116
|
+
return self._eval(interpolation_axis, interval_indexes, self._vel, components_to_interpolate)
|
|
117
|
+
|
|
118
|
+
@check_eval_function_input
|
|
119
|
+
def eval_second_derivative(self, interpolation_axis, interval_indexes, components_to_interpolate=None):
|
|
120
|
+
"""Interpolate the second derivative of the data on the given interpolation axis
|
|
121
|
+
|
|
122
|
+
:param interpolation_axis: interpolation axis
|
|
123
|
+
:param interval_indexes: vector or single scalar or None. Denotes the interval where the given interpolation
|
|
124
|
+
points are expected
|
|
125
|
+
:param components_to_interpolate: list of the components to interpolate, identified by their index [optional]
|
|
126
|
+
|
|
127
|
+
:return: CxP array of interpolated values, where C is the number of interpolated components and P is the length
|
|
128
|
+
of the interpolation axis
|
|
129
|
+
"""
|
|
130
|
+
|
|
131
|
+
return self._eval(interpolation_axis, interval_indexes, self._acc, components_to_interpolate)
|
|
132
|
+
|
|
133
|
+
def _eval(
|
|
134
|
+
self,
|
|
135
|
+
interpolation_axis,
|
|
136
|
+
interval_indexes,
|
|
137
|
+
polynomial,
|
|
138
|
+
components_to_interpolate=None,
|
|
139
|
+
):
|
|
140
|
+
"""Interpolate the data on the given interpolation axis by evaluating interpolation
|
|
141
|
+
polynomials (or a their modified version) on the interpolation axis
|
|
142
|
+
|
|
143
|
+
:param interpolation_axis: interpolation axis
|
|
144
|
+
:param interval_indexes: vector or single scalar or None. Denotes the interval where the given time is expected
|
|
145
|
+
:param polynomial: interpolation polynomials to evaluate
|
|
146
|
+
:param components_to_interpolate: list of the components to interpolate, identified by their index [optional]
|
|
147
|
+
|
|
148
|
+
:return: CxP array of interpolated values, where C is the number of interpolated components and P is the length
|
|
149
|
+
of the interpolation axis
|
|
150
|
+
"""
|
|
151
|
+
|
|
152
|
+
if components_to_interpolate is None:
|
|
153
|
+
components_to_interpolate = range(self._num_of_data_components)
|
|
154
|
+
|
|
155
|
+
poly_indexes = self.get_polynomial_index(
|
|
156
|
+
interpolation_points=interpolation_axis, interval_indexes=interval_indexes
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
interpolation_results = np.zeros((len(components_to_interpolate), interpolation_axis.size))
|
|
160
|
+
|
|
161
|
+
for interpolation_point_index, (poly_index, interpolation_point) in enumerate(
|
|
162
|
+
zip(poly_indexes, interpolation_axis)
|
|
163
|
+
):
|
|
164
|
+
interpolation_point_poly_rel = interpolation_point - self._data_axis_array[poly_index]
|
|
165
|
+
|
|
166
|
+
for out_component_index, component_index in enumerate(components_to_interpolate):
|
|
167
|
+
interpolation_results[out_component_index, interpolation_point_index] = polynomial[
|
|
168
|
+
poly_index, component_index
|
|
169
|
+
](interpolation_point_poly_rel)
|
|
170
|
+
|
|
171
|
+
return interpolation_results
|
|
172
|
+
|
|
173
|
+
def get_interval_index(self, interpolation_points):
|
|
174
|
+
"""Get the indexes of the intervals where the interpolation_points lie
|
|
175
|
+
|
|
176
|
+
:param interpolation_points: vector of required interpolation points
|
|
177
|
+
|
|
178
|
+
:return: array of interval indexes
|
|
179
|
+
"""
|
|
180
|
+
return self._data_axis.get_interval_id(interpolation_points)
|
|
181
|
+
|
|
182
|
+
def get_polynomial_index(self, interpolation_points=None, interval_indexes=None):
|
|
183
|
+
"""Get the indexes of the polynomials to be used for interpolation
|
|
184
|
+
|
|
185
|
+
:param interpolation_points: vector of required interpolation points
|
|
186
|
+
:param interval_indexes: interval indexes of the interpolation points
|
|
187
|
+
|
|
188
|
+
:return: array of polynomial indexes
|
|
189
|
+
|
|
190
|
+
If interpolation points are specified, the positions on the interpolation axis are computed internally to find
|
|
191
|
+
the corresponding polynomial indexes;
|
|
192
|
+
If the interval indexes of the interpolation points on the axis are given, the polynomial indexes are computed
|
|
193
|
+
directly (ignoring the interpolation points).
|
|
194
|
+
"""
|
|
195
|
+
if interval_indexes is None:
|
|
196
|
+
if interpolation_points is not None:
|
|
197
|
+
interval_indexes = self._data_axis.get_interval_id(interpolation_points)
|
|
198
|
+
else:
|
|
199
|
+
raise RuntimeError("Specify either interpolation points or interval indexes")
|
|
200
|
+
if isinstance(interval_indexes, int):
|
|
201
|
+
interval_indexes = np.asarray([interval_indexes])
|
|
202
|
+
return np.clip(
|
|
203
|
+
interval_indexes - self._POLY_CENTER_REL_INTERVAL_INDEX,
|
|
204
|
+
0,
|
|
205
|
+
self._num_of_polynomials - 1,
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
@property
|
|
209
|
+
def num_of_polynomials(self):
|
|
210
|
+
return self._num_of_polynomials
|