Metadata-Version: 2.4
Name: gri-tracksim
Version: 0.3.0
Summary: Tracking-scenario simulator and replay visualizer over a shared JSONL stream contract
Project-URL: Homepage, https://geosolresearch.com
Project-URL: Repository, https://gitlab.com/geosol-foss/python/gri-tracksim
Project-URL: Issues, https://gitlab.com/geosol-foss/python/gri-tracksim/-/issues
Project-URL: Changelog, https://gitlab.com/geosol-foss/python/gri-tracksim/-/releases
Author-email: GeoSol Research Inc <contact@geosolresearch.com>
License-Expression: MIT
License-File: LICENSE
Keywords: geolocation,replay,scenario,simulation,tracking
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Scientific/Engineering
Classifier: Topic :: Scientific/Engineering :: GIS
Requires-Python: >=3.12
Requires-Dist: dash>=2.17
Requires-Dist: gri-ell>=0.2.0
Requires-Dist: gri-geosim>=0.4.1
Requires-Dist: gri-kalman>=0.2.0
Requires-Dist: gri-multitrack>=0.2.0
Requires-Dist: gri-obs>=0.1.0
Requires-Dist: gri-plot>=0.2.0
Requires-Dist: gri-pos>=0.2.0
Requires-Dist: gri-trajectory>=0.1.0
Requires-Dist: gri-utils>=0.4.0
Requires-Dist: numpy>=2.3.3
Requires-Dist: plotly>=5.22
Requires-Dist: pyyaml>=6.0
Requires-Dist: scipy>=1.16.2
Description-Content-Type: text/markdown

[![GeoSol Research Logo](https://geosolresearch.com/logos/foss_logo.png "GeoSol Research")](https://geosolresearch.com)

# 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 `AGENTS.md`).

## Installation

```bash
pip install gri-tracksim          # simulator + replay viewer
```

## Quick Start

### Generate a scenario (CLI)

```bash
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)

```bash
gri-tracksim-viz _scratch/air_racetrack_T2_s3
```

### Author a scenario in Python

```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

```python
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:

```yaml
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:

```bash
# 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 (estimate / association / predicted),
  association keyed back to the input `id`. Mode-sequence replays also carry
  `settled_t` / `settled_mode_probabilities`: the fixed-lag smoothed mode mix
  a few scans behind the playhead (the "settled" complement to the instant
  `mode_probabilities`); each `predicted` entry names the `model` that
  produced it.
- `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](https://gitlab.com/geosol-foss/python/gri-tracksim/-/blob/main/.docs_other_projects.md) we are building and maintaining.

## License

MIT License. See [LICENSE](https://gitlab.com/geosol-foss/python/gri-tracksim/-/blob/main/LICENSE) for details.
