Skip to main content

GeoSol Research Logo

TrackSim (Tracking-Scenario Simulation)

Tracking-scenario simulator and replay visualizer over a shared JSONL stream contract. Generate labeled truth, degrade it into observables across fidelity tiers, replay it through a reference estimator, and scrub the result on a timeline. Requires Python 3.12+.

gri-tracksim is two paired tools joined by one file contract: a simulator that emits truth / input / output streams, and a Dash/Plotly replay viewer that reads them. The boundary is the JSONL contract alone, so the viewer renders the output of any contract-conformant tracker, not just this package's.

The viewer is a 2D replay tool. The 3D analyst app ("Crucible") is a separate, closed product and is not part of this repository.

Key Features

  • Scenario simulator: leg-based truth (straight / turn / climb / hold), degraded observables (geo / TDOA / FDOA / AOA / altitude), and a four-tier fidelity ladder (T0..T3) driven from one physical scene.
  • Declarative scenarios: author scenarios in YAML from the shipped vocabulary - no source checkout required.
  • Reference replay: a single-target IMM replay produces the output stream with forward-prediction horizons.
  • Replay viewer: a 2D top-down ENU map plus linked time-series panes, with a play/scrub timeline.
  • Self-contained contract: a language-agnostic JSONL wire format you can emit from your own tracker and render here.

Capability Tiers

gri-tracksim is built around three ways to use it:

  1. Viz-only consumer - you already have a tracker. Emit the JSONL contract and run gri-tracksim-viz to scrub it.
  2. Scenario author - write scenario YAML from the shipped vocabulary (emitters, legs, tiers, collector presets, noise) and generate the truth / input / output triple. Needs the package; no source.
  3. Vocabulary developer - add new leg primitives, collector geometries, fidelity tiers, or parametric sweeps. These live in registries in the source and require a checkout (see CLAUDE.md).

Installation

pip install gri-tracksim          # simulator + replay viewer

Quick Start

Generate a scenario (CLI)

gri-tracksim --list                  # list bundled example scenarios
gri-tracksim air_racetrack           # render a bundled scenario
gri-tracksim air_racetrack --tier T3 # same scene, harder tier
gri-tracksim air_racetrack --seed 7  # same scene, new realization
gri-tracksim my_scenario.yaml        # render your own YAML

The scene name (air_racetrack) describes the physical scenario; --tier (T0-T3) and --seed are orthogonal run knobs layered over it. Each defaults to the scene's own value (a --seed-less scene with no seed: draws a random one), and the effective tier and seed are folded into the output directory so sweeps never clobber: streams land in _scratch/<name>_<tier>_s<seed>/. The output root defaults to _scratch/ (a gitignored scratch dir); override it with -o <dir>.

Scrub a run (viewer)

gri-tracksim-viz _scratch/air_racetrack_T2_s3

Author a scenario in Python

from gri_tracksim.sim import load_scenario, write_scenario_streams

scenario = load_scenario("my_scenario.yaml")
n_truth, n_input, n_output = write_scenario_streams(
    scenario, "_scratch/my_scenario", predict_horizons_s=(10.0, 30.0),
)

Read the contract from your own tracker

from gri_tracksim.contract import Header, load_stream, write_jsonl

header, records = load_stream("output.jsonl")   # parsed Header + event records

You only need gri_tracksim.contract to emit or read the streams - it has no dependency on the simulator or the viewer.

Scenario YAML

A scenario is a single declarative file. All keys but name, origin_lla, dt, and emitters are optional:

name: air_racetrack
origin_lla: [38.0, -77.0, 0.0]   # ENU anchor [lat_deg, lon_deg, alt_m]
dt: 2.0                          # grid step (s)
seed: 3                          # default realization (--seed overrides; random if omitted)
tier: T2                         # default tier (--tier overrides): T0 | T1 | T2 | T3
collectors: diverse              # good | weak | diverse | null
motion: air                      # level (cruise) | air (climb-aware IMM)
noise:
  altitude_std_m: 200.0
emitters:
  E1:
    start_enu: [0.0, 0.0, 1000.0]
    azimuth_deg: 90.0
    speed_mps: 120.0
    legs:
      - {type: straight, duration_s: 30.0}
      - {type: climb, duration_s: 20.0, climb_rate_mps: 10.0}
      - {type: turn, delta_azimuth_deg: 180.0, radius_m: 2000.0}

The leg types (straight, turn, climb, hold), fidelity tiers (T0..T3), collector presets (good, weak, diverse), and replay motion banks (level, level_fx, air) are fixed vocabularies; adding to them is the source-only developer path.

Reference Replay Options

