Population calibration report
Alpha-boundary calibration, synthetic control families, ROC / AUC and what the numbers do and do not support.
1. Why calibration is needed
The draft fixes the biological band at α ∈ [0.30, 0.80], but notes that the boundary needs population calibration and that the ROC and confidence intervals of single-trajectory aggregate statistics remain unvalidated. Calibration is not about proving the protocol right — it is about turning those numbers into evidence that can be inspected and contradicted.
2. Correctness first, conclusions second
Three defects in the calibration pipeline would have produced wrong conclusions, so they were fixed before any number was published:
| Defect | Before | After |
|---|---|---|
| Wrong analysis timestamp | utc_now_iso() treated secs/31536000 as a “year”, so the date written into report metadata was wrong | Added Howard Hinnant civil_from_days + iso8601_from_unix, with round-trip tests against the existing days_from_civil |
| One NaN aborted the batch | Three partial_cmp(..).unwrap() sites (α/β sorting, Youden argmax) panicked on dirty data | Unified into sorted_finite(): drop non-finite values before comparing |
| Pseudo ROC | Only the human population was used, defining FPR as “below threshold and above 0.10”; AUC was hardcoded to None | Replaced with a genuine two-sample ROC; without a control group roc = None rather than fabricated |
3. Discriminative power: a real ROC
The score is score(α) = −|α − 0.55|: the closer to the pink-noise centre the more human-like, penalising both the white-noise and brown-noise tails. The negative class is three synthetic attack families:
| Family | Generator | measured mean α | expected |
|---|---|---|---|
iid_levy | i.i.d. truncated-Lévy steps (the §7.3.3 literal generator) | -0.0141 | ≈ 0 |
replay_drift | replayed recording plus linear drift | 1.6370 | ≳ 1.2 |
correlated_gaussian | AR(1) velocity integration | 2.0184 | ≳ 1.0 |
Synthetic baseline (offline, reproducible)
gyid calibrate synth --humans 150 --control 150 --window 256 | AUC | 0.9761 |
| optimal TPR / FPR | 0.9533 / 0.1244 |
| equivalent α decision band | [0.0119, 1.0881] |
| human α mean / median | 0.5001 / 0.4936 |
| biological-band coverage | 55.3% |
Human α quantiles (synthetic baseline)
| P5 | 0.0190 |
| P25 | 0.2791 |
| Median | 0.4936 |
| P75 | 0.7216 |
| P95 | 1.0479 |
4. What these numbers do and do not support
| Claim | Supported |
|---|---|
| α separates structured-Lévy trajectories from the three synthetic attack families | Yes (AUC 0.98 on the synthetic baseline) |
| α separates real humans from adaptive adversaries | No — requires real GeoLife data and iteration in the TRIP-Arena |
| The draft band [0.30, 0.80] fits the Chinese urban population | Open — run the geolife subcommand after downloading the dataset |
| One statistic is enough for high-stakes decisions | No — must be combined with the six-component Hamiltonian |
5. How to reproduce
# Fully offline (no download required)
gyid calibrate synth --humans 150 --control 150 --window 256 --output /tmp/synth.json
gyid calibrate whitepaper --input /tmp/synth.json --output /tmp/synth.md
# Real dataset
tools/calibration/download_geolife.sh
tools/calibration/prepare_dataset.sh --root "tools/calibration/data/GeoLife Trajectories 1.3"
gyid calibrate geolife --data-dir "tools/calibration/data/GeoLife Trajectories 1.3" --control 200 --output /tmp/geolife.json The regression baseline lives in trip-core/tests/calibration_golden.rs and tests/vectors/calibration-vectors.json; regenerating it requires explicitly setting UPDATE_CALIBRATION_VECTORS=1.
6. Future work
- Add MDC (Lausanne) for a cross-population comparison
- Add T-Drive as an occupational-bias reference
- Stratify by mobility pattern (commuter vs. tourist)
- Bootstrap confidence intervals for AUC and α quantiles
- Temporal drift monitoring for seasonal effects