Skip to content

IPS-Stuttgart/RaFT-UAV

Repository files navigation

RaFT-UAV

Radar-RF Fusion Tracking for UAVs.

This repository contains implementation and evaluation code for tracking UAVs with AERPAW Dataset-28 / Dryad DOI 10.5061/dryad.7d7wm3898. The initial baseline is an asynchronous constant-velocity Kalman fusion tracker built on PyRecEst.

Large datasets and generated bulk artifacts are intentionally not stored in this repository.

Setup

python -m pip install -e ".[dev]"

After installation, prefer the raft-uav console script for experiments. It routes through the canonical tracklet-Viterbi wrapper, registers the tracklet-viterbi radar-association mode, and exposes the wrapper-only --tracklet-* options. Use python -m raft_uav.cli only for legacy base-CLI debugging.

Data Layout

Download and extract the Dryad archive outside git, for example:

data/raw/AADM2025Dryad/
  RF Sensor and Radar/
    <flight>/
      AADM*.csv
      radar_data_*.json
      date_time_vehicleOut.txt

The loader starts with the RF Sensor and Radar folder because it contains the modalities needed for the tracking work.

First Commands

Inspect available flights:

raft-uav inspect data/raw/AADM2025Dryad

Run the canonical range-covariance tracklet-Viterbi fusion baseline on one flight:

raft-uav run-baseline data/raw/AADM2025Dryad \
  --flight Opt2 \
  --radar-association tracklet-viterbi \
  --tracklet-variant range-covariance

For a maneuver-aware replay of the same association path, add --tracklet-replay-tracker imm. For a strictly legacy CV/catProb baseline, spell it out explicitly:

raft-uav run-baseline data/raw/AADM2025Dryad --flight Opt2 --radar-association catprob

Run the normalized-innovation-squared gated baseline on one flight:

raft-uav run-baseline data/raw/AADM2025Dryad --flight Opt2 --enable-gating --rf-gate-prob 0.99 --radar-gate-prob 0.99

Run the soft NIS covariance-inflation baseline on one flight:

raft-uav run-baseline data/raw/AADM2025Dryad --flight Opt2 --robust-update nis-inflate --rf-gate-prob 0.99 --radar-gate-prob 0.99

Tune source-specific inflation strength:

raft-uav run-baseline data/raw/AADM2025Dryad --flight Opt2 --robust-update nis-inflate --rf-inflation-alpha 1.5 --radar-inflation-alpha 0.5

Run the Opt1-Opt3 source-specific inflation grid:

python scripts/run_source_specific_inflation_grid.py data/raw/AADM2025Dryad

Run the Opt1-Opt3 radar association ablation:

python scripts/run_radar_association_ablation.py data/raw/AADM2025Dryad

Run the Opt1-Opt3 smoothing ablation:

python scripts/run_smoothing_ablation.py data/raw/AADM2025Dryad

Analyze online radar association against the diagnostic oracle on Opt1:

python scripts/analyze_association_failures.py data/raw/AADM2025Dryad --flight Opt1

Calibrate residual RF/radar time offsets on training flights, then apply the held-out offsets explicitly in the baseline run:

raft-uav-lofo-time-offset data/raw/AADM2025Dryad \
  --flight Opt1 --flight Opt2 --flight Opt3 \
  --output-dir outputs/lofo_time_offset

python -m raft_uav.cli run-baseline data/raw/AADM2025Dryad \
  --flight Opt2 \
  --rf-time-offset-correction-s <rf_offset_s_from_train_folds> \
  --radar-time-offset-correction-s <radar_offset_s_from_train_folds>

The loader-level --rf-clock-offset-s and --radar-clock-offset-s arguments control conversion from raw sensor timestamps to the truth timeline. The --*-time-offset-correction-s arguments are residual calibrated corrections applied after normalization, which matches the output convention of raft-uav-lofo-time-offset.

Build a paper-style comparison table with the paper-compatible hard-gated fusion row:

raft-uav-diagnose-paper-table data/raw/AADM2025Dryad \
  --flight Opt1 \
  --fusion-association paper-compatible \
  --stable-segment-min-frames 100 \
  --stable-segment-max-transition-speed-mps 65

By default, raft-uav-diagnose-paper-table emits unsmoothed paper-table fusion rows. Pass --include-smoothed-fusion only when fixed-lag rows are desired as offline enhancement diagnostics.

Run the strict Table-II parity diagnostic. This path uses a 95% chi-square NIS gate, disables catProb by default, requires Fortem range_m for the 800 m radar gate, estimates RF/radar covariances from truth residuals, evaluates errors at measurement/output timestamps, and bootstraps the Kalman filter from the selected radar track rather than the first RF row:

