├── .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 |
8 |
9 |
10 | Kessler
11 |
12 | Explore the docs »
13 |
14 |
15 | Report bug
16 | ·
17 | Request feature
18 |
19 |
20 |
21 | -----------------------------------------
22 | [](https://github.com/kesslerlib/kessler/actions)
23 | [](https://codecov.io/gh/kesslerlib/kessler)
24 | [](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 |
--------------------------------------------------------------------------------