Traduction automatique, non relue par un locuteur natif. L'anglais fait foi.

Confiance du récepteur et maritimeModifier sur GitHubSource : docs/INTERFERENCE-MAP.md

Carte des interférences et exposition d'un itinéraire

kshana interference-map construit, jour par jour, une image des endroits où des aéronefs et des navires ont signalé des données de navigation dégradées, à partir de fichiers de suivi sous licence ouverte que vous fournissez. kshana route-exposure indique ensuite quelle part d'un itinéraire prévu se trouvait dans les cellules touchées chaque jour.

Ce que c'est : une description de l'aspect qu'avaient les comptes rendus de position publiés lors de jours passés. Ce que ce n'est pas : une mesure d'un récepteur quelconque, une prévision, ni la preuve d'une interférence. Une cellule dégradée ou anormale a plusieurs causes possibles (énumérées ci-dessous), et une cellule sans entrée n'a tout simplement pas été observée.

Tout s'exécute sur des fichiers locaux. Les commandes par défaut n'ouvrent jamais de connexion réseau ; l'unique assistant de téléchargement facultatif exige un indicateur explicite.

Deux jours synthétiques de carte d'interférence, tirés des échantillons versionnés dans examples/interference-map/output, chacun avec son propre itinéraire synthétique et les parts d'exposition d'itinéraire que le moteur rapporte. À gauche, un jour ADS-B : 1 cellule dégradée, 6 non dégradées, 4 non évaluées (hachurées) et des cellules sans entrée, dessinées vides, qui n'ont pas été observées. L'itinéraire fait 525 km : 11,5 % de sa longueur dans des cellules dégradées, 38,3 % non dégradées, 9,1 % non évaluées et 41,1 % non observées. À droite, un jour AIS : cellules signalées par les détecteurs de cercle et de terre, cellules non anormales et cellules vides ; l'itinéraire fait 454 km avec 10,5 % dans des cellules anormales, 21,2 % non anormales, 0,0 % non évaluées et 68,3 % non observées. L'ADS-B et l'AIS sont des couches distinctes, jamais combinées. Une cellule signalée n'est pas un constat d'interférence, et une cellule sans couleur n'a pas été observée, ce qui n'est pas la même chose que dégagée. Toutes les données sont inventées, en plein milieu de l'Atlantique, et ne sont pas une mesure.Deux jours synthétiques de carte d'interférence, tirés des échantillons versionnés dans examples/interference-map/output, chacun avec son propre itinéraire synthétique et les parts d'exposition d'itinéraire que le moteur rapporte. À gauche, un jour ADS-B : 1 cellule dégradée, 6 non dégradées, 4 non évaluées (hachurées) et des cellules sans entrée, dessinées vides, qui n'ont pas été observées. L'itinéraire fait 525 km : 11,5 % de sa longueur dans des cellules dégradées, 38,3 % non dégradées, 9,1 % non évaluées et 41,1 % non observées. À droite, un jour AIS : cellules signalées par les détecteurs de cercle et de terre, cellules non anormales et cellules vides ; l'itinéraire fait 454 km avec 10,5 % dans des cellules anormales, 21,2 % non anormales, 0,0 % non évaluées et 68,3 % non observées. L'ADS-B et l'AIS sont des couches distinctes, jamais combinées. Une cellule signalée n'est pas un constat d'interférence, et une cellule sans couleur n'a pas été observée, ce qui n'est pas la même chose que dégagée. Toutes les données sont inventées, en plein milieu de l'Atlantique, et ne sont pas une mesure.

Les deux jours sont les échantillons synthétiques de examples/interference-map/output/, chacun avec un itinéraire synthétique dans examples/interference-map/input/ ; les parts d'exposition d'itinéraire sont ce que kshana route-exposure affiche pour eux. Rien dans ces données n'est un lieu, un aéronef ou un navire réel.

Données et licences#

Seules les sources examinées dans data/INTERFERENCE-DATA-SOURCES.md sont intégrées, sélectionnées avec --dataset :

