Metadata-Version: 2.4
Name: ccsds-ndm
Version: 3.1
Summary: Read and write utility for CCSDS 'Navigation Data Messages.
Keywords: satellite,satellite design,mission analysis,aerospace,engineering,astrodynamics,orbits,orbital mechanics
Author: Egemen Imre
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Scientific/Engineering
Classifier: Topic :: Scientific/Engineering :: Physics
License-File: LICENSE
Requires-Dist: lxml >=6.0
Requires-Dist: lxml-stubs >=0.5
Requires-Dist: xsdata >=26
Requires-Dist: astropy ; extra == "astropy"
Requires-Dist: sphinx ; extra == "doc"
Requires-Dist: pint ; extra == "pint"
Requires-Dist: pytest ; extra == "test"
Requires-Dist: pytest-cov ; extra == "test"
Requires-Dist: pytest-xdist ; extra == "test"
Project-URL: Documentation, https://ccsds-ndm.readthedocs.io
Project-URL: Source, https://github.com/egemenimre/ccsds-ndm/
Provides-Extra: astropy
Provides-Extra: doc
Provides-Extra: pint
Provides-Extra: test

# CCSDS "Navigation Data Messages" Read and Write

[![CircleCI Status](https://img.shields.io/circleci/build/github/egemenimre/ccsds-ndm.svg?style=svg)](https://circleci.com/gh/egemenimre/ccsds-ndm)
[![Codacy Badge](https://app.codacy.com/project/badge/Grade/18f1e1e99cb64fe0a86d8b6185949448)](https://app.codacy.com/gh/egemenimre/ccsds-ndm/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade)
[![Codacy Badge](https://app.codacy.com/project/badge/Coverage/18f1e1e99cb64fe0a86d8b6185949448)](https://app.codacy.com/gh/egemenimre/ccsds-ndm/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_coverage)
[![Documentation Status](https://readthedocs.org/projects/ccsds-ndm/badge/?version=latest)](https://ccsds-ndm.readthedocs.io/en/latest/?badge=latest)
[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.4765552.svg)](https://doi.org/10.5281/zenodo.4765552)

## Description

The Consultative Committee for Space Data Systems (CCSDS) develops communications and data systems standards for spaceflight. [CCSDS Navigation Data Messages (NDM)](https://ccsds.org) is the set of file standards to define common data types such as trajectory, orbit, attitude and conjunction events. These data types are routinely generated and exchanged within and between spacecraft operators, space agencies, researchers, amateurs and commercial companies. As such, accurate definition and common interpretation of the data is crucial (and sometimes mission-critical).

The standard description for each data type is encapsulated in an XML Schema file. This project `ccsds-ndm` aims to be the reference open-source Python implementation to read and write the NDM XML and KVN files, through an object tree API, auto-generated by these schema files. It supports the up-to-date NDM XML 4.0 standard as well as the old NDM XML 2.0 and 1.0 standards.

The source code is [on Github](https://github.com/egemenimre/ccsds-ndm) and the documentation is
[on Readthedocs](https://ccsds-ndm.readthedocs.io/).

Current functionality:

|       | Read                                       | Write                                      |
|-------|--------------------------------------------|--------------------------------------------|
| XML   | All NDM Types                              | All NDM Types                              |
| KVN   | All except NDM Combined Instantiation      | All except NDM Combined Instantiation      |
| JSON  | Not specified in CCSDS Standards           | Not specified in CCSDS Standards           |

## Usage and Examples

There are two main use cases:

- The `ccsds-ndm` library reads the NDM file, fills an object tree and offers it to the users. The users will then have to fill their own attitude, orbit or trajectory objects used in their libraries.
- The user fills an object tree from their own attitude, orbit or trajectory object. The `ccsds-ndm` library writes the NDM file using this object tree.

For the first use case, reading an OEM file from `xml_read_path` is as simple as:

```python
cdm = NdmIo().from_path(xml_read_path)
```

Note that file format (XML or KVN) and data type (e.g. CDM or NDM) are inferred automatically. The output `cdm` is the object tree for a Conjunction Data Message (CDM). The contents can then be reached going deeper in the object tree as specified in the corresponding NDM Standard. This example shows how to reach the orbit normal position component of the relative state vector:

```python
print(cdm.body.relative_metadata_data.relative_state_vector.relative_position_n)
```

The data can sometimes be of type NDM Combined Instantiation. This means that there are multiple NDM data bodies (e.g. 2 AEMs, 3 OEMs and one OMM) within a single file. The file reader supports these types as well and they are kept within the `Ndm` object as individual lists for each of the file types. The following example retrieves the second `Omm` object in the NDM file and then continues to dive deeper into the object tree to retrieve the eccentricity value.

```python
print(ndm.omm[1].body.segment.data.mean_elements.eccentricity)
```

If the file is of the type NDM Combined Instantiation but there is only a single data (e.g. OMM) in it, the ndm tags are stripped and only the single data is presented to the user.

Filling the objects with data properly requires some care. As the standard is understandably strict, the object tree derived from the XSD files are also rather exacting in how they accept data. Every field that holds a physical quantity must be set with the corresponding *wrapper type* (e.g. `LengthType`, `DvType`). Assigning a plain number or string raises a `TypeError` immediately.

```python
# Correct: wrapper type with explicit units
cdm.body.relative_metadata_data.relative_state_vector.relative_position_t = LengthType(value=800, units=LengthUnits.M)

# Also correct: pint or astropy Quantity — auto-wrapped to the right type
import pint
u = pint.UnitRegistry()
cdm.body.relative_metadata_data.relative_state_vector.relative_position_r = 700 * u.m

# Also correct with auto-convert enabled: any compatible unit is silently converted
from ccsds_ndm.model_quantity import set_auto_convert
set_auto_convert(True)
cdm.body.relative_metadata_data.relative_state_vector.relative_position_r = 0.7 * u.km  # → 700.0 m

# Invalid: raises TypeError
cdm.body.relative_metadata_data.relative_state_vector.relative_position_r = 600
```

The XML output for the correct assignments properly transmits unit information:

```xml
<relativeStateVector>
  <RELATIVE_POSITION_R units="m">700</RELATIVE_POSITION_R>
  <RELATIVE_POSITION_T units="m">800</RELATIVE_POSITION_T>
```

Optional unit support: reading a value back as a pint or astropy `Quantity` is done via the `.q()` method on any wrapper instance:

```python
from ccsds_ndm.model_quantity import set_quantity_mode, QuantityMode
set_quantity_mode(QuantityMode.PINT)

q = cdm.body.relative_metadata_data.relative_state_vector.relative_position_t.q()
# q is a pint Quantity: 800.0 meter
```

Therefore, care must be taken (and standard documents must be kept as a reference) when mapping the user objects into the object tree. Valuable information on units, models and methods can be found there to correctly interpret the data. Also, comments can also be used to provide supplementary information on how this data is generated.

Finally, once filled with the relevant data, the `cdm` object can be written to `xml_write_path` in XML data format as:

```python
NdmIo().to_file(cdm, NDMFileFormats.XML, xml_write_path)
```

The `ndm` object trees are not very user friendly and most probably will have to be filled by the users' own equivalent objects (trajectory, orbit, attitude etc.).

## Installing `ccsds-ndm`

The `ccsds-ndm` package is on [PyPI](https://pypi.org/project/ccsds_ndm/) and you can install it simply by running:

```bash
pip install ccsds_ndm
```

You can also install it via [conda-forge](https://anaconda.org/conda-forge/ccsds_ndm):

```bash
conda install -c conda-forge ccsds_ndm
```

Do not install `ccsds-ndm` using `sudo`.

## More Information Regarding the CCSDS-NDM

The top-level description of the standard is given in the [Navigation Data — Definitions and Conventions Green Book](https://ccsds.org/Pubs/500x0g4.pdf) and [Navigation Data Messages Overview Green Book](https://ccsds.org/Pubs/500x2g3.pdf). Individual data types are defined in their individual definitions (e.g. [Conjunction Data Message](https://ccsds.org/Pubs/508x0b1e2c2.pdf) and [Orbit Data Messages](https://ccsds.org/Pubs/502x0b3e1.pdf)). The centre for all the standards is the [CCSDS Website](https://ccsds.org).

The Schema files are found in the [SANA Registry](https://sanaregistry.org/r/ndmxml).

## Design and Limitations

The object tree is created by [xsdata](https://xsdata.readthedocs.io/en/latest/) library, which also handles parsing and writing of the XML data. As such, there is no detailed documentation generated for this object tree.

File read is usually fast (on the order of milliseconds) for small files. That said, KVN parsing for large files can take some time. Due to the fragility of the KVN format and the restrictions the standards put on the order of keys, no parallelization has been attempted.

## Requirements

- `xsData` is used to read and write XML files (and also to generate the object tree)
- `lxml` to support XML object creation
- `pint` *(optional)* for pint Quantity input/output — install with `pip install ccsds_ndm[pint]`
- `astropy` *(optional)* for astropy Quantity input/output — install with `pip install ccsds_ndm[astropy]`

## Citation

Please use the DOI for citations. This is the latest version:

[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.5152279.svg)](https://zenodo.org/records/5152279)

## License

This project is Copyright (c) Egemen Imre and licensed under the terms of the GNU GPL v3+ license.

