Skip to content

Getting Started

This guide walks through installing ACONS, running the bundled lunar scenario, and adapting the configuration to other celestial bodies.

Prerequisites

  • Python 3.11 (matching the pyproject.toml requirement)
  • Poetry for dependency management

Install Poetry via pipx (recommended):

pip install --user pipx
pipx ensurepath
pipx install poetry

or through the official installer:

curl -sSL https://install.python-poetry.org | python3 -

Verify the installation:

poetry --version

Installation

git clone https://github.com/<your-org>/acons.git
cd acons
poetry install          # create the virtual environment and install dependencies

(Optional) spawn a Poetry-managed shell:

poetry shell

Running the lunar example

The repository ships with a fully configured lunar navigation scenario. Execute the full pipeline from ingest to estimation with:

poetry run acons all --config configs/scenarios/lunar_case.yaml --run-dir outputs/lunar_static

This performs the three stages sequentially:

  1. Ingest – resample the satellite ephemerides onto the scenario grid and render quick-look plots.
  2. Simulate – synthesise one-way range and Doppler measurements, including Friis-based C/N₀, and write the complete measurement catalogue to measurements.json.
  3. Estimate – run the eight-state EKF (position, velocity, clock bias/drift), produce state and covariance histories, and generate residual/error plots. Reporting automatically drops robust outliers before computing statistics.

You can drive individual stages if you only need a subset:

poetry run acons ingest  --config configs/scenarios/lunar_case.yaml --run-dir outputs/lunar_static
poetry run acons simulate --config configs/scenarios/lunar_case.yaml --run-dir outputs/lunar_static
poetry run acons estimate --config configs/scenarios/lunar_case.yaml --run-dir outputs/lunar_static

Re-running a stage overwrites only that stage’s outputs, letting you quickly iterate on scenarios.

Running the Mars example

configs/scenarios/mars_case.yaml reproduces a surface user that ingests the MARCONI constellation ephemerides from ephemeris/MARS/. These tracks are provided in the JCRF inertial frame and the scenario’s frames block requests a JCRF → MARS-IAU conversion, so make sure the referenced SPICE kernels include the NAIF leapseconds file plus Mars frame/orientation kernels (e.g., data/SPICE/mars_iau2000.tf and data/SPICE/mars_pa_de440_2000-2050.bpc).

Run the full pipeline with:

poetry run acons all --config configs/scenarios/mars_case.yaml --run-dir outputs/mars_static

Swap in ingest, simulate, or estimate if you only need a subset of the flow just like the lunar example.

The Mars scenario ships with delayed two-way measurements disabled by default (measurement.two_way_delay_simulate: false and estimation.delayed_twm_enabled: false). Flip both to true (and set a delay in seconds or samples) if you want to exercise the delayed-TWM estimator path.

If you need delayed two-way data but want to keep the standard EKF, set measurement.two_way_delay_simulate: true and keep estimation.delayed_twm_enabled: false. Seconds are rounded to a sample delay, and the estimator will ingest the delayed columns automatically.

Mars regression check

The regression harness uses configs/scenarios/regression_test/mars_regression.yaml, which inlines every Mars setting (no !include fragments) so the check remains self-contained. The scenario now exposes measurement.two_way_delay_seconds, measurement.two_way_delay_simulate, and estimation.delayed_twm_enabled so you can toggle delayed two-way measurements without touching the code—leave the defaults (0.0 seconds, disabled flags) for the baseline comparison. The CLI automatically compares against ref/regression/mars_case/state_error_stats.csv and writes results to outputs/regression/mars_case. Execute the baseline comparison with:

poetry run acons regression

The command re-runs ingest/simulate/estimate and fails if either estimate/state_error_stats.csv or simulate/measurements.json differs from the reference. When the comparison succeeds the temporary run directory is deleted automatically. Pass --reference <yaml> if you ever need to point at an alternative scenario/baseline bundle.

Adapting to another body

Scenario configuration is consolidated into a single YAML/JSON file. The key sections are:

  1. time – start/end timestamps and sampling cadence.
  2. celestial_body – human-readable label for the target body and default constants lookup.
  3. planet_shapesphere uses the body mean radius; ellipsoid uses semimajor/semiminor axes from configs/environment/constants.yaml to derive the local surface radius (overrides user.body_radius_m when set).
  4. frames – source and body-fixed frames (e.g., J2000MOON_PA).
  5. spice.kernels – list of SPICE kernels furnished before ingest.
  6. user – geodetic location, elevation mask, and user type (surface, orbiter, or edl).
  7. measurement – carrier frequency, DLL/FLL parameters, transmitter/receiver gain patterns, RNG seed, observable list (currently range and range_rate), an oscillator entry with at least two Allan deviation samples (any averaging times are accepted), and a sise block describing ODTS one-sigma errors for satellite position, velocity, clock bias, and clock drift.
  8. constellation – satellite identifiers with ephemeris file paths (CSV/SP3/OEM).
  9. estimation – initial position/velocity/clock bias/drift, process-noise settings (process_noise for orbiters/EDL, process_noise_diag for surface users), and 1‑σ initial covariance.

Bundled scenario YAMLs now include short comment banners ahead of each section so you can glance at configs/scenarios/*.yaml to understand what knobs a block controls before editing it.

Scenario files may also compose smaller YAML/JSON snippets. Use !include to pull in a block relative to the master scenario:

measurement:
  transmitter: !include measurements/components/transmitter.yaml
  receiver_rf: !include measurements/components/receiver.yaml
frames: !include environment/lunar/frames.yaml#frames
spice: !include environment/lunar/frames.yaml#spice

The bundled lunar_case.yaml and mars_case.yaml now split time, frames, spice, user, constellation, measurement, and estimation across directories named environment/, measurements/, and estimation/. Multiple scenarios can include the same fragments while keeping each master file readable. The constellation block is now the sole place to list ephemeris files, replacing the older orbits alias used by legacy tooling.

When initial_state.use_user_as_truth is true you can specify random_position_error_m (e.g., 1000 m) to inject a random offset with that magnitude, optionally fixing the direction via position_error_seed for reproducibility.

Update those sections to reflect the new body or constellation, then rerun the same acons commands. No code changes are required as long as ephemerides and SPICE kernels are supplied.

Project layout

acon/
├── configs/
│   └── scenarios/               # <body>_case entry points + environment/estimation/measurement fragments
├── data/SPICE/                  # Furnished kernels (LSK, frame, SPK…)
├── docs/                        # MkDocs documentation set
├── ephemeris/                   # Tabulated orbit samples (CSV)
├── outputs/                     # Generated artefacts (gitignored)
├── src/
│   ├── constants.py             # Shared physical/logging constants
│   ├── cli.py                   # CLI entry point (`poetry run acons …`)
│   ├── measurement_simulator.py # Measurement synthesis & JSON exporter
│   ├── filtering.py             # Eight-state EKF
│   └── reporting.py             # Plots and CSV summaries with outlier removal
└── README.md

Refer to the Outputs & Reporting page for a breakdown of stage artefacts.