| period | days | state vectors | ground-truth flights | |
|---|---|---|---|---|
| 0 | 2026 | 5–7 June 2026 | 153,407,259 | 93,150 |
| 1 | 2025 | 5–7 June 2025 | 142,943,290 | 92,338 |
| 2 | 2024 | 5–7 June 2024 | 137,655,927 | 90,167 |
About
Sample, provenance, limitations, and how to regenerate.
The sample
Three days, same month, three years running: isolates growth from reception’s seasonal swings (foliage, propagation, traffic, summer schedule) that June-to-February would confound.
Segmentation is the A8 recommended rule: group on icao24, break on a genuine callsign change, lookback bounded to the gap threshold. Ground truth is the Network Manager table, cross-checked against APDF where available.
Provenance
One row per file: job, commit, time produced. A file with no entry is unverified, not fact.
| output | script | git_sha | dirty | produced_utc | rows | |
|---|---|---|---|---|---|---|
| 0 | airport_stats_2024.csv | scripts/aggregate.py | c76d97e | True | 2026-08-28T15:59:31+00:00 | |
| 1 | airport_stats_2025.csv | scripts/aggregate.py | c76d97e | True | 2026-08-28T15:59:22+00:00 | |
| 2 | airport_stats_2026.csv | scripts/aggregate.py | c76d97e | True | 2026-08-28T15:59:12+00:00 | |
| 3 | airport_stats_9999.csv | scripts/aggregate.py | 83aa8cd | True | 2026-08-27T16:20:10+00:00 | |
| 4 | example_tracks_2026.parquet | scripts/run_examples.py | 6d8af1a | False | 2026-08-28T07:40:08+00:00 | |
| 5 | flight_offsets_2024.parquet | scripts/run_offsets.py | 8077c4a | False | 2026-08-28T13:37:24+00:00 | 90167 |
| 6 | flight_offsets_2025.parquet | scripts/run_offsets.py | 8077c4a | False | 2026-08-28T13:17:48+00:00 | 92338 |
| 7 | flight_offsets_2026.parquet | scripts/run_offsets.py | 8077c4a | False | 2026-08-28T13:09:56+00:00 | 93150 |
| 8 | h3_cells_2024.parquet | scripts/run_h3.py | 6d8af1a | False | 2026-08-28T00:50:17+00:00 | |
| 9 | h3_cells_2025.parquet | scripts/run_h3.py | 6d8af1a | False | 2026-08-28T00:48:53+00:00 | |
| 10 | h3_cells_2026.parquet | scripts/run_h3.py | 6d8af1a | False | 2026-08-28T00:47:30+00:00 | |
| 11 | ranking_tier_a_2024.csv | scripts/aggregate.py | c76d97e | True | 2026-08-28T15:59:31+00:00 | |
| 12 | ranking_tier_a_2025.csv | scripts/aggregate.py | c76d97e | True | 2026-08-28T15:59:22+00:00 | |
| 13 | ranking_tier_a_2026.csv | scripts/aggregate.py | c76d97e | True | 2026-08-28T15:59:12+00:00 | |
| 14 | ranking_tier_a_9999.csv | scripts/aggregate.py | 83aa8cd | True | 2026-08-27T16:20:10+00:00 | |
| 15 | ranking_tier_b_2024.csv | scripts/aggregate.py | c76d97e | True | 2026-08-28T15:59:31+00:00 | |
| 16 | ranking_tier_b_2025.csv | scripts/aggregate.py | c76d97e | True | 2026-08-28T15:59:22+00:00 | |
| 17 | ranking_tier_b_2026.csv | scripts/aggregate.py | c76d97e | True | 2026-08-28T15:59:12+00:00 | |
| 18 | ranking_tier_b_9999.csv | scripts/aggregate.py | 83aa8cd | True | 2026-08-27T16:20:10+00:00 |
This matters more than in a report that re-runs its own analysis: the site renders offline, exactly when a stale CSV renders cleanly and says nothing about being stale.
What changed
The coverage measure changed: it used to be reach, how far before take-off a track’s first report lay, letting one stand report count as full coverage. It is now continuity: the ground phase cut into 30-second slices, each asked whether anything was heard.
Every number changed; the versions aren’t comparable. Reach is still in the CSVs as dep_reach_p50/arr_reach_p50.
A report with no latitude and longitude no longer counts. Position rides in its own message type, so a row can name the aircraft and say nothing about where it was. Counting those gave Istanbul a positive land_s at an aerodrome receiving nothing from its surface. They are dropped before tracks are cut.
2026, 2025, 2024 predate the filter: their land_s and signal figures still count reports with no position.
Limitations
Each bounds a claim the site makes.
- Nine days in total, three per period. Cleaned tracks exist only for these days (quota’d bucket, ~10 GB/period); the estimated tail is cut at
n_gt ≥ 20because a percentile over a handful of flights is noise. - June only. Says nothing about winter reception.
- A8 is not the segmentation any published OPDI dataset used. opdi’s default only since 2026-08-27; earlier data uses the legacy rule, so these numbers don’t match downloadable OPDI, and
track_iddiffers. - Coverage means receiver coverage as OPDI ingests it: after the bounding-box filter, 5 s decimation and the position filter, not OpenSky’s denser raw feed. Dropping position-less reports can also split a track, since tracks are cut on time gaps those reports used to bridge.
- Estimated take-off times are inferred, at a Europe-wide median error of 0 s, IQR 17 s; unusual taxi behaviour at one aerodrome could exceed that.
- A flight bound for a non-European destination has no measurable arrival. Its track ends where receiver coverage does (median six hours before landing), counted only at departure.
- Continuity is measured in 30-second bins, so shorter gaps are invisible. A receiver dropping every other message still fills its bins, so 1.00 means no half-minute unheard, not a perfect rate.
- Segmentation errors bias reach both ways (0.8% merged vs 8.2% fragmented, 2025): a merged track’s clips to 1.0, a fragmented one’s is understated. Reach appears on no page. Continuity, counting observations in a fixed window, is far less exposed.
- Aerodromes outside the ingestion bounding box are excluded entirely, not ranked last: never sampled, so detection would measure the box, not the network.
Regenerating
# 1. Ground truth for a month -- WORK LAPTOP ONLY, needs PRISME/ROracle
Rscript scripts/fetch_reference.R 2026-06 --days 05,06,07
# 2. Mirror it to S3 so cluster executors can read it (in the opdi checkout)
python benchmarks/mirror_reference.py --include '*_202606.parquet'
# 3. Per-flight offsets -- cluster, tens of minutes, ONE period at a time
python scripts/run_offsets.py --period 2026
# 4. Everything below here is offline and needs no credentials
python scripts/aggregate.py
python scripts/gen_pages.py
quarto render siteStep 3 alone needs access to anything; steps 4 on are what GitHub Actions runs on every push.