--dataset Type Licence Champ de licence de sortie
adsb-lol ADS-B ODbL 1,0 ODbL-1.0
noaa-marinecadastre AIS Domaine public américain (CC0 1,0 selon l'éditeur) domaine public
kystverket AIS NLOD 2,0 NLOD-2.0
custom l'un ou l'autre ce que vous indiquez --licence, --licence-url, --attribution requis

Chaque fichier de sortie intègre la licence, l'URL de la licence, l'attribution requise et les limites de couverture de la source. Il n'existe aucune entrée intégrée pour les sources dont les conditions interdisent l'usage commercial ou la redistribution des cartes dérivées.

ODbL et éditions de Kshana. Un fichier ADS-B par cellule produit à partir des données d'adsb.lol est une Derived Database et est diffusé sous ODbL 1,0 ; son champ licence l'indique. Le code propre de Kshana reste sous AGPL-3.0. Les éditions commerciales de Kshana qui écrivent de tels fichiers portent la même mention, et quiconque republie le fichier doit la conserver. Les résultats ADS-B et AIS ne sont jamais combinés dans un même fichier, de sorte que l'ODbL ne s'applique pas à la couche AIS.

Biais de couverture. Les cartes héritent de la couverture de leur source. adsb.lol s'appuie sur des récepteurs bénévoles, de sorte que la haute mer et les régions peu couvertes sont clairsemées. Les données ouvertes de Kystverket omettent les navires de pêche de moins de 15 m et les embarcations de plaisance de moins de 45 m, de sorte que sa carte reflète les grands navires. MarineCadastre ne couvre que les eaux américaines.

Identifiants. Les lignes d'entrée portent un identifiant d'aéronef ou de navire. Il est haché en mémoire avec un sel aléatoire propre à chaque exécution, utilisé uniquement pour compter les aéronefs ou navires distincts, et jamais écrit, journalisé ni affiché. Les sorties sont agrégées : aucun identifiant n'y figure nulle part.

Suppression. Une cellule comptant moins de 5 aéronefs ou navires distincts observés ce jour-là n'est pas publiée du tout, et pour l'AIS un nombre de signalements de un ou deux dans une cellule publiée est rapporté comme null. Aucune valeur publiée ne peut désigner un aéronef ou un navire en particulier.

Formats d'entrée#

CSV simple avec une ligne d'en-tête, séparé par des virgules, sans guillemets, heures en UTC. L'ordre des colonnes est libre ; les colonnes inconnues sont ignorées. Un horodatage est en secondes Unix ou YYYY-MM-DDTHH:MM:SS[.fff]Z. Les lignes qui ne peuvent pas être analysées sont comptées dans les métadonnées de sortie, et non écartées silencieusement.

ADS-B (kshana interference-map adsb) :

Colonne Requis Signification
timestamp oui heure du compte rendu
aircraft_id oui identifiant opaque (haché, jamais stocké)
lat, lon oui degrés
alt_baro_ft oui altitude en pieds ; ground ou vide exclut la ligne
nic, nacp au moins un entiers de 0 à 11 ; vide signifie non rapporté
source_type non si présente, seules les valeurs commençant par adsb sont utilisées (MLAT, TIS-B et similaires sont exclues)

Historique readsb d'adsb.lol, lu directement. Les archives quotidiennes sont un tar découpé de fichiers de trace readsb. Extrayez-en une comme le décrit l'éditeur (concaténer les parties, tar -xf -), puis donnez à Kshana le répertoire extrait, un seul fichier trace_full_*.json, ou un CSV :

kshana interference-map adsb extracted-day/ --dataset adsb-lol --out maps/

Un répertoire est parcouru récursivement à la recherche de fichiers trace_full_* (les autres fichiers, tels que trace_recent_*, sont ignorés et les liens symboliques ne sont pas suivis). Chaque fichier est compressé en gzip ou en JSON brut, détecté par ses premiers octets, car readsb écrit du gzip sous un nom .json ; la décompression est plafonnée à 512 MiB par fichier. Dans chaque entrée de trace, Kshana lit le décalage temporel, la latitude, la longitude, l'altitude (le marqueur ground exclut l'entrée), les champs nic et nac_p de l'objet de détails de l'aéronef, et la chaîne de source de position (les entrées provenant d'autre chose que l'ADS-B sont exclues). Une entrée sans objet de détails n'a pas de champs de précision et est comptée comme exclue. Un fichier qui ne peut pas être lu est compté dans trace_files_unreadable dans les métadonnées de sortie et ignoré.

AIS (kshana interference-map ais) :

Colonne Requis Signification
timestamp oui heure du compte rendu
vessel_id oui identifiant opaque (haché, jamais stocké)
lat, lon oui degrés ; les valeurs AIS « non disponible » et (0, 0) sont écartées
sog_kn non vitesse sur le fond en nœuds ; 102,3 (non disponible) est traitée comme manquante

Le détecteur de position à terre a besoin d'un fichier de polygones de terres (--land) : GeoJSON Polygon ou MultiPolygon. La couche de terres Natural Earth au 1:10 million (domaine public) est le fichier prévu. Sans --land, le détecteur est désactivé et la sortie le dit. Pour le télécharger (le seul accès réseau de cette fonctionnalité) :

kshana interference-map fetch-land --out ne_10m_land.geojson --allow-network