raft-uav-paper-strict data/raw/AADM2025Dryad \
  --flight Opt1 \
  --origin-config config/origins.toml \
  --variant rerun \
  --count-mismatch-action fail \
  --output-dir outputs/paper-strict

Create config/origins.toml from config/origins.example.toml and fill in the LW1 coordinates before running strict paper-parity reproduction.

Before comparing algorithms against Table II, run the count-fingerprint audit. It writes the RF/radar/KF stage counts, file paths, and count deltas against the published reference rows so wrong flight variants, timestamp normalization, or range-gate semantics show up before tuning starts:

raft-uav-paper-fingerprint data/raw/AADM2025Dryad \
  --flight Opt1 \
  --origin-config config/origins.toml \
  --variant rerun \
  --output-dir outputs/paper-fingerprint

When the paper-reference counts still do not match, enumerate both likely file variants and the radar-track selection-order ambiguity before changing tracker parameters. The summary CSV is ranked by absolute count delta, so the top row is the best paper-fingerprint candidate for a subsequent raft-uav-paper-strict run:

raft-uav-paper-fingerprint data/raw/AADM2025Dryad \
  --flight Opt1 \
  --origin-config config/origins.toml \
  --enumerate-file-variants \
  --enumerate-radar-track-selection-orders \
  --output-dir outputs/paper-fingerprint-grid

For LW1-origin reproduction, pass the origin explicitly because the coordinates are not hard-coded in the repository:

raft-uav-paper-strict data/raw/AADM2025Dryad \
  --flight Opt1 \
  --enu-origin lw1 \
  --lw1-origin-lla <LAT>,<LON>,<ALT>  # or set RAFT_UAV_LW1_ORIGIN_LLA

Paper-parity commands persist the selected RF/radar/truth filenames, variants, sizes, SHA-256 digests, and ENU origin in their manifests. Use --variant original or --variant rerun when reproducing a specific Opt1 file choice; --variant auto keeps the historical behavior of preferring rerun files when present. The example config/origins.example.toml intentionally contains a 0,0,0 placeholder and strict paper diagnostics reject it until the actual LW1 origin is supplied.

Run the same paper-compatible hard-preselector path directly through the baseline runner, so the output artifacts are comparable with other run-baseline rows:

raft-uav run-baseline data/raw/AADM2025Dryad \
  --flight Opt1 \
  --radar-association paper-compatible \
  --paper-compatible-bootstrap-source radar \
  --stable-segment-range-gate-m 800 \
  --smoother fixed-lag --smoother-lag-s 20

For a deliberate catProb ablation of the paper-compatible path, use --paper-compatible-catprob-threshold <value>. The generic --radar-catprob-threshold continues to configure legacy catProb and non-paper association modes, but it does not affect paper-compatible parity runs.

The paper-compatible fusion path applies an 800 m radar range gate, radar bootstrap by default, optional radar class-probability thresholding, NIS gates for RF/radar updates, and records a radar missed_detection posterior when no radar candidate passes the hard preselector. The table also includes stable range-gated radar segment rows, including an interpolated full-frame diagnostic, to separate clean radar coverage from long-gap fill behavior. The stable-segment knobs control how long a same-track run must be before it is trusted and how aggressively separate segments may be stitched across radar ID changes.

Run the Opt1-Opt3 radar candidate class-probability threshold ablation:

python scripts/run_candidate_threshold_ablation.py data/raw/AADM2025Dryad --thresholds 0.4 0.5

Sweep the stable radar segment diagnostic without running fusion or oracle rows:

python scripts/run_stable_radar_segment_ablation.py data/raw/AADM2025Dryad \
  --min-segment-frames 75 100 150 \
  --max-transition-speeds-mps 35 65 100

The script writes per-flight rows plus aggregate rows to the summary CSV, and a separate ranking CSV next to it for quickly identifying the best knob setting. Ranking defaults to --ranking-min-coverage 0.95, so low-coverage rows remain visible but are not treated as recommendation-eligible. Ranking rows also include coverage-penalized error columns and a Pareto-front flag for comparing coverage/error tradeoffs. A compact recommendation JSON is written next to the summary and ranking CSVs for workflow and paper-note automation.

Run the Opt1-Opt3 PDA-mixture association ablation:

python scripts/run_pda_association_ablation.py data/raw/AADM2025Dryad

Run the Opt1-Opt3 PyRecEst MHT track-bank ablation:

