Metadata-Version: 2.5
Name: gdar-orbit
Version: 1.3.0rc2
Summary: GDAR-ORBIT -- satellite orbits for GDAR
Author-email: Geir Engen <geen@norceresearch.no>, Yngvar Larsen <ynla@norceresearch.no>, Tom Grydeland <tgry@norceresearch.no>, Heidi Hindberg <hehi@norceresearch.no>, Jakob Grahn <jgra@norceresearch.no>, Daniel Johansen Trosten <dtro@norceresearch.no>, Temesgen Gebrie Yitayew <teyi@norceresearch.no>
License-Expression: Apache-2.0
License-File: LICENSE
Keywords: InSAR,SAR,geospatial,raster,remote-sensing,satellite-orbits
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Scientific/Engineering :: GIS
Classifier: Topic :: Scientific/Engineering :: Image Processing
Requires-Python: >=3.10
Requires-Dist: gdar-base>=1.3.0rc1
Requires-Dist: numpy-quaternion>=2023.0.0
Provides-Extra: interactive
Requires-Dist: gdar-base[interactive]; extra == 'interactive'
Requires-Dist: ipython; extra == 'interactive'
Provides-Extra: plotting
Requires-Dist: gdar-base[plotting]; extra == 'plotting'
Requires-Dist: matplotlib; extra == 'plotting'
Provides-Extra: remote
Requires-Dist: requests; extra == 'remote'
Description-Content-Type: text/markdown

# gdar-orbit

