├── .github └── workflows │ └── build.yml ├── .gitignore ├── LICENSE.md ├── README.md ├── codecov.yml ├── docs ├── Makefile ├── _static │ ├── Space_Debris_Low_Earth_Orbit.png │ └── kessler_logo.png ├── api.rst ├── capabilities.ipynb ├── conf.py ├── credits.ipynb ├── index.md ├── install.rst ├── make.bat ├── notebooks │ ├── LSTM_training.ipynb │ ├── basics.ipynb │ ├── cdms_analysis_and_plotting.ipynb │ ├── kelvins_dataset.ipynb │ ├── plotting.ipynb │ ├── probabilistic_programming_module.ipynb │ ├── synthetic_cdms │ │ ├── event1_0.kvn │ │ ├── event1_1.kvn │ │ ├── event1_2.kvn │ │ ├── event1_3.kvn │ │ ├── event1_4.kvn │ │ ├── event1_5.kvn │ │ ├── event1_6.kvn │ │ ├── event2_0.kvn │ │ ├── event2_1.kvn │ │ ├── event2_2.kvn │ │ ├── event2_3.kvn │ │ ├── event2_4.kvn │ │ ├── event2_5.kvn │ │ └── event2_6.kvn │ ├── tles_sample_population.txt │ └── trace.pickle └── tutorials.rst ├── kessler ├── __init__.py ├── cdm.py ├── data.py ├── event.py ├── model.py ├── nn.py ├── observation_model.py ├── plot.py └── util.py ├── setup.py └── tests ├── run_basics.sh ├── test_cdm.py ├── test_event.py ├── test_model.py ├── test_observation_model.py └── test_util.py /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | env: 4 | # Use the same ssh-agent socket value across all jobs 5 | # Useful when a GH action is using SSH behind-the-scenes 6 | SSH_AUTH_SOCK: /tmp/ssh_agent.sock 7 | 8 | on: 9 | push: 10 | branches: [ master ] 11 | pull_request: 12 | branches: [ '**' ] 13 | 14 | jobs: 15 | build: 16 | 17 | runs-on: ubuntu-latest 18 | 19 | steps: 20 | - name: Checkout repository 21 | uses: actions/checkout@v3 22 | - name: Set up Python 3.9 23 | uses: actions/setup-python@master 24 | with: 25 | python-version: 3.9 26 | - name: Install 27 | run: | 28 | python -m pip install --upgrade pip 29 | pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu 30 | pip install .[dev] 31 | pip install sphinx 32 | pip install sphinx-book-theme 33 | pip install myst-nb 34 | cd docs 35 | make html linkcheck 36 | - name: Test 37 | run: | 38 | coverage run -m pytest 39 | coverage xml 40 | - name: Codecov 41 | uses: codecov/codecov-action@v3 42 | with: 43 | token: ${{ secrets.CODECOV_TOKEN }} 44 | verbose: true 45 | - name: Upload to github pages 🚀 46 | if: ${{ github.event_name == 'push' }} 47 | uses: JamesIves/github-pages-deploy-action@v4 48 | with: 49 | folder: docs/_build/html # The folder the action should deploy. 50 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | cover/ 54 | 55 | # Translations 56 | *.mo 57 | *.pot 58 | 59 | # Django stuff: 60 | *.log 61 | local_settings.py 62 | db.sqlite3 63 | db.sqlite3-journal 64 | 65 | # Flask stuff: 66 | instance/ 67 | .webassets-cache 68 | 69 | # Scrapy stuff: 70 | .scrapy 71 | 72 | # Sphinx documentation 73 | docs/_build/ 74 | docs/source/_autosummary 75 | 76 | # PyBuilder 77 | .pybuilder/ 78 | target/ 79 | 80 | # Jupyter Notebook 81 | .ipynb_checkpoints 82 | 83 | # IPython 84 | profile_default/ 85 | ipython_config.py 86 | 87 | # pyenv 88 | # For a library or package, you might want to ignore these files since the code is 89 | # intended to run in multiple environments; otherwise, check them in: 90 | # .python-version 91 | 92 | # pipenv 93 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 94 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 95 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 96 | # install all needed dependencies. 97 | #Pipfile.lock 98 | 99 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 100 | __pypackages__/ 101 | 102 | # Celery stuff 103 | celerybeat-schedule 104 | celerybeat.pid 105 | 106 | # SageMath parsed files 107 | *.sage.py 108 | 109 | # Environments 110 | .env 111 | .venv 112 | env/ 113 | venv/ 114 | ENV/ 115 | env.bak/ 116 | venv.bak/ 117 | 118 | # Spyder project settings 119 | .spyderproject 120 | .spyproject 121 | 122 | # Rope project settings 123 | .ropeproject 124 | 125 | # mkdocs documentation 126 | /site 127 | 128 | # mypy 129 | .mypy_cache/ 130 | .dmypy.json 131 | dmypy.json 132 | 133 | # Pyre type checker 134 | .pyre/ 135 | 136 | # pytype static type analyzer 137 | .pytype/ 138 | 139 | # Cython debug symbols 140 | cython_debug/ 141 | 142 | .vscode 143 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Kessler 2 | 3 | 4 |
5 |

6 | 7 | Logo 8 | 9 |

10 | Kessler 11 |
12 | Explore the docs » 13 |
14 |
15 | Report bug 16 | · 17 | Request feature 18 |

19 |

