Repo structure
.
├── data
│ ├── airport_map
│ ├── dataset
│ │ ├── static_dataset
│ │ │ ├── train
│ │ │ └── validation
│ │ └── trajectories
│ │ ├── test
│ │ └── validation
│ ├── filter_eval
│ └── segmentation_model
├── configs
│ └── best_config.json
├── output
│ ├── figures
│ └── tables
├── README.md
├── scripts
│ ├── 00_airport_map.sh
│ ├── 01_generate_dataset.sh
│ ├── 02_train_segmentation_model.sh
│ ├── 03_precompute_segmentation_masks.sh
│ ├── 04_train_pca.sh
│ ├── 05_hyperparameter_optimization.sh
│ ├── 06_filter_eval.sh
│ ├── 07_calibration_recalibration.sh
│ ├── 08_plots_tables.sh
│ └── config.json
└── src
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txtAll pipeline settings live in one file, scripts/config.json; paths in it are
repo-relative. For machine-specific locations (e.g. your X-Plane install dir
or a shared NAS), copy the example and edit — it deep-merges over the defaults:
cp scripts/config.local.json.example scripts/config.local.json
# edit scripts/config.local.json (gitignored)Every step script is a thin wrapper that forwards flags to its Python module, so
./scripts/NN_*.sh --help (or python -m <module> --help) lists each step's
options. The only environment variables the scripts read are PYTHON (interpreter,
default python) and CONFIG (config path, default scripts/config.json).
Download the published checkpoint (optional, for eval):
pip install huggingface_hub
hf download ejprince26/VisualTaxiULI best_model_avg.pth --local-dir data/segmentation_modelDownload the published dataset (optional, instead of generating it with Steps 0–1).
It is hosted on the Stanford Digital Repository (purl.stanford.edu/zr063zq9238)
and unpacks into the exact data/dataset/ layout the pipeline expects:
./scripts/download_dataset.sh # static_dataset.zip (~84 GB) + trajectories.zip (~193 GB)
SUBSET=static ./scripts/download_dataset.sh # only static_dataset/{train,validation}
SUBSET=trajectories ./scripts/download_dataset.sh
DATASET_ROOT=/srv/nasauli/AVIATION_DATASET ./scripts/download_dataset.sh # unpack elsewhereThe script resumes interrupted downloads, verifies each archive's md5, and extracts into
paths.dataset_root (default data/dataset). Use KEEP_ZIP=1 to keep the .zip files and
FORCE=1 to re-download even if a subset already exists. The published trajectory subset is
60 test / 60 validation (the canonical split that accompanies the paper).
Note: Building the airport map requires the installation of XPPython and a custom plugin. Follow the instructions to install XPPython, then copy the
./src/data_generation/xplane_plugin/PI_taxi_localization.pyto[X-Plane root]/Resoures/plugins/PythonPlugins/before starting X-Plane.
Downloads the airport's X-Plane data and builds the parsed map pickle
(data/airport_map/<ICAO>.pkl) that the rest of the pipeline reads.
Requires a running X-Plane with the PI plugin listening on tcp://localhost:5588
(same dependency as Step 1).
./scripts/00_airport_map.sh # builds data/airport_map/KUNI.pkl
./scripts/00_airport_map.sh --icao KXYZ # different airport
./scripts/00_airport_map.sh --force # rebuild even if the pickle already exists
./scripts/00_airport_map.sh --yes # skip the X-Plane placement confirmationWarning: While in theory this pipeline also should work with other airports, we have not tested it and also want to point out that the line widths that are defined in src/data_generation/helpers.py need to be empirically set for most line types in order for the rendering to work properly at airports other than KUNI.
Generates both datasets into the data/dataset/ layout:
- static →
static_dataset/{train,validation}— a flat pool is generated, then split deterministically (seed 42, 90/10; 9000/1000 at full scale). - trajectories →
trajectories/{test,validation}— controller-driven taxi sequences.
Requires X-Plane, the PI plugin, and data/airport_map/KUNI.pkl (build it with script 00; see Step 0).
X-Plane's install location (where Output/screenshots is read from) comes from
xplane.install_dir in config (default ~/X-Plane 12; set yours in scripts/config.local.json).
./scripts/01_generate_dataset.sh # quick smoke: tiny static + trajectories
./scripts/01_generate_dataset.sh --full # paper-scale run
./scripts/01_generate_dataset.sh --mode static # only static_dataset/{train,validation}
./scripts/01_generate_dataset.sh --mode trajectories # only trajectories/{test,validation}The smoke and paper-scale counts are plain variables at the top of
scripts/01_generate_dataset.sh. For custom counts or destinations, call the
modules directly (python -m data_generation.generate_dataset --help,
... get_trajectory_sequences --help, ... split_static_dataset --help).
Destinations default to the paths.static_dataset_* and paths.trajectories_*
config keys; the intermediate flat static pool goes under
paths.dataset_generation_root.
Optional quick training smoke test (requires activated venv):
./scripts/validate_config.sh
./scripts/02_train_segmentation_model.shFull training (no smoke subset):
./scripts/02_train_segmentation_model.sh --full-trainOverride interpreter if needed: PYTHON=python3.12 ./scripts/02_train_segmentation_model.sh.
W&B logging is off by default (WANDB_DISABLED=0 to enable it).
Checkpoints save under data/segmentation_model/.
Runs the configured segmentation checkpoint over each trajectory's rgb/ frames
and caches per-frame .pt observations consumed by the filter steps. Settings
live under predicted_segmentation in scripts/config.json.
./scripts/03_precompute_segmentation_masks.sh
CONFIG=path/to/config.json ./scripts/03_precompute_segmentation_masks.shOutput is written per sequence as segmentation_predicted_best_model_avg/
alongside each trajectory_*/ by default.
Trains the PCA observation embedding used by the UKF. The committed
configs/best_config.json stores the paper hyperparameters and PCA recipe;
the Optuna values come from
VisualTaxiULI/results/optuna_search_20260507_002108/best_config.json.
scripts/config.json stores paths, including the output artifact path.
./scripts/04_train_pca.shOptuna search over UKF + PCA hyperparameters (k, observation/process noise,
downsampling) on the trajectory validation set. Outputs (study db, best_config.json,
PCA cache) go under data/filter_eval/.
./scripts/05_hyperparameter_optimization.sh # quick: 2 trials / 2 trajectories
./scripts/05_hyperparameter_optimization.sh --full_opt # full: 50 trials / 20 trajectoriesRuns the UKF over each trajectory in a split using the PCA artifact from Step 4,
writing calibration_results/raw_calibration_data.json per run under a batch
dir in data/filter_eval/ukf_runs/. Hyperparameters default to
configs/best_config.json and are overridable via flags (--pca_k,
--pca_downsample_factor, --observation_noise_scalar, --process_noise, …).
./scripts/06_filter_eval.sh # quick: first 3 trajectories
./scripts/06_filter_eval.sh --full_eval # all trajectories in the split
./scripts/06_filter_eval.sh --split test # evaluate the test splitPooled multi-trajectory recalibration over a Step 6 batch (defaults to the latest
run). Writes before/after coverage curves + corrected-covariance artifacts under
data/filter_eval/recalibration/.
./scripts/07_calibration_recalibration.sh # uses latest Step 6 batch
./scripts/07_calibration_recalibration.sh --batch-dir /path/to/run_dir # explicit batchAggregates a Step 6 batch (defaults to the latest run) into publication plots and
tables: calibration coverage triptych and error-vs-time figures, plus .tex/.csv
summaries. Figures are written to output/figures/ and tables to output/tables/.
./scripts/08_plots_tables.sh # uses latest Step 6 batch
./scripts/08_plots_tables.sh --batch-dir /path/to/run_dir # explicit batch
./scripts/08_plots_tables.sh --force # regenerate existing outputs