The replay tracker has three orthogonal knobs (defaults are the validated configuration; legacy values remain available for comparison runs):

  • Motion bank (motion: in the YAML): level (cv / turn / static), air (adds a climb mode so altitude changes read as a mode), level_fx (adds a fixed +/- nominal-rate turn pair -- instant turn discrimination when the platform's maneuver-rate class is known; harmful off-nominal).
  • Segmentation (segmentation=): mode_sequence (default) -- a retrospective MAP decode over the whole track, recomputed each scan, which also emits settled (fixed-lag smoothed) mode probabilities per scan; or locked, the online residual-trigger segmenter.
  • Prediction (prediction=): locked (default) -- predict under the current settled segment's model (settle-gated, speed-guarded); evolved or blend for comparison.

Evaluation Harness

Two console scripts score tracker configurations against truth, corpus-wide:

# render + score scenario x seed runs (metrics.json per run, summary.json per sweep)
gri-tracksim-eval --seeds 10 --tier T2 -o _scratch/eval_new
gri-tracksim-eval --seeds 10 --tier T2 --segmentation locked --prediction blend \
    --model-selection mean_ll -o _scratch/eval_legacy   # the legacy stack

# paired (scenario, seed) comparison: median delta, bootstrap CI, sign test
gri-tracksim-compare _scratch/eval_legacy _scratch/eval_new
gri-tracksim-compare _scratch/eval_legacy _scratch/eval_new --scenario boat_racetrack

Per-run metrics cover segmentation (count, boundary error, label accuracy), characterization (instant and settled mode agreement, lock latency, thrash), smoothing (RMS and straight-leg bow, with a truth-boundary oracle bound), and prediction (per-horizon RMS plus the phantom-curve ratio vs a CV extrapolation).

The Stream Contract

Each stream is JSON Lines: a self-describing header record followed by one record per event.

  • truth - {"t", "emitter_id", "pos_enu", "vel_enu", "leg_mode"}
  • input - {"t", "id", "type", ...} where type is one of geo | tdoa | fdoa | aoa | altitude; the stable id (obs_0000...) is what the output's association references.
  • output - the estimator replay, in two record kinds per scan:
    • per-track records {"t", "track", "pos_enu", "cov_enu", "vel_enu", "existence", "mode_probabilities", "stationary_locked", "resolved", "predicted", ...} - the track estimate (position + velocity in the ENU frame), one predicted entry per requested horizon, each naming the model that produced it. Mode-sequence replays also carry settled_t / settled_mode_probabilities (the fixed-lag smoothed mode mix a few scans behind the playhead).
    • one scene record per scan {"t", "scene", "count_distribution", "association", "events", "worlds"}. The per-observation dispositions live at association.dispositions - one entry per input observation {"obs_id", "verdict", "track", "prob", "variant", "repaired"}, where verdict is assigned | birthed | clutter | healed (the outlier / unused observations are the clutter verdicts, and a healed one was absorbed under the alternative reading named by variant). association also holds gates / marginals / hypotheses / variants (the per-reading marginal probabilities). worlds carries the MFA's surviving global hypotheses with weights (empty for the committal GNN).
  • smoothed (optional) - one retrospective snapshot per scan: the smoothed trajectory the tracker had settled on by that playhead, plus segments ({model, t_start, t_end}) naming the motion model the smoother used per leg. Segments revise as data accrues, so scrubbing replays the boundary back-dating.

The wire format is plain JSON (no gri types on the wire), so any tracker, in any language, can emit a stream the viewer will render.

Dependencies

A top-tier package in the GRI FOSS ecosystem; a sibling consumer of the same mid-tier libraries as gri-multitrack.

  • gri-geosim (iterative locate), gri-kalman (reference IMM replay), gri-trajectory (legs), gri-obs, gri-pos, gri-ell, gri-utils
  • gri-plot, dash, plotly (the replay viewer)
  • numpy, scipy, pyyaml

Other Projects

Current list of other GRI FOSS Projects we are building and maintaining.

License

MIT License. See LICENSE for details.

Release files for gri-tracksim 0.3.4

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for gri-tracksim 0.3.4
File Size Uploaded
gri_tracksim-0.3.4.tar.gz 191.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for gri-tracksim 0.3.4
File Interpreter ABI Platform
gri_tracksim-0.3.4-py3-none-any.whl Python 3 none any Details

Total release size: 344.1 kB

Release files / gri_tracksim-0.3.4.tar.gz

Download URL gri_tracksim-0.3.4.tar.gz
Size 191.9 kB
Tags Source
SHA-256 checksum
How to use checksums
c4d29ed1155af56be2255b6dc06659feddcc426e92c5bbd866b84fe718e5d4af
BLAKE2b-256 checksum
How to use checksums
fbad1e76729f5009c318c6f2364e8a551e19ffbd381dc491ec744bbadad83a5f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.9.30 {"installer":{"name":"uv","version":"0.9.30","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"12","id":"bookworm","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / gri_tracksim-0.3.4-py3-none-any.whl

Download URL gri_tracksim-0.3.4-py3-none-any.whl
Size 152.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c3e0e534b2691801a39ac28fa04e44289061353b117607a8099f0fe3268c5fc2
BLAKE2b-256 checksum
How to use checksums
5b6b44cac50e6a1603a55351bbfd0fb3aacce118c3a73bfe1099bb7ee85db4a9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.9.30 {"installer":{"name":"uv","version":"0.9.30","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"12","id":"bookworm","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release history Release notifications | RSS feed

This release

0.3.4 This release

2 release files

0.3.3

2 release files

0.3.2

2 release files

0.3.1

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page