20 | 21 | ----------------------------------------- 22 | [![Build Status](https://github.com/kesslerlib/kessler/workflows/build/badge.svg)](https://github.com/kesslerlib/kessler/actions) 23 | [![codecov](https://codecov.io/gh/kesslerlib/kessler/branch/master/graph/badge.svg?token=EQ9CLXD909)](https://codecov.io/gh/kesslerlib/kessler) 24 | [![Anaconda-Server Badge](https://anaconda.org/conda-forge/kessler/badges/latest_release_relative_date.svg)](https://anaconda.org/conda-forge/kessler) 25 | 26 | Kessler is a Python package for simulation-based inference and machine learning for space collision avoidance and assessment. It is named in honor of NASA scientist [Donald J. Kessler](https://en.wikipedia.org/wiki/Donald_J._Kessler) known for his studies regarding [space debris](https://en.wikipedia.org/wiki/Space_debris) and proposing the [Kessler syndrome](https://en.wikipedia.org/wiki/Kessler_syndrome). 27 | 28 | Initially developed by the [FDL Europe](https://fdleurope.org/) Constellations team in collaboration with [European Space Operations Centre (ESOC)](http://www.esa.int/esoc) of the [European Space Agency (ESA)](http://www.esa.int). 29 | 30 | ## Documentation and roadmap 31 | 32 | To get started, follow the [documentation](https://kesslerlib.github.io/kessler/) examples. 33 | 34 | ## Authors 35 | 36 | Kessler was initiated by the Constellations team at the Frontier Development Lab (FDL) Europe 2020, a public–private partnership between the European Space Agency (ESA), Trillium Technologies, and University of Oxford. The main developer is [Giacomo Acciarini](https://www.esa.int/gsp/ACT/team/giacomo_acciarini/). 37 | 38 | Constellations team members: Giacomo Acciarini, Francesco Pinto, Sascha Metz, Sarah Boufelja, Sylvester Kaczmarek, Klaus Merz, José A. Martinez-Heras, Francesca Letizia, Christopher Bridges, Atılım Güneş Baydin 39 | 40 | ## License 41 | 42 | Kessler is distributed under the GNU General Public License version 3. Get in touch with the authors for other licensing options. 43 | 44 | ## More info and how to cite 45 | 46 | If you use `kessler`, we would be grateful if you could star the repository and/or cite our work. 47 | If you would like to learn more about or cite the techniques `kessler` uses, please see the following papers: 48 | 49 | * Giacomo Acciarini, Nicola Baresi, Christopher Bridges, Leonard Felicetti, Stephen Hobbs, Atılım Güneş Baydin. 2023. [“Observation Strategies and Megaconstellations Impact on Current LEO Population.”](https://conference.sdo.esoc.esa.int/proceedings/neosst2/paper/88) In 2nd NEO and Debris Detection Conference. 50 | ```bibtex 51 | @inproceedings{acciarini-2023-observation, 52 | title = {Observation Strategies and Megaconstellations Impact on Current LEO Population}, 53 | author = {Acciarini, Giacomo and Baresi, Nicola and Bridges, Christopher and Felicetti, Leonard and Hobbs, Stephen and Baydin, Atılım Güneş}, 54 | booktitle = {2nd NEO and Debris Detection Conference}, 55 | year = {2023} 56 | } 57 | ``` 58 | * Giacomo Acciarini, Francesco Pinto, Francesca Letizia, José A. Martinez-Heras, Klaus Merz, Christopher Bridges, and Atılım Güneş Baydin. 2021. [“Kessler: a Machine Learning Library for Spacecraft Collision Avoidance.”](https://conference.sdo.esoc.esa.int/proceedings/sdc8/paper/226) In 8th European Conference on Space Debris. 59 | ```bibtex 60 | @inproceedings{acciarini-2020-kessler, 61 | title = {Kessler: a Machine Learning Library for Spacecraft Collision Avoidance}, 62 | author = {Acciarini, Giacomo and Pinto, Francesco and Letizia, Francesca and Martinez-Heras, José A. and Merz, Klaus and Bridges, Christopher and Baydin, Atılım Güneş}, 63 | booktitle = {8th European Conference on Space Debris}, 64 | year = {2021} 65 | } 66 | ``` 67 | * Francesco Pinto, Giacomo Acciarini, Sascha Metz, Sarah Boufelja, Sylvester Kaczmarek, Klaus Merz, José A. Martinez-Heras, Francesca Letizia, Christopher Bridges, and Atılım Güneş Baydin. 2020. “Towards Automated Satellite Conjunction Management with Bayesian Deep Learning.” In AI for Earth Sciences Workshop at NeurIPS 2020, Vancouver, Canada. [arXiv:2012.12450](https://arxiv.org/abs/2012.12450) 68 | ```bibtex 69 | @inproceedings{pinto-2020-automated, 70 | title = {Towards Automated Satellite Conjunction Management with Bayesian Deep Learning}, 71 | author = {Pinto, Francesco and Acciarini, Giacomo and Metz, Sascha and Boufelja, Sarah and Kaczmarek, Sylvester and Merz, Klaus and Martinez-Heras, José A. and Letizia, Francesca and Bridges, Christopher and Baydin, Atılım Güneş}, 72 | booktitle = {AI for Earth Sciences Workshop at NeurIPS 2020, Vancouver, Canada}, 73 | year = {2020} 74 | } 75 | ``` 76 | * Giacomo Acciarini, Francesco Pinto, Sascha Metz, Sarah Boufelja, Sylvester Kaczmarek, Klaus Merz, José A. Martinez-Heras, Francesca Letizia, Christopher Bridges, and Atılım Güneş Baydin. 2020. “Spacecraft Collision Risk Assessment with Probabilistic Programming.” In Third Workshop on Machine Learning and the Physical Sciences (NeurIPS 2020), Vancouver, Canada. [arXiv:2012.10260](https://arxiv.org/abs/2012.10260) 77 | ```bibtex 78 | @inproceedings{acciarini-2020-spacecraft, 79 | title = {Spacecraft Collision Risk Assessment with Probabilistic Programming}, 80 | author = {Acciarini, Giacomo and Pinto, Francesco and Metz, Sascha and Boufelja, Sarah and Kaczmarek, Sylvester and Merz, Klaus and Martinez-Heras, José A. and Letizia, Francesca and Bridges, Christopher and Baydin, Atılım Güneş}, 81 | booktitle = {Third Workshop on Machine Learning and the Physical Sciences (NeurIPS 2020), Vancouver, Canada}, 82 | year = {2020} 83 | } 84 | ``` 85 | 86 | ## Installation 87 | 88 | Via [conda](https://anaconda.org/conda-forge/kessler): 89 | ``` 90 | conda install conda-forge::kessler 91 | ``` 92 | 93 | or mamba: 94 | ``` 95 | mamba install kessler 96 | ``` 97 | 98 | Via [pip](https://pypi.org/project/kessler/): 99 | ``` 100 | pip install kessler 101 | ``` 102 | Local installation: 103 | 104 | ``` 105 | git clone https://github.com/kesslerlib/kessler.git 106 | cd kessler 107 | pip install -e . 108 | ``` 109 | 110 | ## Installation 111 | * `giacomo.acciarini@gmail.com` -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | coverage: 2 | ignore: 3 | - "test/.*" 4 | 5 | comment: off 6 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= -WT --keep-going 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = . 9 | BUILDDIR = _build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /docs/_static/Space_Debris_Low_Earth_Orbit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kesslerlib/kessler/cc9404a73d6e9719b1c1be317ab2271e9dedea45/docs/_static/Space_Debris_Low_Earth_Orbit.png -------------------------------------------------------------------------------- /docs/_static/kessler_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kesslerlib/kessler/cc9404a73d6e9719b1c1be317ab2271e9dedea45/docs/_static/kessler_logo.png -------------------------------------------------------------------------------- /docs/api.rst: -------------------------------------------------------------------------------- 1 | .. _api: 2 | 3 | API 4 | ####### 5 | 6 | Kessler API 7 | 8 | .. currentmodule:: kessler 9 | 10 | .. autosummary:: 11 | :toctree: _autosummary 12 | :recursive: 13 | 14 | cdm 15 | data 16 | event 17 | model 18 | nn 19 | observation_model 20 | plot 21 | util -------------------------------------------------------------------------------- /docs/capabilities.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "b8ca3794", 6 | "metadata": {}, 7 | "source": [ 8 | "# Capabilities\n", 9 | "\n", 10 | "Kessler is an open-source Python package that currently includes Bayesian ML and probabilistic programming components. The library currently provides the following key capabiolities:\n", 11 | "\n", 12 | "\n", 13 | "* Functionality to import and export Conjunction Data Messages (CDM) data, using either the CDM standard format or databases that can be connected to Kessler through an API based on pandas DataFrame objects, and grouping CDMs into Events objects representing conjunctions.\n", 14 | "\n", 15 | "* Plotting code to visualize event evolution of existing CDMs or predicted ones.\n", 16 | "\n", 17 | "* A ML module that currently implements a stack of Bayesian long short-term memory (LSTM) neural networks that can be used to train with user’s private collection of CDM data.\n", 18 | "\n", 19 | "* A probabilistic programming module built on [Pyro](https://github.com/pyro-ppl/pyro) simulating conjunction events and CDM generation process. This can be useful both for performing event analysis using Bayesian inference or for generating synthetic CDM datasets sampled from this probabilistic generative model.\n", 20 | "\n" 21 | ] 22 | } 23 | ], 24 | "metadata": { 25 | "kernelspec": { 26 | "display_name": "Python 3 (ipykernel)", 27 | "language": "python", 28 | "name": "python3" 29 | }, 30 | "language_info": { 31 | "codemirror_mode": { 32 | "name": "ipython", 33 | "version": 3 34 | }, 35 | "file_extension": ".py", 36 | "mimetype": "text/x-python", 37 | "name": "python", 38 | "nbconvert_exporter": "python", 39 | "pygments_lexer": "ipython3", 40 | "version": "3.8.15" 41 | } 42 | }, 43 | "nbformat": 4, 44 | "nbformat_minor": 5 45 | } 46 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # Configuration file for the Sphinx documentation builder. 2 | # 3 | # This file only contains a selection of the most common options. For a full 4 | # list see the documentation: 5 | # https://www.sphinx-doc.org/en/master/usage/configuration.html 6 | 7 | # -- Path setup -------------------------------------------------------------- 8 | 9 | # If extensions (or modules to document with autodoc) are in another directory, 10 | # add these directories to sys.path here. If the directory is relative to the 11 | # documentation root, use os.path.abspath to make it absolute, like shown here. 12 | # 13 | project = 'kessler' 14 | copyright = "2020-2025, Kessler contributors" 15 | author = 'Giacomo Acciarini, Atılım Güneş Baydin' 16 | 17 | 18 | # The full version, including alpha/beta/rc tags 19 | import kessler 20 | 21 | release = kessler.__version__ 22 | 23 | 24 | 25 | # -- General configuration --------------------------------------------------- 26 | 27 | # Add any Sphinx extension module names here, as strings. They can be 28 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 29 | # ones. 30 | extensions = ["myst_nb", "sphinx.ext.autodoc", "sphinx.ext.doctest", "sphinx.ext.intersphinx", "sphinx.ext.autosummary","sphinx.ext.napoleon"] 31 | 32 | 33 | # build the templated autosummary files 34 | autosummary_generate = True 35 | autosummary_imported_members = True 36 | napoleon_google_docstring = True 37 | numpydoc_show_class_members = False 38 | panels_add_bootstrap_css = False 39 | 40 | autosectionlabel_prefix_document = True 41 | 42 | # katex options 43 | # 44 | # 45 | katex_prerender = True 46 | 47 | napoleon_use_ivar = True 48 | 49 | # Add any paths that contain templates here, relative to this directory. 50 | templates_path = ["_templates"] 51 | 52 | intersphinx_mapping = { 53 | "numpy": ("https://numpy.org/doc/stable/", None), 54 | "python": ("https://docs.python.org/3", None), 55 | } 56 | 57 | autoclass_content = 'both' 58 | 59 | # List of patterns, relative to source directory, that match files and 60 | # directories to ignore when looking for source files. 61 | # This pattern also affects html_static_path and html_extra_path. 62 | exclude_patterns = ["_build", ".DS_Store", ".pickle",".txt",'jupyter_execute/**/*.ipynb','jupyter_execute/*.ipynb'] 63 | 64 | 65 | # -- Options for HTML output ------------------------------------------------- 66 | 67 | # The theme to use for HTML and HTML Help pages. See the documentation for 68 | # a list of builtin themes. 69 | # 70 | html_theme = "sphinx_book_theme" 71 | 72 | # Add any paths that contain custom static files (such as style sheets) here, 73 | # relative to this directory. They are copied after the builtin static files, 74 | # so a file named "default.css" will overwrite the builtin "default.css". 75 | html_static_path = ["_static"] 76 | 77 | html_logo = "_static/kessler_logo.png" 78 | 79 | linkcheck_ignore = [ 80 | r'https://www\.esa\.int/gsp/ACT/team/giacomo_acciarini/', 81 | r'https://kelvins.esa.int/collision-avoidance-challenge/' 82 | ] 83 | 84 | html_theme_options = { 85 | "repository_url": "https://github.com/kesslerlib/kessler/", 86 | "repository_branch": "master", 87 | "path_to_docs": "doc", 88 | "use_repository_button": True, 89 | "use_issues_button": True, 90 | "launch_buttons": { 91 | "binderhub_url": "https://mybinder.org", 92 | "notebook_interface": "jupyterlab" 93 | }, 94 | "navigation_with_keys": False, 95 | } 96 | 97 | nb_execution_mode = "force" 98 | 99 | nb_execution_excludepatterns = [ 100 | "LSTM_training.ipynb", 101 | "basics.ipynb", 102 | "probabilistic_programming_module.ipynb", 103 | "plotting.ipynb", 104 | "kelvins_dataset.ipynb" 105 | ] 106 | 107 | latex_engine = "xelatex" 108 | 109 | myst_enable_extensions = [ 110 | "amsmath", 111 | "colon_fence", 112 | "deflist", 113 | "dollarmath", 114 | "html_image", 115 | ] -------------------------------------------------------------------------------- /docs/credits.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "96b808b8", 6 | "metadata": {}, 7 | "source": [ 8 | "# Credits\n", 9 | "\n", 10 | "Kessler was initially developed by the Constellations team at the [Frontier Development Lab](https://frontierdevelopmentlab.org/) (FDL) Europe 2020, a public-private partnership between the European Space Agency (ESA), Trillium Technologies, and University of Oxford.\n", 11 | "\n", 12 | "The main developer is: Giacomo Acciarini ( giacomo.acciarini@gmail.com )." 13 | ] 14 | } 15 | ], 16 | "metadata": { 17 | "kernelspec": { 18 | "display_name": "Python 3 (ipykernel)", 19 | "language": "python", 20 | "name": "python3" 21 | }, 22 | "language_info": { 23 | "codemirror_mode": { 24 | "name": "ipython", 25 | "version": 3 26 | }, 27 | "file_extension": ".py", 28 | "mimetype": "text/x-python", 29 | "name": "python", 30 | "nbconvert_exporter": "python", 31 | "pygments_lexer": "ipython3", 32 | "version": "3.8.15" 33 | } 34 | }, 35 | "nbformat": 4, 36 | "nbformat_minor": 5 37 | } 38 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | Kessler Reference Documentation 2 | ================================ 3 | 4 | Kessler is a Python package for machine learning applied to spacecraft collision avoidance. It provides functionalities to import, export, analyze, and plot conjunction data messages (CDMs) in their standard format and predict the evolution of satellite conjunction events based on explainable machine learning models. 5 | 6 | The package comprises a Deep Learning module, where a Bayesian recurrent neural network can be trained with existing collections of CDM data and then deployed in order to predict the contents of future CDMs received up to now, with associated uncertainty estimates about all predictions. 7 | 8 | Kessler also includes a novel generative model of conjunction events and CDM sequences implemented using probabilistic programming and simulating the CDM generation process. 9 | 10 | For more details on the model and results, check out our publications listed in the README of the repository. 11 | 12 | The authors are [Giacomo Acciarini](https://www.esa.int/gsp/ACT/team/giacomo_acciarini/), [Atılım Güneş Baydin](https://gbaydin.github.io/), Francesco Pinto, and the FDL Europe Constellation team. 13 | 14 | 15 | ```{toctree} 16 | :maxdepth: 1 17 | :caption: Getting Started 18 | 19 | install 20 | capabilities 21 | credits 22 | ``` 23 | 24 | ```{toctree} 25 | :maxdepth: 1 26 | :caption: Contents 27 | 28 | tutorials 29 | api 30 | ``` 31 | 32 | Indices and tables 33 | ================== 34 | 35 | * :ref:`genindex` 36 | * :ref:`modindex` 37 | 38 | -------------------------------------------------------------------------------- /docs/install.rst: -------------------------------------------------------------------------------- 1 | Installation 2 | ============ 3 | 4 | .. _installation_deps: 5 | 6 | 7 | Packages 8 | -------- 9 | 10 | conda 11 | ^^^^^ 12 | 13 | `kessler` is available on [Anaconda](https://anaconda.org/conda-forge/kessler). 14 | To install it via `conda`, we add `conda-forge` channel to the channels: 15 | 16 | .. code-block:: console 17 | 18 | $ conda config --add channels conda-forge 19 | $ conda config --set channel_priority strict 20 | 21 | Now, we can install `kessler` either through `conda`: 22 | 23 | .. code-block:: console 24 | 25 | $ conda install kessler 26 | 27 | or `mamba`: 28 | 29 | .. code-block:: console 30 | 31 | $ mamba install kessler 32 | 33 | 34 | 35 | pip 36 | ^^^ 37 | 38 | `kessler` is available on [Pypi](https://pypi.org/project/kessler/). You can install it via `pip` as: 39 | 40 | .. code-block:: console 41 | 42 | $ pip install kessler 43 | 44 | Installation from source 45 | ------------------------ 46 | 47 | 48 | Using ``git``: 49 | 50 | .. code-block:: console 51 | 52 | $ git clone https://github.com/kesslerlib/kessler 53 | 54 | We follow the usual PR-based development workflow, thus kessler's ``master`` 55 | branch is normally kept in a working state. 56 | 57 | Verifying the installation 58 | -------------------------- 59 | 60 | You can verify that kessler was successfully compiled and 61 | installed by running the tests. To do so, you must first install the 62 | optional dependencies. 63 | 64 | .. code-block:: bash 65 | 66 | $ pytest 67 | 68 | If this command executes without any error, then 69 | your kessler installation is ready for use. 70 | 71 | Getting help 72 | ------------ 73 | 74 | If you run into troubles installing `kessler`, please do not hesitate 75 | to contact us by opening an issue report on `github `__. -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=. 11 | set BUILDDIR=_build 12 | 13 | if "%1" == "" goto help 14 | 15 | %SPHINXBUILD% >NUL 2>NUL 16 | if errorlevel 9009 ( 17 | echo. 18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 19 | echo.installed, then set the SPHINXBUILD environment variable to point 20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 21 | echo.may add the Sphinx directory to PATH. 22 | echo. 23 | echo.If you don't have Sphinx installed, grab it from 24 | echo.http://sphinx-doc.org/ 25 | exit /b 1 26 | ) 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 | 34 | :end 35 | popd -------------------------------------------------------------------------------- /docs/notebooks/basics.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Basics: loading CDMs\n", 8 | "\n" 9 | ] 10 | }, 11 | { 12 | "cell_type": "markdown", 13 | "metadata": {}, 14 | "source": [ 15 | "## Load CDMs from .kvn \n", 16 | "\n" 17 | ] 18 | }, 19 | { 20 | "cell_type": "markdown", 21 | "metadata": {}, 22 | "source": [ 23 | "In this tutorial, we show how to load CDMs from ``.kvn`` format.\n", 24 | "\n", 25 | "First, the CDMs in ``.kvn`` format need to be placed inside the ``path_to_cdms_folder``, for correctly loading the data. Furthermore, the code expects the CDMs in the folder to have file names grouped by: individual event and the CDM sequence in each event.\n", 26 | "\n", 27 | "For instance, if we have to load two events with 3 and 2 CDMs each, we might then have file names in the following format:\n", 28 | "* ``event_1_01.cdm.kvn.txt``\n", 29 | "* ``event_1_02.cdm.kvn.txt``\n", 30 | "* ``event_1_03.cdm.kvn.txt``\n", 31 | "* ``event_2_01.cdm.kvn.txt``\n", 32 | "* ``event_2_02.cdm.kvn.txt``\n", 33 | "\n", 34 | "\n" 35 | ] 36 | }, 37 | { 38 | "cell_type": "code", 39 | "execution_count": 1, 40 | "metadata": {}, 41 | "outputs": [], 42 | "source": [ 43 | "from kessler import EventDataset" 44 | ] 45 | }, 46 | { 47 | "cell_type": "markdown", 48 | "metadata": {}, 49 | "source": [ 50 | "We can then proceed in creating the ``EventDataset`` object:\n", 51 | "\n" 52 | ] 53 | }, 54 | { 55 | "cell_type": "code", 56 | "execution_count": 2, 57 | "metadata": {}, 58 | "outputs": [ 59 | { 60 | "name": "stdout", 61 | "output_type": "stream", 62 | "text": [ 63 | "Loading CDMS (with extension .kvn) from directory: synthetic_cdms/\n", 64 | "Loaded 14 CDMs grouped into 2 events\n" 65 | ] 66 | } 67 | ], 68 | "source": [ 69 | "path_to_cdms_folder='synthetic_cdms/'\n", 70 | "\n", 71 | "events=EventDataset(path_to_cdms_folder,cdm_extension='.kvn')\n", 72 | "#A message appears confirming that the loading has happened, with the number of CDMs and events." 73 | ] 74 | }, 75 | { 76 | "cell_type": "markdown", 77 | "metadata": {}, 78 | "source": [ 79 | "## Loading CDMs from [Kelvins Challenge](https://kelvins.esa.int/collision-avoidance-challenge/) dataset\n", 80 | "\n", 81 | "\n", 82 | "\n", 83 | "\n", 84 | "\n" 85 | ] 86 | }, 87 | { 88 | "cell_type": "markdown", 89 | "metadata": {}, 90 | "source": [ 91 | "In this tutorial, we show the case in which the data to be loaded comes from the [Kelvins competition](https://kelvins.esa.int/collision-avoidance-challenge/data/): a collision avoidance challenge organized by ESA in 2019.\n", 92 | "\n", 93 | "\n", 94 | "For this purpose, we built a specific converter that takes care of the conversion from the Kelvins format to standard CDM format.\n", 95 | "First, we perform the relevant imports:\n" 96 | ] 97 | }, 98 | { 99 | "cell_type": "code", 100 | "execution_count": 3, 101 | "metadata": {}, 102 | "outputs": [], 103 | "source": [ 104 | "from kessler.data import kelvins_to_event_dataset" 105 | ] 106 | }, 107 | { 108 | "cell_type": "markdown", 109 | "metadata": {}, 110 | "source": [ 111 | "Then, we proceed in converting the Kelvins dataset as an ``EventDataset`` objetc. In the following example, we leverage two extra entries (i.e., ``drop_features`` and ``num_events``) to exclude certain features when importing, and to only import a limited number of events (in this case 1000)." 112 | ] 113 | }, 114 | { 115 | "cell_type": "code", 116 | "execution_count": 10, 117 | "metadata": {}, 118 | "outputs": [ 119 | { 120 | "name": "stdout", 121 | "output_type": "stream", 122 | "text": [ 123 | "Loading Kelvins dataset from file name: /Users/giacomoacciarini/cdm_data/kelvins_data/test_data.csv\n", 124 | "24484 entries\n", 125 | "Dropping features: ['c_rcs_estimate', 't_rcs_estimate']\n", 126 | "Dropping rows with NaNs\n", 127 | "21932 entries\n", 128 | "Removing outliers\n", 129 | "19531 entries\n", 130 | "Shuffling\n", 131 | "Grouped rows into 1726 events\n", 132 | "Taking TCA as current time: 2022-02-17 23:50:10.189235\n", 133 | "Converting Kelvins challenge data to EventDataset\n", 134 | "Time spent | Time remain.| Progress | Events | Events/sec\n", 135 | "0d:00:00:07 | 0d:00:00:00 | #################### | 1000/1000 | 128.69 \n" 136 | ] 137 | } 138 | ], 139 | "source": [ 140 | "file_name='kelvins_data/test_data.csv'\n", 141 | "events=kelvins_to_event_dataset(file_name, drop_features=['c_rcs_estimate', 't_rcs_estimate'], num_events=1000)\n", 142 | "#The output will show the number of CDMs and events loaded, as they progress.\n" 143 | ] 144 | } 145 | ], 146 | "metadata": { 147 | "kernelspec": { 148 | "display_name": "kessler", 149 | "language": "python", 150 | "name": "python3" 151 | }, 152 | "language_info": { 153 | "codemirror_mode": { 154 | "name": "ipython", 155 | "version": 3 156 | }, 157 | "file_extension": ".py", 158 | "mimetype": "text/x-python", 159 | "name": "python", 160 | "nbconvert_exporter": "python", 161 | "pygments_lexer": "ipython3", 162 | "version": "3.12.8" 163 | } 164 | }, 165 | "nbformat": 4, 166 | "nbformat_minor": 4 167 | } 168 | -------------------------------------------------------------------------------- /docs/notebooks/kelvins_dataset.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import kessler\n", 10 | "from kessler.nn import LSTMPredictor\n", 11 | "from kessler.data import kelvins_to_event_dataset\n", 12 | "import pandas as pd\n", 13 | "\n", 14 | "# Set the random number generator seed for reproducibility\n", 15 | "kessler.seed(1)" 16 | ] 17 | }, 18 | { 19 | "cell_type": "markdown", 20 | "metadata": {}, 21 | "source": [ 22 | "# Data Loading\n", 23 | "\n", 24 | "Kessler accepts CDMs either in KVN format or as pandas dataframes. We hereby show a pandas dataframe loading example:" 25 | ] 26 | }, 27 | { 28 | "cell_type": "code", 29 | "execution_count": null, 30 | "id": "322e9b06", 31 | "metadata": {}, 32 | "outputs": [], 33 | "source": [ 34 | "#As an example, we first show the case in which the data comes from the Kelvins competition.\n", 35 | "#For this, we built a specific converter that takes care of the conversion from Kelvins format\n", 36 | "#to standard CDM format (the data can be downloaded at https://kelvins.esa.int/collision-avoidance-challenge/data/):\n", 37 | "file_name='kelvins_data/train_data.csv'\n", 38 | "events = kelvins_to_event_dataset(file_name, drop_features=['c_rcs_estimate', 't_rcs_estimate'], num_events=1000) #we use only 200 events" 39 | ] 40 | }, 41 | { 42 | "cell_type": "code", 43 | "execution_count": null, 44 | "metadata": {}, 45 | "outputs": [], 46 | "source": [ 47 | "#Instead, this is a generic real CDM data loader that should parse your Pandas (uncomment the following lines if needed):\n", 48 | "#file_name = 'path_to_csv/file.csv'\n", 49 | "\n", 50 | "#df=pd.read_csv(file_name)\n", 51 | "#events = EventDataset.from_pandas(df)" 52 | ] 53 | }, 54 | { 55 | "cell_type": "markdown", 56 | "metadata": {}, 57 | "source": [ 58 | "# Descriptive Statistics" 59 | ] 60 | }, 61 | { 62 | "cell_type": "code", 63 | "execution_count": null, 64 | "metadata": {}, 65 | "outputs": [], 66 | "source": [ 67 | "#Descriptive statistics of the event:\n", 68 | "kessler_stats = events.to_dataframe().describe()\n", 69 | "print(kessler_stats)\n" 70 | ] 71 | }, 72 | { 73 | "cell_type": "markdown", 74 | "metadata": {}, 75 | "source": [ 76 | "# LSTM Training" 77 | ] 78 | }, 79 | { 80 | "cell_type": "code", 81 | "execution_count": null, 82 | "metadata": {}, 83 | "outputs": [], 84 | "source": [ 85 | "#We only use features with numeric content for the training\n", 86 | "#nn_features is a list of the feature names taken into account for the training:\n", 87 | "#it can be edited in case more features want to be added or removed\n", 88 | "nn_features = events.common_features(only_numeric=True)\n", 89 | "print(nn_features)" 90 | ] 91 | }, 92 | { 93 | "cell_type": "code", 94 | "execution_count": null, 95 | "metadata": {}, 96 | "outputs": [], 97 | "source": [ 98 | "# Split data into a test set (5% of the total number of events)\n", 99 | "len_test_set=int(0.05*len(events))\n", 100 | "print('Test data:', len_test_set)\n", 101 | "events_test=events[-len_test_set:]\n", 102 | "print(events_test)\n", 103 | "\n", 104 | "# The rest of the data will be used for training and validation\n", 105 | "print('Training and validation data:', len(events)-len_test_set)\n", 106 | "events_train_and_val=events[:-len_test_set]\n", 107 | "print(events_train_and_val)" 108 | ] 109 | }, 110 | { 111 | "cell_type": "code", 112 | "execution_count": null, 113 | "metadata": {}, 114 | "outputs": [], 115 | "source": [ 116 | "# Create an LSTM predictor, specialized to the nn_features we extracted above\n", 117 | "model = LSTMPredictor(\n", 118 | " lstm_size=256, # Number of hidden units per LSTM layer\n", 119 | " lstm_depth=2, # Number of stacked LSTM layers\n", 120 | " dropout=0.2, # Dropout probability\n", 121 | " features=nn_features) # The list of feature names to use in the LSTM\n", 122 | "\n", 123 | "# Start training\n", 124 | "model.learn(events_train_and_val, \n", 125 | " epochs=10, # Number of epochs (one epoch is one full pass through the training dataset)\n", 126 | " lr=1e-3, # Learning rate, can decrease it if training diverges\n", 127 | " batch_size=16, # Minibatch size, can be decreased if there are issues with memory use\n", 128 | " device='cpu', # Can be 'cuda' if there is a GPU available\n", 129 | " valid_proportion=0.15, # Proportion of the data to use as a validation set internally\n", 130 | " num_workers=4, # Number of multithreaded dataloader workers, 4 is good for performance, but if there are any issues or errors, please try num_workers=1 as this solves issues with PyTorch most of the time\n", 131 | " event_samples_for_stats=1000) # Number of events to use to compute NN normalization factors, have this number as big as possible (and at least a few thousands)" 132 | ] 133 | }, 134 | { 135 | "cell_type": "code", 136 | "execution_count": null, 137 | "metadata": {}, 138 | "outputs": [], 139 | "source": [ 140 | "#Save the model to a file after training:\n", 141 | "model.save(file_name=\"LSTM_20epochs_lr10-4_batchsize16\")" 142 | ] 143 | }, 144 | { 145 | "cell_type": "code", 146 | "execution_count": null, 147 | "metadata": {}, 148 | "outputs": [], 149 | "source": [ 150 | "#NN loss plotted to a file:\n", 151 | "model.plot_loss(file_name='plot_loss.pdf')" 152 | ] 153 | }, 154 | { 155 | "cell_type": "code", 156 | "execution_count": null, 157 | "metadata": {}, 158 | "outputs": [], 159 | "source": [ 160 | "#we show an example CDM from the set:\n", 161 | "events_train_and_val[0][0]" 162 | ] 163 | }, 164 | { 165 | "cell_type": "code", 166 | "execution_count": null, 167 | "metadata": {}, 168 | "outputs": [], 169 | "source": [ 170 | "#we take a single event, we remove the last CDM and try to predict it\n", 171 | "event=events_test[3]\n", 172 | "event_len = len(event)\n", 173 | "print(event)\n", 174 | "event_beginning = event[0:event_len-1]\n", 175 | "print(event_beginning)\n", 176 | "event_evolution = model.predict_event(event_beginning, num_samples=100, max_length=14)" 177 | ] 178 | }, 179 | { 180 | "cell_type": "code", 181 | "execution_count": null, 182 | "metadata": {}, 183 | "outputs": [], 184 | "source": [ 185 | "#We plot the prediction in red:\n", 186 | "axs = event_evolution.plot_features(['RELATIVE_SPEED', 'MISS_DISTANCE', 'OBJECT1_CT_T'], return_axs=True, linewidth=0.1, color='red', alpha=0.33, label='Prediction')\n", 187 | "#and the ground truth value in blue:\n", 188 | "event.plot_features(['RELATIVE_SPEED', 'MISS_DISTANCE', 'OBJECT1_CT_T'], axs=axs, label='Real', legend=True)" 189 | ] 190 | }, 191 | { 192 | "cell_type": "code", 193 | "execution_count": null, 194 | "metadata": {}, 195 | "outputs": [], 196 | "source": [ 197 | "#we now plot the uncertainty prediction for all the covariance matrix elements of both OBJECT1 and OBJECT2:\n", 198 | "axs = event_evolution.plot_uncertainty(return_axs=True, linewidth=0.5, label='Prediction', alpha=0.5, color='red', legend=True, diagonal=False)\n", 199 | "event.plot_uncertainty(axs=axs, label='Real', diagonal=False)" 200 | ] 201 | } 202 | ], 203 | "metadata": { 204 | "kernelspec": { 205 | "display_name": "Python 3", 206 | "language": "python", 207 | "name": "python3" 208 | }, 209 | "language_info": { 210 | "codemirror_mode": { 211 | "name": "ipython", 212 | "version": 3 213 | }, 214 | "file_extension": ".py", 215 | "mimetype": "text/x-python", 216 | "name": "python", 217 | "nbconvert_exporter": "python", 218 | "pygments_lexer": "ipython3", 219 | "version": "3.8.5" 220 | } 221 | }, 222 | "nbformat": 4, 223 | "nbformat_minor": 5 224 | } 225 | -------------------------------------------------------------------------------- /docs/notebooks/probabilistic_programming_module.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "artificial-clinic", 6 | "metadata": {}, 7 | "source": [ 8 | "# Probabilistic Programming Module\n", 9 | "\n", 10 | "\n", 11 | "Here, we discuss how to use the probabilistic programming module to synthetically generate CDMs.\n", 12 | "\n" 13 | ] 14 | }, 15 | { 16 | "cell_type": "code", 17 | "execution_count": 1, 18 | "id": "d6f58e4e", 19 | "metadata": {}, 20 | "outputs": [], 21 | "source": [ 22 | "import kessler\n", 23 | "import pyro\n", 24 | "import numpy as np\n", 25 | "import dsgp4" 26 | ] 27 | }, 28 | { 29 | "cell_type": "code", 30 | "execution_count": 2, 31 | "id": "c0f44a09", 32 | "metadata": {}, 33 | "outputs": [], 34 | "source": [ 35 | "#we seed everything for reproducibility\n", 36 | "pyro.set_rng_seed(10)\n", 37 | "\n", 38 | "#we define the observing instruments\n", 39 | "#GNSS first:\n", 40 | "gnss_cov_rtn=np.array([1e-9, 1.115849341564346, 0.059309835843067, 1e-9, 1e-9, 1e-9])**2,\n", 41 | "instrument_characteristics_gnss={'bias_xyz': np.array([[0., 0., 0.],\n", 42 | " [0., 0., 0.]]), 'covariance_rtn': gnss_cov_rtn}\n", 43 | "gnss = kessler.GNSS(instrument_characteristics_gnss)\n", 44 | "\n", 45 | "#and then radar:\n", 46 | "radar_cov_rtn=np.array([1.9628939405514678, 2.2307686944695706, 0.9660907831563862, 1e-9, 1e-9, 1e-9])**2\n", 47 | "instrument_characteristics_radar={'bias_xyz': np.array([[0., 0., 0.],\n", 48 | " [0., 0., 0.]]), 'covariance_rtn': radar_cov_rtn}\n", 49 | "radar = kessler.Radar(instrument_characteristics_radar)\n" 50 | ] 51 | }, 52 | { 53 | "cell_type": "code", 54 | "execution_count": 3, 55 | "id": "245991f4", 56 | "metadata": {}, 57 | "outputs": [ 58 | { 59 | "name": "stdout", 60 | "output_type": "stream", 61 | "text": [ 62 | "loaded 20 TLEs\n" 63 | ] 64 | } 65 | ], 66 | "source": [ 67 | "tles=dsgp4.tle.load('tles_sample_population.txt')\n", 68 | "print(f\"loaded {len(tles)} TLEs\")" 69 | ] 70 | }, 71 | { 72 | "cell_type": "code", 73 | "execution_count": 6, 74 | "id": "29cf82bb", 75 | "metadata": {}, 76 | "outputs": [], 77 | "source": [ 78 | "# tles=dsgp4.tle.load('tles_sample_population.txt')\n", 79 | "\n", 80 | "# tles_filtered=[]\n", 81 | "# for tle in tqdm(tles):\n", 82 | "# try: \n", 83 | "# dsgp4.initialize_tle(tle)\n", 84 | "# if tle.apogee_alt()<560*1e3:\n", 85 | "# tles_filtered.append(tle)\n", 86 | "# except:\n", 87 | "# continue" 88 | ] 89 | }, 90 | { 91 | "cell_type": "code", 92 | "execution_count": 5, 93 | "id": "7eb20f3f", 94 | "metadata": {}, 95 | "outputs": [], 96 | "source": [ 97 | "conjunction_model = kessler.model.ConjunctionSimplified(time0=60727.13899462018,\n", 98 | " # max_duration_days=7.0,\n", 99 | " # time_resolution=600000.0,\n", 100 | " # time_upsample_factor=100,\n", 101 | " miss_dist_threshold=5000.0,\n", 102 | " prior_dict=None,\n", 103 | " t_prob_new_obs=0.96,\n", 104 | " c_prob_new_obs=0.4,\n", 105 | " cdm_update_every_hours=8.0,\n", 106 | " mc_samples=100,\n", 107 | " mc_upsample_factor=100,\n", 108 | " pc_method='MC',\n", 109 | " collision_threshold=70,\n", 110 | " # likelihood_t_stddev=[371.068006, 0.0999999999, 0.172560879],\n", 111 | " # likelihood_c_stddev=[371.068006, 0.0999999999, 0.172560879],\n", 112 | " likelihood_time_to_tca_stddev=0.7,\n", 113 | " t_observing_instruments=[gnss],\n", 114 | " c_observing_instruments=[radar],\n", 115 | " tles=tles,)" 116 | ] 117 | }, 118 | { 119 | "cell_type": "code", 120 | "execution_count": 6, 121 | "id": "20c49ee3", 122 | "metadata": {}, 123 | "outputs": [ 124 | { 125 | "name": "stderr", 126 | "output_type": "stream", 127 | "text": [ 128 | "/Users/ga00693/Develop/kessler/kessler/model.py:765: UserWarning: To copy construct from a tensor, it is recommended to use sourceTensor.clone().detach() or sourceTensor.clone().detach().requires_grad_(True), rather than torch.tensor(sourceTensor).\n", 129 | " pyro.deterministic('conj',torch.tensor(conj))\n", 130 | "/Users/ga00693/Develop/kessler/kessler/util.py:85: UserWarning: Using torch.cross without specifying the dim arg is deprecated.\n", 131 | "Please either pass the dim explicitly or simply use torch.linalg.cross.\n", 132 | "The default value of dim will change to agree with that of linalg.cross in a future release. (Triggered internally at /Users/runner/miniforge3/conda-bld/libtorch_1738206012956/work/aten/src/ATen/native/Cross.cpp:66.)\n", 133 | " h_vec = torch.cross(r_vec, v_vec)\n" 134 | ] 135 | }, 136 | { 137 | "name": "stdout", 138 | "output_type": "stream", 139 | "text": [ 140 | "After 1170 iterations, generated event with 2 CDMs\n" 141 | ] 142 | } 143 | ], 144 | "source": [ 145 | "trace,iterations=conjunction_model.get_conjunction()" 146 | ] 147 | }, 148 | { 149 | "cell_type": "code", 150 | "execution_count": 9, 151 | "id": "d1fcae4b", 152 | "metadata": {}, 153 | "outputs": [ 154 | { 155 | "data": { 156 | "text/plain": [ 157 | "[CCSDS_CDM_VERS = 1.0\n", 158 | " CREATION_DATE = 2025-02-21T03:20:09.135184\n", 159 | " ORIGINATOR = KESSLER_SOFTWARE\n", 160 | " MESSAGE_ID = KESSLER_SOFTWARE_ac66059e-20e6-11f0-b2ee-f2a9f71f7e1a\n", 161 | " TCA = 2025-02-22T01:17:28.408663\n", 162 | " MISS_DISTANCE = 141514.9960370336\n", 163 | " RELATIVE_SPEED = 8783.071096663718\n", 164 | " RELATIVE_POSITION_R = -3769.8761935982398\n", 165 | " RELATIVE_POSITION_T = -110791.09624826182\n", 166 | " RELATIVE_POSITION_N = -87963.71484285413\n", 167 | " RELATIVE_VELOCITY_R = -144.7709891581174\n", 168 | " RELATIVE_VELOCITY_T = -5424.100602146948\n", 169 | " RELATIVE_VELOCITY_N = -6906.555719570857\n", 170 | " COLLISION_PROBABILITY = 0.0\n", 171 | " COLLISION_PROBABILITY_METHOD = MC\n", 172 | " OBJECT = OBJECT1\n", 173 | " OBJECT_DESIGNATOR = 76126AP\n", 174 | " CATALOG_NAME = 9827\n", 175 | " OBJECT_NAME = COSMOS 886 DEB\n", 176 | " INTERNATIONAL_DESIGNATOR = 76126AP\n", 177 | " EPHEMERIS_NAME = NONE\n", 178 | " COVARIANCE_METHOD = CALCULATED\n", 179 | " MANEUVERABLE = N/A\n", 180 | " ORBIT_CENTER = EARTH\n", 181 | " REF_FRAME = ITRF\n", 182 | " X = 2980.1734541932515\n", 183 | " Y = -5181.782698754123\n", 184 | " Z = -3422.116689930527\n", 185 | " X_DOT = 4.425575967702924\n", 186 | " Y_DOT = -1.3655090728792418\n", 187 | " Z_DOT = 5.7673902574303915\n", 188 | " CR_R = 434.5847746412686\n", 189 | " CT_R = 3804.230266317108\n", 190 | " CT_T = 41269.012800060416\n", 191 | " CN_R = -224.26822649455545\n", 192 | " CN_T = -3739.194423008724\n", 193 | " CN_N = 4893.388541408624\n", 194 | " CRDOT_R = -2.690240978331646\n", 195 | " CRDOT_T = -32.45608595843143\n", 196 | " CRDOT_N = 3.3748910113664388\n", 197 | " CRDOT_RDOT = 0.026616660879604667\n", 198 | " CTDOT_R = -0.45587521823581134\n", 199 | " CTDOT_T = -3.891974449268055\n", 200 | " CTDOT_N = 0.21602245879137436\n", 201 | " CTDOT_RDOT = 0.002711690719702106\n", 202 | " CTDOT_TDOT = 0.000479432666082355\n", 203 | " CNDOT_R = 0.27513941996415164\n", 204 | " CNDOT_T = 0.4561951334680935\n", 205 | " CNDOT_N = -0.44165624627125066\n", 206 | " CNDOT_RDOT = 0.0004400365334853134\n", 207 | " CNDOT_TDOT = -0.0003127338855863759\n", 208 | " CNDOT_NDOT = 0.004822710541832547\n", 209 | " OBJECT = OBJECT2\n", 210 | " OBJECT_DESIGNATOR = 65082PT\n", 211 | " CATALOG_NAME = 3462\n", 212 | " OBJECT_NAME = TITAN 3C TRANSTAGE DEB\n", 213 | " INTERNATIONAL_DESIGNATOR = 65082PT\n", 214 | " EPHEMERIS_NAME = NONE\n", 215 | " COVARIANCE_METHOD = CALCULATED\n", 216 | " MANEUVERABLE = N/A\n", 217 | " ORBIT_CENTER = EARTH\n", 218 | " REF_FRAME = ITRF\n", 219 | " X = 2972.4172682119224\n", 220 | " Y = -5103.530721008279\n", 221 | " Z = -3539.772814553296\n", 222 | " X_DOT = 5.826757151768794\n", 223 | " Y_DOT = 4.085711393314795\n", 224 | " Z_DOT = -0.9752519996834083\n", 225 | " CR_R = 15.608895194536064\n", 226 | " CT_R = -1831.7454009406745\n", 227 | " CT_T = 387066.15903594147\n", 228 | " CN_R = 71.5596813096827\n", 229 | " CN_T = -6122.2782569260735\n", 230 | " CN_N = 5424.209709946298\n", 231 | " CRDOT_R = 2.1418685416237584\n", 232 | " CRDOT_T = -416.38358827942716\n", 233 | " CRDOT_N = 8.17067859275866\n", 234 | " CRDOT_RDOT = 0.45361166277724996\n", 235 | " CTDOT_R = -0.005166751853750279\n", 236 | " CTDOT_T = -0.1424221310036492\n", 237 | " CTDOT_N = -0.019218390871709318\n", 238 | " CTDOT_RDOT = 1.609E-05\n", 239 | " CTDOT_TDOT = 5.202E-06\n", 240 | " CNDOT_R = 0.06170571196677281\n", 241 | " CNDOT_T = -8.629383890813989\n", 242 | " CNDOT_N = 1.1567101080406283\n", 243 | " CNDOT_RDOT = 0.010208457878684038\n", 244 | " CNDOT_TDOT = -1.756E-05\n", 245 | " CNDOT_NDOT = 0.0021928221709182245,\n", 246 | " CCSDS_CDM_VERS = 1.0\n", 247 | " CREATION_DATE = 2025-02-21T11:20:08.694966\n", 248 | " ORIGINATOR = KESSLER_SOFTWARE\n", 249 | " MESSAGE_ID = KESSLER_SOFTWARE_adc65ed4-20e6-11f0-b2ee-f2a9f71f7e1a\n", 250 | " TCA = 2025-02-22T01:17:28.408663\n", 251 | " MISS_DISTANCE = 119296.4071367849\n", 252 | " RELATIVE_SPEED = 8781.77597072965\n", 253 | " RELATIVE_POSITION_R = -3392.400548990203\n", 254 | " RELATIVE_POSITION_T = -79317.283331336\n", 255 | " RELATIVE_POSITION_N = -89044.33131422414\n", 256 | " RELATIVE_VELOCITY_R = -154.91187193411943\n", 257 | " RELATIVE_VELOCITY_T = -5422.481073457308\n", 258 | " RELATIVE_VELOCITY_N = -6905.960506693898\n", 259 | " COLLISION_PROBABILITY = 0.0\n", 260 | " COLLISION_PROBABILITY_METHOD = MC\n", 261 | " OBJECT = OBJECT1\n", 262 | " OBJECT_DESIGNATOR = 76126AP\n", 263 | " CATALOG_NAME = 9827\n", 264 | " OBJECT_NAME = COSMOS 886 DEB\n", 265 | " INTERNATIONAL_DESIGNATOR = 76126AP\n", 266 | " EPHEMERIS_NAME = NONE\n", 267 | " COVARIANCE_METHOD = CALCULATED\n", 268 | " MANEUVERABLE = N/A\n", 269 | " ORBIT_CENTER = EARTH\n", 270 | " REF_FRAME = ITRF\n", 271 | " X = 2961.416138954747\n", 272 | " Y = -5176.42090647565\n", 273 | " Z = -3446.5166602514805\n", 274 | " X_DOT = 4.441367932633197\n", 275 | " Y_DOT = -1.3893739558637068\n", 276 | " Z_DOT = 5.749634804852701\n", 277 | " CR_R = 418.4789881653135\n", 278 | " CT_R = 2833.654900508839\n", 279 | " CT_T = 26275.07871526111\n", 280 | " CN_R = 235.96450630189815\n", 281 | " CN_T = 1379.1837684683846\n", 282 | " CN_N = 3824.354403059597\n", 283 | " CRDOT_R = -1.629021196870671\n", 284 | " CRDOT_T = -18.917640141448356\n", 285 | " CRDOT_N = -0.6906003255748716\n", 286 | " CRDOT_RDOT = 0.015134294118617029\n", 287 | " CTDOT_R = -0.44696031062349284\n", 288 | " CTDOT_T = -2.9384291761156875\n", 289 | " CTDOT_N = -0.2522263711844156\n", 290 | " CTDOT_RDOT = 0.001641663225350465\n", 291 | " CTDOT_TDOT = 0.0004784788899478311\n", 292 | " CNDOT_R = 0.15032615582479048\n", 293 | " CNDOT_T = 0.0059359771572660164\n", 294 | " CNDOT_N = -0.3262798823098171\n", 295 | " CNDOT_RDOT = 0.0004967254843707441\n", 296 | " CNDOT_TDOT = -0.00017283616485068076\n", 297 | " CNDOT_NDOT = 0.005746080835028397\n", 298 | " OBJECT = OBJECT2\n", 299 | " OBJECT_DESIGNATOR = 65082PT\n", 300 | " CATALOG_NAME = 3462\n", 301 | " OBJECT_NAME = TITAN 3C TRANSTAGE DEB\n", 302 | " INTERNATIONAL_DESIGNATOR = 65082PT\n", 303 | " EPHEMERIS_NAME = NONE\n", 304 | " COVARIANCE_METHOD = CALCULATED\n", 305 | " MANEUVERABLE = N/A\n", 306 | " ORBIT_CENTER = EARTH\n", 307 | " REF_FRAME = ITRF\n", 308 | " X = 2973.071864839906\n", 309 | " Y = -5103.077176433223\n", 310 | " Z = -3539.878719318852\n", 311 | " X_DOT = 5.826399482002183\n", 312 | " Y_DOT = 4.0863283565475435\n", 313 | " Z_DOT = -0.9747953563722136\n", 314 | " CR_R = 19.416112754758714\n", 315 | " CT_R = -1063.96729664468\n", 316 | " CT_T = 122541.70103023999\n", 317 | " CN_R = -35.02940219476802\n", 318 | " CN_T = 1550.9822755102928\n", 319 | " CN_N = 5255.002744568752\n", 320 | " CRDOT_R = 1.2925239374152526\n", 321 | " CRDOT_T = -126.57004812480902\n", 322 | " CRDOT_N = -2.22107658156981\n", 323 | " CRDOT_RDOT = 0.1356785119000294\n", 324 | " CTDOT_R = -0.010480352857442607\n", 325 | " CTDOT_T = 0.30203170115238487\n", 326 | " CTDOT_N = 0.03313019924386015\n", 327 | " CTDOT_RDOT = -0.00046144760169145884\n", 328 | " CTDOT_TDOT = 7.133E-06\n", 329 | " CNDOT_R = -0.01550631317382298\n", 330 | " CNDOT_T = -0.7484418552935522\n", 331 | " CNDOT_N = 1.171583503661754\n", 332 | " CNDOT_RDOT = 0.0008530656635604496\n", 333 | " CNDOT_TDOT = 1.209E-05\n", 334 | " CNDOT_NDOT = 0.0018826631138264438]" 335 | ] 336 | }, 337 | "execution_count": 9, 338 | "metadata": {}, 339 | "output_type": "execute_result" 340 | } 341 | ], 342 | "source": [ 343 | "trace.nodes['cdms']['infer']['cdms']" 344 | ] 345 | }, 346 | { 347 | "cell_type": "code", 348 | "execution_count": 35, 349 | "id": "1313a4f5", 350 | "metadata": {}, 351 | "outputs": [], 352 | "source": [ 353 | "#let's save all cdms to kvn files:\n", 354 | "#for i in range(len(trace.nodes['cdms']['infer']['cdms'])): \n", 355 | "# trace.nodes['cdms']['infer']['cdms'][i].save(f'event2_{i}.kvn')" 356 | ] 357 | } 358 | ], 359 | "metadata": { 360 | "kernelspec": { 361 | "display_name": "kessler", 362 | "language": "python", 363 | "name": "python3" 364 | }, 365 | "language_info": { 366 | "codemirror_mode": { 367 | "name": "ipython", 368 | "version": 3 369 | }, 370 | "file_extension": ".py", 371 | "mimetype": "text/x-python", 372 | "name": "python", 373 | "nbconvert_exporter": "python", 374 | "pygments_lexer": "ipython3", 375 | "version": "3.12.8" 376 | } 377 | }, 378 | "nbformat": 4, 379 | "nbformat_minor": 5 380 | } 381 | -------------------------------------------------------------------------------- /docs/notebooks/synthetic_cdms/event1_0.kvn: -------------------------------------------------------------------------------- 1 | CCSDS_CDM_VERS = 1.0 2 | CREATION_DATE = 2025-02-21T03:20:45.423178 3 | ORIGINATOR = KESSLER_SOFTWARE 4 | MESSAGE_ID = KESSLER_SOFTWARE_0487ea22-138a-11f0-a1a9-f2a9f71f7e19 5 | TCA = 2025-02-23T16:41:51.264217 6 | MISS_DISTANCE = 1599.385783304641 7 | RELATIVE_SPEED = 8.406610360741997 8 | RELATIVE_POSITION_R = -200.339469550585 9 | RELATIVE_POSITION_T = -58.25940943259976 10 | RELATIVE_POSITION_N = 1585.7190236576453 11 | RELATIVE_VELOCITY_R = -1.6575886604725651 12 | RELATIVE_VELOCITY_T = -4.702562654172012 13 | RELATIVE_VELOCITY_N = 6.768264332426308 14 | COLLISION_PROBABILITY = 0.0 15 | COLLISION_PROBABILITY_METHOD = MC 16 | OBJECT = OBJECT1 17 | OBJECT_DESIGNATOR = 76126AP 18 | CATALOG_NAME = 9827 19 | OBJECT_NAME = COSMOS 886 DEB 20 | INTERNATIONAL_DESIGNATOR = 76126AP 21 | EPHEMERIS_NAME = NONE 22 | COVARIANCE_METHOD = CALCULATED 23 | MANEUVERABLE = N/A 24 | ORBIT_CENTER = EARTH 25 | REF_FRAME = ITRF 26 | X = 2541.099784251016 27 | Y = -1354.1077713033583 28 | Z = -6172.194444916209 29 | X_DOT = 1.9821417932075793 30 | Y_DOT = 7.152468300076865 31 | Z_DOT = -0.8184870561932284 32 | CR_R = 0.15212996364233536 33 | CT_R = 1.767066619611639 34 | CT_T = 61.13843097922123 35 | CN_R = -0.00022143993045502212 36 | CN_T = -0.002137168496384415 37 | CN_N = 5.538E-07 38 | CRDOT_R = -0.001387624846756269 39 | CRDOT_T = -0.059321445102163514 40 | CRDOT_N = 1.253E-06 41 | CRDOT_RDOT = 5.902E-05 42 | CTDOT_R = -0.00016387167746678447 43 | CTDOT_T = -0.0016034103637458102 44 | CTDOT_N = 2.467E-07 45 | CTDOT_RDOT = 1.169E-06 46 | CTDOT_TDOT = 1.788E-07 47 | CNDOT_R = 4.418E-06 48 | CNDOT_T = 9.513E-05 49 | CNDOT_N = -8.329E-09 50 | CNDOT_RDOT = -8.374E-08 51 | CNDOT_TDOT = -4.487E-09 52 | CNDOT_NDOT = 2.003E-10 53 | OBJECT = OBJECT2 54 | OBJECT_DESIGNATOR = 69082CJ 55 | CATALOG_NAME = 4227 56 | OBJECT_NAME = THORAD AGENA D DEB 57 | INTERNATIONAL_DESIGNATOR = 69082CJ 58 | EPHEMERIS_NAME = NONE 59 | COVARIANCE_METHOD = CALCULATED 60 | MANEUVERABLE = N/A 61 | ORBIT_CENTER = EARTH 62 | REF_FRAME = ITRF 63 | X = 3862.163156007167 64 | Y = -1686.8001744420503 65 | Z = -5334.255177107932 66 | X_DOT = 6.152228410666328 67 | Y_DOT = 1.618574029450763 68 | Z_DOT = 3.9415013431369377 69 | CR_R = 3.852952621853669 70 | CT_R = 0.0 71 | CT_T = 4.976328968225473 72 | CN_R = 0.0 73 | CN_T = 0.0 74 | CN_N = 0.9333314012997196 75 | CRDOT_R = 0.0 76 | CRDOT_T = 0.0 77 | CRDOT_N = 0.0 78 | CRDOT_RDOT = 1.000E-18 79 | CTDOT_R = 0.0 80 | CTDOT_T = 0.0 81 | CTDOT_N = 0.0 82 | CTDOT_RDOT = 0.0 83 | CTDOT_TDOT = 1.000E-18 84 | CNDOT_R = 0.0 85 | CNDOT_T = 0.0 86 | CNDOT_N = 0.0 87 | CNDOT_RDOT = 0.0 88 | CNDOT_TDOT = 0.0 89 | CNDOT_NDOT = 1.000E-18 90 | -------------------------------------------------------------------------------- /docs/notebooks/synthetic_cdms/event1_1.kvn: -------------------------------------------------------------------------------- 1 | CCSDS_CDM_VERS = 1.0 2 | CREATION_DATE = 2025-02-21T11:21:54.534947 3 | ORIGINATOR = KESSLER_SOFTWARE 4 | MESSAGE_ID = KESSLER_SOFTWARE_065dc20e-138a-11f0-a1a9-f2a9f71f7e19 5 | TCA = 2025-02-23T16:41:51.264217 6 | MISS_DISTANCE = 1348.1981020987255 7 | RELATIVE_SPEED = 8.426512407592309 8 | RELATIVE_POSITION_R = -144.82803645001906 9 | RELATIVE_POSITION_T = -37.32697360897995 10 | RELATIVE_POSITION_N = 1339.8767329130812 11 | RELATIVE_VELOCITY_R = -1.4171204689506622 12 | RELATIVE_VELOCITY_T = -4.728716409300112 13 | RELATIVE_VELOCITY_N = 6.829137723915373 14 | COLLISION_PROBABILITY = 0.0 15 | COLLISION_PROBABILITY_METHOD = MC 16 | OBJECT = OBJECT1 17 | OBJECT_DESIGNATOR = 76126AP 18 | CATALOG_NAME = 9827 19 | OBJECT_NAME = COSMOS 886 DEB 20 | INTERNATIONAL_DESIGNATOR = 76126AP 21 | EPHEMERIS_NAME = NONE 22 | COVARIANCE_METHOD = CALCULATED 23 | MANEUVERABLE = N/A 24 | ORBIT_CENTER = EARTH 25 | REF_FRAME = ITRF 26 | X = 2504.3526317855785 27 | Y = -1483.0394779111418 28 | Z = -6156.889776809131 29 | X_DOT = 2.026748694780936 30 | Y_DOT = 7.123981881789366 31 | Z_DOT = -0.9557733246802299 32 | CR_R = 1.000E-18 33 | CT_R = 0.0 34 | CT_T = 1.2451197530695846 35 | CN_R = 0.0 36 | CN_T = 0.0 37 | CN_N = 0.0035176566277315556 38 | CRDOT_R = 0.0 39 | CRDOT_T = 0.0 40 | CRDOT_N = 0.0 41 | CRDOT_RDOT = 1.000E-18 42 | CTDOT_R = 0.0 43 | CTDOT_T = 0.0 44 | CTDOT_N = 0.0 45 | CTDOT_RDOT = 0.0 46 | CTDOT_TDOT = 1.000E-18 47 | CNDOT_R = 0.0 48 | CNDOT_T = 0.0 49 | CNDOT_N = 0.0 50 | CNDOT_RDOT = 0.0 51 | CNDOT_TDOT = 0.0 52 | CNDOT_NDOT = 1.000E-18 53 | OBJECT = OBJECT2 54 | OBJECT_DESIGNATOR = 69082CJ 55 | CATALOG_NAME = 4227 56 | OBJECT_NAME = THORAD AGENA D DEB 57 | INTERNATIONAL_DESIGNATOR = 69082CJ 58 | EPHEMERIS_NAME = NONE 59 | COVARIANCE_METHOD = CALCULATED 60 | MANEUVERABLE = N/A 61 | ORBIT_CENTER = EARTH 62 | REF_FRAME = ITRF 63 | X = 3633.97930307704 64 | Y = -1752.8652636247746 65 | Z = -5472.2177740416755 66 | X_DOT = 6.3158434028298185 67 | Y_DOT = 1.5594194830663326 68 | Z_DOT = 3.696690888122699 69 | CR_R = 3.852952621853669 70 | CT_R = 0.0 71 | CT_T = 4.976328968225473 72 | CN_R = 0.0 73 | CN_T = 0.0 74 | CN_N = 0.9333314012997196 75 | CRDOT_R = 0.0 76 | CRDOT_T = 0.0 77 | CRDOT_N = 0.0 78 | CRDOT_RDOT = 1.000E-18 79 | CTDOT_R = 0.0 80 | CTDOT_T = 0.0 81 | CTDOT_N = 0.0 82 | CTDOT_RDOT = 0.0 83 | CTDOT_TDOT = 1.000E-18 84 | CNDOT_R = 0.0 85 | CNDOT_T = 0.0 86 | CNDOT_N = 0.0 87 | CNDOT_RDOT = 0.0 88 | CNDOT_TDOT = 0.0 89 | CNDOT_NDOT = 1.000E-18 90 | -------------------------------------------------------------------------------- /docs/notebooks/synthetic_cdms/event1_2.kvn: -------------------------------------------------------------------------------- 1 | CCSDS_CDM_VERS = 1.0 2 | CREATION_DATE = 2025-02-21T19:23:27.838699 3 | ORIGINATOR = KESSLER_SOFTWARE 4 | MESSAGE_ID = KESSLER_SOFTWARE_08026d94-138a-11f0-a1a9-f2a9f71f7e19 5 | TCA = 2025-02-23T16:41:51.264217 6 | MISS_DISTANCE = 1350.0796621043116 7 | RELATIVE_SPEED = 8.454050021758691 8 | RELATIVE_POSITION_R = -144.81703693484633 9 | RELATIVE_POSITION_T = 67.94727738222727 10 | RELATIVE_POSITION_N = 1340.5693892288627 11 | RELATIVE_VELOCITY_R = -1.4604528250723996 12 | RELATIVE_VELOCITY_T = -4.759987253763458 13 | RELATIVE_VELOCITY_N = 6.832317371152016 14 | COLLISION_PROBABILITY = 0.0 15 | COLLISION_PROBABILITY_METHOD = MC 16 | OBJECT = OBJECT1 17 | OBJECT_DESIGNATOR = 76126AP 18 | CATALOG_NAME = 9827 19 | OBJECT_NAME = COSMOS 886 DEB 20 | INTERNATIONAL_DESIGNATOR = 76126AP 21 | EPHEMERIS_NAME = NONE 22 | COVARIANCE_METHOD = CALCULATED 23 | MANEUVERABLE = N/A 24 | ORBIT_CENTER = EARTH 25 | REF_FRAME = ITRF 26 | X = 2474.002537681344 27 | Y = -1587.015954247346 28 | Z = -6142.786938519778 29 | X_DOT = 2.0620055705717224 30 | Y_DOT = 7.098892719307384 31 | Z_DOT = -1.066717737243908 32 | CR_R = 1.000E-18 33 | CT_R = 0.0 34 | CT_T = 1.2451197530695846 35 | CN_R = 0.0 36 | CN_T = 0.0 37 | CN_N = 0.0035176566277315556 38 | CRDOT_R = 0.0 39 | CRDOT_T = 0.0 40 | CRDOT_N = 0.0 41 | CRDOT_RDOT = 1.000E-18 42 | CTDOT_R = 0.0 43 | CTDOT_T = 0.0 44 | CTDOT_N = 0.0 45 | CTDOT_RDOT = 0.0 46 | CTDOT_TDOT = 1.000E-18 47 | CNDOT_R = 0.0 48 | CNDOT_T = 0.0 49 | CNDOT_N = 0.0 50 | CNDOT_RDOT = 0.0 51 | CNDOT_TDOT = 0.0 52 | CNDOT_NDOT = 1.000E-18 53 | OBJECT = OBJECT2 54 | OBJECT_DESIGNATOR = 69082CJ 55 | CATALOG_NAME = 4227 56 | OBJECT_NAME = THORAD AGENA D DEB 57 | INTERNATIONAL_DESIGNATOR = 69082CJ 58 | EPHEMERIS_NAME = NONE 59 | COVARIANCE_METHOD = CALCULATED 60 | MANEUVERABLE = N/A 61 | ORBIT_CENTER = EARTH 62 | REF_FRAME = ITRF 63 | X = 3633.97930307704 64 | Y = -1752.8652636247746 65 | Z = -5472.2177740416755 66 | X_DOT = 6.3158434028298185 67 | Y_DOT = 1.5594194830663326 68 | Z_DOT = 3.696690888122699 69 | CR_R = 3.852952621853669 70 | CT_R = 0.0 71 | CT_T = 4.976328968225473 72 | CN_R = 0.0 73 | CN_T = 0.0 74 | CN_N = 0.9333314012997196 75 | CRDOT_R = 0.0 76 | CRDOT_T = 0.0 77 | CRDOT_N = 0.0 78 | CRDOT_RDOT = 1.000E-18 79 | CTDOT_R = 0.0 80 | CTDOT_T = 0.0 81 | CTDOT_N = 0.0 82 | CTDOT_RDOT = 0.0 83 | CTDOT_TDOT = 1.000E-18 84 | CNDOT_R = 0.0 85 | CNDOT_T = 0.0 86 | CNDOT_N = 0.0 87 | CNDOT_RDOT = 0.0 88 | CNDOT_TDOT = 0.0 89 | CNDOT_NDOT = 1.000E-18 90 | -------------------------------------------------------------------------------- /docs/notebooks/synthetic_cdms/event1_3.kvn: -------------------------------------------------------------------------------- 1 | CCSDS_CDM_VERS = 1.0 2 | CREATION_DATE = 2025-02-22T03:21:09.302550 3 | ORIGINATOR = KESSLER_SOFTWARE 4 | MESSAGE_ID = KESSLER_SOFTWARE_08db3ae8-138a-11f0-a1a9-f2a9f71f7e19 5 | TCA = 2025-02-23T16:41:51.264217 6 | MISS_DISTANCE = 1357.4019853542814 7 | RELATIVE_SPEED = 8.47595736838985 8 | RELATIVE_POSITION_R = -146.08669906273596 9 | RELATIVE_POSITION_T = 149.50290341697263 10 | RELATIVE_POSITION_N = 1341.2112839036936 11 | RELATIVE_VELOCITY_R = -1.493709934496736 12 | RELATIVE_VELOCITY_T = -4.7849122253265985 13 | RELATIVE_VELOCITY_N = 6.8348591015666145 14 | COLLISION_PROBABILITY = 0.0 15 | COLLISION_PROBABILITY_METHOD = MC 16 | OBJECT = OBJECT1 17 | OBJECT_DESIGNATOR = 76126AP 18 | CATALOG_NAME = 9827 19 | OBJECT_NAME = COSMOS 886 DEB 20 | INTERNATIONAL_DESIGNATOR = 76126AP 21 | EPHEMERIS_NAME = NONE 22 | COVARIANCE_METHOD = CALCULATED 23 | MANEUVERABLE = N/A 24 | ORBIT_CENTER = EARTH 25 | REF_FRAME = ITRF 26 | X = 2450.147919877682 27 | Y = -1667.3884471962406 28 | Z = -6130.835356443848 29 | X_DOT = 2.08868484494596 30 | Y_DOT = 7.07817696868682 31 | Z_DOT = -1.1526698586334423 32 | CR_R = 1.000E-18 33 | CT_R = 0.0 34 | CT_T = 1.2451197530695846 35 | CN_R = 0.0 36 | CN_T = 0.0 37 | CN_N = 0.0035176566277315556 38 | CRDOT_R = 0.0 39 | CRDOT_T = 0.0 40 | CRDOT_N = 0.0 41 | CRDOT_RDOT = 1.000E-18 42 | CTDOT_R = 0.0 43 | CTDOT_T = 0.0 44 | CTDOT_N = 0.0 45 | CTDOT_RDOT = 0.0 46 | CTDOT_TDOT = 1.000E-18 47 | CNDOT_R = 0.0 48 | CNDOT_T = 0.0 49 | CNDOT_N = 0.0 50 | CNDOT_RDOT = 0.0 51 | CNDOT_TDOT = 0.0 52 | CNDOT_NDOT = 1.000E-18 53 | OBJECT = OBJECT2 54 | OBJECT_DESIGNATOR = 69082CJ 55 | CATALOG_NAME = 4227 56 | OBJECT_NAME = THORAD AGENA D DEB 57 | INTERNATIONAL_DESIGNATOR = 69082CJ 58 | EPHEMERIS_NAME = NONE 59 | COVARIANCE_METHOD = CALCULATED 60 | MANEUVERABLE = N/A 61 | ORBIT_CENTER = EARTH 62 | REF_FRAME = ITRF 63 | X = 3633.97930307704 64 | Y = -1752.8652636247746 65 | Z = -5472.2177740416755 66 | X_DOT = 6.3158434028298185 67 | Y_DOT = 1.5594194830663326 68 | Z_DOT = 3.696690888122699 69 | CR_R = 3.852952621853669 70 | CT_R = 0.0 71 | CT_T = 4.976328968225473 72 | CN_R = 0.0 73 | CN_T = 0.0 74 | CN_N = 0.9333314012997196 75 | CRDOT_R = 0.0 76 | CRDOT_T = 0.0 77 | CRDOT_N = 0.0 78 | CRDOT_RDOT = 1.000E-18 79 | CTDOT_R = 0.0 80 | CTDOT_T = 0.0 81 | CTDOT_N = 0.0 82 | CTDOT_RDOT = 0.0 83 | CTDOT_TDOT = 1.000E-18 84 | CNDOT_R = 0.0 85 | CNDOT_T = 0.0 86 | CNDOT_N = 0.0 87 | CNDOT_RDOT = 0.0 88 | CNDOT_TDOT = 0.0 89 | CNDOT_NDOT = 1.000E-18 90 | -------------------------------------------------------------------------------- /docs/notebooks/synthetic_cdms/event1_4.kvn: -------------------------------------------------------------------------------- 1 | CCSDS_CDM_VERS = 1.0 2 | CREATION_DATE = 2025-02-22T11:20:46.686311 3 | ORIGINATOR = KESSLER_SOFTWARE 4 | MESSAGE_ID = KESSLER_SOFTWARE_0931aedc-138a-11f0-a1a9-f2a9f71f7e19 5 | TCA = 2025-02-23T16:41:51.264217 6 | MISS_DISTANCE = 1366.1428870071306 7 | RELATIVE_SPEED = 8.492784429287536 8 | RELATIVE_POSITION_R = -147.80901947131733 9 | RELATIVE_POSITION_T = 210.39414976645887 10 | RELATIVE_POSITION_N = 1341.7276859434457 11 | RELATIVE_VELOCITY_R = -1.5183418384757468 12 | RELATIVE_VELOCITY_T = -4.8040741328826115 13 | RELATIVE_VELOCITY_N = 6.8368777339989855 14 | COLLISION_PROBABILITY = 0.0 15 | COLLISION_PROBABILITY_METHOD = MC 16 | OBJECT = OBJECT1 17 | OBJECT_DESIGNATOR = 76126AP 18 | CATALOG_NAME = 9827 19 | OBJECT_NAME = COSMOS 886 DEB 20 | INTERNATIONAL_DESIGNATOR = 76126AP 21 | EPHEMERIS_NAME = NONE 22 | COVARIANCE_METHOD = CALCULATED 23 | MANEUVERABLE = N/A 24 | ORBIT_CENTER = EARTH 25 | REF_FRAME = ITRF 26 | X = 2432.180516810938 27 | Y = -1727.351369620969 28 | Z = -6121.3518944376565 29 | X_DOT = 2.108070397228618 30 | Y_DOT = 7.061974545463908 31 | Z_DOT = -1.2169555664938194 32 | CR_R = 1.000E-18 33 | CT_R = 0.0 34 | CT_T = 1.2451197530695846 35 | CN_R = 0.0 36 | CN_T = 0.0 37 | CN_N = 0.0035176566277315556 38 | CRDOT_R = 0.0 39 | CRDOT_T = 0.0 40 | CRDOT_N = 0.0 41 | CRDOT_RDOT = 1.000E-18 42 | CTDOT_R = 0.0 43 | CTDOT_T = 0.0 44 | CTDOT_N = 0.0 45 | CTDOT_RDOT = 0.0 46 | CTDOT_TDOT = 1.000E-18 47 | CNDOT_R = 0.0 48 | CNDOT_T = 0.0 49 | CNDOT_N = 0.0 50 | CNDOT_RDOT = 0.0 51 | CNDOT_TDOT = 0.0 52 | CNDOT_NDOT = 1.000E-18 53 | OBJECT = OBJECT2 54 | OBJECT_DESIGNATOR = 69082CJ 55 | CATALOG_NAME = 4227 56 | OBJECT_NAME = THORAD AGENA D DEB 57 | INTERNATIONAL_DESIGNATOR = 69082CJ 58 | EPHEMERIS_NAME = NONE 59 | COVARIANCE_METHOD = CALCULATED 60 | MANEUVERABLE = N/A 61 | ORBIT_CENTER = EARTH 62 | REF_FRAME = ITRF 63 | X = 3633.97930307704 64 | Y = -1752.8652636247746 65 | Z = -5472.2177740416755 66 | X_DOT = 6.3158434028298185 67 | Y_DOT = 1.5594194830663326 68 | Z_DOT = 3.696690888122699 69 | CR_R = 3.852952621853669 70 | CT_R = 0.0 71 | CT_T = 4.976328968225473 72 | CN_R = 0.0 73 | CN_T = 0.0 74 | CN_N = 0.9333314012997196 75 | CRDOT_R = 0.0 76 | CRDOT_T = 0.0 77 | CRDOT_N = 0.0 78 | CRDOT_RDOT = 1.000E-18 79 | CTDOT_R = 0.0 80 | CTDOT_T = 0.0 81 | CTDOT_N = 0.0 82 | CTDOT_RDOT = 0.0 83 | CTDOT_TDOT = 1.000E-18 84 | CNDOT_R = 0.0 85 | CNDOT_T = 0.0 86 | CNDOT_N = 0.0 87 | CNDOT_RDOT = 0.0 88 | CNDOT_TDOT = 0.0 89 | CNDOT_NDOT = 1.000E-18 90 | -------------------------------------------------------------------------------- /docs/notebooks/synthetic_cdms/event1_5.kvn: -------------------------------------------------------------------------------- 1 | CCSDS_CDM_VERS = 1.0 2 | CREATION_DATE = 2025-02-22T19:18:14.038148 3 | ORIGINATOR = KESSLER_SOFTWARE 4 | MESSAGE_ID = KESSLER_SOFTWARE_0983baba-138a-11f0-a1a9-f2a9f71f7e19 5 | TCA = 2025-02-23T16:41:51.264217 6 | MISS_DISTANCE = 1373.6629162193096 7 | RELATIVE_SPEED = 8.504705042276408 8 | RELATIVE_POSITION_R = -149.4069228180587 9 | RELATIVE_POSITION_T = 251.9526793631431 10 | RELATIVE_POSITION_N = 1342.0682643486919 11 | RELATIVE_VELOCITY_R = -1.5350247586664296 12 | RELATIVE_VELOCITY_T = -4.817651728359353 13 | RELATIVE_VELOCITY_N = 6.838416386170043 14 | COLLISION_PROBABILITY = 0.0 15 | COLLISION_PROBABILITY_METHOD = MC 16 | OBJECT = OBJECT1 17 | OBJECT_DESIGNATOR = 76126AP 18 | CATALOG_NAME = 9827 19 | OBJECT_NAME = COSMOS 886 DEB 20 | INTERNATIONAL_DESIGNATOR = 76126AP 21 | EPHEMERIS_NAME = NONE 22 | COVARIANCE_METHOD = CALCULATED 23 | MANEUVERABLE = N/A 24 | ORBIT_CENTER = EARTH 25 | REF_FRAME = ITRF 26 | X = 2419.8829708392755 27 | Y = -1768.3222726967042 28 | Z = -6114.620283620752 29 | X_DOT = 2.120815224860317 30 | Y_DOT = 7.050570365652701 31 | Z_DOT = -1.2610312124830407 32 | CR_R = 1.000E-18 33 | CT_R = 0.0 34 | CT_T = 1.2451197530695846 35 | CN_R = 0.0 36 | CN_T = 0.0 37 | CN_N = 0.0035176566277315556 38 | CRDOT_R = 0.0 39 | CRDOT_T = 0.0 40 | CRDOT_N = 0.0 41 | CRDOT_RDOT = 1.000E-18 42 | CTDOT_R = 0.0 43 | CTDOT_T = 0.0 44 | CTDOT_N = 0.0 45 | CTDOT_RDOT = 0.0 46 | CTDOT_TDOT = 1.000E-18 47 | CNDOT_R = 0.0 48 | CNDOT_T = 0.0 49 | CNDOT_N = 0.0 50 | CNDOT_RDOT = 0.0 51 | CNDOT_TDOT = 0.0 52 | CNDOT_NDOT = 1.000E-18 53 | OBJECT = OBJECT2 54 | OBJECT_DESIGNATOR = 69082CJ 55 | CATALOG_NAME = 4227 56 | OBJECT_NAME = THORAD AGENA D DEB 57 | INTERNATIONAL_DESIGNATOR = 69082CJ 58 | EPHEMERIS_NAME = NONE 59 | COVARIANCE_METHOD = CALCULATED 60 | MANEUVERABLE = N/A 61 | ORBIT_CENTER = EARTH 62 | REF_FRAME = ITRF 63 | X = 3633.97930307704 64 | Y = -1752.8652636247746 65 | Z = -5472.2177740416755 66 | X_DOT = 6.3158434028298185 67 | Y_DOT = 1.5594194830663326 68 | Z_DOT = 3.696690888122699 69 | CR_R = 3.852952621853669 70 | CT_R = 0.0 71 | CT_T = 4.976328968225473 72 | CN_R = 0.0 73 | CN_T = 0.0 74 | CN_N = 0.9333314012997196 75 | CRDOT_R = 0.0 76 | CRDOT_T = 0.0 77 | CRDOT_N = 0.0 78 | CRDOT_RDOT = 1.000E-18 79 | CTDOT_R = 0.0 80 | CTDOT_T = 0.0 81 | CTDOT_N = 0.0 82 | CTDOT_RDOT = 0.0 83 | CTDOT_TDOT = 1.000E-18 84 | CNDOT_R = 0.0 85 | CNDOT_T = 0.0 86 | CNDOT_N = 0.0 87 | CNDOT_RDOT = 0.0 88 | CNDOT_TDOT = 0.0 89 | CNDOT_NDOT = 1.000E-18 90 | -------------------------------------------------------------------------------- /docs/notebooks/synthetic_cdms/event1_6.kvn: -------------------------------------------------------------------------------- 1 | CCSDS_CDM_VERS = 1.0 2 | CREATION_DATE = 2025-02-23T03:21:08.989898 3 | ORIGINATOR = KESSLER_SOFTWARE 4 | MESSAGE_ID = KESSLER_SOFTWARE_0a26ad38-138a-11f0-a1a9-f2a9f71f7e19 5 | TCA = 2025-02-23T16:41:51.264217 6 | MISS_DISTANCE = 354.84590453373755 7 | RELATIVE_SPEED = 8.42625398500104 8 | RELATIVE_POSITION_R = -15.020823412631614 9 | RELATIVE_POSITION_T = -149.8841221514796 10 | RELATIVE_POSITION_N = 321.28607308013403 11 | RELATIVE_VELOCITY_R = -0.32232223597393334 12 | RELATIVE_VELOCITY_T = -4.744482870169403 13 | RELATIVE_VELOCITY_N = 6.956130166307398 14 | COLLISION_PROBABILITY = 0.0 15 | COLLISION_PROBABILITY_METHOD = MC 16 | OBJECT = OBJECT1 17 | OBJECT_DESIGNATOR = 76126AP 18 | CATALOG_NAME = 9827 19 | OBJECT_NAME = COSMOS 886 DEB 20 | INTERNATIONAL_DESIGNATOR = 76126AP 21 | EPHEMERIS_NAME = NONE 22 | COVARIANCE_METHOD = CALCULATED 23 | MANEUVERABLE = N/A 24 | ORBIT_CENTER = EARTH 25 | REF_FRAME = ITRF 26 | X = 2412.7031423372655 27 | Y = -1792.572495511168 28 | Z = -6110.5999321474055 29 | X_DOT = 2.12775781780801 30 | Y_DOT = 7.043736771327517 31 | Z_DOT = -1.2872901798390795 32 | CR_R = 0.028362027022496288 33 | CT_R = 0.013207602921336086 34 | CT_T = 34.979296132040574 35 | CN_R = 5.613E-06 36 | CN_T = 0.002938093856714331 37 | CN_N = 2.603E-07 38 | CRDOT_R = -8.890E-06 39 | CRDOT_T = -0.03718113693533108 40 | CRDOT_N = -3.212E-06 41 | CRDOT_RDOT = 4.015E-05 42 | CTDOT_R = -3.164E-05 43 | CTDOT_T = 0.00023115170145658072 44 | CTDOT_N = 1.518E-08 45 | CTDOT_RDOT = -2.571E-07 46 | CTDOT_TDOT = 3.708E-08 47 | CNDOT_R = -2.104E-08 48 | CNDOT_T = 2.254E-05 49 | CNDOT_N = 1.804E-09 50 | CNDOT_RDOT = -2.337E-08 51 | CNDOT_TDOT = 1.767E-10 52 | CNDOT_NDOT = 1.511E-11 53 | OBJECT = OBJECT2 54 | OBJECT_DESIGNATOR = 69082CJ 55 | CATALOG_NAME = 4227 56 | OBJECT_NAME = THORAD AGENA D DEB 57 | INTERNATIONAL_DESIGNATOR = 69082CJ 58 | EPHEMERIS_NAME = NONE 59 | COVARIANCE_METHOD = CALCULATED 60 | MANEUVERABLE = N/A 61 | ORBIT_CENTER = EARTH 62 | REF_FRAME = ITRF 63 | X = 2651.508819778745 64 | Y = -1992.751079116357 65 | Z = -5940.847173548605 66 | X_DOT = 6.875939836757923 67 | Y_DOT = 1.2921681846740356 68 | Z_DOT = 2.6339318908536167 69 | CR_R = 3.852952621853669 70 | CT_R = 0.0 71 | CT_T = 4.976328968225473 72 | CN_R = 0.0 73 | CN_T = 0.0 74 | CN_N = 0.9333314012997196 75 | CRDOT_R = 0.0 76 | CRDOT_T = 0.0 77 | CRDOT_N = 0.0 78 | CRDOT_RDOT = 1.000E-18 79 | CTDOT_R = 0.0 80 | CTDOT_T = 0.0 81 | CTDOT_N = 0.0 82 | CTDOT_RDOT = 0.0 83 | CTDOT_TDOT = 1.000E-18 84 | CNDOT_R = 0.0 85 | CNDOT_T = 0.0 86 | CNDOT_N = 0.0 87 | CNDOT_RDOT = 0.0 88 | CNDOT_TDOT = 0.0 89 | CNDOT_NDOT = 1.000E-18 90 | -------------------------------------------------------------------------------- /docs/notebooks/synthetic_cdms/event2_0.kvn: -------------------------------------------------------------------------------- 1 | CCSDS_CDM_VERS = 1.0 2 | CREATION_DATE = 2025-02-21T03:20:09.135184 3 | ORIGINATOR = KESSLER_SOFTWARE 4 | MESSAGE_ID = KESSLER_SOFTWARE_71693a9c-138a-11f0-a1a9-f2a9f71f7e19 5 | TCA = 2025-02-23T11:32:33.989495 6 | MISS_DISTANCE = 1025.1262273970647 7 | RELATIVE_SPEED = 8.41124195350178 8 | RELATIVE_POSITION_R = -68.56104425610593 9 | RELATIVE_POSITION_T = -846.4173760251797 10 | RELATIVE_POSITION_N = -574.2480220867114 11 | RELATIVE_VELOCITY_R = -0.1886852794280612 12 | RELATIVE_VELOCITY_T = -4.7406966194413105 13 | RELATIVE_VELOCITY_N = -6.945443443588991 14 | COLLISION_PROBABILITY = 0.0 15 | COLLISION_PROBABILITY_METHOD = MC 16 | OBJECT = OBJECT1 17 | OBJECT_DESIGNATOR = 69082CJ 18 | CATALOG_NAME = 4227 19 | OBJECT_NAME = THORAD AGENA D DEB 20 | INTERNATIONAL_DESIGNATOR = 69082CJ 21 | EPHEMERIS_NAME = NONE 22 | COVARIANCE_METHOD = CALCULATED 23 | MANEUVERABLE = N/A 24 | ORBIT_CENTER = EARTH 25 | REF_FRAME = ITRF 26 | X = 2483.74510640759 27 | Y = 2861.325021520417 28 | Z = -5648.294611704676 29 | X_DOT = -0.0941301067400026 30 | Y_DOT = 6.687495571331908 31 | Z_DOT = 3.3470247024338815 32 | CR_R = 1.000E-18 33 | CT_R = 0.0 34 | CT_T = 1.2451197530695846 35 | CN_R = 0.0 36 | CN_T = 0.0 37 | CN_N = 0.0035176566277315556 38 | CRDOT_R = 0.0 39 | CRDOT_T = 0.0 40 | CRDOT_N = 0.0 41 | CRDOT_RDOT = 1.000E-18 42 | CTDOT_R = 0.0 43 | CTDOT_T = 0.0 44 | CTDOT_N = 0.0 45 | CTDOT_RDOT = 0.0 46 | CTDOT_TDOT = 1.000E-18 47 | CNDOT_R = 0.0 48 | CNDOT_T = 0.0 49 | CNDOT_N = 0.0 50 | CNDOT_RDOT = 0.0 51 | CNDOT_TDOT = 0.0 52 | CNDOT_NDOT = 1.000E-18 53 | OBJECT = OBJECT2 54 | OBJECT_DESIGNATOR = 76126AP 55 | CATALOG_NAME = 9827 56 | OBJECT_NAME = COSMOS 886 DEB 57 | INTERNATIONAL_DESIGNATOR = 76126AP 58 | EPHEMERIS_NAME = NONE 59 | COVARIANCE_METHOD = CALCULATED 60 | MANEUVERABLE = N/A 61 | ORBIT_CENTER = EARTH 62 | REF_FRAME = ITRF 63 | X = 1934.7986774883261 64 | Y = 2163.451996914955 65 | Z = -6160.656633913729 66 | X_DOT = -6.568673859600255 67 | Y_DOT = 3.4314199219712815 68 | Z_DOT = -0.922313157034195 69 | CR_R = 3.852952621853669 70 | CT_R = 0.0 71 | CT_T = 4.976328968225473 72 | CN_R = 0.0 73 | CN_T = 0.0 74 | CN_N = 0.9333314012997196 75 | CRDOT_R = 0.0 76 | CRDOT_T = 0.0 77 | CRDOT_N = 0.0 78 | CRDOT_RDOT = 1.000E-18 79 | CTDOT_R = 0.0 80 | CTDOT_T = 0.0 81 | CTDOT_N = 0.0 82 | CTDOT_RDOT = 0.0 83 | CTDOT_TDOT = 1.000E-18 84 | CNDOT_R = 0.0 85 | CNDOT_T = 0.0 86 | CNDOT_N = 0.0 87 | CNDOT_RDOT = 0.0 88 | CNDOT_TDOT = 0.0 89 | CNDOT_NDOT = 1.000E-18 90 | -------------------------------------------------------------------------------- /docs/notebooks/synthetic_cdms/event2_1.kvn: -------------------------------------------------------------------------------- 1 | CCSDS_CDM_VERS = 1.0 2 | CREATION_DATE = 2025-02-21T11:22:00.582953 3 | ORIGINATOR = KESSLER_SOFTWARE 4 | MESSAGE_ID = KESSLER_SOFTWARE_732c2e3e-138a-11f0-a1a9-f2a9f71f7e19 5 | TCA = 2025-02-23T11:32:33.989495 6 | MISS_DISTANCE = 1039.5531993657187 7 | RELATIVE_SPEED = 8.41026327212856 8 | RELATIVE_POSITION_R = -70.710740935405 9 | RELATIVE_POSITION_T = -864.5029385825628 10 | RELATIVE_POSITION_N = -572.9795062739869 11 | RELATIVE_VELOCITY_R = -0.17812614789863687 12 | RELATIVE_VELOCITY_T = -4.739646389659714 13 | RELATIVE_VELOCITY_N = -6.945253881819946 14 | COLLISION_PROBABILITY = 0.0 15 | COLLISION_PROBABILITY_METHOD = MC 16 | OBJECT = OBJECT1 17 | OBJECT_DESIGNATOR = 69082CJ 18 | CATALOG_NAME = 4227 19 | OBJECT_NAME = THORAD AGENA D DEB 20 | INTERNATIONAL_DESIGNATOR = 69082CJ 21 | EPHEMERIS_NAME = NONE 22 | COVARIANCE_METHOD = CALCULATED 23 | MANEUVERABLE = N/A 24 | ORBIT_CENTER = EARTH 25 | REF_FRAME = ITRF 26 | X = 2482.230958985215 27 | Y = 2877.8869608291307 28 | Z = -5640.491819817693 29 | X_DOT = -0.10271715718174677 30 | Y_DOT = 6.678346704938898 31 | Z_DOT = 3.365040186814587 32 | CR_R = 1.000E-18 33 | CT_R = 0.0 34 | CT_T = 1.2451197530695846 35 | CN_R = 0.0 36 | CN_T = 0.0 37 | CN_N = 0.0035176566277315556 38 | CRDOT_R = 0.0 39 | CRDOT_T = 0.0 40 | CRDOT_N = 0.0 41 | CRDOT_RDOT = 1.000E-18 42 | CTDOT_R = 0.0 43 | CTDOT_T = 0.0 44 | CTDOT_N = 0.0 45 | CTDOT_RDOT = 0.0 46 | CTDOT_TDOT = 1.000E-18 47 | CNDOT_R = 0.0 48 | CNDOT_T = 0.0 49 | CNDOT_N = 0.0 50 | CNDOT_RDOT = 0.0 51 | CNDOT_TDOT = 0.0 52 | CNDOT_NDOT = 1.000E-18 53 | OBJECT = OBJECT2 54 | OBJECT_DESIGNATOR = 76126AP 55 | CATALOG_NAME = 9827 56 | OBJECT_NAME = COSMOS 886 DEB 57 | INTERNATIONAL_DESIGNATOR = 76126AP 58 | EPHEMERIS_NAME = NONE 59 | COVARIANCE_METHOD = CALCULATED 60 | MANEUVERABLE = N/A 61 | ORBIT_CENTER = EARTH 62 | REF_FRAME = ITRF 63 | X = 1934.7986774883261 64 | Y = 2163.451996914955 65 | Z = -6160.656633913729 66 | X_DOT = -6.568673859600255 67 | Y_DOT = 3.4314199219712815 68 | Z_DOT = -0.922313157034195 69 | CR_R = 3.852952621853669 70 | CT_R = 0.0 71 | CT_T = 4.976328968225473 72 | CN_R = 0.0 73 | CN_T = 0.0 74 | CN_N = 0.9333314012997196 75 | CRDOT_R = 0.0 76 | CRDOT_T = 0.0 77 | CRDOT_N = 0.0 78 | CRDOT_RDOT = 1.000E-18 79 | CTDOT_R = 0.0 80 | CTDOT_T = 0.0 81 | CTDOT_N = 0.0 82 | CTDOT_RDOT = 0.0 83 | CTDOT_TDOT = 1.000E-18 84 | CNDOT_R = 0.0 85 | CNDOT_T = 0.0 86 | CNDOT_N = 0.0 87 | CNDOT_RDOT = 0.0 88 | CNDOT_TDOT = 0.0 89 | CNDOT_NDOT = 1.000E-18 90 | -------------------------------------------------------------------------------- /docs/notebooks/synthetic_cdms/event2_2.kvn: -------------------------------------------------------------------------------- 1 | CCSDS_CDM_VERS = 1.0 2 | CREATION_DATE = 2025-02-21T19:19:44.062765 3 | ORIGINATOR = KESSLER_SOFTWARE 4 | MESSAGE_ID = KESSLER_SOFTWARE_747c037c-138a-11f0-a1a9-f2a9f71f7e19 5 | TCA = 2025-02-23T11:32:33.989495 6 | MISS_DISTANCE = 656.3517425786031 7 | RELATIVE_SPEED = 8.400204306797388 8 | RELATIVE_POSITION_R = -25.067336315349497 9 | RELATIVE_POSITION_T = -285.4881797139954 10 | RELATIVE_POSITION_N = -590.4792442411599 11 | RELATIVE_VELOCITY_R = -0.4292424844649117 12 | RELATIVE_VELOCITY_T = -4.727249392375454 13 | RELATIVE_VELOCITY_N = -6.930533635136164 14 | COLLISION_PROBABILITY = 0.0 15 | COLLISION_PROBABILITY_METHOD = MC 16 | OBJECT = OBJECT1 17 | OBJECT_DESIGNATOR = 69082CJ 18 | CATALOG_NAME = 4227 19 | OBJECT_NAME = THORAD AGENA D DEB 20 | INTERNATIONAL_DESIGNATOR = 69082CJ 21 | EPHEMERIS_NAME = NONE 22 | COVARIANCE_METHOD = CALCULATED 23 | MANEUVERABLE = N/A 24 | ORBIT_CENTER = EARTH 25 | REF_FRAME = ITRF 26 | X = 2496.8832174906834 27 | Y = 2348.67412841551 28 | Z = -5876.840950980776 29 | X_DOT = 0.09578954311480503 30 | Y_DOT = 6.927447367584264 31 | Z_DOT = 2.8094628342774146 32 | CR_R = 1.000E-18 33 | CT_R = 0.0 34 | CT_T = 1.2451197530695846 35 | CN_R = 0.0 36 | CN_T = 0.0 37 | CN_N = 0.0035176566277315556 38 | CRDOT_R = 0.0 39 | CRDOT_T = 0.0 40 | CRDOT_N = 0.0 41 | CRDOT_RDOT = 1.000E-18 42 | CTDOT_R = 0.0 43 | CTDOT_T = 0.0 44 | CTDOT_N = 0.0 45 | CTDOT_RDOT = 0.0 46 | CTDOT_TDOT = 1.000E-18 47 | CNDOT_R = 0.0 48 | CNDOT_T = 0.0 49 | CNDOT_N = 0.0 50 | CNDOT_RDOT = 0.0 51 | CNDOT_TDOT = 0.0 52 | CNDOT_NDOT = 1.000E-18 53 | OBJECT = OBJECT2 54 | OBJECT_DESIGNATOR = 76126AP 55 | CATALOG_NAME = 9827 56 | OBJECT_NAME = COSMOS 886 DEB 57 | INTERNATIONAL_DESIGNATOR = 76126AP 58 | EPHEMERIS_NAME = NONE 59 | COVARIANCE_METHOD = CALCULATED 60 | MANEUVERABLE = N/A 61 | ORBIT_CENTER = EARTH 62 | REF_FRAME = ITRF 63 | X = 1934.7986774883261 64 | Y = 2163.451996914955 65 | Z = -6160.656633913729 66 | X_DOT = -6.568673859600255 67 | Y_DOT = 3.4314199219712815 68 | Z_DOT = -0.922313157034195 69 | CR_R = 3.852952621853669 70 | CT_R = 0.0 71 | CT_T = 4.976328968225473 72 | CN_R = 0.0 73 | CN_T = 0.0 74 | CN_N = 0.9333314012997196 75 | CRDOT_R = 0.0 76 | CRDOT_T = 0.0 77 | CRDOT_N = 0.0 78 | CRDOT_RDOT = 1.000E-18 79 | CTDOT_R = 0.0 80 | CTDOT_T = 0.0 81 | CTDOT_N = 0.0 82 | CTDOT_RDOT = 0.0 83 | CTDOT_TDOT = 1.000E-18 84 | CNDOT_R = 0.0 85 | CNDOT_T = 0.0 86 | CNDOT_N = 0.0 87 | CNDOT_RDOT = 0.0 88 | CNDOT_TDOT = 0.0 89 | CNDOT_NDOT = 1.000E-18 90 | -------------------------------------------------------------------------------- /docs/notebooks/synthetic_cdms/event2_3.kvn: -------------------------------------------------------------------------------- 1 | CCSDS_CDM_VERS = 1.0 2 | CREATION_DATE = 2025-02-22T03:21:02.246543 3 | ORIGINATOR = KESSLER_SOFTWARE 4 | MESSAGE_ID = KESSLER_SOFTWARE_7614c750-138a-11f0-a1a9-f2a9f71f7e19 5 | TCA = 2025-02-23T11:32:33.989495 6 | MISS_DISTANCE = 336.7164664356748 7 | RELATIVE_SPEED = 8.421971184629339 8 | RELATIVE_POSITION_R = -4.437186746503206 9 | RELATIVE_POSITION_T = 57.33529984469695 10 | RELATIVE_POSITION_N = -331.76942826972817 11 | RELATIVE_VELOCITY_R = -0.30516412002349635 12 | RELATIVE_VELOCITY_T = -4.7492169598501714 13 | RELATIVE_VELOCITY_N = -6.948482695009658 14 | COLLISION_PROBABILITY = 0.0 15 | COLLISION_PROBABILITY_METHOD = MC 16 | OBJECT = OBJECT1 17 | OBJECT_DESIGNATOR = 69082CJ 18 | CATALOG_NAME = 4227 19 | OBJECT_NAME = THORAD AGENA D DEB 20 | INTERNATIONAL_DESIGNATOR = 69082CJ 21 | EPHEMERIS_NAME = NONE 22 | COVARIANCE_METHOD = CALCULATED 23 | MANEUVERABLE = N/A 24 | ORBIT_CENTER = EARTH 25 | REF_FRAME = ITRF 26 | X = 2496.001549455363 27 | Y = 1926.3034783274513 28 | Z = -6031.073889192313 29 | X_DOT = 0.24776788820778156 30 | Y_DOT = 7.085098680286528 31 | Z_DOT = 2.366827407886658 32 | CR_R = 1.000E-18 33 | CT_R = 0.0 34 | CT_T = 1.2451197530695846 35 | CN_R = 0.0 36 | CN_T = 0.0 37 | CN_N = 0.0035176566277315556 38 | CRDOT_R = 0.0 39 | CRDOT_T = 0.0 40 | CRDOT_N = 0.0 41 | CRDOT_RDOT = 1.000E-18 42 | CTDOT_R = 0.0 43 | CTDOT_T = 0.0 44 | CTDOT_N = 0.0 45 | CTDOT_RDOT = 0.0 46 | CTDOT_TDOT = 1.000E-18 47 | CNDOT_R = 0.0 48 | CNDOT_T = 0.0 49 | CNDOT_N = 0.0 50 | CNDOT_RDOT = 0.0 51 | CNDOT_TDOT = 0.0 52 | CNDOT_NDOT = 1.000E-18 53 | OBJECT = OBJECT2 54 | OBJECT_DESIGNATOR = 76126AP 55 | CATALOG_NAME = 9827 56 | OBJECT_NAME = COSMOS 886 DEB 57 | INTERNATIONAL_DESIGNATOR = 76126AP 58 | EPHEMERIS_NAME = NONE 59 | COVARIANCE_METHOD = CALCULATED 60 | MANEUVERABLE = N/A 61 | ORBIT_CENTER = EARTH 62 | REF_FRAME = ITRF 63 | X = 2187.825055563409 64 | Y = 2027.681043312939 65 | Z = -6121.228293959925 66 | X_DOT = -6.48202035426559 67 | Y_DOT = 3.507615461306938 68 | Z_DOT = -1.2166293958314358 69 | CR_R = 0.029855111184815902 70 | CT_R = -36.455242653665344 71 | CT_T = 485447.3382402141 72 | CN_R = 0.004114526596943422 73 | CN_T = -54.147490135149845 74 | CN_N = 0.006040531131919577 75 | CRDOT_R = 0.04085965130505657 76 | CRDOT_T = -542.1311006322615 77 | CRDOT_N = 0.060471278965901515 78 | CRDOT_RDOT = 0.6054379937293098 79 | CTDOT_R = -0.00020380169189888187 80 | CTDOT_T = 2.3347537894444854 81 | CTDOT_N = -0.00026049027277115196 82 | CTDOT_RDOT = -0.0026075655924565214 83 | CTDOT_TDOT = 1.127E-05 84 | CNDOT_R = -7.069E-05 85 | CNDOT_T = 0.9368742581746528 86 | CNDOT_N = -0.00010450579240147632 87 | CNDOT_RDOT = -0.001046277168866979 88 | CNDOT_TDOT = 4.506E-06 89 | CNDOT_NDOT = 1.808E-06 90 | -------------------------------------------------------------------------------- /docs/notebooks/synthetic_cdms/event2_4.kvn: -------------------------------------------------------------------------------- 1 | CCSDS_CDM_VERS = 1.0 2 | CREATION_DATE = 2025-02-22T11:16:57.870372 3 | ORIGINATOR = KESSLER_SOFTWARE 4 | MESSAGE_ID = KESSLER_SOFTWARE_77d15efa-138a-11f0-a1a9-f2a9f71f7e19 5 | TCA = 2025-02-23T11:32:33.989495 6 | MISS_DISTANCE = 355.8752718357519 7 | RELATIVE_SPEED = 8.432715788553805 8 | RELATIVE_POSITION_R = -4.526224325793488 9 | RELATIVE_POSITION_T = -222.19460552093963 10 | RELATIVE_POSITION_N = -277.95013882874196 11 | RELATIVE_VELOCITY_R = -0.1413377124356699 12 | RELATIVE_VELOCITY_T = -4.761376811766602 13 | RELATIVE_VELOCITY_N = -6.95844882699725 14 | COLLISION_PROBABILITY = 0.0 15 | COLLISION_PROBABILITY_METHOD = MC 16 | OBJECT = OBJECT1 17 | OBJECT_DESIGNATOR = 69082CJ 18 | CATALOG_NAME = 4227 19 | OBJECT_NAME = THORAD AGENA D DEB 20 | INTERNATIONAL_DESIGNATOR = 69082CJ 21 | EPHEMERIS_NAME = NONE 22 | COVARIANCE_METHOD = CALCULATED 23 | MANEUVERABLE = N/A 24 | ORBIT_CENTER = EARTH 25 | REF_FRAME = ITRF 26 | X = 2497.0503363905723 27 | Y = 2172.040093286947 28 | Z = -5945.569579008451 29 | X_DOT = 0.15798077859579895 30 | Y_DOT = 6.998223425763956 31 | Z_DOT = 2.6221661542474664 32 | CR_R = 1.000E-18 33 | CT_R = 0.0 34 | CT_T = 1.2451197530695846 35 | CN_R = 0.0 36 | CN_T = 0.0 37 | CN_N = 0.0035176566277315556 38 | CRDOT_R = 0.0 39 | CRDOT_T = 0.0 40 | CRDOT_N = 0.0 41 | CRDOT_RDOT = 1.000E-18 42 | CTDOT_R = 0.0 43 | CTDOT_T = 0.0 44 | CTDOT_N = 0.0 45 | CTDOT_RDOT = 0.0 46 | CTDOT_TDOT = 1.000E-18 47 | CNDOT_R = 0.0 48 | CNDOT_T = 0.0 49 | CNDOT_N = 0.0 50 | CNDOT_RDOT = 0.0 51 | CNDOT_TDOT = 0.0 52 | CNDOT_NDOT = 1.000E-18 53 | OBJECT = OBJECT2 54 | OBJECT_DESIGNATOR = 76126AP 55 | CATALOG_NAME = 9827 56 | OBJECT_NAME = COSMOS 886 DEB 57 | INTERNATIONAL_DESIGNATOR = 76126AP 58 | EPHEMERIS_NAME = NONE 59 | COVARIANCE_METHOD = CALCULATED 60 | MANEUVERABLE = N/A 61 | ORBIT_CENTER = EARTH 62 | REF_FRAME = ITRF 63 | X = 2232.2083862398003 64 | Y = 2003.4923799492785 65 | Z = -6113.193022694439 66 | X_DOT = -6.465682990762491 67 | Y_DOT = 3.519814797912875 68 | Z_DOT = -1.2686496032391492 69 | CR_R = 2.3318232199245887 70 | CT_R = -826.3013263198949 71 | CT_T = 303792.99459934974 72 | CN_R = 0.1681178452972925 73 | CN_T = -60.63300502366046 74 | CN_N = 0.7806180034112329 75 | CRDOT_R = 0.9233767919859629 76 | CRDOT_T = -339.683764977155 77 | CRDOT_N = 0.06786734827691328 78 | CRDOT_RDOT = 0.3798192817634991 79 | CTDOT_R = -0.005669549067886144 80 | CTDOT_T = 2.051027277080463 81 | CTDOT_N = -0.0004009432081608951 82 | CTDOT_RDOT = -0.0022927389317536472 83 | CTDOT_TDOT = 1.395E-05 84 | CNDOT_R = -0.002053718100766171 85 | CNDOT_T = 0.7475825513544112 86 | CNDOT_N = -0.005038593953879326 87 | CNDOT_RDOT = -0.0008363554794435568 88 | CNDOT_TDOT = 4.994E-06 89 | CNDOT_NDOT = 3.295E-05 90 | -------------------------------------------------------------------------------- /docs/notebooks/synthetic_cdms/event2_5.kvn: -------------------------------------------------------------------------------- 1 | CCSDS_CDM_VERS = 1.0 2 | CREATION_DATE = 2025-02-22T19:18:45.286138 3 | ORIGINATOR = KESSLER_SOFTWARE 4 | MESSAGE_ID = KESSLER_SOFTWARE_7974c440-138a-11f0-a1a9-f2a9f71f7e19 5 | TCA = 2025-02-23T11:32:33.989495 6 | MISS_DISTANCE = 454.14211145657777 7 | RELATIVE_SPEED = 8.444058855408288 8 | RELATIVE_POSITION_R = -6.7602935045226085 9 | RELATIVE_POSITION_T = -383.4108495461509 10 | RELATIVE_POSITION_N = -243.30120484755153 11 | RELATIVE_VELOCITY_R = -0.041211643704205284 12 | RELATIVE_VELOCITY_T = -4.775380098829026 13 | RELATIVE_VELOCITY_N = -6.963919619419081 14 | COLLISION_PROBABILITY = 0.0 15 | COLLISION_PROBABILITY_METHOD = MC 16 | OBJECT = OBJECT1 17 | OBJECT_DESIGNATOR = 69082CJ 18 | CATALOG_NAME = 4227 19 | OBJECT_NAME = THORAD AGENA D DEB 20 | INTERNATIONAL_DESIGNATOR = 69082CJ 21 | EPHEMERIS_NAME = NONE 22 | COVARIANCE_METHOD = CALCULATED 23 | MANEUVERABLE = N/A 24 | ORBIT_CENTER = EARTH 25 | REF_FRAME = ITRF 26 | X = 2494.6384300124305 27 | Y = 2310.5653866221082 28 | Z = -5890.112574631742 29 | X_DOT = 0.10472869825239639 30 | Y_DOT = 6.945820856360042 31 | Z_DOT = 2.7699860815721564 32 | CR_R = 1.000E-18 33 | CT_R = 0.0 34 | CT_T = 1.2451197530695846 35 | CN_R = 0.0 36 | CN_T = 0.0 37 | CN_N = 0.0035176566277315556 38 | CRDOT_R = 0.0 39 | CRDOT_T = 0.0 40 | CRDOT_N = 0.0 41 | CRDOT_RDOT = 1.000E-18 42 | CTDOT_R = 0.0 43 | CTDOT_T = 0.0 44 | CTDOT_N = 0.0 45 | CTDOT_RDOT = 0.0 46 | CTDOT_TDOT = 1.000E-18 47 | CNDOT_R = 0.0 48 | CNDOT_T = 0.0 49 | CNDOT_N = 0.0 50 | CNDOT_RDOT = 0.0 51 | CNDOT_TDOT = 0.0 52 | CNDOT_NDOT = 1.000E-18 53 | OBJECT = OBJECT2 54 | OBJECT_DESIGNATOR = 76126AP 55 | CATALOG_NAME = 9827 56 | OBJECT_NAME = COSMOS 886 DEB 57 | INTERNATIONAL_DESIGNATOR = 76126AP 58 | EPHEMERIS_NAME = NONE 59 | COVARIANCE_METHOD = CALCULATED 60 | MANEUVERABLE = N/A 61 | ORBIT_CENTER = EARTH 62 | REF_FRAME = ITRF 63 | X = 2260.4568111727845 64 | Y = 1988.1596578540568 65 | Z = -6107.962460685013 66 | X_DOT = -6.455252403087823 67 | Y_DOT = 3.5269865941685343 68 | Z_DOT = -1.3019115339535272 69 | CR_R = 3.852952621853669 70 | CT_R = 0.0 71 | CT_T = 4.976328968225473 72 | CN_R = 0.0 73 | CN_T = 0.0 74 | CN_N = 0.9333314012997196 75 | CRDOT_R = 0.0 76 | CRDOT_T = 0.0 77 | CRDOT_N = 0.0 78 | CRDOT_RDOT = 1.000E-18 79 | CTDOT_R = 0.0 80 | CTDOT_T = 0.0 81 | CTDOT_N = 0.0 82 | CTDOT_RDOT = 0.0 83 | CTDOT_TDOT = 1.000E-18 84 | CNDOT_R = 0.0 85 | CNDOT_T = 0.0 86 | CNDOT_N = 0.0 87 | CNDOT_RDOT = 0.0 88 | CNDOT_TDOT = 0.0 89 | CNDOT_NDOT = 1.000E-18 90 | -------------------------------------------------------------------------------- /docs/notebooks/synthetic_cdms/event2_6.kvn: -------------------------------------------------------------------------------- 1 | CCSDS_CDM_VERS = 1.0 2 | CREATION_DATE = 2025-02-23T03:19:16.093910 3 | ORIGINATOR = KESSLER_SOFTWARE 4 | MESSAGE_ID = KESSLER_SOFTWARE_7b203630-138a-11f0-a1a9-f2a9f71f7e19 5 | TCA = 2025-02-23T11:32:33.989495 6 | MISS_DISTANCE = 306.6743258990981 7 | RELATIVE_SPEED = 8.432117629824914 8 | RELATIVE_POSITION_R = -2.4152145032400973 9 | RELATIVE_POSITION_T = -180.46591835639683 10 | RELATIVE_POSITION_N = -247.9422537938056 11 | RELATIVE_VELOCITY_R = -0.12688441843952009 12 | RELATIVE_VELOCITY_T = -4.760516024612067 13 | RELATIVE_VELOCITY_N = -6.958591470044288 14 | COLLISION_PROBABILITY = 0.0 15 | COLLISION_PROBABILITY_METHOD = MC 16 | OBJECT = OBJECT1 17 | OBJECT_DESIGNATOR = 69082CJ 18 | CATALOG_NAME = 4227 19 | OBJECT_NAME = THORAD AGENA D DEB 20 | INTERNATIONAL_DESIGNATOR = 69082CJ 21 | EPHEMERIS_NAME = NONE 22 | COVARIANCE_METHOD = CALCULATED 23 | MANEUVERABLE = N/A 24 | ORBIT_CENTER = EARTH 25 | REF_FRAME = ITRF 26 | X = 2496.1102642305405 27 | Y = 2122.0435865323107 28 | Z = -5964.464426310676 29 | X_DOT = 0.1730808517896394 30 | Y_DOT = 7.017217551744274 31 | Z_DOT = 2.5690177922250865 32 | CR_R = 1.000E-18 33 | CT_R = 0.0 34 | CT_T = 1.2451197530695846 35 | CN_R = 0.0 36 | CN_T = 0.0 37 | CN_N = 0.0035176566277315556 38 | CRDOT_R = 0.0 39 | CRDOT_T = 0.0 40 | CRDOT_N = 0.0 41 | CRDOT_RDOT = 1.000E-18 42 | CTDOT_R = 0.0 43 | CTDOT_T = 0.0 44 | CTDOT_N = 0.0 45 | CTDOT_RDOT = 0.0 46 | CTDOT_TDOT = 1.000E-18 47 | CNDOT_R = 0.0 48 | CNDOT_T = 0.0 49 | CNDOT_N = 0.0 50 | CNDOT_RDOT = 0.0 51 | CNDOT_TDOT = 0.0 52 | CNDOT_NDOT = 1.000E-18 53 | OBJECT = OBJECT2 54 | OBJECT_DESIGNATOR = 76126AP 55 | CATALOG_NAME = 9827 56 | OBJECT_NAME = COSMOS 886 DEB 57 | INTERNATIONAL_DESIGNATOR = 76126AP 58 | EPHEMERIS_NAME = NONE 59 | COVARIANCE_METHOD = CALCULATED 60 | MANEUVERABLE = N/A 61 | ORBIT_CENTER = EARTH 62 | REF_FRAME = ITRF 63 | X = 2260.4568111727845 64 | Y = 1988.1596578540568 65 | Z = -6107.962460685013 66 | X_DOT = -6.455252403087823 67 | Y_DOT = 3.5269865941685343 68 | Z_DOT = -1.3019115339535272 69 | CR_R = 3.852952621853669 70 | CT_R = 0.0 71 | CT_T = 4.976328968225473 72 | CN_R = 0.0 73 | CN_T = 0.0 74 | CN_N = 0.9333314012997196 75 | CRDOT_R = 0.0 76 | CRDOT_T = 0.0 77 | CRDOT_N = 0.0 78 | CRDOT_RDOT = 1.000E-18 79 | CTDOT_R = 0.0 80 | CTDOT_T = 0.0 81 | CTDOT_N = 0.0 82 | CTDOT_RDOT = 0.0 83 | CTDOT_TDOT = 1.000E-18 84 | CNDOT_R = 0.0 85 | CNDOT_T = 0.0 86 | CNDOT_N = 0.0 87 | CNDOT_RDOT = 0.0 88 | CNDOT_TDOT = 0.0 89 | CNDOT_NDOT = 1.000E-18 90 | -------------------------------------------------------------------------------- /docs/notebooks/tles_sample_population.txt: -------------------------------------------------------------------------------- 1 | 0 DELTA 1 DEB (YO) 2 | 1 00228U 62002C 25077.54063668 .00036109 00000-0 13308-2 0 9997 3 | 2 00228 48.4320 169.8687 0009240 182.7749 177.3135 15.27346117372942 4 | 0 THOR ABLESTAR DEB 5 | 1 00233U 61015BR 25077.21110220 .00138674 00000-0 80281-2 0 9991 6 | 2 00233 66.8325 29.6624 0010819 52.7398 307.4727 15.11387947311283 7 | 0 THOR ABLESTAR DEB 8 | 1 00318U 61015CU 25077.40716751 .00171359 00000-0 37727-2 0 9991 9 | 2 00318 66.5329 69.6277 0029092 347.6670 12.3768 15.42685744345675 10 | 0 TITAN 3C TRANSTAGE DEB 11 | 1 01883U 65082EY 25077.32923920 .00015166 00000-0 75111-3 0 9999 12 | 2 01883 32.0909 109.1381 0016537 249.0243 110.8648 15.16560694195875 13 | 0 TITAN 3C TRANSTAGE DEB 14 | 1 01961U 65082GW 25077.04069644 .00016491 00000-0 10218-2 0 9997 15 | 2 01961 31.8604 334.8960 0003329 45.6758 314.4168 15.08686927175031 16 | 0 SURCAL 150B 17 | 1 02909U 67053J 25077.23301999 .00109357 00000-0 66025-2 0 9994 18 | 2 02909 69.9293 342.6093 0005534 249.2386 110.8186 15.10090266 11948 19 | 0 TITAN 3C TRANSTAGE DEB 20 | 1 03462U 65082PT 25077.28948752 .00019341 00000-0 84635-3 0 9999 21 | 2 03462 32.0223 61.1093 0015626 225.5133 134.4250 15.20840135193821 22 | 0 THORAD AGENA D DEB 23 | 1 04190U 69082BD 25052.33546809 .17677494 43718-5 21895-2 0 9991 24 | 2 04190 69.9747 346.9478 0009344 201.4829 158.6009 16.35790429919740 25 | 0 THORAD AGENA D DEB 26 | 1 04227U 69082CJ 25077.15466224 .00541744 00000-0 55225-2 0 9997 27 | 2 04227 69.8453 346.6453 0005319 147.5879 212.5640 15.63204935913621 28 | 0 THORAD AGENA D DEB 29 | 1 04276U 69082DK 25077.19876761 .00090503 00000-0 52406-2 0 9996 30 | 2 04276 70.0505 8.4719 0014498 180.4215 179.6942 15.11637859914079 31 | 0 COSMOS 394 32 | 1 04922U 71010A 25077.03209553 .00010483 00000-0 24522-3 0 9998 33 | 2 04922 65.8226 315.4649 0004234 205.9230 154.1706 15.42539397987583 34 | 0 SL-3 R/B 35 | 1 05118U 71028B 25077.55365863 .00028413 00000-0 67602-3 0 9997 36 | 2 05118 81.2425 124.1901 0029133 103.4548 256.9944 15.41027203933515 37 | 0 COSMOS 397 DEB * 38 | 1 05597U 71015CA 25077.55901694 .00114867 00000-0 69557-2 0 9991 39 | 2 05597 66.5507 131.7609 0004843 30.3353 329.8064 15.09913823805972 40 | 0 SL-8 DEB 41 | 1 06063U 72043C 25071.87703339 .09541389 19057-5 36298-2 0 9992 42 | 2 06063 73.9845 244.7173 0009861 297.8621 62.1631 16.23966074803419 43 | 0 COSMOS 546 44 | 1 06350U 73005A 25077.55675771 .00005170 00000-0 20163-3 0 9991 45 | 2 06350 50.6355 236.7484 0015602 308.8222 51.1350 15.27483013873516 46 | 0 SL-8 DEB 47 | 1 06396U 72104D 25055.98782945 .07406227 18833-5 36867-2 0 9995 48 | 2 06396 74.0533 57.3572 0007473 239.1616 120.8899 16.20673105781291 49 | 0 COSMOS 803 50 | 1 08688U 76014A 25077.31870503 .00018173 00000-0 29239-3 0 9994 51 | 2 08688 65.8404 49.1611 0019250 305.1781 54.7568 15.52866360720830 52 | 0 SL-8 DEB * 53 | 1 09569U 73098D 25077.08166003 .00146769 00000-0 35409-2 0 9997 54 | 2 09569 74.0204 92.0435 0011820 295.6760 64.3227 15.40501227843981 55 | 0 COSMOS 886 DEB 56 | 1 09827U 76126AP 25077.30971045 .00524791 00000-0 97247-2 0 9997 57 | 2 09827 65.7570 49.2145 0080731 206.3726 153.3303 15.43513976398156 58 | 0 SL-3 DEB 59 | 1 09907U 77024C 25077.38293267 .00260049 00000-0 14670-1 0 9996 60 | 2 09907 82.8886 221.1139 0013752 299.2098 60.7757 15.11843917460005 61 | -------------------------------------------------------------------------------- /docs/notebooks/trace.pickle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kesslerlib/kessler/cc9404a73d6e9719b1c1be317ab2271e9dedea45/docs/notebooks/trace.pickle -------------------------------------------------------------------------------- /docs/tutorials.rst: -------------------------------------------------------------------------------- 1 | .. _tutorials: 2 | 3 | Tutorials 4 | =============== 5 | 6 | Basics 7 | ^^^^^^^^^^^ 8 | These tutorials include some basic examples on how to use kessler 9 | 10 | .. toctree:: 11 | :maxdepth: 1 12 | 13 | notebooks/basics.ipynb 14 | notebooks/cdms_analysis_and_plotting.ipynb 15 | notebooks/plotting.ipynb 16 | notebooks/kelvins_dataset.ipynb 17 | 18 | 19 | Advanced 20 | ^^^^^^^^^^^ 21 | These tutorials are more advanced examples on how to leverage kessler framework 22 | for more complex tasks. In particular, we will cover both the deep learning module (where 23 | kessler is used to predict CDMs) and the probabilistic programming one (where kessler is used 24 | as a probabilistic generative model for CDMs) 25 | 26 | .. toctree:: 27 | :maxdepth: 1 28 | 29 | notebooks/LSTM_training.ipynb 30 | notebooks/probabilistic_programming_module.ipynb 31 | -------------------------------------------------------------------------------- /kessler/__init__.py: -------------------------------------------------------------------------------- 1 | # This code is part of Kessler, a machine learning library for spacecraft collision avoidance. 2 | # 3 | # Copyright (c) 2020- 4 | # Trillium Technologies 5 | # University of Oxford 6 | # Giacomo Acciarini (giacomo.acciarini@gmail.com) 7 | # and other contributors, see README in root of repository. 8 | # 9 | # GNU General Public License version 3. See LICENSE in root of repository. 10 | 11 | __version__ = '1.0.1' 12 | 13 | from .util import seed 14 | from .cdm import ConjunctionDataMessage, CDM 15 | from .event import Event, EventDataset 16 | from .observation_model import GNSS, Radar 17 | from . import plot, model 18 | from . import util 19 | -------------------------------------------------------------------------------- /kessler/cdm.py: -------------------------------------------------------------------------------- 1 | # This code is part of Kessler, a machine learning library for spacecraft collision avoidance. 2 | # 3 | # Copyright (c) 2020- 4 | # Trillium Technologies 5 | # University of Oxford 6 | # Giacomo Acciarini (giacomo.acciarini@gmail.com) 7 | # and other contributors, see README in root of repository. 8 | # 9 | # GNU General Public License version 3. See LICENSE in root of repository. 10 | 11 | import numpy as np 12 | import warnings 13 | import datetime 14 | import copy 15 | import pandas as pd 16 | from . import util 17 | 18 | 19 | # Based on CCSDS 508.0-B-1 20 | # https://public.ccsds.org/Pubs/508x0b1e2c1.pdf 21 | class ConjunctionDataMessage(): 22 | def __init__(self, file_name=None, set_defaults=True): 23 | # Header 24 | # Relative metadata 25 | # Object 1 26 | # Metadata, OD, State, Covariance 27 | # Object 2 28 | # Metadata, OD, State, Covariance 29 | # Comments are optional and not currently supported by this class 30 | 31 | self._keys_header = ['CCSDS_CDM_VERS', 'CREATION_DATE', 'ORIGINATOR', 'MESSAGE_FOR', 'MESSAGE_ID'] 32 | self._keys_relative_metadata = ['TCA', 'MISS_DISTANCE', 'RELATIVE_SPEED', 'RELATIVE_POSITION_R', 'RELATIVE_POSITION_T', 'RELATIVE_POSITION_N', 'RELATIVE_VELOCITY_R', 'RELATIVE_VELOCITY_T', 'RELATIVE_VELOCITY_N', 'START_SCREEN_PERIOD', 'STOP_SCREEN_PERIOD', 'SCREEN_VOLUME_FRAME', 'SCREEN_VOLUME_SHAPE', 'SCREEN_VOLUME_X', 'SCREEN_VOLUME_Y', 'SCREEN_VOLUME_Z', 'SCREEN_ENTRY_TIME', 'SCREEN_EXIT_TIME', 'COLLISION_PROBABILITY', 'COLLISION_PROBABILITY_METHOD'] 33 | self._keys_metadata = ['OBJECT', 'OBJECT_DESIGNATOR', 'CATALOG_NAME', 'OBJECT_NAME', 'INTERNATIONAL_DESIGNATOR', 'OBJECT_TYPE', 'OPERATOR_CONTACT_POSITION', 'OPERATOR_ORGANIZATION', 'OPERATOR_PHONE', 'OPERATOR_EMAIL', 'EPHEMERIS_NAME', 'COVARIANCE_METHOD', 'MANEUVERABLE', 'ORBIT_CENTER', 'REF_FRAME', 'GRAVITY_MODEL', 'ATMOSPHERIC_MODEL', 'N_BODY_PERTURBATIONS', 'SOLAR_RAD_PRESSURE', 'EARTH_TIDES', 'INTRACK_THRUST'] 34 | self._keys_data_od = ['TIME_LASTOB_START', 'TIME_LASTOB_END', 'RECOMMENDED_OD_SPAN', 'ACTUAL_OD_SPAN', 'OBS_AVAILABLE', 'OBS_USED', 'TRACKS_AVAILABLE', 'TRACKS_USED', 'RESIDUALS_ACCEPTED', 'WEIGHTED_RMS', 'AREA_PC', 'AREA_DRG', 'AREA_SRP', 'MASS', 'CD_AREA_OVER_MASS', 'CR_AREA_OVER_MASS', 'THRUST_ACCELERATION', 'SEDR'] 35 | self._keys_data_state = ['X', 'Y', 'Z', 'X_DOT', 'Y_DOT', 'Z_DOT'] 36 | self._keys_data_covariance = ['CR_R', 'CT_R', 'CT_T', 'CN_R', 'CN_T', 'CN_N', 'CRDOT_R', 'CRDOT_T', 'CRDOT_N', 'CRDOT_RDOT', 'CTDOT_R', 'CTDOT_T', 'CTDOT_N', 'CTDOT_RDOT', 'CTDOT_TDOT', 'CNDOT_R', 'CNDOT_T', 'CNDOT_N', 'CNDOT_RDOT', 'CNDOT_TDOT', 'CNDOT_NDOT', 'CDRG_R', 'CDRG_T', 'CDRG_N', 'CDRG_RDOT', 'CDRG_TDOT', 'CDRG_NDOT', 'CDRG_DRG', 'CSRP_R', 'CSRP_T', 'CSRP_N', 'CSRP_RDOT', 'CSRP_TDOT', 'CSRP_NDOT', 'CSRP_DRG', 'CSRP_SRP', 'CTHR_R', 'CTHR_T', 'CTHR_N', 'CTHR_RDOT', 'CTHR_TDOT', 'CTHR_NDOT', 'CTHR_DRG', 'CTHR_SRP', 'CTHR_THR'] 37 | 38 | self._keys_header_obligatory = ['CCSDS_CDM_VERS', 'CREATION_DATE', 'ORIGINATOR', 'MESSAGE_ID'] 39 | self._keys_relative_metadata_obligatory = ['TCA', 'MISS_DISTANCE'] 40 | self._keys_metadata_obligatory = ['OBJECT', 'OBJECT_DESIGNATOR', 'CATALOG_NAME', 'OBJECT_NAME', 'INTERNATIONAL_DESIGNATOR', 'EPHEMERIS_NAME', 'COVARIANCE_METHOD', 'MANEUVERABLE', 'REF_FRAME'] 41 | self._keys_data_od_obligatory = [] 42 | self._keys_data_state_obligatory = ['X', 'Y', 'Z', 'X_DOT', 'Y_DOT', 'Z_DOT'] 43 | self._keys_data_covariance_obligatory = ['CR_R', 'CT_R', 'CT_T', 'CN_R', 'CN_T', 'CN_N', 'CRDOT_R', 'CRDOT_T', 'CRDOT_N', 'CRDOT_RDOT', 'CTDOT_R', 'CTDOT_T', 'CTDOT_N', 'CTDOT_RDOT', 'CTDOT_TDOT', 'CNDOT_R', 'CNDOT_T', 'CNDOT_N', 'CNDOT_RDOT', 'CNDOT_TDOT', 'CNDOT_NDOT'] 44 | 45 | self._values_header = dict.fromkeys(self._keys_header) 46 | self._values_relative_metadata = dict.fromkeys(self._keys_relative_metadata) 47 | self._values_object_metadata = [dict.fromkeys(self._keys_metadata), dict.fromkeys(self._keys_metadata)] 48 | self._values_object_data_od = [dict.fromkeys(self._keys_data_od), dict.fromkeys(self._keys_data_od)] 49 | self._values_object_data_state = [dict.fromkeys(self._keys_data_state), dict.fromkeys(self._keys_data_state)] 50 | self._values_object_data_covariance = [dict.fromkeys(self._keys_data_covariance), dict.fromkeys(self._keys_data_covariance)] 51 | self._values_extra = {} # This holds extra key, value pairs associated with each CDM object, used internally by the Kessler codebase and not a part of the CDM standard 52 | 53 | self._keys_with_dates = ['CREATION_DATE', 'TCA', 'SCREEN_ENTRY_TIME', 'START_SCREEN_PERIOD', 'STOP_SCREEN_PERIOD', 'SCREEN_EXIT_TIME', 'OBJECT1_TIME_LASTOB_START', 'OBJECT1_TIME_LASTOB_END', 'OBJECT2_TIME_LASTOB_START', 'OBJECT2_TIME_LASTOB_END'] 54 | 55 | if set_defaults: 56 | self.set_header('CCSDS_CDM_VERS', '1.0') 57 | self.set_header('CREATION_DATE', datetime.datetime.utcnow().isoformat()) 58 | self.set_object(0, 'OBJECT', 'OBJECT1') 59 | self.set_object(1, 'OBJECT', 'OBJECT2') 60 | 61 | if file_name: 62 | self.copy_from(ConjunctionDataMessage.load(file_name)) 63 | 64 | def copy(self): 65 | ret = ConjunctionDataMessage() 66 | ret._values_header = copy.deepcopy(self._values_header) 67 | ret._values_relative_metadata = copy.deepcopy(self._values_relative_metadata) 68 | ret._values_object_metadata = copy.deepcopy(self._values_object_metadata) 69 | ret._values_object_data_od = copy.deepcopy(self._values_object_data_od) 70 | ret._values_object_data_state = copy.deepcopy(self._values_object_data_state) 71 | ret._values_object_data_covariance = copy.deepcopy(self._values_object_data_covariance) 72 | return ret 73 | 74 | def copy_from(self, other_cdm): 75 | self._values_header = copy.deepcopy(other_cdm._values_header) 76 | self._values_relative_metadata = copy.deepcopy(other_cdm._values_relative_metadata) 77 | self._values_object_metadata = copy.deepcopy(other_cdm._values_object_metadata) 78 | self._values_object_data_od = copy.deepcopy(other_cdm._values_object_data_od) 79 | self._values_object_data_state = copy.deepcopy(other_cdm._values_object_data_state) 80 | self._values_object_data_covariance = copy.deepcopy(other_cdm._values_object_data_covariance) 81 | 82 | def to_dict(self): 83 | data = {} 84 | data_header = dict.fromkeys(self._keys_header) 85 | for key, value in self._values_header.items(): 86 | data_header[key] = value 87 | data.update(data_header) 88 | 89 | data_relative_metadata = dict.fromkeys(self._keys_relative_metadata) 90 | for key, value in self._values_relative_metadata.items(): 91 | data_relative_metadata[key] = value 92 | data.update(data_relative_metadata) 93 | 94 | for i in [0, 1]: 95 | prefix = 'OBJECT{}_'.format(i+1) 96 | keys_metadata = map(lambda x: prefix+x, self._keys_metadata) 97 | keys_data_od = map(lambda x: prefix+x, self._keys_data_od) 98 | keys_data_state = map(lambda x: prefix+x, self._keys_data_state) 99 | keys_data_covariance = map(lambda x: prefix+x, self._keys_data_covariance) 100 | 101 | data_metadata = dict.fromkeys(keys_metadata) 102 | for key, value in self._values_object_metadata[i].items(): 103 | data_metadata[prefix+key] = value 104 | data.update(data_metadata) 105 | 106 | data_data_od = dict.fromkeys(keys_data_od) 107 | for key, value in self._values_object_data_od[i].items(): 108 | data_data_od[prefix+key] = value 109 | data.update(data_data_od) 110 | 111 | data_data_state = dict.fromkeys(keys_data_state) 112 | for key, value in self._values_object_data_state[i].items(): 113 | data_data_state[prefix+key] = value 114 | data.update(data_data_state) 115 | 116 | data_data_covariance = dict.fromkeys(keys_data_covariance) 117 | for key, value in self._values_object_data_covariance[i].items(): 118 | data_data_covariance[prefix+key] = value 119 | data.update(data_data_covariance) 120 | 121 | data.update(self._values_extra) 122 | 123 | return data 124 | 125 | def to_dataframe(self): 126 | data = self.to_dict() 127 | return pd.DataFrame(data, index=[0]) 128 | 129 | def load(file_name): 130 | content = [] 131 | with open(file_name) as f: 132 | lines = f.readlines() 133 | for line in lines: 134 | line = line.replace(u'\ufeff', '') 135 | line = line.strip() 136 | if line.startswith('COMMENT') or len(line) == 0: 137 | continue 138 | key, value = line.split('=') 139 | key, value = key.strip(), value.strip() 140 | if util.is_number(value): 141 | value = float(value) 142 | # print(line) 143 | content.append((key, value)) 144 | cdm = ConjunctionDataMessage(set_defaults=False) 145 | currently_parsing = 'header_and_relative_metadata' 146 | for key, value in content: 147 | if currently_parsing == 'header_and_relative_metadata': 148 | if key in cdm._keys_header: 149 | cdm.set_header(key, value) 150 | elif key in cdm._keys_relative_metadata: 151 | cdm.set_relative_metadata(key, value) 152 | elif key == 'OBJECT' and value == 'OBJECT1': 153 | cdm.set_object(0, key, value) 154 | currently_parsing = 'object1' 155 | continue 156 | elif key == 'OBJECT' and value == 'OBJECT2': 157 | cdm.set_object(1, key, value) 158 | currently_parsing = 'object2' 159 | continue 160 | elif currently_parsing == 'object1': 161 | if key == 'OBJECT' and value == 'OBJECT2': 162 | cdm.set_object(1, key, value) 163 | currently_parsing = 'object2' 164 | continue 165 | try: 166 | cdm.set_object(0, key, value) 167 | except: 168 | continue 169 | elif currently_parsing == 'object2': 170 | if key == 'OBJECT' and value == 'OBJECT1': 171 | cdm.set_object(0, key, value) 172 | currently_parsing = 'object1' 173 | continue 174 | try: 175 | cdm.set_object(1, key, value) 176 | except: 177 | continue 178 | return cdm 179 | 180 | def save(self, file_name): 181 | content = self.kvn() 182 | with open(file_name, 'w') as f: 183 | f.write(content) 184 | 185 | def __hash__(self): 186 | return hash(self.kvn(show_all=True)) 187 | 188 | def __eq__(self, other): 189 | if isinstance(other, ConjunctionDataMessage): 190 | return hash(self) == hash(other) 191 | return False 192 | 193 | def set_header(self, key, value): 194 | if key in self._keys_header: 195 | if key in self._keys_with_dates: 196 | # We have a field with a date string as the value. Check if the string is in the format needed by the CCSDS 508.0-B-1 standard 197 | time_format = util.get_ccsds_time_format(value) 198 | idx = time_format.find('DDD') 199 | if idx!=-1: 200 | value = util.doy_2_date(value, value[idx:idx+3], value[0:4], idx) 201 | try: 202 | _ = datetime.datetime.strptime(value, '%Y-%m-%dT%H:%M:%S.%f') 203 | except Exception as e: 204 | raise RuntimeError('{} ({}) is not in the expected format.\n{}'.format(key, value, str(e))) 205 | self._values_header[key] = value 206 | else: 207 | raise ValueError('Invalid key ({}) for header'.format(key)) 208 | 209 | def set_relative_metadata(self, key, value): 210 | if key in self._keys_relative_metadata: 211 | self._values_relative_metadata[key] = value 212 | else: 213 | raise ValueError('Invalid key ({}) for relative metadata'.format(key)) 214 | 215 | def set_object(self, object_id, key, value): 216 | if object_id != 0 and object_id != 1: 217 | raise ValueError('Expecting object_id to be 0 or 1') 218 | if key in self._keys_metadata: 219 | self._values_object_metadata[object_id][key] = value 220 | elif key in self._keys_data_od: 221 | self._values_object_data_od[object_id][key] = value 222 | elif key in self._keys_data_state: 223 | self._values_object_data_state[object_id][key] = value 224 | elif key in self._keys_data_covariance: 225 | self._values_object_data_covariance[object_id][key] = value 226 | else: 227 | raise ValueError('Invalid key ({}) for object data'.format(key)) 228 | 229 | def get_object(self, object_id, key): 230 | if object_id != 0 and object_id != 1: 231 | raise ValueError('Expecting object_id to be 0 or 1') 232 | if key in self._keys_metadata: 233 | return self._values_object_metadata[object_id][key] 234 | elif key in self._keys_data_od: 235 | return self._values_object_data_od[object_id][key] 236 | elif key in self._keys_data_state: 237 | return self._values_object_data_state[object_id][key] 238 | elif key in self._keys_data_covariance: 239 | return self._values_object_data_covariance[object_id][key] 240 | else: 241 | raise ValueError('Invalid key ({}) for object data'.format(key)) 242 | 243 | def get_relative_metadata(self, key): 244 | if key in self._keys_relative_metadata: 245 | return self._values_relative_metadata[key] 246 | else: 247 | raise ValueError('Invalid key ({}) for relative metadata'.format(key)) 248 | 249 | def set_state(self, object_id, state): 250 | self.set_object(object_id, 'X', state[0, 0]) 251 | self.set_object(object_id, 'Y', state[0, 1]) 252 | self.set_object(object_id, 'Z', state[0, 2]) 253 | self.set_object(object_id, 'X_DOT', state[1, 0]) 254 | self.set_object(object_id, 'Y_DOT', state[1, 1]) 255 | self.set_object(object_id, 'Z_DOT', state[1, 2]) 256 | self._update_state_relative() 257 | self._update_miss_distance() 258 | 259 | def _update_miss_distance(self): 260 | state_object1 = self.get_state(0)*1e3 261 | # if np.isnan(state_object1.sum()): 262 | # warnings.warn('state_object1 has NaN') 263 | state_object2 = self.get_state(1)*1e3 264 | # if np.isnan(state_object2.sum()): 265 | # warnings.warn('state_object2 has NaN') 266 | 267 | miss_distance = np.linalg.norm(state_object1[0] - state_object2[0]) 268 | self.set_relative_metadata('MISS_DISTANCE', miss_distance) 269 | 270 | def _update_state_relative(self): 271 | def uvw_matrix(r, v): 272 | u = r / np.linalg.norm(r) 273 | w = np.cross(r, v) 274 | w = w / np.linalg.norm(w) 275 | v = np.cross(w, u) 276 | return np.vstack((u, v, w)) 277 | 278 | # Takes states in ITRF and returns relative state in RTN with target as reference 279 | def relative_state(state_obj_1, state_obj_2): 280 | rot_matrix = uvw_matrix(state_obj_1[0], state_obj_1[1]) 281 | rel_position_xyz = state_obj_2[0] - state_obj_1[0] 282 | rel_velocity_xyz = state_obj_2[1] - state_obj_1[1] 283 | relative_state = np.zeros([2, 3]) 284 | relative_state[0] = np.array([np.dot(rot_matrix[0], rel_position_xyz), np.dot(rot_matrix[1], rel_position_xyz), np.dot(rot_matrix[2], rel_position_xyz)]) 285 | relative_state[1] = np.array([np.dot(rot_matrix[0], rel_velocity_xyz), np.dot(rot_matrix[1], rel_velocity_xyz), np.dot(rot_matrix[2], rel_velocity_xyz)]) 286 | return relative_state 287 | 288 | state_object1 = self.get_state(0)*1e3 289 | # if np.isnan(state_object1.sum()): 290 | # warnings.warn('state_object1 has NaN') 291 | state_object2 = self.get_state(1)*1e3 292 | # if np.isnan(state_object2.sum()): 293 | # warnings.warn('state_object2 has NaN') 294 | 295 | relative_state = relative_state(state_object1, state_object2) 296 | 297 | self.set_relative_metadata('RELATIVE_POSITION_R', relative_state[0, 0]) 298 | self.set_relative_metadata('RELATIVE_POSITION_T', relative_state[0, 1]) 299 | self.set_relative_metadata('RELATIVE_POSITION_N', relative_state[0, 2]) 300 | self.set_relative_metadata('RELATIVE_VELOCITY_R', relative_state[1, 0]) 301 | self.set_relative_metadata('RELATIVE_VELOCITY_T', relative_state[1, 1]) 302 | self.set_relative_metadata('RELATIVE_VELOCITY_N', relative_state[1, 2]) 303 | self.set_relative_metadata('RELATIVE_SPEED', np.linalg.norm(relative_state[1])) 304 | 305 | def get_state_relative(self): 306 | relative_state = np.zeros([2, 3]) 307 | relative_state[0, 0] = self.get_relative_metadata('RELATIVE_POSITION_R') 308 | relative_state[0, 1] = self.get_relative_metadata('RELATIVE_POSITION_T') 309 | relative_state[0, 2] = self.get_relative_metadata('RELATIVE_POSITION_N') 310 | relative_state[1, 0] = self.get_relative_metadata('RELATIVE_VELOCITY_R') 311 | relative_state[1, 1] = self.get_relative_metadata('RELATIVE_VELOCITY_T') 312 | relative_state[1, 2] = self.get_relative_metadata('RELATIVE_VELOCITY_N') 313 | return relative_state 314 | 315 | def get_state(self, object_id): 316 | state = np.zeros([2, 3]) 317 | state[0, 0] = self.get_object(object_id, 'X') 318 | state[0, 1] = self.get_object(object_id, 'Y') 319 | state[0, 2] = self.get_object(object_id, 'Z') 320 | state[1, 0] = self.get_object(object_id, 'X_DOT') 321 | state[1, 1] = self.get_object(object_id, 'Y_DOT') 322 | state[1, 2] = self.get_object(object_id, 'Z_DOT') 323 | return state 324 | 325 | def get_covariance(self, object_id): 326 | covariance = np.zeros([6, 6]) 327 | covariance[0, 0] = self.get_object(object_id, 'CR_R') 328 | covariance[1, 0] = self.get_object(object_id, 'CT_R') 329 | covariance[1, 1] = self.get_object(object_id, 'CT_T') 330 | covariance[2, 0] = self.get_object(object_id, 'CN_R') 331 | covariance[2, 1] = self.get_object(object_id, 'CN_T') 332 | covariance[2, 2] = self.get_object(object_id, 'CN_N') 333 | covariance[3, 0] = self.get_object(object_id, 'CRDOT_R') 334 | covariance[3, 1] = self.get_object(object_id, 'CRDOT_T') 335 | covariance[3, 2] = self.get_object(object_id, 'CRDOT_N') 336 | covariance[3, 3] = self.get_object(object_id, 'CRDOT_RDOT') 337 | covariance[4, 0] = self.get_object(object_id, 'CTDOT_R') 338 | covariance[4, 1] = self.get_object(object_id, 'CTDOT_T') 339 | covariance[4, 2] = self.get_object(object_id, 'CTDOT_N') 340 | covariance[4, 3] = self.get_object(object_id, 'CTDOT_RDOT') 341 | covariance[4, 4] = self.get_object(object_id, 'CTDOT_TDOT') 342 | covariance[5, 0] = self.get_object(object_id, 'CNDOT_R') 343 | covariance[5, 1] = self.get_object(object_id, 'CNDOT_T') 344 | covariance[5, 2] = self.get_object(object_id, 'CNDOT_N') 345 | covariance[5, 3] = self.get_object(object_id, 'CNDOT_RDOT') 346 | covariance[5, 4] = self.get_object(object_id, 'CNDOT_TDOT') 347 | covariance[5, 5] = self.get_object(object_id, 'CNDOT_NDOT') 348 | # Copies lower triangle to the upper part 349 | covariance = covariance + covariance.T - np.diag(np.diag(covariance)) 350 | return covariance 351 | 352 | def set_covariance(self, object_id, covariance_matrix): 353 | self.set_object(object_id, 'CR_R', covariance_matrix[0, 0]) 354 | self.set_object(object_id, 'CT_R', covariance_matrix[1, 0]) 355 | self.set_object(object_id, 'CT_T', covariance_matrix[1, 1]) 356 | self.set_object(object_id, 'CN_R', covariance_matrix[2, 0]) 357 | self.set_object(object_id, 'CN_T', covariance_matrix[2, 1]) 358 | self.set_object(object_id, 'CN_N', covariance_matrix[2, 2]) 359 | self.set_object(object_id, 'CRDOT_R', covariance_matrix[3, 0]) 360 | self.set_object(object_id, 'CRDOT_T', covariance_matrix[3, 1]) 361 | self.set_object(object_id, 'CRDOT_N', covariance_matrix[3, 2]) 362 | self.set_object(object_id, 'CRDOT_RDOT', covariance_matrix[3, 3]) 363 | self.set_object(object_id, 'CTDOT_R', covariance_matrix[4, 0]) 364 | self.set_object(object_id, 'CTDOT_T', covariance_matrix[4, 1]) 365 | self.set_object(object_id, 'CTDOT_N', covariance_matrix[4, 2]) 366 | self.set_object(object_id, 'CTDOT_RDOT', covariance_matrix[4, 3]) 367 | self.set_object(object_id, 'CTDOT_TDOT', covariance_matrix[4, 4]) 368 | self.set_object(object_id, 'CNDOT_R', covariance_matrix[5, 0]) 369 | self.set_object(object_id, 'CNDOT_T', covariance_matrix[5, 1]) 370 | self.set_object(object_id, 'CNDOT_N', covariance_matrix[5, 2]) 371 | self.set_object(object_id, 'CNDOT_RDOT', covariance_matrix[5, 3]) 372 | self.set_object(object_id, 'CNDOT_TDOT', covariance_matrix[5, 4]) 373 | self.set_object(object_id, 'CNDOT_NDOT', covariance_matrix[5, 5]) 374 | 375 | def validate(self): 376 | def val(keys, vals, part): 377 | for key in keys: 378 | if vals[key] is None: 379 | print('Missing obligatory value in {}: {}'.format(part, key)) 380 | val(self._keys_header_obligatory, self._values_header, 'header') 381 | val(self._keys_relative_metadata_obligatory, self._values_relative_metadata, 'relative metadata') 382 | val(self._keys_metadata_obligatory, self._values_object_metadata[0], 'Object1 metadata') 383 | val(self._keys_data_od_obligatory, self._values_object_data_od[0], 'Object1 data (od)') 384 | val(self._keys_data_state_obligatory, self._values_object_data_state[0], 'Object1 data (state)') 385 | val(self._keys_data_covariance_obligatory, self._values_object_data_covariance[0], 'Object1 data (covariance)') 386 | val(self._keys_metadata_obligatory, self._values_object_metadata[1], 'Object2 metadata') 387 | val(self._keys_data_od_obligatory, self._values_object_data_od[1], 'Object2 data (od)') 388 | val(self._keys_data_state_obligatory, self._values_object_data_state[1], 'Object2 data (state)') 389 | val(self._keys_data_covariance_obligatory, self._values_object_data_covariance[1], 'Object2 data (covariance)') 390 | 391 | def kvn(self, show_all=False): 392 | def append(s, d, d_obligatory): 393 | for k, v in d.items(): 394 | k_str = k.ljust(37, ' ') 395 | if v is None: 396 | if show_all or k in d_obligatory: 397 | s += '{} =\n'.format(k_str) 398 | else: 399 | if isinstance(v, float) or isinstance(v, int): 400 | v_str = '{}'.format(v) 401 | if 'e' in v_str: 402 | v_str = '{:.3E}'.format(v) 403 | else: 404 | v_str = str(v) 405 | s += '{} = {}\n'.format(k_str, v_str) 406 | return s 407 | ret = '' 408 | ret = append(ret, self._values_header, self._keys_header_obligatory) 409 | ret = append(ret, self._values_relative_metadata, self._keys_relative_metadata_obligatory) 410 | ret = append(ret, self._values_object_metadata[0], self._keys_metadata_obligatory) 411 | ret = append(ret, self._values_object_data_od[0], self._keys_data_od_obligatory) 412 | ret = append(ret, self._values_object_data_state[0], self._keys_data_state_obligatory) 413 | ret = append(ret, self._values_object_data_covariance[0], self._keys_data_covariance_obligatory) 414 | ret = append(ret, self._values_object_metadata[1], self._keys_metadata_obligatory) 415 | ret = append(ret, self._values_object_data_od[1], self._keys_data_od_obligatory) 416 | ret = append(ret, self._values_object_data_state[1], self._keys_data_state_obligatory) 417 | ret = append(ret, self._values_object_data_covariance[1], self._keys_data_covariance_obligatory) 418 | return ret 419 | 420 | def __repr__(self): 421 | return self.kvn() 422 | 423 | def __getitem__(self, key): 424 | return self.to_dict()[key] 425 | 426 | def __setitem__(self, key, value): 427 | if key in self._keys_header: 428 | self.set_header(key, value) 429 | elif key in self._keys_relative_metadata: 430 | self.set_relative_metadata(key, value) 431 | elif key.startswith('OBJECT1_'): 432 | key = key.split('OBJECT1_')[1] 433 | self.set_object(0, key, value) 434 | elif key.startswith('OBJECT2_'): 435 | key = key.split('OBJECT2_')[1] 436 | self.set_object(1, key, value) 437 | else: 438 | raise ValueError('Invalid key: {}'.format(key)) 439 | 440 | 441 | CDM = ConjunctionDataMessage 442 | -------------------------------------------------------------------------------- /kessler/data.py: -------------------------------------------------------------------------------- 1 | # This code is part of Kessler, a machine learning library for spacecraft collision avoidance. 2 | # 3 | # Copyright (c) 2020- 4 | # Trillium Technologies 5 | # University of Oxford 6 | # Giacomo Acciarini (giacomo.acciarini@gmail.com) 7 | # and other contributors, see README in root of repository. 8 | # 9 | # GNU General Public License version 3. See LICENSE in root of repository. 10 | 11 | import pandas as pd 12 | from datetime import datetime, timedelta 13 | 14 | from . import util 15 | from .cdm import CDM 16 | from .event import Event, EventDataset 17 | 18 | 19 | def kelvins_to_event_dataset(file_name, num_events=None, date_tca=None, remove_outliers=True, drop_features=['c_rcs_estimate', 't_rcs_estimate']): 20 | print('Loading Kelvins dataset from file name: {}'.format(file_name)) 21 | kelvins = pd.read_csv(file_name) 22 | print('{} entries'.format(len(kelvins))) 23 | print('Dropping features: {}'.format(drop_features)) 24 | kelvins = kelvins.drop(drop_features, axis=1) 25 | print('Dropping rows with NaNs') 26 | kelvins = kelvins.dropna() 27 | print('{} entries'.format(len(kelvins))) 28 | 29 | if remove_outliers: 30 | # outlier_features = ['CR_R', 'CT_T', 'CN_N', 'CRDOT_RDOT', 'CTDOT_TDOT', 'CNDOT_NDOT'] 31 | # outlier_features = ['t_sigma_r', 't_sigma_t', 't_sigma_n', 't_sigma_rdot', 't_sigma_tdot', 't_sigma_ndot'] 32 | print('Removing outliers') 33 | kelvins = kelvins[kelvins['t_sigma_r'] <= 20] 34 | kelvins = kelvins[kelvins['c_sigma_r'] <= 1000] 35 | kelvins = kelvins[kelvins['t_sigma_t'] <= 2000] 36 | kelvins = kelvins[kelvins['c_sigma_t'] <= 100000] 37 | kelvins = kelvins[kelvins['t_sigma_n'] <= 10] 38 | kelvins = kelvins[kelvins['c_sigma_n'] <= 450] 39 | 40 | # for feature in outlier_features: 41 | # # Q1 = kelvins[feature].quantile(0.25) 42 | # # Q3 = kelvins[feature].quantile(0.75) 43 | # # IQR = Q3 - Q1 44 | # # limit = 1.5 * IQR 45 | # # kelvins = kelvins[~((kelvins[feature] < (Q1 - limit)) | (kelvins[feature] > (Q3 + limit)))] 46 | # kelvins = kelvins[kelvins[feature].between(kelvins[feature].quantile(.001), kelvins[feature].quantile(.75))] # without outliers 47 | # kelvins = kelvins.reset_index() 48 | print('{} entries'.format(len(kelvins))) 49 | 50 | print('Shuffling') 51 | kelvins = kelvins.sample(frac=1, axis=1).reset_index(drop=True) 52 | kelvins_events = kelvins.groupby('event_id').groups 53 | print('Grouped rows into {} events'.format(len(kelvins_events))) 54 | if date_tca is None: 55 | date_tca = datetime.now() 56 | print('Taking TCA as current time: {}'.format(date_tca)) 57 | events = [] 58 | if num_events is None: 59 | num_events = len(kelvins_events) 60 | num_events = min(num_events, len(kelvins_events)) 61 | i = 0 62 | util.progress_bar_init('Converting Kelvins challenge data to EventDataset', num_events, 'Events') 63 | for k, v in kelvins_events.items(): 64 | util.progress_bar_update(i) 65 | i += 1 66 | if i > num_events: 67 | break 68 | kelvins_event = kelvins.iloc[v] 69 | cdms = [] 70 | for _, kelvins_cdm in kelvins_event.iterrows(): 71 | cdm = CDM() 72 | time_to_tca = kelvins_cdm['time_to_tca'] # days 73 | date_creation = date_tca - timedelta(days=time_to_tca) 74 | cdm['CREATION_DATE'] = util.from_datetime_to_cdm_datetime_str(date_creation) 75 | cdm['TCA'] = util.from_datetime_to_cdm_datetime_str(date_tca) 76 | cdm['MISS_DISTANCE'] = kelvins_cdm['miss_distance'] 77 | cdm['RELATIVE_SPEED'] = kelvins_cdm['relative_speed'] 78 | cdm['RELATIVE_POSITION_R'] = kelvins_cdm['relative_position_r'] 79 | cdm['RELATIVE_POSITION_T'] = kelvins_cdm['relative_position_t'] 80 | cdm['RELATIVE_POSITION_N'] = kelvins_cdm['relative_position_n'] 81 | cdm['RELATIVE_VELOCITY_R'] = kelvins_cdm['relative_velocity_r'] 82 | cdm['RELATIVE_VELOCITY_T'] = kelvins_cdm['relative_velocity_t'] 83 | cdm['RELATIVE_VELOCITY_N'] = kelvins_cdm['relative_velocity_n'] 84 | cdm['OBJECT1_CR_R'] = kelvins_cdm['t_sigma_r']**2. 85 | cdm['OBJECT1_CT_R'] = kelvins_cdm['t_ct_r'] * kelvins_cdm['t_sigma_r'] * kelvins_cdm['t_sigma_t'] 86 | cdm['OBJECT1_CT_T'] = kelvins_cdm['t_sigma_t']**2. 87 | cdm['OBJECT1_CN_R'] = kelvins_cdm['t_cn_r'] * kelvins_cdm['t_sigma_n'] * kelvins_cdm['t_sigma_r'] 88 | cdm['OBJECT1_CN_T'] = kelvins_cdm['t_cn_t'] * kelvins_cdm['t_sigma_n'] * kelvins_cdm['t_sigma_t'] 89 | cdm['OBJECT1_CN_N'] = kelvins_cdm['t_sigma_n']**2. 90 | cdm['OBJECT1_CRDOT_R'] = kelvins_cdm['t_crdot_r'] * kelvins_cdm['t_sigma_rdot'] * kelvins_cdm['t_sigma_r'] 91 | cdm['OBJECT1_CRDOT_T'] = kelvins_cdm['t_crdot_t'] * kelvins_cdm['t_sigma_rdot'] * kelvins_cdm['t_sigma_t'] 92 | cdm['OBJECT1_CRDOT_N'] = kelvins_cdm['t_crdot_n'] * kelvins_cdm['t_sigma_rdot'] * kelvins_cdm['t_sigma_n'] 93 | cdm['OBJECT1_CRDOT_RDOT'] = kelvins_cdm['t_sigma_rdot']**2. 94 | cdm['OBJECT1_CTDOT_R'] = kelvins_cdm['t_ctdot_r'] * kelvins_cdm['t_sigma_tdot'] * kelvins_cdm['t_sigma_r'] 95 | cdm['OBJECT1_CTDOT_T'] = kelvins_cdm['t_ctdot_t'] * kelvins_cdm['t_sigma_tdot'] * kelvins_cdm['t_sigma_t'] 96 | cdm['OBJECT1_CTDOT_N'] = kelvins_cdm['t_ctdot_n'] * kelvins_cdm['t_sigma_tdot'] * kelvins_cdm['t_sigma_n'] 97 | cdm['OBJECT1_CTDOT_RDOT'] = kelvins_cdm['t_ctdot_rdot'] * kelvins_cdm['t_sigma_tdot'] * kelvins_cdm['t_sigma_rdot'] 98 | cdm['OBJECT1_CTDOT_TDOT'] = kelvins_cdm['t_sigma_tdot']**2. 99 | cdm['OBJECT1_CNDOT_R'] = kelvins_cdm['t_cndot_r'] * kelvins_cdm['t_sigma_ndot'] * kelvins_cdm['t_sigma_r'] 100 | cdm['OBJECT1_CNDOT_T'] = kelvins_cdm['t_cndot_t'] * kelvins_cdm['t_sigma_ndot'] * kelvins_cdm['t_sigma_t'] 101 | cdm['OBJECT1_CNDOT_N'] = kelvins_cdm['t_cndot_n'] * kelvins_cdm['t_sigma_ndot'] * kelvins_cdm['t_sigma_n'] 102 | cdm['OBJECT1_CNDOT_RDOT'] = kelvins_cdm['t_cndot_rdot'] * kelvins_cdm['t_sigma_ndot'] * kelvins_cdm['t_sigma_rdot'] 103 | cdm['OBJECT1_CNDOT_TDOT'] = kelvins_cdm['t_cndot_tdot'] * kelvins_cdm['t_sigma_ndot'] * kelvins_cdm['t_sigma_tdot'] 104 | cdm['OBJECT1_CNDOT_NDOT'] = kelvins_cdm['t_sigma_ndot']**2. 105 | 106 | cdm['OBJECT1_RECOMMENDED_OD_SPAN'] = kelvins_cdm['t_recommended_od_span'] 107 | cdm['OBJECT1_ACTUAL_OD_SPAN'] = kelvins_cdm['t_actual_od_span'] 108 | cdm['OBJECT1_OBS_AVAILABLE'] = kelvins_cdm['t_obs_available'] 109 | cdm['OBJECT1_OBS_USED'] = kelvins_cdm['t_obs_used'] 110 | cdm['OBJECT1_RESIDUALS_ACCEPTED'] = kelvins_cdm['t_residuals_accepted'] 111 | cdm['OBJECT1_WEIGHTED_RMS'] = kelvins_cdm['t_weighted_rms'] 112 | cdm['OBJECT1_SEDR'] = kelvins_cdm['t_sedr'] 113 | time_lastob_start = kelvins_cdm['t_time_lastob_start'] # days until CDM creation 114 | time_lastob_start = date_creation - timedelta(days=time_lastob_start) 115 | cdm['OBJECT1_TIME_LASTOB_START'] = util.from_datetime_to_cdm_datetime_str(time_lastob_start) 116 | time_lastob_end = kelvins_cdm['t_time_lastob_end'] # days until CDM creation 117 | time_lastob_end = date_creation - timedelta(days=time_lastob_end) 118 | cdm['OBJECT1_TIME_LASTOB_END'] = util.from_datetime_to_cdm_datetime_str(time_lastob_end) 119 | 120 | cdm['OBJECT2_CR_R'] = kelvins_cdm['c_sigma_r']**2. 121 | cdm['OBJECT2_CT_R'] = kelvins_cdm['c_ct_r'] * kelvins_cdm['c_sigma_r'] * kelvins_cdm['c_sigma_t'] 122 | cdm['OBJECT2_CT_T'] = kelvins_cdm['c_sigma_t']**2. 123 | cdm['OBJECT2_CN_R'] = kelvins_cdm['c_cn_r'] * kelvins_cdm['c_sigma_n'] * kelvins_cdm['c_sigma_r'] 124 | cdm['OBJECT2_CN_T'] = kelvins_cdm['c_cn_t'] * kelvins_cdm['c_sigma_n'] * kelvins_cdm['c_sigma_t'] 125 | cdm['OBJECT2_CN_N'] = kelvins_cdm['c_sigma_n']**2. 126 | cdm['OBJECT2_CRDOT_R'] = kelvins_cdm['c_crdot_r'] * kelvins_cdm['c_sigma_rdot'] * kelvins_cdm['c_sigma_r'] 127 | cdm['OBJECT2_CRDOT_T'] = kelvins_cdm['c_crdot_t'] * kelvins_cdm['c_sigma_rdot'] * kelvins_cdm['c_sigma_t'] 128 | cdm['OBJECT2_CRDOT_N'] = kelvins_cdm['c_crdot_n'] * kelvins_cdm['c_sigma_rdot'] * kelvins_cdm['c_sigma_n'] 129 | cdm['OBJECT2_CRDOT_RDOT'] = kelvins_cdm['c_sigma_rdot']**2. 130 | cdm['OBJECT2_CTDOT_R'] = kelvins_cdm['c_ctdot_r'] * kelvins_cdm['c_sigma_tdot'] * kelvins_cdm['c_sigma_r'] 131 | cdm['OBJECT2_CTDOT_T'] = kelvins_cdm['c_ctdot_t'] * kelvins_cdm['c_sigma_tdot'] * kelvins_cdm['c_sigma_t'] 132 | cdm['OBJECT2_CTDOT_N'] = kelvins_cdm['c_ctdot_n'] * kelvins_cdm['c_sigma_tdot'] * kelvins_cdm['c_sigma_n'] 133 | cdm['OBJECT2_CTDOT_RDOT'] = kelvins_cdm['c_ctdot_rdot'] * kelvins_cdm['c_sigma_tdot'] * kelvins_cdm['c_sigma_rdot'] 134 | cdm['OBJECT2_CTDOT_TDOT'] = kelvins_cdm['c_sigma_tdot']**2. 135 | cdm['OBJECT2_CNDOT_R'] = kelvins_cdm['c_cndot_r'] * kelvins_cdm['c_sigma_ndot'] * kelvins_cdm['c_sigma_r'] 136 | cdm['OBJECT2_CNDOT_T'] = kelvins_cdm['c_cndot_t'] * kelvins_cdm['c_sigma_ndot'] * kelvins_cdm['c_sigma_t'] 137 | cdm['OBJECT2_CNDOT_N'] = kelvins_cdm['c_cndot_n'] * kelvins_cdm['c_sigma_ndot'] * kelvins_cdm['c_sigma_n'] 138 | cdm['OBJECT2_CNDOT_RDOT'] = kelvins_cdm['c_cndot_rdot'] * kelvins_cdm['c_sigma_ndot'] * kelvins_cdm['c_sigma_rdot'] 139 | cdm['OBJECT2_CNDOT_TDOT'] = kelvins_cdm['c_cndot_tdot'] * kelvins_cdm['c_sigma_ndot'] * kelvins_cdm['c_sigma_tdot'] 140 | cdm['OBJECT2_CNDOT_NDOT'] = kelvins_cdm['c_sigma_ndot']**2. 141 | 142 | cdm['OBJECT2_OBJECT_TYPE'] = kelvins_cdm['c_object_type'] 143 | cdm['OBJECT2_RECOMMENDED_OD_SPAN'] = kelvins_cdm['c_recommended_od_span'] 144 | cdm['OBJECT2_ACTUAL_OD_SPAN'] = kelvins_cdm['c_actual_od_span'] 145 | cdm['OBJECT2_OBS_AVAILABLE'] = kelvins_cdm['c_obs_available'] 146 | cdm['OBJECT2_OBS_USED'] = kelvins_cdm['c_obs_used'] 147 | cdm['OBJECT2_RESIDUALS_ACCEPTED'] = kelvins_cdm['c_residuals_accepted'] 148 | cdm['OBJECT2_WEIGHTED_RMS'] = kelvins_cdm['c_weighted_rms'] 149 | cdm['OBJECT2_SEDR'] = kelvins_cdm['c_sedr'] 150 | time_lastob_start = kelvins_cdm['c_time_lastob_start'] # days until CDM creation 151 | time_lastob_start = date_creation - timedelta(days=time_lastob_start) 152 | cdm['OBJECT2_TIME_LASTOB_START'] = util.from_datetime_to_cdm_datetime_str(time_lastob_start) 153 | time_lastob_end = kelvins_cdm['c_time_lastob_end'] # days until CDM creation 154 | time_lastob_end = date_creation - timedelta(days=time_lastob_end) 155 | cdm['OBJECT2_TIME_LASTOB_END'] = util.from_datetime_to_cdm_datetime_str(time_lastob_end) 156 | 157 | cdms.append(cdm) 158 | events.append(Event(cdms)) 159 | 160 | util.progress_bar_end() 161 | return EventDataset(events=events) 162 | -------------------------------------------------------------------------------- /kessler/nn.py: -------------------------------------------------------------------------------- 1 | # This code is part of Kessler, a machine learning library for spacecraft collision avoidance. 2 | # 3 | # Copyright (c) 2020- 4 | # Trillium Technologies 5 | # University of Oxford 6 | # Giacomo Acciarini (giacomo.acciarini@gmail.com) 7 | # and other contributors, see README in root of repository. 8 | # 9 | # GNU General Public License version 3. See LICENSE in root of repository. 10 | 11 | 12 | import torch 13 | import torch.nn as nn 14 | import torch.optim as optim 15 | from torch.utils.data import Dataset, DataLoader 16 | import matplotlib.pyplot as plt 17 | import sys 18 | 19 | from . import util 20 | from .cdm import ConjunctionDataMessage 21 | from .event import EventDataset 22 | 23 | 24 | class DatasetEventDataset(Dataset): 25 | def __init__(self, event_set, features, features_stats=None): 26 | self._event_set = event_set 27 | self._max_event_length = max(map(len, self._event_set)) 28 | self._features = features 29 | self._features_length = len(features) 30 | if features_stats is None: 31 | df = event_set.to_dataframe() 32 | null_features = df.columns[df.isnull().any()] 33 | for feature in features: 34 | if feature in null_features: 35 | raise RuntimeError('Feature {} is not present in the dataset'.format(feature)) 36 | features_numpy = df[features].to_numpy() 37 | mean = features_numpy.mean(0) 38 | stddev = features_numpy.std(0) 39 | self._features_stats = {'mean': mean, 'stddev': stddev} 40 | else: 41 | self._features_stats = features_stats 42 | 43 | def __len__(self): 44 | return len(self._event_set) 45 | 46 | # single item (from Dataset): max_event_length x features 47 | # minibatch of several items (from DataLoader): batch_size x max_event_length x features 48 | def __getitem__(self, i): 49 | event = self._event_set[i] 50 | x = torch.zeros(self._max_event_length, self._features_length) 51 | for i, cdm in enumerate(event): 52 | x[i] = torch.tensor([(cdm[feature]-self._features_stats['mean'][j])/(self._features_stats['stddev'][j]+1e-8) for j, feature in enumerate(self._features)]) 53 | return x, torch.tensor(len(event)) 54 | 55 | 56 | class LSTMPredictor(nn.Module): 57 | def __init__(self, lstm_size=256, lstm_depth=2, dropout=0.2, features=None): 58 | super().__init__() 59 | if features is None: 60 | features = ['__CREATION_DATE', 61 | '__TCA', 62 | 'MISS_DISTANCE', 63 | 'RELATIVE_SPEED', 64 | 'RELATIVE_POSITION_R', 65 | 'RELATIVE_POSITION_T', 66 | 'RELATIVE_POSITION_N', 67 | 'RELATIVE_VELOCITY_R', 68 | 'RELATIVE_VELOCITY_T', 69 | 'RELATIVE_VELOCITY_N', 70 | 'OBJECT1_X', 71 | 'OBJECT1_Y', 72 | 'OBJECT1_Z', 73 | 'OBJECT1_X_DOT', 74 | 'OBJECT1_Y_DOT', 75 | 'OBJECT1_Z_DOT', 76 | 'OBJECT1_CR_R', 77 | 'OBJECT1_CT_R', 78 | 'OBJECT1_CT_T', 79 | 'OBJECT1_CN_R', 80 | 'OBJECT1_CN_T', 81 | 'OBJECT1_CN_N', 82 | 'OBJECT1_CRDOT_R', 83 | 'OBJECT1_CRDOT_T', 84 | 'OBJECT1_CRDOT_N', 85 | 'OBJECT1_CRDOT_RDOT', 86 | 'OBJECT1_CTDOT_R', 87 | 'OBJECT1_CTDOT_T', 88 | 'OBJECT1_CTDOT_N', 89 | 'OBJECT1_CTDOT_RDOT', 90 | 'OBJECT1_CTDOT_TDOT', 91 | 'OBJECT1_CNDOT_R', 92 | 'OBJECT1_CNDOT_T', 93 | 'OBJECT1_CNDOT_N', 94 | 'OBJECT1_CNDOT_RDOT', 95 | 'OBJECT1_CNDOT_TDOT', 96 | 'OBJECT1_CNDOT_NDOT', 97 | 'OBJECT2_X', 98 | 'OBJECT2_Y', 99 | 'OBJECT2_Z', 100 | 'OBJECT2_X_DOT', 101 | 'OBJECT2_Y_DOT', 102 | 'OBJECT2_Z_DOT', 103 | 'OBJECT2_CR_R', 104 | 'OBJECT2_CT_R', 105 | 'OBJECT2_CT_T', 106 | 'OBJECT2_CN_R', 107 | 'OBJECT2_CN_T', 108 | 'OBJECT2_CN_N', 109 | 'OBJECT2_CRDOT_R', 110 | 'OBJECT2_CRDOT_T', 111 | 'OBJECT2_CRDOT_N', 112 | 'OBJECT2_CRDOT_RDOT', 113 | 'OBJECT2_CTDOT_R', 114 | 'OBJECT2_CTDOT_T', 115 | 'OBJECT2_CTDOT_N', 116 | 'OBJECT2_CTDOT_RDOT', 117 | 'OBJECT2_CTDOT_TDOT', 118 | 'OBJECT2_CNDOT_R', 119 | 'OBJECT2_CNDOT_T', 120 | 'OBJECT2_CNDOT_N', 121 | 'OBJECT2_CNDOT_RDOT', 122 | 'OBJECT2_CNDOT_TDOT', 123 | 'OBJECT2_CNDOT_NDOT'] 124 | 125 | self.input_size = len(features) 126 | self.lstm_size = lstm_size 127 | self.lstm_depth = lstm_depth 128 | self.dropout = dropout 129 | 130 | self.lstm = nn.LSTM(input_size=self.input_size, hidden_size=self.lstm_size, num_layers=lstm_depth, batch_first=True, dropout=dropout if dropout else 0) 131 | self.fc1 = nn.Linear(lstm_size, self.input_size) 132 | if dropout is not None: 133 | self.dropout1 = nn.Dropout(p=dropout) 134 | 135 | self._features = features 136 | self._features_stats = None 137 | self._hist_train_loss = [] 138 | self._hist_train_loss_iters = [] 139 | self._hist_valid_loss = [] 140 | self._hist_valid_loss_iters = [] 141 | 142 | def plot_loss(self, file_name=None): 143 | fig, ax = plt.subplots() 144 | ax.plot(self._hist_train_loss_iters, self._hist_train_loss, label='Training') 145 | ax.plot(self._hist_valid_loss_iters, self._hist_valid_loss, label='Validation') 146 | ax.set_xlabel('Iterations') 147 | ax.set_ylabel('Loss') 148 | ax.legend() 149 | if file_name is not None: 150 | print('Plotting to file: {}'.format(file_name)) 151 | plt.savefig(file_name) 152 | 153 | def learn(self, event_set, epochs=2, lr=1e-3, batch_size=8, device='cpu', valid_proportion=0.15, num_workers=4, event_samples_for_stats=250, file_name_prefix=None): 154 | if device is None: 155 | device = torch.device('cpu') 156 | 157 | num_params = sum(p.numel() for p in self.parameters()) 158 | print('LSTM predictor with params: {:,}'.format(num_params)) 159 | 160 | if event_samples_for_stats > len(event_set): 161 | event_samples_for_stats = len(event_set) 162 | 163 | if self._features_stats is None: 164 | print('Computing normalization statistics') 165 | self._features_stats = DatasetEventDataset(event_set[:event_samples_for_stats], self._features)._features_stats 166 | 167 | self.to(device) 168 | optimizer = optim.Adam(self.parameters(), lr=lr) 169 | 170 | event_set = event_set.filter(lambda event: len(event) > 1) 171 | 172 | valid_set_size = int(len(event_set) * valid_proportion) 173 | if valid_set_size == 0: 174 | raise RuntimeError('Validation set size is 0 for the given valid_proportion ({}) and number of events ({})'.format(valid_proportion, len(event_set))) 175 | train_set_size = len(event_set) - valid_set_size 176 | train_set = DatasetEventDataset(event_set[:train_set_size], self._features, self._features_stats) 177 | valid_set = DatasetEventDataset(event_set[train_set_size:], self._features, self._features_stats) 178 | 179 | train_loader = DataLoader(train_set, batch_size=batch_size, shuffle=True, num_workers=num_workers) 180 | valid_loader = DataLoader(valid_set, batch_size=len(valid_set), shuffle=True, num_workers=num_workers) 181 | self.train() 182 | if len(self._hist_train_loss_iters) == 0: 183 | total_iters = 0 184 | else: 185 | total_iters = self._hist_train_loss_iters[-1] 186 | for epoch in range(epochs): 187 | with torch.no_grad(): 188 | for _, (events, event_lengths) in enumerate(valid_loader): 189 | events, event_lengths = events.to(device), event_lengths.to(device) 190 | batch_size = event_lengths.nelement() # Can be smaller than batch_size for the last minibatch of an epoch 191 | input = events[:, :-1] 192 | target = events[:, 1:] 193 | event_lengths -= 1 194 | self.reset(batch_size) 195 | output = self(input, event_lengths) 196 | loss = nn.functional.mse_loss(output, target) 197 | valid_loss = float(loss) 198 | self._hist_valid_loss_iters.append(total_iters) 199 | self._hist_valid_loss.append(valid_loss) 200 | 201 | for i_minibatch, (events, event_lengths) in enumerate(train_loader): 202 | total_iters += 1 203 | events, event_lengths = events.to(device), event_lengths.to(device) 204 | batch_size = event_lengths.nelement() # Can be smaller than batch_size for the last minibatch of an epoch 205 | input = events[:, :-1] 206 | target = events[:, 1:] 207 | event_lengths -= 1 208 | self.reset(batch_size) 209 | optimizer.zero_grad() 210 | output = self(input, event_lengths) 211 | loss = nn.functional.mse_loss(output, target) 212 | loss.backward() 213 | optimizer.step() 214 | 215 | train_loss = float(loss) 216 | self._hist_train_loss_iters.append(total_iters) 217 | self._hist_train_loss.append(train_loss) 218 | 219 | print('iter {} | minibatch {}/{} | epoch {}/{} | train loss {:.4e} | valid loss {:.4e} '.format(total_iters, i_minibatch+1, len(train_loader), epoch+1, epochs, train_loss, valid_loss), end='\r') 220 | sys.stdout.flush() 221 | 222 | if file_name_prefix is not None: 223 | file_name = file_name_prefix + '_epoch_{}'.format(epoch+1) 224 | print('Saving model checkpoint to file {}'.format(file_name)) 225 | self.save(file_name) 226 | 227 | def predict(self, event): 228 | ds = DatasetEventDataset(EventDataset(events=[event]), features=self._features, features_stats=self._features_stats) 229 | input, input_length = ds[0] 230 | device = list(self.parameters())[0].device 231 | input, input_length = input.to(device), input_length.to(device) 232 | self.train() 233 | self.reset(1) 234 | output = self.forward(input.unsqueeze(0), input_length.unsqueeze(0)).squeeze() 235 | if util.has_nan_or_inf(output): 236 | raise RuntimeError('Network output has nan or inf: {}\n'.format(output)) 237 | if output.ndim == 1: 238 | output_last = output 239 | else: 240 | output_last = output[-1] 241 | 242 | date0 = event[0]['CREATION_DATE'] 243 | cdm = ConjunctionDataMessage() 244 | for i in range(len(self._features)): 245 | feature = self._features[i] 246 | value = self._features_stats['mean'][i] + float(output_last[i].item()) * self._features_stats['stddev'][i] 247 | if feature == '__CREATION_DATE': 248 | if value < event[-1]['__CREATION_DATE']: 249 | value = event[-1]['__CREATION_DATE'] 250 | cdm['CREATION_DATE'] = util.add_days_to_date_str(date0, value) 251 | elif feature == '__TCA': 252 | cdm['TCA'] = util.add_days_to_date_str(date0, value) 253 | else: 254 | cdm[feature] = value 255 | return cdm 256 | 257 | def predict_event_step(self, event, num_samples=1): 258 | es = [] 259 | for i in range(num_samples): 260 | e = event.copy() 261 | cdm = self.predict(e) 262 | e.add(cdm) 263 | es.append(e) 264 | if num_samples == 1: 265 | return es[0] 266 | else: 267 | return EventDataset(events=es) 268 | 269 | def predict_event(self, event, num_samples=1, max_length=22): 270 | es = [] 271 | 272 | util.progress_bar_init('Predicting event evolution', num_samples, 'Samples') 273 | for i in range(num_samples): 274 | util.progress_bar_update(i) 275 | e = event.copy() 276 | while True: 277 | cdm = self.predict(e) 278 | e.add(cdm) 279 | # print('Next cdm {}, {}'.format(cdm['__CREATION_DATE'], cdm['__TCA'])) 280 | if cdm['__CREATION_DATE'] > cdm['__TCA']: 281 | break 282 | if cdm['__TCA'] > 7: 283 | break 284 | if len(e) > max_length: 285 | # print('Max length ({}) reached'.format(max_length)) 286 | break 287 | es.append(e) 288 | util.progress_bar_end() 289 | if num_samples == 1: 290 | return es[0] 291 | else: 292 | return EventDataset(events=es) 293 | 294 | def save(self, file_name): 295 | print('Saving LSTM predictor to file: {}'.format(file_name)) 296 | torch.save(self, file_name) 297 | 298 | @staticmethod 299 | def load(file_name): 300 | print('Loading LSTM predictor from file: {}'.format(file_name)) 301 | return torch.load(file_name) 302 | 303 | def reset(self, batch_size): 304 | h = torch.zeros(self.lstm_depth, batch_size, self.lstm_size) 305 | c = torch.zeros(self.lstm_depth, batch_size, self.lstm_size) 306 | device = list(self.parameters())[0].device 307 | h = h.to(device) 308 | c = c.to(device) 309 | self.hidden = (h, c) 310 | 311 | def forward(self, x, x_lengths): 312 | batch_size, x_length_max, _ = x.size() 313 | x = torch.nn.utils.rnn.pack_padded_sequence(x, x_lengths, batch_first=True, enforce_sorted=False) 314 | x, self.hidden = self.lstm(x, self.hidden) 315 | x, _ = torch.nn.utils.rnn.pad_packed_sequence(x, batch_first=True, total_length=x_length_max) 316 | if self.dropout: 317 | x = self.dropout1(x) 318 | x = torch.relu(x) 319 | x = self.fc1(x) 320 | return x 321 | -------------------------------------------------------------------------------- /kessler/observation_model.py: -------------------------------------------------------------------------------- 1 | # This code is part of Kessler, a machine learning library for spacecraft collision avoidance. 2 | # 3 | # Copyright (c) 2020- 4 | # Trillium Technologies 5 | # University of Oxford 6 | # Giacomo Acciarini (giacomo.acciarini@gmail.com) 7 | # and other contributors, see README in root of repository. 8 | # 9 | # GNU General Public License version 3. See LICENSE in root of repository. 10 | 11 | import numpy as np 12 | 13 | 14 | class ObservationModel(): 15 | def __init__(self, instrument_characteristics = {}): 16 | self._instrument_characteristics=instrument_characteristics 17 | 18 | def __repr__(self): 19 | return 'ObservationModel' 20 | 21 | def observe(self, time, spacecraft): 22 | raise NotImplementedError() 23 | 24 | 25 | class GNSS(ObservationModel): 26 | def __init__(self, instrument_characteristics = {'bias_xyz': np.zeros((2,3)), 'covariance_rtn': np.array([1e-9, 0.00115849341564346, 0.000059309835843067, 1e-9, 1e-9, 1e-9])**2}): 27 | super().__init__(instrument_characteristics) 28 | 29 | def __repr__(self): 30 | return('GNNS({})'.format(self._instrument_characteristics)) 31 | 32 | def observe(self, time, spacecraft): 33 | state_xyz = spacecraft['state_xyz'] + self._instrument_characteristics['bias_xyz'] 34 | covariance_rtn = self._instrument_characteristics['covariance_rtn'] 35 | return state_xyz, covariance_rtn 36 | 37 | 38 | class Radar(ObservationModel): 39 | def __init__(self, instrument_characteristics = {'bias_xyz': np.zeros((2,3)), 'covariance_rtn': np.array([20, 500, 1, 0.0001, 0.0001, 0.0001])**2}): 40 | super().__init__(instrument_characteristics) 41 | 42 | def __repr__(self): 43 | return('Radar({})'.format(self._instrument_characteristics)) 44 | 45 | def observe(self, time, spacecraft): 46 | state_xyz = spacecraft['state_xyz'] + self._instrument_characteristics['bias_xyz'] 47 | covariance_rtn = self._instrument_characteristics['covariance_rtn'] 48 | return state_xyz, covariance_rtn 49 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | from setuptools import setup, find_packages 4 | PACKAGE_NAME = 'kessler' 5 | MINIMUM_PYTHON_VERSION = 3, 9 6 | 7 | 8 | def check_python_version(): 9 | """Exit when the Python version is too low.""" 10 | if sys.version_info < MINIMUM_PYTHON_VERSION: 11 | sys.exit("Python {}.{}+ is required.".format(*MINIMUM_PYTHON_VERSION)) 12 | 13 | 14 | def read_package_variable(key): 15 | """Read the value of a variable from the package without importing.""" 16 | module_path = os.path.join(PACKAGE_NAME, '__init__.py') 17 | with open(module_path) as module: 18 | for line in module: 19 | parts = line.strip().split(' ') 20 | if parts and parts[0] == key: 21 | return parts[-1].strip("'") 22 | assert 0, "'{0}' not found in '{1}'".format(key, module_path) 23 | 24 | 25 | check_python_version() 26 | setup( 27 | name='kessler', 28 | version=read_package_variable('__version__'), 29 | description='Machine learning and simulation-based inference and machine learning for space collision assessment and avoidance.', 30 | long_description_content_type='text/markdown', 31 | long_description=open('README.md').read(), 32 | author='Giacomo Acciarini', 33 | author_email='giacomo.acciarini@gmail.com', 34 | packages=find_packages(), 35 | install_requires=['pyro-ppl', 'numpy', 'matplotlib', 'torch>=1.5.1', 'dsgp4', 'skyfield>=1.26', 'pandas'], 36 | extras_require={'dev': ['pytest', 'coverage', 'pytest-xdist', 'scikit-learn']}, 37 | url='https://kesslerlib.github.io/kessler/', 38 | classifiers=['License :: OSI Approved :: BSD License', 'Programming Language :: Python :: 3'], 39 | license='BSD', 40 | keywords='Spacecraft Collision Avoidance Kessler Machine Learning Artificial Intelligence Probabilistic Programming', 41 | ) 42 | -------------------------------------------------------------------------------- /tests/run_basics.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | coverage run -m pytest 3 | coverage xml 4 | -------------------------------------------------------------------------------- /tests/test_cdm.py: -------------------------------------------------------------------------------- 1 | # This code is part of Kessler, a machine learning library for spacecraft collision avoidance. 2 | # 3 | # Copyright (c) 2020- 4 | # Trillium Technologies 5 | # University of Oxford 6 | # Giacomo Acciarini (giacomo.acciarini@gmail.com) 7 | # and other contributors, see README in root of repository. 8 | # 9 | # GNU General Public License version 3. See LICENSE in root of repository. 10 | 11 | 12 | import unittest 13 | import tempfile 14 | import uuid 15 | import os 16 | import numpy as np 17 | 18 | from kessler import ConjunctionDataMessage 19 | 20 | 21 | class CDMTestCase(unittest.TestCase): 22 | def test_cdm_load_save_load(self): 23 | file_content = """ 24 | CCSDS_CDM_VERS = 1.0 25 | CREATION_DATE = 2013-01-09T20:59:56.000 26 | ORIGINATOR = JSpOC 27 | MESSAGE_FOR = IRIDIUM 26 28 | MESSAGE_ID = 2013009205956Z 29 | TCA = 2013-01-10T13:22:45.117 30 | MISS_DISTANCE = 180.0 31 | RELATIVE_SPEED = 8111.0 32 | RELATIVE_POSITION_R = 35.9 33 | RELATIVE_POSITION_T = -148.8 34 | RELATIVE_POSITION_N = 95.7 35 | RELATIVE_VELOCITY_R = -4.1 36 | RELATIVE_VELOCITY_T = -4421.4 37 | RELATIVE_VELOCITY_N = -6800.2 38 | OBJECT = OBJECT1 39 | OBJECT_DESIGNATOR = 24903.0 40 | CATALOG_NAME = US SATCAT 41 | OBJECT_NAME = IRIDIUM 26 42 | INTERNATIONAL_DESIGNATOR = 1997-043A 43 | EPHEMERIS_NAME = NONE 44 | COVARIANCE_METHOD = CALCULATED 45 | MANEUVERABLE = N/A 46 | ORBIT_CENTER = EARTH 47 | REF_FRAME = ITRF 48 | GRAVITY_MODEL = EGM-96: 36D 36O 49 | ATMOSPHERIC_MODEL = JACCHIA 70 DCA 50 | SOLAR_RAD_PRESSURE = NO 51 | EARTH_TIDES = NO 52 | INTRACK_THRUST = NO 53 | RECOMMENDED_OD_SPAN = 6.58 54 | ACTUAL_OD_SPAN = 6.58 55 | OBS_AVAILABLE = 573.0 56 | OBS_USED = 571.0 57 | RESIDUALS_ACCEPTED = 98.1 58 | WEIGHTED_RMS = 0.944 59 | CD_AREA_OVER_MASS = 0.035005 60 | CR_AREA_OVER_MASS = 0.0 61 | SEDR = 7.305E-05 62 | X = -731.972155846 63 | Y = -1871.205777005 64 | Z = -6876.444217211 65 | X_DOT = -1.117777619 66 | Y_DOT = -7.044089359 67 | Z_DOT = 2.036664419 68 | CR_R = 38.33 69 | CT_R = 93.6 70 | CT_T = 3410.0 71 | CN_R = -13.06 72 | CN_T = 2.131 73 | CN_N = 93.39 74 | CRDOT_R = 0.0 75 | CRDOT_T = 0.0 76 | CRDOT_N = 0.0 77 | CRDOT_RDOT = 0.0 78 | CTDOT_R = 0.0 79 | CTDOT_T = 0.0 80 | CTDOT_N = 0.0 81 | CTDOT_RDOT = 0.0 82 | CTDOT_TDOT = 0.0 83 | CNDOT_R = 0.0 84 | CNDOT_T = 0.0 85 | CNDOT_N = 0.0 86 | CNDOT_RDOT = 0.0 87 | CNDOT_TDOT = 0.0 88 | CNDOT_NDOT = 0.0 89 | OBJECT = OBJECT2 90 | OBJECT_DESIGNATOR = 33759.0 91 | CATALOG_NAME = US SATCAT 92 | OBJECT_NAME = COSMOS 2251 DEB 93 | INTERNATIONAL_DESIGNATOR = 1993-036G 94 | EPHEMERIS_NAME = NONE 95 | COVARIANCE_METHOD = CALCULATED 96 | MANEUVERABLE = N/A 97 | ORBIT_CENTER = EARTH 98 | REF_FRAME = ITRF 99 | GRAVITY_MODEL = EGM-96: 36D 36O 100 | ATMOSPHERIC_MODEL = JACCHIA 70 DCA 101 | SOLAR_RAD_PRESSURE = YES 102 | EARTH_TIDES = NO 103 | INTRACK_THRUST = NO 104 | RECOMMENDED_OD_SPAN = 6.06 105 | ACTUAL_OD_SPAN = 6.06 106 | OBS_AVAILABLE = 180.0 107 | OBS_USED = 180.0 108 | RESIDUALS_ACCEPTED = 99.5 109 | WEIGHTED_RMS = 1.426 110 | CD_AREA_OVER_MASS = 0.20058 111 | CR_AREA_OVER_MASS = 0.087953 112 | SEDR = 0.000525006 113 | X = -732.050575868 114 | Y = -1871.058618906 115 | Z = -6876.513305974 116 | X_DOT = 6.170235153 117 | Y_DOT = -3.879972556 118 | Z_DOT = 0.404182951 119 | CR_R = 408.7 120 | CT_R = -535.0 121 | CT_T = 77970.0 122 | CN_R = -17.21 123 | CN_T = -79.98 124 | CN_N = 239.9 125 | CRDOT_R = 0.0 126 | CRDOT_T = 0.0 127 | CRDOT_N = 0.0 128 | CRDOT_RDOT = 0.0 129 | CTDOT_R = 0.0 130 | CTDOT_T = 0.0 131 | CTDOT_N = 0.0 132 | CTDOT_RDOT = 0.0 133 | CTDOT_TDOT = 0.0 134 | CNDOT_R = 0.0 135 | CNDOT_T = 0.0 136 | CNDOT_N = 0.0 137 | CNDOT_RDOT = 0.0 138 | CNDOT_TDOT = 0.0 139 | CNDOT_NDOT = 0.0 140 | """ 141 | file_name = os.path.join(tempfile.mkdtemp(), str(uuid.uuid4())) 142 | with open(file_name, 'w') as f: 143 | f.write(file_content) 144 | 145 | cdm = ConjunctionDataMessage.load(file_name) 146 | 147 | file_name = os.path.join(tempfile.mkdtemp(), str(uuid.uuid4())) 148 | cdm.save(file_name) 149 | 150 | cdm = ConjunctionDataMessage.load(file_name) 151 | 152 | cdm_covariance_1 = cdm.get_covariance(0) 153 | cdm_covariance_2 = cdm.get_covariance(1) 154 | cdm_covariance_1_correct = np.array([[3.833e+01, 9.360e+01, -1.306e+01, 0.000e+00, 0.000e+00, 0.000e+00], 155 | [9.360e+01, 3.410e+03, 2.131e+00, 0.000e+00, 0.000e+00, 0.000e+00], 156 | [-1.306e+01, 2.131e+00, 9.339e+01, 0.000e+00, 0.000e+00, 0.000e+00], 157 | [0.000e+00, 0.000e+00, 0.000e+00, 0.000e+00, 0.000e+00, 0.000e+00], 158 | [0.000e+00, 0.000e+00, 0.000e+00, 0.000e+00, 0.000e+00, 0.000e+00], 159 | [0.000e+00, 0.000e+00, 0.000e+00, 0.000e+00, 0.000e+00, 0.000e+00]]) 160 | cdm_covariance_2_correct = np.array([[4.087e+02, -5.350e+02, -1.721e+01, 0.000e+00, 0.000e+00, 0.000e+00], 161 | [-5.350e+02, 7.797e+04, -7.998e+01, 0.000e+00, 0.000e+00, 0.000e+00], 162 | [-1.721e+01, -7.998e+01, 2.399e+02, 0.000e+00, 0.000e+00, 0.000e+00], 163 | [0.000e+00, 0.000e+00, 0.000e+00, 0.000e+00, 0.000e+00, 0.000e+00], 164 | [0.000e+00, 0.000e+00, 0.000e+00, 0.000e+00, 0.000e+00, 0.000e+00], 165 | [0.000e+00, 0.000e+00, 0.000e+00, 0.000e+00, 0.000e+00, 0.000e+00]]) 166 | 167 | self.assertEqual(cdm_covariance_1_correct.tolist(), cdm_covariance_1.tolist()) 168 | self.assertEqual(cdm_covariance_2_correct.tolist(), cdm_covariance_2.tolist()) 169 | -------------------------------------------------------------------------------- /tests/test_event.py: -------------------------------------------------------------------------------- 1 | # This code is part of Kessler, a machine learning library for spacecraft collision avoidance. 2 | # 3 | # Copyright (c) 2020- 4 | # Trillium Technologies 5 | # University of Oxford 6 | # Giacomo Acciarini (giacomo.acciarini@gmail.com) 7 | # and other contributors, see README in root of repository. 8 | # 9 | # GNU General Public License version 3. See LICENSE in root of repository. 10 | 11 | 12 | import unittest 13 | import tempfile 14 | import uuid 15 | import os 16 | import pandas as pd 17 | 18 | from kessler import EventDataset 19 | 20 | 21 | class EventDatasetTestCase(unittest.TestCase): 22 | def test_from_pandas(self): 23 | file_content = """ 24 | ,event_id,batch_insertion_epoch,header_comment,ccsds_cdm_vers,creation_date,originator,message_id,message_for,relative_metadata_data_comment,tca,miss_distance,relative_speed,relative_position_r,relative_position_t,relative_position_n,relative_velocity_r,relative_velocity_t,relative_velocity_n,start_screen_period,stop_screen_period,screen_volume_frame,screen_volume_shape,screen_volume_x,screen_volume_y,screen_volume_z,screen_entry_time,screen_exit_time,probability,max_probability,jspoc_probability,depth_of_intrusion,t_object_metadata_comment,t_object_designator,t_catalog_name,t_object_name,t_international_designator,t_ephemeris_name,t_covariance_method,t_maneuverable,t_ref_frame,t_object_type,t_operator_id,t_orbit_center,t_gravity_model,t_atmospheric_model,t_n_body_perturbations,t_solar_rad_pressure,t_earth_tides,t_intrack_thrust,t_object_data_comment,t_object_od_params_comment,t_time_lastob_start,t_time_lastob_end,t_recommended_od_span,t_actual_od_span,t_obs_available,t_obs_used,t_tracks_available,t_tracks_used,t_residuals_accepted,t_weighted_rms,t_object_add_params_comment,t_area_pc,t_area_drg,t_area_srg,t_mass,t_cd_area_over_mass,t_cr_area_over_mass,t_thrust_acceleration,t_sedr,t_object_state_comment,t_x,t_y,t_z,t_x_dot,t_y_dot,t_z_dot,t_j2k_sma,t_j2k_ecc,t_j2k_inc,t_j2k_a_per,t_j2k_m_ano,t_j2k_raan,t_object_covar_comment,t_cr_r,t_ct_r,t_ct_t,t_cn_r,t_cn_t,t_cn_n,t_crdot_r,t_crdot_t,t_crdot_n,t_crdot_rdot,t_ctdot_r,t_ctdot_t,t_ctdot_n,t_ctdot_rdot,t_ctdot_tdot,t_cndot_r,t_cndot_t,t_cndot_n,t_cndot_rdot,t_cndot_tdot,t_cndot_ndot,t_cdrg_r,t_cdrg_t,t_cdrg_n,t_cdrg_rdot,t_cdrg_tdot,t_cdrg_ndot,t_cdrg_drg,t_csrp_r,t_csrp_t,t_csrp_n,t_csrp_rdot,t_csrp_tdot,t_csrp_ndot,t_csrp_drg,t_csrp_srp,t_cthr_r,t_cthr_t,t_cthr_n,t_cthr_rdot,t_cthr_tdot,t_cthr_ndot,t_cthr_drg,t_cthr_srp,t_cthr_thr,c_object_metadata_comment,c_object_designator,c_catalog_name,c_object_name,c_international_designator,c_ephemeris_name,c_covariance_method,c_maneuverable,c_ref_frame,c_object_type,c_operator_id,c_orbit_center,c_gravity_model,c_atmospheric_model,c_n_body_perturbations,c_solar_rad_pressure,c_earth_tides,c_intrack_thrust,c_object_data_comment,c_object_od_params_comment,c_time_lastob_start,c_time_lastob_end,c_recommended_od_span,c_actual_od_span,c_obs_available,c_obs_used,c_tracks_available,c_tracks_used,c_residuals_accepted,c_weighted_rms,c_object_add_params_comment,c_area_pc,c_area_drg,c_area_srg,c_mass,c_cd_area_over_mass,c_cr_area_over_mass,c_thrust_acceleration,c_sedr,c_object_state_comment,c_x,c_y,c_z,c_x_dot,c_y_dot,c_z_dot,c_j2k_sma,c_j2k_ecc,c_j2k_inc,c_j2k_a_per,c_j2k_m_ano,c_j2k_raan,c_object_covar_comment,c_cr_r,c_ct_r,c_ct_t,c_cn_r,c_cn_t,c_cn_n,c_crdot_r,c_crdot_t,c_crdot_n,c_crdot_rdot,c_ctdot_r,c_ctdot_t,c_ctdot_n,c_ctdot_rdot,c_ctdot_tdot,c_cndot_r,c_cndot_t,c_cndot_n,c_cndot_rdot,c_cndot_tdot,c_cndot_ndot,c_cdrg_r,c_cdrg_t,c_cdrg_n,c_cdrg_rdot,c_cdrg_tdot,c_cdrg_ndot,c_cdrg_drg,c_csrp_r,c_csrp_t,c_csrp_n,c_csrp_rdot,c_csrp_tdot,c_csrp_ndot,c_csrp_drg,c_csrp_srp,c_cthr_r,c_cthr_t,c_cthr_n,c_cthr_rdot,c_cthr_tdot,c_cthr_ndot,c_cthr_drg,c_cthr_srp,c_cthr_thr,jspoc_cdm_id,t_span,c_span 25 | 0,12345,2018-08-26 09:21:01.000000,,1,2016-05-16 08:08:45.000000,ABC12345,ABC12345,ABC12345,,2016-05-16 08:08:45.000000,0.834492808294835,0.124632824264698,0.80069109437128,0.561214665433106,0.816825630572017,0.208607555206536,0.731592025459866,0.570303067220067,,,,,,,,,,0.1,0.458882862383152,0,,,1234,ABC12345,ABC12345,ABC12345,NONE,CALCULATED,YES,ITRF,PAYLOAD,2,,ABC12345,ABC12345,"MOON,SUN",True,True,False,,,2016-05-16 08:08:45.000000,2016-05-16 08:08:45.000000,0.458882862383152,0.458882862383152,0.458882862383152,0.458882862383152,,,0.458882862383152,0.458882862383152,ABC12345,0.458882862383152,,,,0.458882862383152,0.458882862383152,0,0.458882862383152,,0.25498437500894,0.112376563676326,0.118703524110389,0.452650747012971,0.214489162297546,0.803282382755525,0.786085040093702,0.990171633378862,0.307736824573957,0.50965140364303,0.714555349450332,0.984888473667389,,0.711134792929336,0.198921153455887,0.831195371950245,0.954944212000877,0.704534234094459,0.249467464608224,0.853648472746269,0.415487189920632,0.908484946608889,0.205790492133707,0.955441709404618,0.443781744705242,0.934633773841681,0.113669321432054,0.346558342029125,0.999943982577824,0.260165052897464,0.534910595773655,0.003138518289742,0.645058510230789,0.665414786995049,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,,,,,,,,,,,1234,ABC12345,ABC12345,ABC12345,NONE,CALCULATED,,ITRF,DEBRIS,1,,ABC12345,ABC12345,"MOON,SUN",True,True,False,,,2016-05-16 08:08:45.000000,2016-05-16 08:08:45.000000,0.324514175884396,0.324514175884396,0.324514175884396,0.324514175884396,,,0.324514175884396,0.324514175884396,ABC12345,0.324514175884396,,,,0.324514175884396,0.324514175884396,0,0.324514175884396,,0.758968377374672,0.599509570566248,0.541702597404864,0.657962800075275,0.133389637846314,0.314389472287636,0.172063653702484,0.680568231092825,0.118929030153042,0.402688316488102,0.241770108925465,0.955386508712671,,0.787782142485196,0.683142973728186,0.723077873320779,0.73410866374641,0.699027719390639,0.034462566703314,0.559550929813111,0.905949292244197,0.125685830718603,0.70393549649449,0.331441271306996,0.600239238337988,0.651717098345195,0.169477542016838,0.635691408775896,0.289353669273576,0.35808862247228,0.030280326018385,0.908101381313104,0.068303959763316,0.214876608923229,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,,,,,,,,,,12345,11,1 26 | 1,12345,2018-08-26 06:51:01.000000,MAN,1,2016-05-16 08:08:45.000000,ABC12345,ABC12345,,,2016-05-16 08:08:45.000000,0.89873750846093,0.628380794238599,0.277830602478051,0.388502510320027,0.947139473062045,0.288681055107551,0.330496807664414,0.579047626342338,,,RTN,ELLIPSOID,1000,1000,1000,,,0.1,0.458882862383152,,,,1234,ABC12345,ABC12345,ABC12345,NONE,CALCULATED,,EME2000,PAYLOAD,,,,,,,,,,,,,,,,,,,,,,0.458882862383152,,,0.458882862383152,,,,,,0.458882862383152,0.619593868338859,0.280361151863788,0.517707153564549,0.714241233692547,0.896372753026402,0.608950551433962,0.610078567260023,0.99595085102525,0.437724979814095,0.783441124769422,0.329659907491579,,0.999480876708531,0.0427529023373,0.708967665008883,0.384518308333597,0.304580463020946,0.671728496068814,0.032383339709698,0.465593444565189,0.652971618884818,0.060653418516399,0.59523840375538,0.724882649734235,0.267616325965723,0.234322500028149,0.476667920151508,0.398651489942665,0.57705976320159,0.378791681290921,0.704649407619613,0.388876464311396,0.66124248082016,,,,,,,,,,,,,,,,,,,,,,,,,,1234,ABC12345,ABC12345,ABC12345,NONE,CALCULATED,,EME2000,DEBRIS,,,,,,,,,ABC12345,,,,,,,,,,,,,0.324514175884396,,,0.324514175884396,,,,,,0.324514175884396,0.902389838589119,0.814302547930863,0.741191579850528,0.38587542986633,0.642231309351491,0.906550908711897,0.123148444539083,0.650368061638809,0.010587221576897,0.854000303273469,0.684061564016819,,0.632567404007586,0.075007806550711,0.592565527585434,0.749688928299355,0.50972428079729,0.574285445943895,0.969742310001293,0.737128177440502,0.107949278907619,0.290943703797091,0.703043092143929,0.949642846878678,0.064790432064323,0.72636822759012,0.230985476177261,0.136556355763866,0.460149398175066,0.982745545187407,0.918595138753813,0.346770256028981,0.790935062204615,,,,,,,,,,,,,,,,,,,,,,,,,,12,1 27 | 2,12346,2018-08-26 06:51:01.000000,MAN,1,2016-05-16 08:08:45.000000,ABC12345,ABC12345,,,2016-05-16 08:08:45.000000,0.89873750846093,0.628380794238599,0.277830602478051,0.388502510320027,0.947139473062045,0.288681055107551,0.330496807664414,0.579047626342338,,,RTN,ELLIPSOID,1000,1000,1000,,,0.1,0.458882862383152,,,,1234,ABC12345,ABC12345,ABC12345,NONE,CALCULATED,,EME2000,PAYLOAD,,,,,,,,,,,,,,,,,,,,,,0.458882862383152,,,0.458882862383152,,,,,,0.458882862383152,0.619593868338859,0.280361151863788,0.517707153564549,0.714241233692547,0.896372753026402,0.608950551433962,0.610078567260023,0.99595085102525,0.437724979814095,0.783441124769422,0.329659907491579,,0.999480876708531,0.0427529023373,0.708967665008883,0.384518308333597,0.304580463020946,0.671728496068814,0.032383339709698,0.465593444565189,0.652971618884818,0.060653418516399,0.59523840375538,0.724882649734235,0.267616325965723,0.234322500028149,0.476667920151508,0.398651489942665,0.57705976320159,0.378791681290921,0.704649407619613,0.388876464311396,0.66124248082016,,,,,,,,,,,,,,,,,,,,,,,,,,1234,ABC12345,ABC12345,ABC12345,NONE,CALCULATED,,EME2000,DEBRIS,,,,,,,,,ABC12345,,,,,,,,,,,,,0.324514175884396,,,0.324514175884396,,,,,,0.324514175884396,0.902389838589119,0.814302547930863,0.741191579850528,0.38587542986633,0.642231309351491,0.906550908711897,0.123148444539083,0.650368061638809,0.010587221576897,0.854000303273469,0.684061564016819,,0.632567404007586,0.075007806550711,0.592565527585434,0.749688928299355,0.50972428079729,0.574285445943895,0.969742310001293,0.737128177440502,0.107949278907619,0.290943703797091,0.703043092143929,0.949642846878678,0.064790432064323,0.72636822759012,0.230985476177261,0.136556355763866,0.460149398175066,0.982745545187407,0.918595138753813,0.346770256028981,0.790935062204615,,,,,,,,,,,,,,,,,,,,,,,,,,12,1 28 | 3,12347,2018-08-26 06:51:01.000000,MAN,1,2016-05-16 08:08:45.000000,ABC12345,ABC12345,,,2016-05-16 08:08:45.000000,0.89873750846093,0.628380794238599,0.277830602478051,0.388502510320027,0.947139473062045,0.288681055107551,0.330496807664414,0.579047626342338,,,RTN,ELLIPSOID,1000,1000,1000,,,0.1,0.458882862383152,,,,1234,ABC12345,ABC12345,ABC12345,NONE,CALCULATED,,EME2000,PAYLOAD,,,,,,,,,,,,,,,,,,,,,,0.458882862383152,,,0.458882862383152,,,,,,0.458882862383152,0.619593868338859,0.280361151863788,0.517707153564549,0.714241233692547,0.896372753026402,0.608950551433962,0.610078567260023,0.99595085102525,0.437724979814095,0.783441124769422,0.329659907491579,,0.999480876708531,0.0427529023373,0.708967665008883,0.384518308333597,0.304580463020946,0.671728496068814,0.032383339709698,0.465593444565189,0.652971618884818,0.060653418516399,0.59523840375538,0.724882649734235,0.267616325965723,0.234322500028149,0.476667920151508,0.398651489942665,0.57705976320159,0.378791681290921,0.704649407619613,0.388876464311396,0.66124248082016,,,,,,,,,,,,,,,,,,,,,,,,,,1234,ABC12345,ABC12345,ABC12345,NONE,CALCULATED,,EME2000,DEBRIS,,,,,,,,,ABC12345,,,,,,,,,,,,,0.324514175884396,,,0.324514175884396,,,,,,0.324514175884396,0.902389838589119,0.814302547930863,0.741191579850528,0.38587542986633,0.642231309351491,0.906550908711897,0.123148444539083,0.650368061638809,0.010587221576897,0.854000303273469,0.684061564016819,,0.632567404007586,0.075007806550711,0.592565527585434,0.749688928299355,0.50972428079729,0.574285445943895,0.969742310001293,0.737128177440502,0.107949278907619,0.290943703797091,0.703043092143929,0.949642846878678,0.064790432064323,0.72636822759012,0.230985476177261,0.136556355763866,0.460149398175066,0.982745545187407,0.918595138753813,0.346770256028981,0.790935062204615,,,,,,,,,,,,,,,,,,,,,,,,,,12,1 29 | 4,12346,2018-08-26 06:51:01.000000,MAN,1,2016-05-16 08:08:45.000000,ABC12345,ABC12345,,,2016-05-16 08:08:45.000000,0.89873750846093,0.628380794238599,0.277830602478051,0.388502510320027,0.947139473062045,0.288681055107551,0.330496807664414,0.579047626342338,,,RTN,ELLIPSOID,1000,1000,1000,,,0.1,0.458882862383152,,,,1234,ABC12345,ABC12345,ABC12345,NONE,CALCULATED,,EME2000,PAYLOAD,,,,,,,,,,,,,,,,,,,,,,0.458882862383152,,,0.458882862383152,,,,,,0.458882862383152,0.619593868338859,0.280361151863788,0.517707153564549,0.714241233692547,0.896372753026402,0.608950551433962,0.610078567260023,0.99595085102525,0.437724979814095,0.783441124769422,0.329659907491579,,0.999480876708531,0.0427529023373,0.708967665008883,0.384518308333597,0.304580463020946,0.671728496068814,0.032383339709698,0.465593444565189,0.652971618884818,0.060653418516399,0.59523840375538,0.724882649734235,0.267616325965723,0.234322500028149,0.476667920151508,0.398651489942665,0.57705976320159,0.378791681290921,0.704649407619613,0.388876464311396,0.66124248082016,,,,,,,,,,,,,,,,,,,,,,,,,,1234,ABC12345,ABC12345,ABC12345,NONE,CALCULATED,,EME2000,DEBRIS,,,,,,,,,ABC12345,,,,,,,,,,,,,0.324514175884396,,,0.324514175884396,,,,,,0.324514175884396,0.902389838589119,0.814302547930863,0.741191579850528,0.38587542986633,0.642231309351491,0.906550908711897,0.123148444539083,0.650368061638809,0.010587221576897,0.854000303273469,0.684061564016819,,0.632567404007586,0.075007806550711,0.592565527585434,0.749688928299355,0.50972428079729,0.574285445943895,0.969742310001293,0.737128177440502,0.107949278907619,0.290943703797091,0.703043092143929,0.949642846878678,0.064790432064323,0.72636822759012,0.230985476177261,0.136556355763866,0.460149398175066,0.982745545187407,0.918595138753813,0.346770256028981,0.790935062204615,,,,,,,,,,,,,,,,,,,,,,,,,,12,1 30 | 31 | """ 32 | file_name = os.path.join(tempfile.mkdtemp(), str(uuid.uuid4())) 33 | with open(file_name, 'w') as f: 34 | f.write(file_content) 35 | 36 | df = pd.read_csv(file_name) # Read the csv 37 | 38 | # Make EventDataset from Pandas DataFrame 39 | e = EventDataset.from_pandas(df) 40 | 41 | # Make Pandas DataFrame from EventDataset 42 | df = e.to_dataframe() 43 | self.assertTrue(True) 44 | -------------------------------------------------------------------------------- /tests/test_model.py: -------------------------------------------------------------------------------- 1 | # This code is part of Kessler, a machine learning library for spacecraft collision avoidance. 2 | # 3 | # Copyright (c) 2020- 4 | # Trillium Technologies 5 | # University of Oxford 6 | # Giacomo Acciarini (giacomo.acciarini@gmail.com) 7 | # and other contributors, see README in root of repository. 8 | # 9 | # GNU General Public License version 3. See LICENSE in root of repository. 10 | 11 | import numpy as np 12 | import unittest 13 | import dsgp4 14 | 15 | import kessler.model 16 | from kessler import GNSS, Radar 17 | 18 | class UtilTestCase(unittest.TestCase): 19 | def test_make_chaser_make_target(self): 20 | t_tle_list=['0 ELECTRON KICK STAGE R/B', 21 | '1 44227U 19026C 22068.79876951 .00010731 00000-0 41303-3 0 9993', 22 | '2 44227 40.0221 252.2030 0008096 5.2961 354.7926 15.26135826158481'] 23 | 24 | c_tle_list=['0 HARBINGER', 25 | '1 44229U 19026E 22068.90017356 .00004812 00000-0 20383-3 0 9992', 26 | '2 44229 40.0180 261.5261 0008532 356.1827 3.8908 15.23652474158314'] 27 | t_tle = dsgp4.tle.TLE(t_tle_list) 28 | c_tle = dsgp4.tle.TLE(c_tle_list) 29 | model = kessler.model.Conjunction(t_observing_instruments=[GNSS()], c_observing_instruments=[Radar()], t_tle=t_tle, c_tle=c_tle) 30 | model_tle_target = model.make_target() 31 | model_tle_chaser = model.make_chaser() 32 | 33 | model_tle_target.update({"mean_anomaly": float(t_tle.mean_anomaly)}) 34 | model_tle_chaser.update({"mean_anomaly": float(c_tle.mean_anomaly)}) 35 | 36 | self.assertEqual(model_tle_target.line1, t_tle_list[1]) 37 | self.assertEqual(model_tle_target.line2, t_tle_list[2]) 38 | self.assertEqual(model_tle_chaser.line1, c_tle_list[1]) 39 | self.assertEqual(model_tle_chaser.line2, c_tle_list[2]) 40 | -------------------------------------------------------------------------------- /tests/test_observation_model.py: -------------------------------------------------------------------------------- 1 | # This code is part of Kessler, a machine learning library for spacecraft collision avoidance. 2 | # 3 | # Copyright (c) 2020- 4 | # Trillium Technologies 5 | # University of Oxford 6 | # Giacomo Acciarini (giacomo.acciarini@gmail.com) 7 | # and other contributors, see README in root of repository. 8 | # 9 | # GNU General Public License version 3. See LICENSE in root of repository. 10 | 11 | import numpy as np 12 | import unittest 13 | 14 | from kessler import GNSS, Radar 15 | 16 | class UtilTestCase(unittest.TestCase): 17 | def test_radar(self): 18 | spacecraft = {} 19 | spacecraft['state_xyz']= np.array([[1002.3, 202.2, 103.0], [0.1, 0.23, 0.4]]) 20 | instrument_characteristics = {} 21 | instrument_characteristics['bias_xyz']= np.zeros((2,3)) 22 | instrument_characteristics['covariance_rtn'] = np.array([1e-9, 1.115849341564346, 0.059309835843067, 1e-9, 1e-9, 1e-9])**2 23 | instrument = Radar(instrument_characteristics) 24 | state_observed, covariance_rtn = instrument.observe(time=0., spacecraft=spacecraft) 25 | self.assertTrue(np.allclose(state_observed, spacecraft['state_xyz'])) 26 | self.assertTrue(np.allclose(covariance_rtn, instrument_characteristics['covariance_rtn'])) 27 | instrument_characteristics_2 = {} 28 | instrument_characteristics_2['bias_xyz']= np.array([[0.2, 30.3, 40.4],[102.3, 404.4, 22.2]]) 29 | instrument_characteristics_2['covariance_rtn'] = np.array([1e-9, 1.115849341564346, 0.059309835843067, 1e-9, 1e-9, 1e-9])**2 30 | instrument_2 = Radar(instrument_characteristics_2) 31 | state_observed, _ = instrument_2.observe(time=0., spacecraft=spacecraft) 32 | self.assertTrue(np.allclose(state_observed, spacecraft['state_xyz']+instrument_characteristics_2['bias_xyz'])) 33 | 34 | def test_gnss(self): 35 | spacecraft = {} 36 | spacecraft['state_xyz']= np.array([[1002.3, 202.2, 103.0], [0.1, 0.23, 0.4]]) 37 | instrument_characteristics = {} 38 | instrument_characteristics['bias_xyz']= np.zeros((2,3)) 39 | instrument_characteristics['covariance_rtn'] = np.array([1e-9, 1.115849341564346, 0.059309835843067, 1e-9, 1e-9, 1e-9])**2 40 | instrument = GNSS(instrument_characteristics) 41 | state_observed, covariance_rtn = instrument.observe(time=0., spacecraft=spacecraft) 42 | self.assertTrue(np.allclose(state_observed, spacecraft['state_xyz'])) 43 | self.assertTrue(np.allclose(covariance_rtn, instrument_characteristics['covariance_rtn'])) 44 | instrument_characteristics_2 = {} 45 | instrument_characteristics_2['bias_xyz']= np.array([[0.2, 30.3, 40.4],[102.3, 404.4, 22.2]]) 46 | instrument_characteristics_2['covariance_rtn'] = np.array([1e-9, 1.115849341564346, 0.059309835843067, 1e-9, 1e-9, 1e-9])**2 47 | instrument_2 = GNSS(instrument_characteristics_2) 48 | state_observed, _ = instrument_2.observe(time=0., spacecraft=spacecraft) 49 | self.assertTrue(np.allclose(state_observed, spacecraft['state_xyz']+instrument_characteristics_2['bias_xyz'])) 50 | -------------------------------------------------------------------------------- /tests/test_util.py: -------------------------------------------------------------------------------- 1 | # This code is part of Kessler, a machine learning library for spacecraft collision avoidance. 2 | # 3 | # Copyright (c) 2020- 4 | # Trillium Technologies 5 | # University of Oxford 6 | # Giacomo Acciarini (giacomo.acciarini@gmail.com) 7 | # and other contributors, see README in root of repository. 8 | # 9 | # GNU General Public License version 3. See LICENSE in root of repository. 10 | 11 | import unittest 12 | import numpy as np 13 | import datetime 14 | import torch 15 | import dsgp4 16 | import kessler 17 | import kessler.util 18 | 19 | from pyro.distributions import Categorical, MixtureSameFamily 20 | class UtilTestCase(unittest.TestCase): 21 | def test_from_datetime_to_cdm_datetime_str(self): 22 | date = datetime.datetime(2823, 3, 4, 12, 1, 23, 252 ) 23 | date_str = kessler.util.from_datetime_to_cdm_datetime_str(date) 24 | date_str_correct = '2823-03-04T12:01:23.000252' 25 | self.assertEqual(date_str_correct, date_str) 26 | 27 | def test_from_jd_to_cdm_datetime_str(self): 28 | jd_date = 2469808.0229167 29 | date_str = kessler.util.from_jd_to_cdm_datetime_str(jd_date) 30 | date_str_correct = '2050-01-01T12:33:00.002899' 31 | self.assertEqual(date_str_correct, date_str) 32 | 33 | def test_from_TEME_to_ITRF(self): 34 | state_TEME = np.array([[5094.18016210*1e3, 6127.64465950*1e3, 6380.34453270*1e3], [-4.746131487*1e3, 0.785818041*1e3, 5.531931288*1e3]]) 35 | 36 | jd_date = 2433282.4235 37 | state_ITRF = kessler.util.from_TEME_to_ITRF(state_TEME, jd_date) 38 | state_ITRF_correct = np.array([np.array([ 7377976.66089733,-3010674.50719708, 6380344.5327]), np.array([-900.58420598,4224.28457883,5531.931288])]) 39 | print('state_ITRF', state_ITRF) 40 | print('state_ITRF_correct', state_ITRF_correct) 41 | print('state_TEME', state_TEME) 42 | self.assertTrue(np.allclose(state_ITRF_correct, state_ITRF)) 43 | self.assertAlmostEqual(np.linalg.norm(state_TEME[0]), np.linalg.norm(state_ITRF[0]), places=1) 44 | 45 | def test_from_cartesian_to_rtn(self): 46 | state_xyz = np.array([[1.0, 2.0, 3.4], [4.5, 6.2, 7.4]]) 47 | state_rtn, cartesian_to_rtn_rotation_matrix = kessler.util.from_cartesian_to_rtn(state_xyz) 48 | rtn_to_cartesian_rotation_matrix = cartesian_to_rtn_rotation_matrix.T 49 | r_xyz, v_xyz = np.matmul(rtn_to_cartesian_rotation_matrix, state_rtn[0]), np.matmul(rtn_to_cartesian_rotation_matrix, state_rtn[1]) 50 | 51 | self.assertTrue(np.allclose(state_xyz[0], r_xyz)) 52 | self.assertTrue(np.allclose(state_xyz[1], v_xyz)) 53 | self.assertAlmostEqual(np.linalg.norm(state_xyz[0]), np.linalg.norm(state_rtn[0]), places=1) 54 | self.assertAlmostEqual(np.linalg.norm(state_xyz[1]), np.linalg.norm(state_rtn[1]), places=1) 55 | 56 | def test_from_cartesian_to_rtn_2(self): 57 | state_xyz = np.array([[1.0, 2.0, 3.4], [4.5, 6.2, 7.4]]) 58 | state_rtn, _ = kessler.util.from_cartesian_to_rtn(state_xyz) 59 | self.assertAlmostEqual(np.linalg.norm(state_xyz[0]), np.linalg.norm(state_rtn[0]), places=1) 60 | self.assertAlmostEqual(np.linalg.norm(state_xyz[1]), np.linalg.norm(state_rtn[1]), places=1) 61 | 62 | def test_get_ccsds_time_format(self): 63 | # This test is written by Andrew Ng, 19/03/22. It makes use of example CDMs provided by the NASA CARA 64 | # analysis repo at https://github.com/nasa/CARA_Analysis_Tools/tree/master/two-dimension_Pc/UnitTest/InputFiles. 65 | test_case1 = "2000-01-01T00:00:00.000" #From AlfanoTestCase11.cdm 66 | test_case2 = "2018-229T13:56:33.000" # From DensityDecorrelationTestCaseCDM.txt 67 | test_case1_correct = "yyyy-mm-ddTHH:MM:SS.FFF" 68 | test_case2_correct = "yyyy-DDDTHH:MM:SS.FFF" 69 | 70 | self.assertEqual(kessler.util.get_ccsds_time_format(test_case1), test_case1_correct) 71 | self.assertEqual(kessler.util.get_ccsds_time_format(test_case2), test_case2_correct) 72 | 73 | def test_doy_2_date(self): 74 | # This test is written by Andrew Ng, 19/03/22. It makes use of example CDMs provided by the NASA CARA 75 | # analysis repo at https://github.com/nasa/CARA_Analysis_Tools/tree/master/two-dimension_Pc/UnitTest/InputFiles. 76 | example1 = "2010-202T12:25:19.000" # From SingleCovTestCase1-4.cdm 77 | example2 = "2018-229T13:56:33.000" # From DensityDecorrelationTestCaseCDM.txt 78 | example3 = "2010-365T00:00:00.000" # Check that works at the final day of a non leap year 79 | example4 = "2010-001T00:00:00.000" # Check that works at the first day of a year 80 | example5 = "2012-366T00:00:00.000" # Check that works at the final day of a leap year 81 | 82 | doy_1 = example1[5:5+3] 83 | year_1= example1[0:4] 84 | doy_2 = example2[5:5+3] 85 | year_2= example2[0:4] 86 | doy_3 = example3[5:5+3] 87 | year_3= example3[0:4] 88 | doy_4 = example4[5:5+3] 89 | year_4= example4[0:4] 90 | doy_5 = example5[5:5+3] 91 | year_5= example5[0:4] 92 | 93 | test_case1_correct = "2010-07-21T12:25:19.00" 94 | test_case2_correct = "2018-08-17T13:56:33.00" 95 | test_case3_correct = "2010-12-31T00:00:00.00" 96 | test_case4_correct = "2010-01-01T00:00:00.00" 97 | test_case5_correct = "2012-12-31T00:00:00.00" 98 | 99 | self.assertEqual(kessler.util.doy_2_date(example1, doy_1, year_1, 5), test_case1_correct) 100 | self.assertEqual(kessler.util.doy_2_date(example2, doy_2, year_2, 5), test_case2_correct) 101 | self.assertEqual(kessler.util.doy_2_date(example3, doy_3, year_3, 5), test_case3_correct) 102 | self.assertEqual(kessler.util.doy_2_date(example4, doy_4, year_4, 5), test_case4_correct) 103 | self.assertEqual(kessler.util.doy_2_date(example5, doy_5, year_5, 5), test_case5_correct) 104 | 105 | def test_from_cartesian_to_keplerian_torch(self): 106 | lines=[] 107 | lines.append("0 COSMOS 2251 DEB") 108 | lines.append("1 34427U 93036RU 22068.94647328 .00008100 00000-0 11455-2 0 9999") 109 | lines.append("2 34427 74.0145 306.8269 0033346 13.0723 347.1308 14.76870515693886") 110 | tle=dsgp4.TLE(lines) 111 | dsgp4.initialize_tle(tle) 112 | # Extract the state vector from the dSGP4 output 113 | st=dsgp4.sgp4(tle,torch.tensor(0.0))*1e3 # Convert to meters and meters/second 114 | #now let's retrieve the poliastro gravitational parameter of the Earth: 115 | mu = 398600441800000.0000000000000000#Earth.k.to(u.m**3 / u.s**2).value 116 | # Let's then convert Cartesian -> Keplerian using our function 117 | a,e,i,Omega,omega,M=kessler.util.from_cartesian_to_keplerian(r_vec=st[0], v_vec=st[1], mu=mu) 118 | 119 | a_poliastro=7023679.5817881366237998 120 | e_poliastro=0.0041649630912143 121 | i_poliastro=1.2919744331609118 122 | Omega_poliastro=5.3551396410293757 123 | omega_poliastro=0.4409272281996022 124 | M_poliastro=5.8458093777349722 125 | #let's now test they are close: 126 | self.assertAlmostEqual(a.item(), a_poliastro, places=5) 127 | self.assertAlmostEqual(e.item(), e_poliastro, places=5) 128 | self.assertAlmostEqual(i.item(), i_poliastro, places=5) 129 | self.assertAlmostEqual(Omega.item(), Omega_poliastro, places=5) 130 | self.assertAlmostEqual(omega.item(), omega_poliastro, places=5) 131 | self.assertAlmostEqual(M.item(), M_poliastro, places=5) 132 | 133 | def test_TruncatedNormal(self): 134 | #we check the truncated normal distribution, we do this for a mixture of them: 135 | locs=torch.tensor([6.391167644720491e-05, 0.021593032643530245,0.00089714840255561, 0.004279950440413096, ]) 136 | scales=torch.tensor([9.155414891172675e-05, 0.08825398369676822, 0.0006834100202961423,0.003464680595037937]) 137 | probs=torch.tensor([0.36699734 ,0.02809785 ,0.39047779,0.21442703 ]) 138 | min=-0.73577 139 | max=0.68639 140 | 141 | categorical=Categorical(probs=probs) 142 | batched_truncated_normal = kessler.util.TruncatedNormal(loc=locs, scale=scales, low=min, high=max) 143 | mix_truncated=MixtureSameFamily(categorical, batched_truncated_normal) 144 | self.assertAlmostEqual(mix_truncated.log_prob(torch.tensor(0.0001)).item(), 7.382209300994873, places=6) 145 | self.assertAlmostEqual(mix_truncated.log_prob(torch.tensor(0.001)).item(), 5.485926151275635, places=6) 146 | self.assertAlmostEqual(mix_truncated.log_prob(torch.tensor(0.01)).item(), 1.863307237625122, places=6) 147 | self.assertAlmostEqual(mix_truncated.log_prob(torch.tensor(0.1)).item(), -2.458112955093384, places=6) 148 | 149 | 150 | --------------------------------------------------------------------------------