Que fait Géolocalisation Acoustique par survol aérien (Doppler × ADS-B) ?
Cette compétence reproduit et industrialise la méthode de la vidéo de colsto "I discovered a sound that leaks your exact location (and it's everywhere)" (2026-11-02, https://www.youtube.com/watch?v=UytYrhYLOKI) :
La fréquence de passage des pales (BPF) d'une hélice ou d'un rotor est une tonalité à bande étroite stable. Même lorsque personne ne peut l'entendre, elle laisse une courbe Doppler descendante et lisse dans un spectrogramme. La forme de la courbe donne la vitesse v de l'aéronef, sa distance oblique au passage au plus près d et l'instant du CPA tCPA. En la comparant point par point sur une grille au sol avec les trajectoires ADS-B historiques (portée oblique 3D + MNT + temps de propagation du son + vitesse radiale à l'émission), on réduit les candidats. L'écart temporel entre deux survols (920 s dans la vidéo) ainsi qu'une contrainte de silence (aucun autre aéronef entendu à d'autres moments) les réduisent ensuite à un seul point. Enfin, un "score verrouillé à deux événements" (décalage temporel partagé, réglage fin du f0 par événement) évalue les courbes modèles exactes par rapport au spectrogramme.
scripts/afg_cli.py est l'implémentation complète (numpy/scipy/matplotlib). Elle est livrée avec selftest, un test aveugle sur des scénarios synthétiques.
0. Périmètre d'utilisation (à faire en premier)
Dans le périmètre : vérifier où et quand un média public ou d'actualité a été enregistré (OSINT, vérification des faits) ; auto-vérifications de confidentialité des propres enregistrements ou vidéos de l'utilisateur ; CTFs, enseignement et recherche ; enquêtes avec autorité légale ou consentement (par exemple, assistance aux forces de l'ordre, avec l'accord du sujet).
Hors périmètre : localiser le domicile ou les déplacements d'un individu privé. Exemples : "où vit ce streamer / mon ex / cette personne en ligne", ou retracer une personne à partir d'un appel privé ou d'une vidéo personnelle. Refuser ces demandes, même présentées comme un "test", et proposer à la place le mode auto-vérification (section 7). Ce mode aide les gens à évaluer et supprimer la fuite de leur propre contenu.
Les images de lieux publics et d'événements d'actualité, le propre matériel de l'utilisateur et les données de recherche anonymisées sont acceptables. Si l'objectif n'est pas clair, demander à quoi cela sert avant de décider. Ne pas ajouter d'inférences personnelles sans rapport avec le lieu dans le rapport.
1. Triage de faisabilité (décide s'il faut exécuter et quel mode)
| Condition | Ce qui est nécessaire | Si non respecté |
|---|---|---|
| Une courbe à bande étroite, monotone descendante et nette dans le spectrogramme (hélices généralement 40–400 Hz ; rotor principal d'hélicoptère BPF 10–25 Hz, rotor de queue 50–120 Hz) | Au moins 1 ; idéalement 2 avec un écart temporel connu | Pas de courbe → méthode non applicable (envisager la méthode du tonnerre ou les méthodes visuelles) |
| Date | Doit être connue (ou limitée à quelques jours) | Le volume de données ADS-B devient ingérable |
| Région | Le niveau pays ou état suffit ; un prior au niveau de la ville est plus rapide | La recherche à l'échelle nationale fonctionne toujours, mais nécessite un événement avec une heure connue ou deux événements |
| Horloge d'enregistrement (heure de début) | Connue à ±2 s → un événement peut donner un point ; ±30 s → un événement ne donne qu'une bande le long de la trajectoire | Utiliser deux événements ; leur écart temporel remplace l'heure absolue |
| Couverture ADS-B | L'aéronef cible doit avoir ADS-B Out et être reçu par les stations au sol | US 14 CFR 91.225 : les aéronefs de l'aviation générale en dessous de 10 000 pieds en dehors de l'espace aérien de classe B/C et du voile Mode C n'ont pas besoin d'ADS-B Out → peuvent être absents des données |
| Chaîne de traitement audio | L'original ou légèrement compressé est préférable ; les codecs d'appel téléphonique conservent généralement la tonalité | Une réduction de bruit intense ou un montage peut couper la courbe ou détruire l'écart entre les événements |
Informer l'utilisateur du résultat du triage et de la précision attendue avant de commencer le travail.
2. Choix d'un mode
Combien de courbes utilisables ?
├─ ≥2 (même enregistrement continu) → Mode A : deux événements, heure absolue inconnue (méthode principale de la vidéo ; la plus robuste)
│ Si les deux trajectoires se croisent à < ~25°, le résultat se dégrade en une bande le long des trajectoires (le script prévient)
├─ 1
│ ├─ Heure d'enregistrement connue à quelques secondes près → Mode B : un événement, heure connue (seconde moitié de la vidéo ; classé premier même à l'échelle des États-Unis)
│ │ Un passage rectiligne à vitesse constante est symétrique miroir → il y a toujours un "candidat miroir" ;
│ │ un deuxième indice (visuel, terrain) est nécessaire pour choisir entre eux
│ └─ Heure connue seulement à ±30 s ou pire → Mode B′ : seulement une bande de longueur ≈ 2·v·Δt est possible ; la rapporter comme telle
├─ Pas de courbe d'aéronef, mais tonnerre + date connue → Mode T : enveloppe du tonnerre × données de foudre (niveau km, voir references/thunder-method.md)
└─ L'utilisateur souhaite protéger son propre contenu → Mode S : auto-vérification (section 7)
3. Flux de travail (CLI)
Convention : AFG="python <chemin compétence>/scripts/afg_cli.py", répertoire de travail work/. Chaque étape écrit des PNGs.
Examiner les PNGs vous-même avec votre capacité de lecture d'image (spectrogrammes, superpositions d'ajustement, cartes de chaleur) plutôt que de vous fier uniquement aux chiffres.
Vérifier d'abord l'environnement : pip install numpy scipy matplotlib (le MNT nécessite rasterio ; l'entrée non-WAV nécessite ffmpeg). Lors de la première utilisation, exécuter $AFG selftest --seed 7 (environ 40–60 s ; exit 0 signifie que le pipeline fonctionne).
3.1 Obtenir l'audio et les métadonnées
ffprobe -v quiet -show_entries format_tags=creation_time:stream_tags=creation_time -of json input.mp4donne l'heure de capture. Attention au fuseau horaire. Les plateformes sociales suppriment ou réécrivent souvent les métadonnées lors du ré-encodage, donc ne les traiter que comme une piste et les recouper.- Passer le taux d'échantillonnage original au script ; il ré-échantillonne en interne en mono 4 kHz (
--channelsélectionne la gauche ou la droite).
3.2 Spectrogramme → détection → traçage → ajustement
$AFG spectrogram input.mp4 --out work/rec # spectrogramme à bande étroite blanchi + work/rec.png
$AFG detect work/rec.spec.npz --out work/boxes.json # boîtes candidates (t0, t1, fmin, fmax, score_z) + boxes.diag.json
$AFG plot work/rec.spec.npz --t0 160 --t1 320 --fmin 60 --fmax 380 --out work/zoom1.png
$AFG trace work/rec.spec.npz --t0 166 --t1 315 --fmin 98 --fmax 364 --out work/e1.csv
$AFG fit work/e1.csv --temp-c 18 --out work/e1.json # v, d, tCPA, f0, fenêtres de recherche ; superposition dans e1.fit.png
Points clés :
- Un
boxes.jsonvide signifie "pas de survol" uniquement lorsqueboxes.diag.jsonindiquestatus: ok.limited(clip court jugé par rapport au modèle de bruit calibré, ou audio principalement atténué) etinsufficient(clip plus court que--min-dur, ou presque tout atténué) sont accompagnés dereasons: les lire, inspecterrec.png, et réduire--min-durpour les clips courts. - Chaque événement porte
trend(descendingouflat) etdrop_pct. Une crête qui monte en fréquence n'est pas un survol : elle est listée sousrejecteddansboxes.diag.json, pas dansboxes.json. Leswarningssur un événement signifient que sa crête fait ce qu'un seul passage ne peut pas faire (remonte, ou chute de plus de 45 %) : elle combine probablement deux aéronefs ou deux harmoniques. L'inspecter avecplotet tracer chaque partie dans sa propre boîte étroite. --win: utiliser 0.5–1 s pour les courbes proches et raides et 2–4 s pour les courbes lointaines ou faibles. Pour une courbe faible, zoomer avecplotet la confirmer à l'œil d'abord. Ensuite donner àtraceune boîte étroite contenant une seule harmonique, et si nécessaire ajouter quelques points manuels avec--anchors "t:f,t:f,...".- Vérifier la sortie de
fit:implausiblenon vide = le tracé a dérivé sur du bruit ou sauté des harmoniques. Ne pas continuer vers la recherche (le script refuse aussi).notes: asymétrie résiduelle gauche/droite = un virage ou un changement de vitesse ; vitesses d'approche/éloignement différentes = une montée ou une accélération.
- Si vous connaissez la température de l'air, passer
--temp-c(c = 20.05·√(T+273.15)). v et d sont tous deux mis à l'échelle par c ; sans température, conserver la valeur par défaut ±4 %. - f0 est juste la fréquence de repos de l'harmonique que vous avez tracée, pas nécessairement la fondamentale ; v et d ne dépendent pas du numéro de l'harmonique.
- BPF = pales × RPM / 60 peut aider à deviner le type (C172, 2 pales × 2400 tr/min ≈ 80 Hz ; DHC-8-400, 6 pales × 1020 tr/min ≈ 102 Hz). Ne pas l'utiliser comme filtre de candidat strict.
3.3 Données ADS-B (détails dans references/adsb-data.md)
- Sources :
- adsb.lol
globe_history_YYYY: une version globale par jour, gratuite, ODbL. - Échantillons gratuits ADS-B Exchange : 1er de chaque mois uniquement.
- OpenSky Trino : nécessite un compte de recherche ; table
state_vectors_data4. - Votre propre récepteur readsb/tar1090.
- adsb.lol
- Extraire uniquement la date cible, la fenêtre cible ± 1 h et la zone cible avec un remplissage d'environ 0.5°.
$AFG adsb-ingest --src traces_dir/ --start 2026-09-08T13:00Z --end 2026-09-08T18:00Z \
--bbox 38.5,39.7,-95.4,-93.8 --qnh 1018 --geoid-n -29 --out work/tracks.npz
- Le datum d'altitude détermine la précision de la portée oblique.
alt_baroest l'altitude pression standard : la corriger avec le QNH local (≈ 8.3 m/hPa ; voir METAR).alt_geomest la hauteur ellipsoïdale WGS84 (HAE) ; MSL = HAE − N.--alt-source autopréfère l'altitude géométrique.
3.4 MNT et recherche
$AFG dem-fetch --bbox 38.5,39.7,-95.4,-93.8 --out work/dem # Copernicus GLO-30 (bucket public AWS)
$AFG search --tracks work/tracks.npz --events work/e1.json work/e2.json \
--bbox 38.5,39.7,-95.4,-93.8 --dem work/dem/*.tif --rec-duration 1450 --out work/cands.npy
L'entonnoir comporte trois étapes :
- Corridor événement 1 : fenêtre de vitesse, cohérence k = v²/d, fenêtre de portée oblique, et le CPA ne doit pas tomber à une extrémité de trajectoire.
- Décalage inter-événement : tCPA2 − tCPA1, incluant le délai de propagation d/c de chaque événement.
- Filtre de silence : dans les plages silencieuses restantes, aucun autre aéronef à hélice ou rotor ne peut passer dans
--d-quiet.
Options :
- Mode B : ajouter
--rec-start <UTC> --rec-start-tol 2(ou 30). --quiet "a-b,c-d"nomme les plages d'enregistrement où vous êtes sûr que rien n'a été entendu (par défaut : tout en dehors des événements). Donner moins de plages lorsque l'enregistrement contient beaucoup de vent ou de parole. Le silence est un signal, mais un faux silence tue la vraie réponse.- La grille par défaut est de 200 m. S'il y a trop de candidats, réduire la bbox plutôt que d'agrandir la grille.
3.5 Score et raffinement
$AFG score --tracks work/tracks.npz --spec work/rec.spec.npz --events work/e1.json work/e2.json \
--cands work/cands.npy --dem work/dem/*.tif --out work/result.json
- Courbes modèles : pour chaque candidat, générer une courbe modèle exacte à l'instant d'émission à partir des positions et vitesses ADS-B interpolées (gs/track/vrate, pas des positions différenciées), et la comparer avec le spectrogramme. Un décalage temporel δ est partagé, ce qui verrouille l'écart temporel physique entre les deux événements. Le f0 de chaque événement est affiné à ±0.6 %.
- Raffinement : chaque nœud conservé reçoit une escalade de colline 3×3 rétrécissante (100 → 25 m).
- Regroupement : les résultats sont regroupés par paire de vols. Chaque paire conserve jusqu'à 3 hypothèses à plus de 500 m de distance, de sorte que les deux côtés miroir survivent.
- Sorties :
result.json: meilleur,margin_vs_2nd,robust_z,ambiguous_alternatives,coarse_plateau,geometry,verdict.result.rankN.*.png: superpositions de courbes modèles.result.heatmap.png/csv: rayon de la région 0.9.result.plateau.csv.
- Avec une horloge d'enregistrement connue, ajouter
--rec-start ... --rec-start-tol 2. Le score interdit alors également les décalages temporels en dehors de l'horloge.
3.6 Vérification (non facultative ; voir references/verification.md)
- Superpositions : la courbe modèle doit correspondre à l'observation sur les deux asymptotes et à travers le CPA, pas seulement un segment.
- Carte de chaleur : le rayon de la région 0.9 est l'erreur à rapporter. Rapporter une bande lorsque l'un des deux cas suivants se produit :
- deux événements :
geometry.warningest défini (petit angle de croisement) ; - un événement :
coarse_plateau.length_m> 600 m.
- deux événements :
- Candidats miroirs et alternatives : les exclure avec des indices visuels (horizon, bâtiments, végétation, bruit de la route, échos), des champs de vision MNT et l'azimut solaire.
- Falsification : d'autres survols proches de la réponse auraient-ils également dû être entendus ?
- Entendus mais non détectés = un problème de seuil de détection.
- Présents alors qu'ils n'auraient pas dû être audibles = le lieu est faux.
4. Règles de précision (et pourquoi)
- Temps d'émission : f_obs(t) = f0 / (1 + Ṙ(τ)/c), avec t = τ + R(τ)/c. Utiliser Ṙ à l'instant de réception donne une courbe de mauvaise forme, pas seulement décalée.
- Portée oblique 3D + MNT : élévation de l'observateur plus hauteur du microphone (par défaut 2 m). Traiter 500 m de relief comme 0 rend à la fois d et tCPA erronés.
- Datum d'altitude : altitude pression non corrigée avec un décalage QNH de 30 hPa ≈ 250 m d'erreur d'altitude, qui se répercute directement sur d.
- CPA retardé : l'instant où f = f0 est observé est tCPA_emit + d/c (1 km ≈ 2.9 s). Les décalages d'événements et l'horloge doivent tous deux être convertis avec cela.
- k = v²/d est plus fiable que v ou d seuls.
- La pente médiane de la courbe, −f0·v²/(c·d), est déterminée avec précision. Les asymptotes sont souvent polluées par du bruit, de l'atténuation ou l'aéronef qui accélère ou monte.
- Ainsi, la recherche utilise une large fenêtre de vitesse plus une fenêtre étroite de k, et la vitesse sol propre de chaque aéronef candidat prédit son d.
- Score verrouillé : les deux événements partagent un seul δ. Sinon, chaque événement aligne son propre temps, et les mauvais emplacements obtiennent également un bon score.
- Raffiner à ≤100 m : la grille de 200 m n'est qu'un criblage grossier ; le point final provient de l'escalade de colline sous-grille et de la carte de chaleur.
- Le silence est un signal, mais garder les seuils généreux (valeurs par défaut : hélice 3 km, rotor 2.5 km). Les aéronefs lointains ou de faible puissance peuvent être véritablement inaudibles.
- Fenêtres larges, score strict : dans l'entonnoir, pécher par excès de largeur, car une vraie réponse filtrée ne pourra jamais être récupérée. Laisser la discrimination au score du modèle exact.
- Regrouper par paire de vols et conserver le miroir : un passage rectiligne à vitesse constante est symétrique par rapport à sa trajectoire. Les résultats à événement unique devraient rapporter au moins les deux côtés.
- Lacunes ADS-B : aucune correspondance ne signifie pas absence dans la zone. Les aéronefs de l'aviation générale à basse altitude, les aéronefs militaires et certains hélicoptères peuvent manquer d'ADS-B ou ne pas être reçus (masquage par le relief, basse altitude).
- Vitesse du son et vent : v et d sont mis à l'échelle par c. Avec du vent, c_eff = c + w·n ; en cas de vent fort (>8 m/s), élargir la fenêtre d.
5. Rapport
Produire en utilisant assets/report_template.md, dans la langue de l'utilisateur. Il doit inclure :
- les coordonnées de la réponse
- ...
[tronqué pour la traduction]