Satellite orbit and attitude handling for the GDAR processing framework.
Part of the OpenGDAR family of packages.  See
[`gdar-base`](https://pypi.org/project/gdar-base/) for the foundation
package this builds on and an introduction to the `DataRaster`
abstraction.

## Modules

### `gdar.orbit.orbit` -- Orbit interpolation and SAR geocoding

Core orbit classes built on Legendre polynomial interpolation of
statevectors (ECEF position + velocity):

- **`Sampled_orbit`** -- primary orbit class, constructed from a sequence
  of uniformly sampled statevectors.
- **`EllipsoidOrbit`** -- base class providing SAR geocoding methods.
- **`GbradarOrbit`** -- orbit representation for ground-based radar.
- **`AirborneOrbit`** -- orbit representation for airborne platforms.
- **`fixed_SV_orbit`** -- single fixed statevector, for static geometry.

Key geocoding methods (on `EllipsoidOrbit`):

| Method | Description |
|---|---|
| `sar2xyz()` | SAR coordinates (azimuth time, range) to ECEF XYZ |
| `sar2geo()` | SAR coordinates to geographic (lat, lon, height) |
| `xyz2sar()` | ECEF XYZ to SAR coordinates |
| `geo2sar()` | Geographic coordinates to SAR coordinates |
| `sar2geometry()` | Full geometry recarray (incidence angle, look angle, etc.) |

Utilities:

- `canonical_svec()` -- convert various statevector formats to the
  standard recarray dtype.
- `merge_trajectories()` -- merge overlapping orbit segments.
- `replicate_vector()` -- broadcast a vector to match a position array.

### `gdar.orbit.attitude` -- Quaternion-based attitude

Satellite attitude as unit quaternions with SLERP interpolation:

- **`Attitude`** -- stores uniformly sampled quaternions, interpolates to
  arbitrary times.  Quaternions represent the rotation from the GDAR
  body-fixed frame to ITRF.
- **`zero_doppler_steering()`** -- compute attitude quaternions for
  perfect zero-Doppler steering: body x along the reference velocity,
  body z (boresight) as close to geodetic nadir as the perpendicularity
  constraint allows.  Two independent frame keywords:
    - `doppler_reference=` -- which velocity defines the Doppler null,
      i.e. *what the answer is*.  `'ITRS'` (default) nulls against the
      Earth-fixed velocity, which is what actually zeroes the Doppler
      centroid for a ground target; `'GCRS'` nulls against the inertial
      velocity, the convention of `zero_doppler_legacy()`.  The two
      differ by a yaw of up to about 4 degrees.
    - `out_frame=` -- which axes the result is *expressed* in, `'ITRF'`
      (default, matching `Attitude`) or `'GCRS'`.

  Both accept `'ITRF'`/`'ITRS'`/`'ECEF'` and `'GCRS'`/`'ECI'`,
  case-insensitively.  Supports a roll parameter: positive roll points
  the boresight left of the ground track, negative roll points right.
- `zero_doppler_legacy()` -- the earlier formulation, returning **ToD**
  quaternions and always nulling against the inertial velocity.  Its
  nadir reference uses a hard-coded oblateness constant valid at
  h ~ 711 km, so accuracy degrades away from that altitude.  Retained
  for reproducing existing products; prefer `zero_doppler_steering()`
  for new work.
- `pt_from_azel()` -- azimuth/elevation angles to unit pointing vector.
- `quat_as_tait_bryan_angles()` -- quaternion to roll/pitch/yaw.

Body-fixed frame convention:

- **x** -- forward (velocity direction)
- **y** -- completes right-handed system (approximately cross-track right)
- **z** -- boresight (nadir at zero roll)

### `gdar.orbit.frame_transformations` -- Coordinate frame transforms

Statevector-level transformation between the Earth-fixed and inertial
frames.  The rotation-matrix work lives in `gdar.base.coordinates`
(ERFA, IAU 2006/2000A CIO-based composition); this module applies the
matrix to a statevector's position and velocity.

The endpoint-to-endpoint transform:

| Function | Description |
|---|---|
| `itrs_from_gcrs(statevector, inverse=False)` | GCRS to ITRS; `inverse=True` for the reverse |
| `gcrs_from_itrs(statevector)` | ITRS to GCRS |
| `ecef_from_eci`, `eci_from_ecef` | engineering-naming aliases for the above |

The equinox-based intermediate pairs -- `tod_from_gcrs`, `tirs_from_tod`,
`gm2000_from_gcrs`, their inverses, and the ITRS composites -- are kept
for compatibility with reference implementations written against them.
They raise `LegacyFrameWarning`; `legacy_frames()` silences it for a
block:

```python
with frame_transformations.legacy_frames():
    sv_tod = tod_from_itrs(sv_itrs)
```

New code should take the matrix it needs from `gdar.base.coordinates`
and apply it directly.  The CIO-based chain is exposed there as
`cirs_from_gcrs`, `tirs_from_cirs` and `itrs_from_tirs`, each taking
`inverse=` and `derivative=`.

### `gdar.orbit.propagator` -- Semianalytical orbit propagation

Predict an orbit from a single statevector, without numerical
integration.  First order in the mean Keplerian elements with explicit
second-order oblateness corrections (`j2`, `j2**2`, `j3`, `j4`),
following Liu, AIAA paper 79-0123.

- **`Propagator`** -- reduces a statevector to mean elements at the
  preceding true ascending node, then predicts at arbitrary times.

```python
from gdar.orbit.propagator import Propagator

p = Propagator(statevector)         # ITRS statevector, 'tai' populated
sv = p.propagate(times, tai=True)   # ITRS; eci=True for GCRS
```

Times are UTC unless `tai=True`.  Prefer TAI: UTC cannot name an instant
inside an inserted leap second, so those instants are unreachable when
the argument is UTC.  Elapsed time is measured in TAI either way.

Also exposes the Keplerian machinery it is built on -- element and
anomaly conversions, osculating/mean reduction, ascending-node search --
and the EGM96/WGS84 gravity parameters.

This module is not re-exported from `gdar.orbit`; import it explicitly.

### `gdar.orbit.sentinel1` -- Sentinel-1 orbit products

Reads ESA orbit products in EOF format -- POEORB (precise), RESORB
(restituted) and MOEORB -- and presents them as an orbit:

- **`S1_orbit`** -- an `EllipsoidOrbit` built from one or more EOF files,
  loading statevectors lazily and preferring precise over restituted.
- `read_statevectors()` -- parse a single EOF file or URL.
- `orbit_filelist()`, `ra_filelist()` -- find and order orbit files on
  disk by validity period.
- `get_urls_from_remote()` -- query ESA's Sentinel-1 Quality Control
  service for the products covering an interval.

```python
from gdar.orbit.sentinel1 import S1_orbit, orbit_filelist

files = orbit_filelist("/data/auxdata/orbit", "S1A")
orb = S1_orbit(odir=files, platform="S1A", ytime_ref=t0, utc=True)
```

The two functions that reach the network need `requests`; see the
`remote` extra below.  This module is also re-exported from
`gdar.io.sentinel1_orbit`.

This module is not re-exported from `gdar.orbit`; import it explicitly.

## Installation

Install from PyPI:

```bash
pip install gdar-orbit
```

or with [uv](https://docs.astral.sh/uv/):

```bash
uv pip install gdar-orbit
```

Dependencies (including `gdar-base` and
[`numpy-quaternion`](https://pypi.org/project/numpy-quaternion/), used
for SLERP-based attitude interpolation) are installed automatically.

Optional extras:

- `remote` — `requests`, for fetching Sentinel-1 orbit products over the
  network
- `plotting` — matplotlib
- `interactive` — IPython

```bash
pip install "gdar-orbit[remote,plotting,interactive]"
```

`gdar-orbit` has no system-library requirements of its own.  For
conda environments and other topics shared across the OpenGDAR
packages, see the [`gdar-base` README](https://pypi.org/project/gdar-base/).

## License

This project is licensed under the Apache License, Version 2.0.
You may obtain a copy of the license at
<https://www.apache.org/licenses/LICENSE-2.0> or in the
[LICENSE](./LICENSE) file distributed with this source.

Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
either express or implied.  See the License for the specific
language governing permissions and limitations under the License.

