Flux d'entraînement NMEA : kshana nmea-scenario
Les académies maritimes et les centres de simulation peuvent alimenter un simulateur de passerelle ou un traceur de cartes avec du NMEA 0183 généré par Kshana pour entraîner les équipages à reconnaître le brouillage et le leurrage GNSS.
Entraînement et essai uniquement. Les flux générés sont synthétiques. Ils ne doivent jamais être envoyés aux systèmes de navigation actifs d'un navire. Kshana est à titre consultatif, et non un équipement de navigation homologué. Chaque flux commence par une phrase de marqueur propriétaire,
$PKSHT,TRAINING,SYNTHETIC,NOT-FOR-NAVIGATION, et la répète toutes les dix secondes ; les récepteurs l'ignorent ;--no-markerla supprime pour un simulateur qui rejette les phrases inconnues. Cela n'écrit que du texte NMEA : il n'y a aucune sortie RF, IQ ou de forme d'onde, et rien n'est transmis, sauf le texte vers l'adresse que vous indiquez.
La figure est tracée à partir du journal de l'instructeur de scenarios/training/coastal-drag-off.toml.
Utilisation#
# write a file (default <name>.nmea) and the instructor log next to it
kshana nmea-scenario scenarios/training/coastal-drag-off.toml --out drag.nmea
# serve over TCP in real time on this machine only (waits for the simulator to connect)
kshana nmea-scenario scenarios/training/open-sea-jamming.toml --tcp 10110
# reachable from the bridge-simulator host: name the address in full
kshana nmea-scenario scenarios/training/open-sea-jamming.toml --tcp 192.168.1.20:10110
# UDP, one sentence per datagram, ten times faster than real time
kshana nmea-scenario scenarios/training/combined-event.toml --udp 192.168.1.50:10110 --speed 10
# UDP broadcast
kshana nmea-scenario scenarios/training/combined-event.toml --udp 192.168.1.255:10110 --broadcast
| Option | Signification |
|---|---|
--out <file> |
écrit le flux dans un fichier ; sans sortie réseau, la valeur par défaut est <name>.nmea |
--instructor-log <prefix> |
écrit <prefix>.instructor.json et <prefix>.instructor.txt (par défaut : à côté du fichier) |
--tcp <addr:port> ou <port> |
serveur TCP ; l'exécution démarre lorsqu'un client s'est connecté (--wait-clients <n>). Un port seul écoute sur 127.0.0.1 uniquement |
--udp <addr:port> ou <port> |
UDP, une phrase par datagramme ; --broadcast autorise une adresse de diffusion. Un port seul envoie vers 127.0.0.1 |
--realtime, --speed <x> |
cadence le flux ; --speed 0 signifie aussi vite que possible. La sortie réseau est par défaut en temps réel, les fichiers aussi vite que possible |
--seed <n> |
remplace la graine du scénario |
--no-marker |
omet la phrase de marqueur |
Il n'y a aucune authentification. Un serveur TCP auquel on donne une adresse non locale sert le flux à quiconque peut l'atteindre, et UDP envoie à l'adresse que vous indiquez. Un client TCP qui ne prend pas ses données en deux secondes est déconnecté, de sorte qu'un consommateur bloqué ne peut pas retenir les autres.
La même graine donne les mêmes octets sur une plateforme, et la cadence ne change jamais les octets. D'une plateforme à l'autre, l'arithmétique propre du générateur est identique bit à bit (il utilise la couche de mathématiques portable), mais les positions des satellites et les angles de visée proviennent de fonctions du moteur qui appellent la bibliothèque mathématique de l'hôte ; dans un rare cas limite, un chiffre arrondi d'élévation, d'azimut ou de C/N0 dans GSV peut donc différer d'une plateforme à l'autre.
Ce qui est écrit#
Chaque époque (1, 2, 5 ou 10 par seconde) comporte : RMC, GGA, GNS (position calculée, position, heure), GSA (satellites utilisés et DOP, un par constellation), GSV (satellites en vue avec élévation, azimut et SNR en dB-Hz, un jeu par constellation, identifiant de signal NMEA 4,10), VTG (route et vitesse sur le fond), ZDA (heure et date), HDT (cap gyroscopique) et VBW (vitesse sur l'eau et sur le fond issue du loch). L'émetteur est GN avec plusieurs constellations, sinon celui de la constellation. Les lignes se terminent par CRLF et ont une somme de contrôle valide.
HDT et VBW tiennent lieu de capteurs indépendants (un compas gyroscopique et un loch Doppler). Aucun événement ne les touche, ce qui est voulu : l'écart entre ce que rapporte le GNSS et ce que disent le gyroscope et le loch est un indice pour le débriefing.
Lorsque la position est perdue, la qualité GGA est 0, l'état RMC est V, les champs de position sont vides et les champs d'heure continuent (l'horloge du récepteur continue de tourner), comme le font les récepteurs réels.
Le navire#
[vessel] et [[waypoint]] donnent une position de départ, une vitesse et les points par lesquels gouverner. Le navire est gouverné vers le point de cheminement suivant sous une limite de vitesse de giration (max_rot_deg_per_min, par défaut 30), une limite sur la rapidité avec laquelle la vitesse de giration s'établit (max_rot_accel_deg_per_s2) et une limite de changement de vitesse (max_accel_kn_per_min). La vitesse d'un tronçon est le speed_kn du point de cheminement. [environment] ajoute un courant, de sorte que la vitesse sur le fond diffère de la vitesse dans l'eau et que le cap diffère de la route sur le fond, et une variation magnétique. stop_at_end amène le navire au repos au dernier point de cheminement.
Géométrie des satellites#
Les satellites proviennent des constellations nominales propres au moteur (table de créneaux GPS, motifs de Walker MEO de Galileo et BeiDou, ICD GLONASS), propagées par constellation::satellite_positions_fixed (deux corps plus J2 séculaire, rotation de la Terre) et vues depuis le navire avec les angles de visée WGS-84 du moteur. Le nombre de satellites visibles, les élévations et les azimuts dans GSV sont plausibles pour le lieu et l'heure du jour. Il s'agit d'un ciel nominal, et non d'une éphéméride pour la date du flux : les PRN sont attribués dans l'ordre des créneaux et chaque constellation conserve sa disposition de créneaux publiée, propagée en continu depuis l'époque de la table de créneaux GPS (2016-12-31) sous J2, de sorte que la disposition est intacte mais que son orientation n'est pas celle du ciel réel à la date du flux. Le C/N0 suit l'élévation (un niveau nominal au zénith, fixé dans [receiver]), avec un décalage fixe par satellite, un évanouissement lent et du bruit. Un satellite sous track_threshold_dbhz a un champ SNR vide ; un satellite sous use_threshold_dbhz est poursuivi mais non utilisé. Jusqu'à max_used (par défaut 12, le plafond NMEA GGA) satellites utilisables sont utilisés, choisis pour la géométrie (le satellite le plus haut de chaque secteur d'azimut de 30 degrés en premier). Moins de quatre satellites utilisables font perdre la position, qui revient après reacquire_s de signal utilisable.
Événements#
Chaque [[event]] a un kind, un début start_s, une duration_s (du début au commencement du relâchement), une rampe de début ramp_s et une rampe de relâchement recovery_s. L'intensité monte linéairement sur ramp_s, se maintient, puis retombe sur recovery_s ; 0 est un échelon. Tous les effets sont proportionnels à cette intensité. Les paramètres qui n'appartiennent pas au type sont refusés.
| type | paramètres | effet |
|---|---|---|
jamming |
cn0_drop_db, spread_db (par défaut 6) |
le C/N0 de chaque satellite chute jusqu'à cn0_drop_db (dispersion par satellite), les satellites décrochent en commençant par les plus faibles, la position est perdue lorsque moins de quatre sont utilisables, et revient après le relâchement et reacquire_s |
drag-off |
final_offset_m, l'un de bearing_deg (vrai) ou relative_bearing_deg (par rapport à la route au début, puis maintenu), max_accel_mps2 facultatif, counterfeit_cn0_dbhz |
le récepteur conserve une position valide dont la position s'éloigne de la vérité ; SOG et COG incluent la dérive. La dérive suit une fonction smoothstep sur les rampes, de sorte que la fausse trajectoire démarre et s'arrête sans échelon de vitesse ; ses pics sont 1.5 D/T m/s et 6 D/T^2 m/s au carré pour une rampe de T s sur D m (les deux journalisés), et un scénario qui dépasserait max_accel_mps2 est refusé. Un échelon (ramp_s = 0) déplace la position sans toucher à la vitesse |
time-spoof |
offset_s, counterfeit_cn0_dbhz |
l'heure de RMC, GGA, GNS et ZDA est décalée par rapport au véritable UTC ; la position reste exacte |
replay-delay |
delay_s, affect_time (par défaut true), counterfeit_cn0_dbhz |
la position, la vitesse (et l'heure) sont celles du navire d'il y a delay_s, le retard suivant smoothstep sur ses rampes et la vitesse rapportée étant multipliée par 1 - d(delay)/dt pendant qu'il change : une abstraction simplifiée, de type meaconing, et non un modèle de propagation |
counterfeit_cn0_dbhz : tant qu'une dérive, un leurrage de l'heure ou un retard de rejeu est actif, chaque satellite poursuivi affiche ce même niveau relevé unique, signe classique. Omettez-le pour un événement subtil dans lequel le profil de C/N0 authentique est conservé. Tant qu'un événement de contrefaçon est actif, le récepteur suit le signal contrefait, de sorte que le brouillage ne le fait pas décrocher ; une position perdue à cause d'un brouillage antérieur revient après reacquire_s sur le signal contrefait (voir combined-event). Un changement d'heure qui ferait s'arrêter ou reculer l'heure rapportée (vitesse de 1 s par seconde ou plus) est refusé, sauf s'il s'agit d'un échelon (ramp_s = 0).
Les événements peuvent se chevaucher ; leurs effets s'additionnent (décalages, changements d'heure, retards) ou retiennent le plus fort (brouillage). Le onset de la chronologie est la première époque où l'événement a un effet, une époque après le start_s scénarisé lorsque l'événement monte en rampe.
Le journal de l'instructeur#
Avec le flux, <prefix>.instructor.json et <prefix>.instructor.txt donnent :
- les événements tels qu'injectés, en langage courant avec chaque paramètre, et leur début en UTC ;
- une chronologie : début, plein effet, début de récupération, récupéré, et les propres
fix-lostetfix-regaineddu récepteur ; - la trajectoire réelle comparée à la trajectoire rapportée à intervalle
log_interval_s: position réelle et rapportée, vitesse et route, erreur de position en mètres, décalage d'heure, satellites utilisés et poursuivis, C/N0 moyen, et quels événements étaient actifs ; - la vitesse et l'accélération maximales de la trajectoire réelle et de la trajectoire rapportée ;
- le
trainer_notedu scénario.
N'afficher le journal qu'au débriefing.
Champs JSON (schéma kshana-nmea-training/1)#
| champ | type, unité | signification |
|---|---|---|
schema |
chaîne | kshana-nmea-training/1 |
warning |
chaîne | la mention réservée à l'entraînement |
scenario, description, trainer_note |
chaîne | issu du scénario |
seed |
entier | graine utilisée |
start_utc |
UTC ISO 8601 | début de l'exécution |
duration_s |
s | durée de l'exécution |
summary.true_peak_sog_kn, summary.reported_peak_sog_kn |
nœuds | vitesse sur le fond maximale, réelle et rapportée |
summary.true_peak_accel_mps2, summary.reported_peak_accel_mps2 |
m/s au carré | plus grand changement de vitesse par seconde, réel et entre positions rapportées consécutives |
events[] |
un par événement scénarisé | |
events[].id |
entier | base 1 ; utilisé par timeline[].event et track[].active_events |
events[].description |
chaîne | description en langage courant avec les paramètres |
events[].start_utc |
UTC ISO 8601 | début scénarisé |
events[].parameters |
objet | l'événement exactement tel qu'écrit (kind, start_s, duration_s, ramp_s, recovery_s, et les paramètres propres au type ; les absents sont omis) |
events[].resolved_bearing_deg |
degrés vrais ou null | dérive : la direction appliquée (un relèvement relatif est résolu au début) |
events[].peak_drag_speed_mps, events[].peak_drag_accel_mps2 |
m/s, m/s au carré ou null | dérive : les pics que la dérive ajoute à la fausse trajectoire |
timeline[] |
moments pour le débriefing, dans l'ordre chronologique | |
timeline[].t_s, .utc |
s depuis le début, UTC ISO 8601 | quand (heure réelle) |
timeline[].event |
entier ou null | l'identifiant de l'événement ; null pour les changements d'état du récepteur |
timeline[].what |
chaîne | onset, full-effect, recovery-begins, recovered (événements) ; fix-lost, fix-regained (récepteur) |
timeline[].text |
chaîne | explication |
track[] |
une ligne par log_interval_s |
|
track[].t_s, .utc |
s, UTC ISO 8601 | quand (heure réelle) |
track[].true_lat_deg, .true_lon_deg |
degrés | position réelle |
track[].true_sog_kn, .true_cog_deg, .true_heading_deg |
nœuds, degrés vrais | vitesse et route réelles sur le fond, et cap gyroscopique |
track[].fix_valid |
booléen | le récepteur a rapporté une position |
track[].reported_lat_deg, .reported_lon_deg, .reported_sog_kn, .reported_cog_deg |
degrés, nœuds, degrés vrais, ou null | ce que le récepteur a rapporté ; null tant que la position est perdue |
track[].position_error_m |
m ou null | distance horizontale de la position réelle à la position rapportée |
track[].time_offset_s |
s | UTC rapporté moins UTC réel |
track[].n_used, .n_tracked |
entiers | satellites utilisés dans la position calculée, et poursuivis |
track[].mean_cn0_dbhz |
dB-Hz ou null | C/N0 moyen des satellites poursuivis |
track[].active_events |
entiers | identifiants des événements ayant un effet à cet instant |
L'ajout d'un champ ne change pas l'étiquette du schéma. Renommer ou supprimer un champ, ou changer le sens ou l'unité d'un champ, fait passer le numéro au suivant (/2).
La bibliothèque de scénarios#
scenarios/training/, chacun de quelques minutes de traversée avec une note du formateur dans son TOML :
| fichier | ce qu'il montre |
|---|---|
open-sea-jamming.toml |
le C/N0 chute partout, les satellites décrochent, la position est perdue puis revient |
coastal-drag-off.toml |
une position valide, d'apparence saine, dérive de 1,4 km vers le rivage ; C/N0 uniformément relevé |
port-approach-time-spoof.toml |
position correcte, l'UTC dérive de 45 s en avance pendant une lente approche du port |
combined-event.toml |
brouillage, puis prise de contrôle contrefaite avec dérive et décalage d'heure, puis un retard de rejeu |
fjord-natural-degradation.toml |
un ciel obstrué, et non une interférence : les parois d'un fjord (le préréglage de ligne d'horizon REPRESENTATIVE fjord) masquent les satellites à l'est et à l'ouest, puis le chenal se dégage de nouveau (événement natural-degradation, avec une table skyline) |
Les positions, dates et trajectoires sont inventées ; la bibliothèque ne contient aucun navire, opérateur ni enregistrement réel. Elle ne dit rien de la façon dont un récepteur ou un système se comporterait face à une interférence.
Choix de modélisation#
Le générateur est un outil d'entraînement sans référence indépendante, et ses nombres sont des choix de modélisation, et non des mesures d'un récepteur quelconque. Ils sont choisis pour ressembler à un journal de récepteur ordinaire : la pente de C/N0 de 14 dB du zénith à l'horizon sous le niveau au zénith (par défaut 47 dB-Hz) et le décalage par satellite de +/-1.5 dB, un évanouissement lent de 0,8 dB sur 97 s et de 0,5 dB sur 31 s, une gigue de 0,3 dB ; les seuils de poursuite (20 dB-Hz) et d'utilisation (28 dB-Hz) ; le bruit de position (1,5 m à HDOP 1, corrélé sur 30 s, le double à la verticale) ; un bruit de gyroscope de 0,05 degré et un bruit de dérive de 0,03 kn ; la constante de temps de gouverne de 20 s et les rayons d'arrivée aux points de cheminement du modèle de navire ; et le choix des satellites par secteur d'azimut. Les valeurs par défaut se trouvent dans [receiver] et [vessel] et peuvent toutes être modifiées dans le scénario.
Relecture#
kshana receiver-trust peut ingérer ces fichiers (format = "nmea"). Les tests vérifient chaque phrase de chaque scénario de la bibliothèque par rapport à ses propres règles de nombre de champs et de somme de contrôle, et font passer les fichiers par ce lecteur, qui interprète GGA, RMC et GSV et laisse passer les autres types sans en sauter aucun. Les tests figent un extrait de référence par scénario (tests/fixtures/nmea_training/) ; régénérez avec KSHANA_BLESS_GOLDEN=1 après un changement voulu.