Skip to content

Latest commit

 

History

History
294 lines (234 loc) · 9.08 KB

File metadata and controls

294 lines (234 loc) · 9.08 KB

Flight Trajectory Prediction

4D flight trajectory prediction (lat, lon, altitude, time) using real-world ADS-B data from the OpenSky Network.
Temporal Transformer trained on 25,000+ real flights over the Paris terminal area (TMA).

Python PyTorch Docker Data


Motivation

Air traffic management systems need to predict where an aircraft will be in the next few minutes - for conflict detection, runway sequencing, and fuel optimization. This project builds a real ML system for that task, trained on actual ADS-B transponder data rather than a packaged benchmark dataset.


Results

The Transformer is compared against a kinematic baseline (constant velocity + heading + vertical rate - what a radar operator would extrapolate by hand):

Horizon Kinematic Baseline Transformer Gain
+1 min 0.80 km (median) 1.14 km -
+2 min 1.60 km 1.93 km -
+3 min 2.93 km 2.69 km −8%
+6 min 12.42 km 4.84 km −61%

Evaluated on 39,289 test windows from 3,835 held-out flights. Haversine error (great-circle distance), median.

ADE / FDE @ 5 min horizon (baseline): ADE = 5.38 km, FDE = 12.60 km

The model underperforms the baseline at short horizons (+1/+2 min), where constant-velocity kinematics is hard to beat. It gains a significant advantage at longer horizons (+6 min), where aircraft maneuvers, phase transitions, and traffic patterns diverge from naive extrapolation.


Dataset

  • Source: OpenSky Network REST API (ADS-B state vectors)
  • Area: Paris TMA bounding box - lat [48.0, 49.5], lon [1.0, 3.5]
  • Collection: 7 days (June 2026), polling every 30s, ~938k raw state vectors
  • After preprocessing: 25,571 clean flights, median duration 13.5 min
Stage Count
Raw state vectors 937,923
Flight segments detected 32,648
After duration filter 25,698
After resample + quality filter 25,571

Architecture

Input sequence (10 × 30s = 5 min context)
12 features per step:
  Δlat, Δlon, Δaltitude          ← displacement deltas
  velocity, vertical_rate         ← kinematic state
  sin(heading), cos(heading)      ← circular heading encoding
  Δheading, velocity_roc          ← rate of change
  phase (climb/cruise/descent)    ← flight phase embedding
  baro_altitude, elapsed_s_norm   ← absolute context
        │
        ▼
Linear projection → d_model=256
        │
        ▼
Learned positional encoding
        │
        ▼
6 × Transformer encoder layers
  (8 heads, FFN dim=1024, GELU, Pre-LN, dropout=0.3)
        │
        ▼
[CLS] token pooling
        │
        ▼
4 × independent prediction heads
  → [Δlat, Δlon, Δalt] at +1/+2/+3/+6 min

4.9M parameters - trained on a T4 GPU (Google Colab), ~82 epochs, early stopping.

Why a Transformer over LSTM?
Self-attention lets every timestep attend to every other directly - no vanishing gradient over long sequences. Empirically outperforms LSTM on trajectory prediction tasks at horizons > 3 min.


Pipeline

OpenSky API (OAuth2)
      │
      ▼
scripts/run_collector.py     ← ADS-B polling, parquet output, budget management
      │
      ▼
src/data/preprocess.py       ← flight segmentation, resample(30s), interpolation
      │
      ▼
src/data/dataset.py          ← sliding windows, feature engineering, normalisation
      │
      ▼
src/models/transformer.py    ← TrajectoryTransformer
      │
      ▼
scripts/train.py             ← AdamW + cosine LR + warmup + early stopping
      │
      ▼
src/eval/baseline.py         ← kinematic baseline + haversine metrics
      │
      ▼
src/serving/api.py           ← FastAPI inference endpoint
      │
      ▼
docs/demo.html               ← live map demo (Leaflet)

Quickstart

Prerequisites

Setup

git clone https://github.com/JeremyMaille/flight-trajectory-prediction.git
cd flight-trajectory-prediction

python3 -m venv .venv
source .venv/bin/activate        # Windows: .venv\Scripts\activate
pip install -r requirements.txt

cp .env.example .env
# Fill in your OpenSky OAuth2 credentials

