About

Sample, provenance, limitations, and how to regenerate.

The sample

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

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.

WarningNot yet in these figures

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 ≥ 20 because 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_id differs.
  • 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 site

Step 3 alone needs access to anything; steps 4 on are what GitHub Actions runs on every push.