Metadata-Version: 2.4
Name: orbit-converter
Version: 1.4.0
Summary: Convert ECEF X/Y/Z and CCSDS OEM orbit files to WGS84 latitude, longitude, and altitude
Author: Samuel Braman
License-Expression: MIT
Project-URL: Homepage, https://github.com/SBK008/orbit-coordinate-converter
Project-URL: Changelog, https://github.com/SBK008/orbit-coordinate-converter/blob/main/CHANGELOG.md
Project-URL: Issues, https://github.com/SBK008/orbit-coordinate-converter/issues
Project-URL: Security, https://github.com/SBK008/orbit-coordinate-converter/blob/main/SECURITY.md
Keywords: ecef,wgs84,ccsds,oem,orbit,geodesy,coordinates,nairas
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Console
Classifier: Environment :: X11 Applications
Classifier: Intended Audience :: Science/Research
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering :: Astronomy
Classifier: Topic :: Scientific/Engineering :: GIS
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: numpy<3,>=1.24
Requires-Dist: pandas<4,>=2.0
Requires-Dist: pyproj<4,>=3.6
Requires-Dist: astropy<9,>=6.0
Requires-Dist: cryptography<51,>=42
Provides-Extra: test
Requires-Dist: pytest>=7; extra == "test"
Dynamic: license-file

# Coordinate Converter