Collect data

export $(grep -v '^#' .env | xargs)
python scripts/run_collector.py
# Collects ADS-B state vectors every 30s into data/raw/
# Budget: 3500 API credits/day (resets at midnight UTC)

Preprocess

python src/data/preprocess.py
# Segments flights, resamples to 30s grid, engineers features
# Output: data/processed/flights/*.parquet

Evaluate baseline

python src/eval/baseline.py
# Prints kinematic baseline metrics (haversine error, ADE/FDE)

Train (recommended: Google Colab T4)

# Open notebooks/train_colab_v2.ipynb in Colab
# Runtime → Change runtime type → T4 GPU
# Runtime → Run All

Or locally:

python scripts/train.py
mlflow ui   # monitor at http://localhost:5000

Run the API + demo

docker compose up --build
# API available at http://localhost:8000
# Open docs/demo.html in your browser

API

GET  /health              → model status
GET  /flights             → list available flights
GET  /demo/{flight_id}    → fetch a real flight for the demo
POST /predict             → predict future positions

Example prediction request:

curl -X POST http://localhost:8000/predict \
  -H "Content-Type: application/json" \
  -d '{
    "points": [
      {"ts": "2026-06-20T10:00:00Z", "latitude": 48.85, "longitude": 2.35,
       "baro_altitude": 10000, "velocity": 230, "true_track": 90, "vertical_rate": 0},
      ...  // 10 points minimum, ~30s apart
    ]
  }'

Response:

{
  "status": "ok",
  "predictions": [
    {"horizon_label": "+1 min", "pred_latitude": 48.853, "pred_longitude": 2.578, "pred_altitude": 9998},
    {"horizon_label": "+2 min", "pred_latitude": 48.856, "pred_longitude": 2.806, "pred_altitude": 9995},
    {"horizon_label": "+3 min", "pred_latitude": 48.860, "pred_longitude": 3.034, "pred_altitude": 9990},
    {"horizon_label": "+6 min", "pred_latitude": 48.871, "pred_longitude": 3.718, "pred_altitude": 9975}
  ]
}

Limitations & Future Work

  • Short horizons: The kinematic baseline outperforms the model at +1/+2 min. On very short horizons, physics-based extrapolation is hard to beat without a much larger dataset.
  • Data volume: 25k flights over 7 days is a limited training set. Performance would improve significantly with historical data via the OpenSky Trino interface (access requested).
  • Geographic scope: Trained exclusively on the Paris TMA - the model may not generalise to other airspaces without retraining.
  • No intent encoding: The model has no access to flight plan data, which would substantially improve longer-horizon predictions.

Stack

Component Technology
Data collection OpenSky REST API (OAuth2), Python
Data processing pandas, pyarrow, resample/interpolate
ML framework PyTorch 2.x
Model Temporal Transformer (custom)
Experiment tracking MLflow
Serving FastAPI + Uvicorn
Containerisation Docker + docker-compose
Demo Leaflet.js
Training environment Google Colab (T4 GPU)

Project Structure

flight-trajectory-prediction/
├── data/
│   ├── raw/                    # ADS-B parquet files (gitignored)
│   └── processed/flights/      # per-flight parquet (gitignored)
├── docs/
│   └── demo.html               # live map demo
├── models/
│   ├── best_model.pt           # trained checkpoint (gitignored)
│   └── norm_stats.json         # normalisation statistics
├── notebooks/
│   └── train_colab_v2.ipynb    # Colab training notebook (Run All)
├── scripts/
│   ├── run_collector.py        # ADS-B data collector
│   └── train.py                # training entry point
├── src/
│   ├── data/
│   │   ├── preprocess.py       # flight segmentation + resampling
│   │   └── dataset.py          # PyTorch Dataset + feature engineering
│   ├── eval/
│   │   └── baseline.py         # kinematic baseline + metrics
│   ├── models/
│   │   └── transformer.py      # TrajectoryTransformer architecture
│   └── serving/
│       └── api.py              # FastAPI inference service
├── Dockerfile
├── docker-compose.yml
├── requirements.txt
└── .env.example

Author

Jérémy Maille - Ingénieur IA & Machine Learning
CESI École d'Ingénieurs (Bac+5) GitHub · LinkedIn