Cela exécute le curl du système (comme liste d'arguments, et non via un interpréteur de commandes) en HTTPS, une seule fois, pour un seul fichier à une adresse fixe qui désigne un unique commit du dépôt amont. Le téléchargement n'est conservé que si son SHA-256 est égal à la valeur figée dans le code ; en cas de différence, il est supprimé et la commande échoue. Si curl n'est pas installé, la commande le dit et donne l'adresse et la somme de contrôle afin que le fichier puisse être récupéré à la main. Rien n'est livré avec le dépôt.

Sortie#

Un fichier GeoJSON par source et par jour UTC, dans le répertoire --out, nommé <source>-<dataset>-<YYYY-MM-DD>.geojson, où <source> est adsb ou ais, <dataset> est la clé --dataset (adsb-lol, noaa-marinecadastre, kystverket ou custom) et la date est le jour UTC des comptes rendus : adsb-adsb-lol-2026-03-01.geojson, ais-kystverket-2026-03-01.geojson. Le jeu de données figure dans le nom pour que deux jeux de données d'un même type ne puissent pas partager un fichier, et Kshana n'écrase jamais un fichier : si une cible existe, la commande échoue avant d'écrire quoi que ce soit. La CLI affiche une ligne par fichier écrit. Un lecteur peut retrouver les trois parties avec ^(adsb|ais)-(.+)-(\d{4}-\d{2}-\d{2})\.geojson$ ; la même information figure dans le fichier (source_kind, data.dataset, date). Des fichiers d'exemple synthétiques, un par source, se trouvent dans examples/interference-map/output/, avec la commande qui les régénère, pour construire et tester un visualiseur. Un membre de premier niveau kshana_interference_map contient le nom du schéma, la date, la grille, l'identifiant de méthode et chaque paramètre, les chiffres au niveau du jour, la licence des données et l'attribution, et un avis. Chaque entité est un polygone de cellule avec cell_i, cell_j, status, degraded et les comptes agrégés.

La grille est fixe : des cellules carrées de --cell-deg degrés (par défaut 0,5) en latitude et en longitude, indexées à partir de (-90, -180). La largeur est-ouest diminue avec la latitude : environ 55 km à l'équateur et environ 28 km à 60 degrés pour la valeur par défaut. La latitude 90 appartient à la dernière rangée et la longitude 180 est le même méridien que -180. Les méthodes préenregistrées sont définies sur la grille de 0,5 degré. Un autre --cell-deg s'exécute, mais n'est pas la méthode préenregistrée : la CLI le dit, et le fichier enregistre grid.preregistered_cell_deg et grid.is_preregistered (faux) afin qu'un visualiseur puisse le dire aussi.

Comptes retenus. Tout compte par cellule inférieur au minimum de publication (5) est null, zéro compris, de sorte que null ne signifie jamais « aucun » et qu'aucun nombre publié ne peut désigner un aéronef ou un navire en particulier. Les champs status et degraded sont tout de même fournis. Dans les fichiers ADS-B, aircraft_observed est toujours d'au moins 5 pour une cellule publiée ; aircraft_sampled et aircraft_affected valent null en dessous de 5, et affected_share vaut null sauf si les deux sont d'au moins 5 (une part révélerait un compte retenu). Dans les fichiers AIS, chaque entrée de vessels_flagged vaut null en dessous de 5.

Version du format et champs#

Le format est arrêté comme schema: "kshana-interference-map/v1", format_version: 1. Une modification qui supprime ou renomme un champ, ou change son sens, fait monter la version ; l'ajout d'un champ ne le fait pas, de sorte qu'un lecteur doit ignorer les champs qu'il ne connaît pas. Un compte qui vaut null est retenu, et non nul.

FeatureCollection
  kshana_interference_map
    schema, format_version, kshana_version, notice
    source_kind            "adsb" | "ais"
    date                   "YYYY-MM-DD" (UTC)
    grid                   { type: "fixed_lat_lon", cell_deg, preregistered_cell_deg, is_preregistered }
    method                 { id, summary, parameters{...}, guards[], input_stats{...}, caveats[] }
    day                    day-level figures (ADS-B: background_evaluated, background_share,
                           day_confounded, cells_published, cells_suppressed_below_min_distinct;
                           AIS: on_land_detector, cells_published, cells_suppressed_...)
    data                   { dataset, name, licence, licence_url, attribution, coverage_notes[] }
  features[]               Polygon (one closed ring, [lon, lat], counter-clockwise)
    properties             cell_i, cell_j, status, degraded,
                           ADS-B: aircraft_observed, aircraft_sampled|null, aircraft_affected|null,
                                  affected_share|null
                           AIS:   vessels_observed, vessels_flagged{detector: n|null}, detectors[]

Valeurs de status : ADS-B degraded, not_degraded, insufficient_sample, withheld_day_confounded, withheld_no_background ; AIS anomalous, not_anomalous. degraded est vrai pour degraded et anomalous uniquement. Le rapport d'exposition d'itinéraire a son propre schéma kshana-route-exposure/v1.

Observatoire : le produit quotidien#

kshana interference-map daily transforme un jour UTC de comptes rendus ADS-B en les trois fichiers de l'observatoire (GeoJSON, PNG et un JSON de rapport d'incident) et un manifeste de hachages, et kshana interference-map sensitivity rejoue ce jour avec des modifications, une à la fois, des paramètres préenregistrés. La commande applique les règles de publication : au moins 24 h après la fin du jour (--delay-hours ne peut qu'être augmenté), des cellules de 0,5 degré ou plus grossières, trois états seulement (degraded, not_degraded, not_observed), aucune cause attribuée, et aucune donnée OpenSky. La note de méthode, les formats de fichier et les limites se trouvent dans observatory/METHOD.md. Une exécution régionale (--bbox south,west,north,east) ne lit que les comptes rendus de la zone et le dit dans le fichier.

Spécification de la page de carte du Studio#

Pour la page de carte du Studio, qui charge un fichier GeoJSON fourni par l'utilisateur (la page est construite dans les sources du Studio, et non dans ce dépôt). Rien n'est téléversé : le fichier est lu dans le navigateur, et la page n'envoie aucune requête vers une source de données.

Lecture d'un fichier. N'accepter un fichier que si kshana_interference_map.schema commence par kshana-interference-map/ et que format_version est un nombre pris en charge par la page ; sinon, indiquer que le fichier n'est pas une carte d'interférence Kshana prise en charge. Lire les champs énumérés ci-dessus ; ignorer les champs inconnus. Un fichier contient une source et un jour. Plusieurs fichiers peuvent être chargés.

Cellules. Dessiner le polygone de chaque entité. Colorer selon status, et toujours indiquer dans une légende ce que signifie chaque couleur. Quatre états, dont aucun ne doit être masqué ni fusionné :

État Signification D'où il vient
Dégradée (ou anormale pour l'AIS) une part élevée d'aéronefs a signalé une faible précision, ou des navires ont présenté des anomalies, ce jour-là degraded est vrai
Dégagée observée avec assez d'aéronefs ou de navires et non signalée status vaut not_degraded ou not_anomalous
Non évaluée observée mais avec trop peu d'aéronefs échantillonnés, le jour était confondu, ou le fond du jour n'a pas pu être estimé status vaut insufficient_sample, withheld_day_confounded ou withheld_no_background
Non observée trop peu d'aéronefs ou de navires, la cellule n'a donc pas été publiée aucune entité pour cette cellule

« Non observée » est l'absence d'une entité : la dessiner de façon neutre (sans remplissage, ou avec des hachures), jamais de la couleur de « dégagée ». Utiliser un schéma de couleurs qui ne repose pas sur le seul contraste rouge-vert. Les détails d'une cellule au survol ou à la sélection affichent les comptes de properties tels que donnés, et chaque compte null comme « retenu (moins de 5) », jamais comme zéro. Un visualiseur devrait aussi indiquer, lorsque grid.is_preregistered est faux, que le fichier utilise une taille de cellule hors de la méthode préenregistrée.

Couches. L'ADS-B et l'AIS sont des couches distinctes avec leurs propres commutateurs, légendes et lignes de licence. Ne jamais les fusionner en un seul champ de couleur ni en un seul compte, ne jamais les dessiner comme une cellule combinée, et ne jamais additionner leurs cellules. Des jours différents sont des fichiers différents : afficher un jour à la fois, avec un sélecteur de jour, plutôt que de superposer des jours.

Licence et attribution. Pour chaque couche visible, afficher, sur la carte et dans tout export ou capture d'écran, le texte de data.attribution à l'identique, data.licence avec un lien vers data.licence_url, et data.coverage_notes. Si une couche ADS-B est affichée, sa licence ODbL ne s'applique qu'à cette couche. Ne pas proposer d'exporter un fichier combiné.

Méthode. Proposer l'identifiant de méthode et les paramètres (method.id, method.parameters) et les chiffres de day dans un panneau de détails, y compris day_confounded (dire clairement qu'aucune cellule n'a été déclarée dégradée en raison du fond du jour) et input_stats.

Réserves à conserver (afficher les method.caveats et notice propres au fichier, et garder cette formulation ou son équivalent visible avec la carte) :

  • Une cellule dégradée ou anormale n'est pas un constat d'interférence. D'autres causes existent.
  • Une cellule sans couleur n'a pas été observée. Ce n'est pas la preuve que la zone était dégagée.
  • Il s'agit d'une description de comptes rendus de position passés, et non d'une prévision ni d'une mesure d'un récepteur quelconque.
  • La couverture suit la source de données ; lisez les notes de couverture.

La page ne doit nommer ni montrer aucun aéronef ou navire individuel, et les fichiers n'en contiennent aucun.

Exposition d'itinéraire. Si la page charge aussi un rapport kshana-route-exposure/v1, afficher ses lignes par jour et par source avec les quatre parts (dégradée, dégagée, non évaluée, non observée) ensemble, jamais la seule part dégradée, ainsi que les caveats du rapport, et les map_licence et map_attribution de chaque ligne.

Région de l'émetteur (interference-map locate)#

kshana interference-map locate estime où peut se trouver une source d'interférence à partir des mêmes rapports ADS-B ou AIS ouverts : une région à des niveaux de confiance déclarés, un centroïde avec une ellipse d'incertitude, et les sessions dans le temps. Il ne renvoie jamais un simple point. MODELLED (ligne du registre VM-bc70cb57) : la physique est la ligne de visée radio des manuels, la crédibilité des régions est conditionnelle au modèle, et la seule vérification externe est la comparaison de Jammertest préenregistrée dans emitter-region/PREREGISTRATION.md. La publication des régions d'émetteurs dans l'observatoire public est une décision distincte du propriétaire et est désactivée : l'observatoire ne lit pas ce module, et un test le garantit.

kshana interference-map locate input.csv --source adsb --dataset adsb-lol --out regions/
kshana interference-map locate day-dir/  --source adsb --dataset adsb-lol --out regions/     # readsb traces
kshana interference-map locate ais.csv   --source ais  --dataset kystverket --land land.geojson --out regions/

Options : --levels 0.5,0.9,0.95, --cell-km, --session-gap-min, --emitter-height-m min,max, --ship-height-m (AIS), --tdoa fix.json (fusionner une position TDOA ; ci-dessous). Toute option qui diffère de la valeur préenregistrée est annoncée comme « not the pre-registered method ». Les fichiers ne sont jamais écrasés.

Modèle. Les rapports sont regroupés en unités (un aéronef ou un navire dans un intervalle de 2 minutes), chacune touchée (ADS-B : au moins la moitié de ses rapports ont un NIC ou un NACp faible selon la règle propre à la carte ; AIS : une vitesse ou un saut invraisemblable, ou une position à l'intérieur des terres par rapport au littoral) ou non. Un aéronef ou un navire ne compte qu'avec au moins 5 bons rapports dans l'entrée (la même garde de référence d'équipement que la carte). Les unités touchées sont regroupées en sessions : un écart de plus de 30 minutes sépare dans le temps, et au sein d'un groupe temporel deux unités vont ensemble lorsqu'un même émetteur pourrait être à portée des deux. Pour une session, chaque position candidate sur une grille reçoit une vraisemblance :

  • Ligne de visée. Un aéronef à la hauteur h et une antenne d'émetteur à h_e se voient jusqu'à 4.122 (sqrt h + sqrt h_e) km sur un rayon terrestre de 4/3. h_e est marginalisée sur 2 à 100 m (8 valeurs à espacement logarithmique).
  • Puissance. La puissance de l'émetteur est inconnue, de sorte qu'une portée effective de 12 km à 426 km (par pas de 1,25) ou « ligne de visée seulement » plafonne la portée, marginalisée à poids égal. Le bord de la portée est doux : une unité compte comme à portée avec un poids qui décroît linéairement sur 15 % de la portée de chaque côté (au moins les trois quarts d'une cellule de grille), car le relief, le diagramme d'antenne et le trajet ne sont pas connus avec plus de précision.
  • Touché et non touché. Un aéronef ou un navire est sensible avec la probabilité 0,6 (l'équipement du récepteur, l'antenne et le trajet du signal diffèrent), une unité d'un aéronef sensible à portée est touchée avec la probabilité 0,9, et toute autre unité est touchée avec la probabilité de fond 0,03 (autres causes). La sensibilité est une propriété latente de l'aéronef, sommée par aéronef, tout comme un défaut d'équipement persistant (probabilité 0,03 : toutes les unités de cet aéronef sont touchées où qu'il soit), ce qui évite qu'un transpondeur défectueux n'entraîne la région. Ainsi, un aéronef touché tire la postérieure vers les positions qui l'atteignent, et un aéronef non touché en ligne de visée repousse les positions qui l'auraient atteint d'au plus le poids d'un aéronef, quel que soit le nombre de rapports envoyés, tandis qu'un aéronef non touché sans ligne de visée ne dit rien.
  • Sans relief. Le relief, les conduits de propagation et la diffraction ne sont pas modélisés (le relief ne peut que supprimer la ligne de visée).
  • Atténuation. Le log de vraisemblance est multiplié par 0,3 (une postérieure à puissance). Les observations du modèle sont plus dépendantes entre elles et ses bords moins nets que l'indépendance que suppose la vraisemblance, et sur des données synthétiques présentant ces défauts, les régions non atténuées contenaient la vraie source bien en dessous de leur taux déclaré ; 0,3 a été choisi sur des données synthétiques seulement (la dérivation se trouve dans docs/emitter-region/PREREGISTRATION.md, section 8).

La postérieure donne des régions de plus haute densité aux niveaux déclarés (emboîtées ; des polygones avec trous au besoin), le centroïde pondéré par la postérieure et son ellipse de moments (mise à l'échelle de 95 % sous une loi gaussienne ; ce sont les polygones, et non l'ellipse, qui sont les niveaux étalonnés). La grille est grossière (environ 5 à 10 km) sur tout le domaine et chaque cellule grossière contenant de la masse est divisée 4 par 4. Le biais de couverture est traité en conditionnant sur les endroits où des rapports existent : une région est large là où peu d'aéronefs étaient présents, et une session dont la région à 95 % remplit plus de 80 % de son domaine de recherche est rapportée unconstrained sans centroïde.

Sessions et profil. Chaque session publiée a un début, une fin, une durée, la surface des cellules de 0,5 degré qui contiennent une unité touchée et au moins 5 aéronefs ou navires distincts, les nombres distincts de touchés et d'observés, et la preuve contraire (non touchés distincts en ligne de visée du centroïde ; retenue en dessous de 5). Une session avec moins de 5 aéronefs ou navires touchés distincts est retenue et comptée. Le profil donne, par heure UTC du jour, les aéronefs touchés distincts (null en dessous de 5) et les minutes de temps de session, ainsi que les heures de temps de session par jour UTC.

Fusion TDOA facultative. --tdoa fix.json prend {"receivers": [[lat, lon, height_m], ...], "tdoa_s": [...], "sigma_s": 1e-7, "start": [lat, lon]} (au moins trois récepteurs ; tdoa_s[i] est le récepteur i+1 moins le récepteur 0). La position est résolue à la surface de la Terre par Gauss-Newton sur geolocation::tdoa_predict, sa covariance est geolocation::tdoa_crlb_on_sphere, et la gaussienne est multipliée dans la postérieure. La borne de Cramer-Rao est une borne inférieure sur un modèle, et non une précision mesurée.

Sorties (emitter-<source>-<dataset>-<day>) : .geojson (région MultiPolygon par niveau et par session, le polygone de l'ellipse, le point centroïde portant son ellipse), -summary.json, -sessions.csv, -figure.svg. Chacune intègre la licence du jeu de données, l'URL de la licence et l'attribution, l'identifiant de méthode kshana-interference-map/emitter-region/v1, chaque paramètre, les hypothèses et les limites, et porte son étiquette de preuve (niveau MODELLED, identifiants de lignes du registre ; le bandeau sous la figure, les lignes # evidence dans le tableau, un membre evidence dans le JSON). Les fichiers machine sont en anglais quelle que soit la langue ; le texte de la figure et les lignes de la ligne de commande sont localisés. Un exemple synthétique se trouve dans examples/emitter-region/ (regenerate.sh).

Confidentialité et formulation. Aucun identifiant d'aéronef ou de navire n'apparaît dans une sortie ; aucune position de rapport n'est tracée ; une session exige au moins 5 aéronefs ou navires distincts ; les nombres inférieurs à 5 sont null. La formulation est neutre : « région d'émetteur estimée », « région de la source d'interférence ». Une région n'est la position de personne, n'est pas un constat de la cause et ne dit rien de qui ou de ce qui est derrière une source ; le test de formulation étendu vérifie que les sorties ne contiennent aucun mot d'acteurs, d'intention ou de conflit.

Limites. La crédibilité est conditionnelle au modèle. Sur des données synthétiques (un générateur qui partage le modèle, avec des bords de portée incertains à 15 % par aéronef, des défauts d'équipement persistants, une puissance inconnue et une hauteur d'antenne inconnue), la région à 95 % contenait la vraie source dans 0,99 (géométrie d'aéronefs) et 1,00 (géométrie de navires) des sessions et la région à 50 % dans environ 0,77 : les niveaux sont prudents, par l'exposant de vraisemblance de 0,3, et l'erreur de centroïde d'une session a une médiane de 23 km (aéronefs) et 12 km (navires). L'étalonnage n'est vérifié que sur des données synthétiques ; la comparaison de Jammertest a été préenregistrée (emitter-region/PREREGISTRATION.md) et exécutée une fois : NOT ASSESSABLE pour les deux sources (emitter-region/RESULTS.md). Une seule source par session ; plusieurs sources proches ressemblent à une seule. Une cause régionale (une panne de constellation, la météo spatiale) donne une région qui n'est pas une source. L'ADS-B donne peu de rapports hors des espaces aériens chargés, et seulement environ un quart des points de trace de readsb portent le NIC et le NACp, de sorte que les zones peu denses donnent des régions larges ou aucune (31 % des sessions en géométrie de navires étaient unconstrained).

Méthode ADS-B (kshana-interference-map/adsb/v2)#

Chaque compte rendu ADS-B en vol porte deux champs de qualité de navigation auto-évalués : le NIC (le rayon de confinement de la position) et le NACp (la borne de précision à 95 %, EPU). Lorsque le récepteur de bord perd ou ne croit plus sa position par satellite, les deux chutent, ce qui explique qu'ils portent une signature d'interférence. Ils chutent aussi pour d'autres raisons.

Paramètres préenregistrés (constantes dans le code, écrites dans chaque fichier ; un changement signifie une nouvelle version de la méthode) :

Paramètre Valeur
Plancher d'altitude altitude barométrique d'au moins 5000 ft
Compte rendu de faible précision NACp d'au plus 6 (la borne d'EPU rapportée est de 556 m, 0,3 NM, ou plus, ou inconnue) ou NIC d'au plus 5 (la borne de rayon de confinement rapportée est de 1852 m, 1 NM, ou plus, ou inconnue)
Bon compte rendu NACp d'au moins 8 et NIC d'au moins 7 ; jugé sur les champs que contient l'entrée (les deux lorsque les deux sont présents, celui qui est présent sinon)
Référence de base d'équipement un aéronef ne compte dans une cellule que s'il a au moins 5 bons comptes rendus en dehors de cette cellule le même jour
Aéronefs échantillonnés dans une cellule au moins 3 comptes rendus dans la cellule
Aéronefs touchés dans une cellule au moins 50 % de ses comptes rendus dans la cellule sont de faible précision
Échantillon minimal au moins 10 aéronefs échantillonnés
Dégradée au moins 5 aéronefs touchés, une part d'aéronefs touchés parmi les aéronefs échantillonnés d'au moins 0,30, et au moins 0,15 au-dessus de la part médiane des cellules du jour
Jour confondu part médiane des cellules (sur au moins 5 cellules à échantillon complet) d'au moins 0,15 : aucune cellule n'est déclarée dégradée
Pas de fond moins de 5 cellules à échantillon complet, la médiane ne peut donc pas être estimée : une cellule qui atteint les seuils est withheld_no_background, et non dégradée
Minimum de publication au moins 5 aéronefs distincts observés

Ces valeurs ont été fixées à partir des définitions des codes NIC et NACp et de la règle de confidentialité avant que la moindre donnée soit examinée. Elles n'ont pas été ajustées sur des données réelles, et les tests n'utilisent que des données synthétiques. Statuts des cellules : degraded, not_degraded, insufficient_sample (publiée mais avec moins de 10 aéronefs échantillonnés), withheld_day_confounded et withheld_no_background.

Version 2. La version 1 déclarait une cellule dégradée dès 3 aéronefs touchés, soit moins que le minimum de publication de 5 aéronefs, et sautait sans le dire la vérification du fond du jour lorsque moins de 5 cellules étaient entièrement échantillonnées. La version 2 exige au moins 5 aéronefs touchés et retient le verdict (withheld_no_background) lorsque le fond ne peut pas être estimé. Les deux modifications resserrent la méthode (rien de ce qui n'était pas dégradé en version 1 n'est dégradé en version 2) ; la raison est qu'un verdict publié ne doit jamais reposer sur moins d'aéronefs que le nombre en dessous duquel les comptes sont retenus. Les fichiers de la version 1 n'ont pas été publiés.

Pourquoi les champs de précision chutent pour d'autres raisons que l'interférence, et la parade pour chacune :

Cause Parade
Des transpondeurs anciens qui ne rapportent jamais le NIC ou le NACp, ou les rapportent à une valeur basse fixe la référence de base d'équipement : un aéronef sans bon compte rendu ailleurs ce jour-là n'est pas compté
Basse altitude et opérations en surface (masquage par le relief, formats de position différents) plancher d'altitude ; lignes marquées ground exclues
Positions MLAT ou autres positions non GNSS filtre source_type lorsque la colonne est présente
Un aéronef qui envoie de nombreux comptes rendus ce sont les aéronefs distincts qui sont comptés, et non les comptes rendus
Une panne de constellation ou d'augmentation, ou un événement de météorologie spatiale, qui abaisse la précision sur une vaste zone la cellule doit dépasser d'une marge la part médiane des cellules du jour, et un jour dont la médiane est elle-même élevée est marqué confondu et ne déclare aucune cellule
Une défaillance de l'équipement d'un seul aéronef exige une part de nombreux aéronefs distincts, avec un échantillon minimal
Peu d'aéronefs dans la cellule échantillon minimal ; en dessous de 5 observés, la cellule n'est pas publiée

Ce qui reste : la méthode ne peut pas distinguer l'interférence d'une cause régionale qui est locale plutôt qu'étendue (un effet local de géométrie des satellites ou une panne d'augmentation au sol aurait le même aspect), et elle est prudente dans un seul sens : un aéronef qui ne vole qu'à l'intérieur d'une région touchée toute la journée n'a pas de référence de base et n'est pas compté, de sorte que les zones persistantes étendues sont sous-déclarées.

Méthode AIS (kshana-interference-map/ais/v2)#

Par navire et par jour, cinq détecteurs. Un détecteur est qualifiant dans une cellule lorsqu'il signale au moins 5 navires distincts représentant au moins 20 % des navires observés à cet endroit ; la cellule est anomalous si un détecteur est qualifiant.

Détecteur Règle (préenregistrée)
on_land au moins 3 comptes rendus dans la cellule à plus de 2000 m à l'intérieur des terres par rapport au littoral fourni
circle une fenêtre de 20 comptes rendus consécutifs (pas 10, intervalles d'au plus 30 min) dont le rayon moyen par rapport au centroïde est de 500 m à 20 km, coefficient de variation du rayon d'au plus 0,15, un seul sens de déplacement avec un enroulement total d'au moins 270 degrés (pas d'au plus 90 degrés, net d'au moins 80 % du total), et vitesse moyenne d'au moins 2 kn
implausible_jump au moins 2 sauts arrivant dans la cellule : des comptes rendus consécutifs distants d'au moins 1000 m, espacés d'au plus 1 h, impliquant plus de 70 kn (la vitesse impliquée utilise au moins 1 s entre les comptes rendus, de sorte que deux comptes rendus de même horodatage et de positions distantes de 1 km ou plus comptent comme un saut)
implausible_speed au moins 3 vitesses rapportées supérieures à 70 kn dans la cellule
same_position au moins 5 navires distincts rapportant la même position (arrondie à 1e-4 degré, soit environ 11 m) dans la même fenêtre de 10 minutes

Les cellules comptant moins de 5 navires distincts ne sont pas publiées ; tout compte de signalements inférieur à 5, zéro compris, est rapporté comme null.

Version 2. La version 1 qualifiait un détecteur dès 3 navires signalés et publiait des comptes de 3 et 4. La version 2 relève le minimum de navires signalés à 5, le minimum de publication, de sorte qu'un verdict anomalous ne repose jamais sur moins de navires que le nombre en dessous duquel les comptes sont retenus. Cela resserre la méthode et aucun fichier de la version 1 n'a été publié.

Causes connues de faux positifs, que la règle de part et les seuils réduisent mais n'éliminent pas : les navires dans des fleuves, canaux et ports proches d'un littoral grossier (la zone tampon de 2 km à l'intérieur des terres existe pour cela) ; deux navires partageant un même identifiant, ce qui ressemble à des sauts ; des transpondeurs à position erronée ou des équipements d'essai ; et les navires qui louvoient, tels que bateaux-pilotes et navires de recherche, qui peuvent ressembler à des cercles. Un fichier de littoral au 1:10 million est précis à environ un kilomètre.

Les détecteurs de sauts et de vitesse comparent des comptes rendus au sein d'un même fichier d'entrée ; une trace répartie sur plusieurs fichiers ou jours n'est pas raccordée.

Mémoire. L'entrée est lue ligne par ligne et n'est jamais conservée en entier. L'ADS-B ne conserve que des compteurs par aéronef et par cellule. L'AIS conserve chaque compte rendu accepté dans un enregistrement compact (environ 40 octets) jusqu'à l'évaluation de son jour, de sorte que la mémoire croît avec le nombre de comptes rendus AIS de l'entrée ; découpez par jour une entrée AIS très volumineuse.

Exposition d'itinéraire#

kshana route-exposure --route route.geojson --map out/ [--map other/] \
    [--from 2026-03-01] [--to 2026-03-07] [--out report.json] [--json]

--route est une LineString GeoJSON (seule, dans une Feature, ou dans une FeatureCollection) ou un CSV de lignes lat,lon. --map accepte des fichiers de carte ou des répertoires de ceux-ci, et peut être répété. Les points de passage sont reliés par des droites en latitude et en longitude ; densifiez donc les longs tronçons ; un tronçon prend le chemin le plus court en longitude, de sorte que celui qui franchit l'antiméridien (179,5 E à 179,5 W) le franchit. L'itinéraire est découpé en morceaux d'environ 250 m. Chaque morceau est mesuré entre ses deux extrémités sur une sphère de rayon 6371,0088 km (le même chemin qui décide dans quelle cellule il se trouve) et affecté à la cellule qui contient son milieu.

Par jour et par source, le rapport donne la longueur de l'itinéraire et quatre parts dont la somme vaut 1 : share_degraded, share_not_degraded, share_unassessed (cellule présente mais sans verdict) et share_not_observed (cellule absente de la carte). Lisez les deux dernières avec la première : un itinéraire à faible part dégradée et à forte part non observée n'a pas été montré comme dégagé. Les lignes ADS-B et AIS sont rapportées séparément et jamais combinées. Chaque ligne porte la licence et l'attribution de la carte.

Fonctions de bibliothèque#

Pour les appelants qui détiennent des données en mémoire (liaisons, serveur MCP, version navigateur), le module kshana::interference_map::api expose les mêmes méthodes avec du texte ou des octets en entrée et du JSON en sortie, sans toucher à aucun fichier ni au réseau :

Fonction Entrée Sortie
adsb_maps_from_csv(csv, &DatasetSpec, cell_deg) texte CSV ADS-B Vec<DayMap>
adsb_maps_from_readsb_traces(&[&[u8]], &DatasetSpec, cell_deg) une tranche d'octets par fichier de trace readsb (gzip ou brut) Vec<DayMap>
ais_maps_from_csv(csv, &DatasetSpec, cell_deg, Option<&str>) texte CSV AIS, texte GeoJSON de terres facultatif Vec<DayMap>
route_exposure(route_text, &[&str], from, to) texte d'itinéraire, textes GeoJSON de carte, bornes YYYY-MM-DD facultatives JSON kshana-route-exposure/v1

Un DayMap comporte file_name (<source>-<dataset>-<date>.geojson), date et geojson (le document v1). DatasetSpec est Preset("adsb-lol" | "noaa-marinecadastre" | "kystverket") ou Custom { licence, licence_url, attribution } ; DEFAULT_CELL_DEG vaut 0,5. Les erreurs sont des MapError. Les règles des jeux de données (préréglages approuvés, texte de licence requis, le type doit correspondre) s'appliquent exactement comme en ligne de commande.

Validation externe#

tests/interference_map_reference.rs compare Kshana à des implémentations indépendantes sur des entrées synthétiques, avec des tolérances préenregistrées dans tests/fixtures/interference_map_ref/PREREGISTRATION.md : les significations des codes NIC et NACp par rapport au décodage pyModeS de trames ADS-B synthétiques, les valeurs « non disponible » de l'AIS par rapport au décodage pyais de phrases AIVDM synthétiques, l'affectation aux cellules de la grille par rapport à shapely, la longueur d'itinéraire par état de cellule par rapport à shapely et GeographicLib, et le masquage des terres par rapport à shapely et pyproj. Les jeux de test sont produits par scripts/gen_interference_map_ref.py ; la CI n'a pas besoin de Python. Cela valide la façon dont les codes et les valeurs de champ sont lus, ainsi que la géométrie. Cela ne valide pas qu'une cellule signalée soit une interférence.

Tests#

Tous les tests utilisent des données synthétiques générées et aucun réseau : des tests unitaires dans src/interference_map/, et tests/interference_map_cli.rs pour les commandes de bout en bout, y compris le fait qu'aucun identifiant n'atteint une sortie et que les refus ne laissent aucun fichier.