[![tests](https://github.com/SBK008/orbit-coordinate-converter/actions/workflows/tests.yml/badge.svg)](https://github.com/SBK008/orbit-coordinate-converter/actions/workflows/tests.yml)

Convert Earth-centered (ECEF) X/Y/Z coordinates and CCSDS OEM orbit files to WGS84 latitude, longitude, and altitude. Includes a desktop app and a command-line tool, and handles files with millions of points.

## Features

- **Accurate at any altitude:** within a micrometer from the surface out past GEO.
- **CSV input:** any CSV with X, Y, Z columns in meters. Your other columns are kept exactly as they were.
- **CCSDS OEM input:** text (KVN) orbit files in Earth-fixed or space-fixed frames. Space-fixed positions are rotated to Earth-fixed at each epoch.
- **Epoch output** as written in the file, as Gregorian calendar dates, or as Modified Julian Dates.
- **Comma or space separated output.**
- **NAIRAS trajectory export:** OEM files can be saved in the exact trajectory format used by NASA's NAIRAS radiation model on CCMC Runs-on-Request.
- **Large files:** processed in chunks, so memory stays flat. Tested on a 1 GB, 20 million row CSV.
- **Safe writes:** a failed or stopped run never leaves a half-written output file.
- **Signed updates:** the app installs only published releases, and checks every file against SHA-256 checksums signed with the maintainer's offline key.

Standalone apps for Windows, macOS, and Linux are planned. See the [roadmap](https://github.com/SBK008/orbit-coordinate-converter/blob/main/ROADMAP.md) for what's coming next.

## Install

**Option 1: pip (recommended)**

Requires Python 3.11 or newer.

```
pip install orbit-converter
```

This installs the dependencies and two commands:

- `coordinate-converter` opens the desktop app
- `xyz-to-lla` runs the command-line tool

To update:

```
pip install --upgrade orbit-converter
```

Installed with pip before version 1.4.0? That copy was registered under an older name, so switch over once:

```
pip uninstall coordinate-converter orbit-converter
pip install orbit-converter
```

**Option 2: download the zip**

1. Click **Code > Download ZIP** and unzip it.
2. Install the dependencies:
   ```
   pip install -r requirements.txt
   ```
3. Run the app:
   ```
   python converter_gui.py
   ```

To update, click **Check for updates** in the app. It installs the latest release and checks each file against its checksum before replacing anything.

## Desktop app

1. Choose an input file (`.csv`, `.oem`, or `.txt`).
2. Pick the options:
   - **OEM files:** epoch format, and fast mode for space-fixed frames
   - **CSV files:** the names of your X, Y, and Z columns
   - **Output:** comma separated, space separated, or NAIRAS trajectory, and whether to include column names
3. Choose where to save and click **Convert**.

## Command line

```
# CSV
xyz-to-lla input.csv output.csv
xyz-to-lla input.csv output.csv --x X --y Y --z Z

# OEM
xyz-to-lla orbit.oem output.csv
xyz-to-lla orbit.oem output.csv --time-format mjd
xyz-to-lla orbit.oem output.csv --fast
xyz-to-lla orbit.txt output.csv --format oem

# Space separated, no header line
xyz-to-lla orbit.oem output.txt --separator space --no-header

# NAIRAS trajectory, one point per minute
xyz-to-lla orbit.oem trajectory_1.txt --nairas --step 60
```

If you downloaded the zip, use `python xyz_to_lla.py` in place of `xyz-to-lla`.

| Option | What it does |
|---|---|
| `--format auto\|csv\|oem` | Input type. `auto` treats `.oem` files as OEM and everything else as CSV. |
| `--x`, `--y`, `--z` | CSV column names (default `x`, `y`, `z`). |
| `--time-format original\|gregorian\|mjd` | How OEM epochs are written. |
| `--fast` | Faster rotation for space-fixed OEM frames, within 0.05 mm of exact. |
| `--separator comma\|space` | Output column separator. |
| `--no-header` | Leave out the column names line (or the `#` comment lines with `--nairas`). |
| `--nairas` | OEM only: write a NAIRAS trajectory file. |
| `--step SECONDS` | With `--nairas`: keep one point per this many seconds (default 0 keeps all). |
| `--chunksize N` | Rows processed at a time. |
| `--version` | Show the version. |

## Output

**CSV input:** your original columns, plus `lat`, `lon`, `alt`.

**OEM input:** `object, epoch, time_system, x_ecef_m, y_ecef_m, z_ecef_m, lat, lon, alt`

Latitude and longitude are in degrees. Altitude is meters above the WGS84 ellipsoid. In space separated output, empty values are written as `NaN` and text containing spaces is put in quotes.

## Supported OEM files

| Field | Supported |
|---|---|
| Format | Text (KVN). XML is not supported. |
| `CENTER_NAME` | `EARTH` |
| `REF_FRAME` | Earth-fixed: `ITRF*`, `EFG`, `ECEF`. Space-fixed: `EME2000`/`J2000`, `GCRF`, `ICRF`, `TEME`. |
| `TIME_SYSTEM` | `UTC`, `TAI`, `TT`, `TDB`, `TCG`, `TCB`, `UT1`, `GPS` |
| Epochs | `2026-10-19T12:00:00.000` or day-of-year `2026-292T12:00:00.000` |

Covariance blocks are skipped. Space-fixed frames use astropy and IERS Earth orientation data, which it downloads when online.

## NAIRAS trajectories (CCMC Runs-on-Request)

Choose **NAIRAS trajectory** in the app, or use `--nairas`. The output matches the trajectory input files NASA published with the [RaD-X flight data](https://doi.org/10.5281/zenodo.14927669), checked byte for byte against their balloon flight file:

```
# year(yyyy),month(mm),day(dd),hour(hh),min(mm),sec(fractional second),alt(km),lat(deg),lon(deg)
 2015   9  25  17   6  6.000     1.394765    34.490002   255.783325
```

- Space separated, with `#` comment lines at the top
- Date and time in UTC (TAI, TT, GPS and other OEM time systems are converted)
- Altitude in km, **before** latitude
- Longitude from 0 to 360 degrees east
- One vehicle per file, with times in order

Notes:

- NASA's sample files use one point per minute. Long, high-rate OEM files can produce very large trajectories, so `--step 60` (or the "Keep one point every" box) is a good starting point.
- Altitude is height above the WGS84 ellipsoid. NASA's aircraft and balloon files use barometric altitude, which can differ by tens of meters. For spacecraft this makes no practical difference.
- The CCMC uploader checks file names: use only letters, numbers, and underscores (like `trajectory_1.txt`) and keep the file in a folder with no spaces in its path. The app suggests a safe name for you.

## Use in your own code

```python
from xyz_to_lla import xyz_to_lla

lat, lon, alt = xyz_to_lla(x_array, y_array, z_array)
```

## Running the tests

```
pip install ".[test]"
pytest
```

The tests cover the conversion math, CSV and OEM input, every output option, the NAIRAS format (checked byte for byte against an excerpt of NASA's RaD-X trajectory file in `tests/data`), safe writes, and the updater. The desktop app tests need a screen, so they only run when `RUN_GUI_TESTS=1` is set.

GitHub Actions runs everything on Linux, macOS, and Windows on every push. The badge at the top shows the latest result.

## Publishing an update (maintainer notes)

1. Create a branch for the change, for example `v1.4.0`.
2. Make the changes on that branch, raise `__version__` in `xyz_to_lla.py`, and add a section to `CHANGELOG.md`.
3. Open a pull request into `main` and wait for the tests to pass.
4. Merge the pull request.
5. Go to **Releases > Draft a new release**, create a tag named after the version (like `v1.4.0`) on `main`, paste the changelog section, and publish.
6. The **release** workflow checks the tag, signs the files with Sigstore, attaches `SHA256SUMS` and the packages, and publishes to PyPI. Wait for a green check on the Actions tab.
7. On your own computer, sign the release with your offline key:
   ```
   scripts/sign_release.sh v1.4.0
   ```
   It checks that `SHA256SUMS` matches the files at the tag before signing. Attach the `SHA256SUMS.minisig` it makes to the release (**Edit release**, drag the file in, **Update release**).

The app's update button won't install a release until both `SHA256SUMS` and `SHA256SUMS.minisig` are attached. Code merged into `main` without a release is never sent to users.