python scripts/run_track_bank_ablation.py data/raw/AADM2025Dryad

Run the current best non-oracle preset on one flight:

raft-uav-best-non-oracle data/raw/AADM2025Dryad --flight Opt2

Run the integrated result-improvement suite. This executes the leakage-safe calibration/tuning/evaluation workflow used for result-oriented development: LOFO time-offset calibration, LOFO radar covariance tuning, nested LOFO tuning, leave-flight-out SOTA evaluation, oracle-gap diagnostics, and constrained leaderboard ranking.

raft-uav-result-improvement-suite data/raw/AADM2025Dryad \
  --flights Opt1 Opt2 Opt3 \
  --skip-existing

Use --dry-run to write the manifest and print the exact commands without executing them.

The preset expands to range-covariance tracklet-Viterbi association, IMM replay, Student-t robust updates, and 20-second fixed-lag RTS smoothing. It deliberately does not use truth-gated or nearest-truth radar association; truth is used only for the same post-run metrics already produced by run-baseline.

The first baseline is deliberately conservative. It is meant to reproduce the published constant-velocity Kalman fusion setup before adding robust gating, learned sensor uncertainties, maneuvering models, and smoothing.

Baseline runs write gitignored per-flight artifacts under outputs/baseline/:

  • estimates.csv
  • diagnostics.csv
  • selected_radar.csv
  • metrics.json
  • trajectory.png

Radar JSON frames contain many Fortem trackData entries. The lower-level base-CLI default remains --radar-association catprob, which keeps radar rows whose UAV class probability catProb[0] is at least 0.5. For result-oriented reproduction runs, prefer the explicit tracklet-Viterbi path:

raft-uav run-baseline data/raw/AADM2025Dryad \
  --flight Opt2 \
  --radar-association tracklet-viterbi \
  --tracklet-variant range-covariance

The installed wrapper defaults the tracklet implementation to range-covariance when tracklet-viterbi is selected, but commands in this README spell it out to avoid accidental regressions to the base dispatcher. Use --radar-association oracle-nearest-truth only as a diagnostic upper bound because it uses ground truth. The online alternatives are --radar-association prediction-nis, --radar-association track-continuity, --radar-association paper-compatible, which applies hard range/catProb/NIS validation with radar coasting, and the experimental --radar-association geometry-score mode, which adds velocity consistency, track-switch, and UAV class-probability terms to the NIS score. The paper-reproduction-oriented --radar-association paper-largest-continuous-track mode applies the configured radar range gate, defaults to 800 m via --stable-segment-range-gate-m, and keeps the longest continuous Fortem track_id segment without class-probability scoring or segment stitching. The experimental --radar-association pda-mixture mode keeps multiple candidates inside one radar update by using NIS/class-probability weights and adding the candidate spread to the measurement covariance. The experimental --radar-association track-bank mode uses PyRecEst's MultiHypothesisTracker to keep multiple single-UAV association hypotheses alive across radar frames. Baseline runs also write hypotheses.csv for modes that expose per-hypothesis diagnostics. Legacy --radar-selection modes are retained for schema debugging and reproducibility; use --radar-selection catprob-all only to reproduce the historical behavior that feeds every above-threshold radar candidate in a frame into the single-target filter.

Use --smoother fixed-lag --smoother-lag-s 20 to apply a 20-second RTS fixed-lag pass before metrics and plots are written. --smoother rts runs the full offline RTS smoother and is mainly useful as an upper-bound diagnostic.

The IMM runner supports the same post-filter smoothing switches, so online IMM, bounded-latency IMM, and offline upper-bound IMM rows can be compared directly:

raft-uav-imm data/raw/AADM2025Dryad --flight Opt2 --tracker imm

raft-uav-imm data/raw/AADM2025Dryad --flight Opt2 --tracker imm \
  --smoother fixed-lag --smoother-lag-s 20

raft-uav-imm data/raw/AADM2025Dryad --flight Opt2 --tracker imm \
  --smoother rts

Run the leave-one-flight-out SOTA protocol with the explicit online/fixed-lag/RTS IMM rows and the current best non-oracle tracklet replay row:

python scripts/run_leave_flight_out_sota.py data/raw/AADM2025Dryad \
  --methods cv_catprob imm_catprob imm_catprob_fixed_lag imm_catprob_rts \
  imm_tracklet_viterbi_fixed_lag

For the leakage-safe calibrated heteroscedastic CV row, use:

python scripts/run_leave_flight_out_sota.py data/raw/AADM2025Dryad \
  --methods hetero_cv_lofo_nis_fixed_lag

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors