Export d'animation
--animate transforme la série temporelle d'une exécution en quelque chose qui bouge : un fichier Scalable Vector Graphics (SVG) animé, un unique lecteur HyperText Markup Language (HTML) autonome, ou une séquence numérotée d'images SVG pour un encodeur vidéo. Une campagne est jouée par phases (brouillage, leurrage, holdover, alarme d'intégrité) avec ses alarmes marquées ; une exécution de spectre joue sa cascade ligne par ligne ; un passage en orbite terrestre basse (LEO) joue sa liaison par bande et, avec un leurre, les statistiques du moniteur époque par époque.
kshana scenarios/campaign-jam-spoof-holdover-integrity.toml --animate all
kshana scenarios/l-band-waterfall-jamming.toml --animate html
kshana scenarios/clock-holdover.toml --animate frames --animate-fps 24 --animate-duration 10
Code : src/animation.rs. Tests : tests/animation.rs.
Ce que c'est, et ce que ce n'est pas#
L'exportateur lit le document de résultats que l'exécution a déjà écrit. Il ne relance pas la physique, il ne rééchantillonne, ne lisse ni n'interpole entre les échantillons (hormis le segment de droite qui termine une trace au curseur), et il n'ajoute aucun chiffre qui lui soit propre. Une animation vaut donc exactement ce que vaut l'exécution qui la fonde. Son niveau est MODELLED, cohérence interne : c'est un rendu, jamais une preuve, et elle ne porte aucune ligne de matrice de vérification qui lui soit propre.
Sorties#
Chaque format est écrit à côté du scénario, près des habituels result.json, chart.svg et report.html :
| Format | Écrit comme | Ce qu'il contient |
|---|---|---|
svg |
<scenario>.animation.svg |
Un SVG animé par des images clés Cascading Style Sheets (CSS) et sans script : les tracés se dessinent derrière un curseur temporel mobile, les événements apparaissent à leur instant, les lignes de la cascade se révèlent dans l'ordre du temps. Il boucle, avec une pause de 1,5 s sur l'image terminée. |
html |
<scenario>.animation.html |
Un fichier avec script et style en ligne et sans ressource externe : lecture et pause, un curseur de défilement, la vitesse (0.25x à 4x), chaque panneau sur un seul curseur synchronisé, une valeur en direct par tracé, la bande des phases, et une liste d'événements qui se positionne au clic. La barre d'espace lance ou met en pause, les touches fléchées avancent pas à pas, Début et Fin sautent. |
frames |
<scenario>.frames/ |
frame_0000.svg, frame_0001.svg, … et manifest.json. |
--animate est répétable et accepte une liste séparée par des virgules (--animate svg,html) ou all. --animate-fps (1 à 60, 12 par défaut) et --animate-duration (0,5 s à 600 s, 8 s par défaut) règlent la lecture ; la séquence d'images est plafonnée à 7 200 images.
Lorsque --export s'exécute dans la même commande, le lecteur HTML liste les fichiers d'export écrits à côté de lui (CZML, KML, GeoJSON, STK, SigMF) sous forme de liens relatifs vers ces fichiers voisins ; un lien n'est écrit que pour un nom de fichier simple, de sorte qu'aucun ne peut sortir du dossier ni atteindre le réseau. Le rapport avancé (report.html) intègre le dessin animé chaque fois que le résultat a une série temporelle, que --animate ait été exécuté ou non.
Lorsque --animate s'exécute, result.json gagne un bloc animation : les formats, les images par seconde (fps), la durée, le nombre d'images, l'intervalle de temps, les titres des panneaux, les chemins JSON d'où chaque tracé a été lu (sources) et toute série trouvée mais non dessinée (omitted). Sans --animate, le résultat est identique à l'octet près à celui d'une exécution simple.
La séquence d'images#
La séquence compte exactement round(duration × fps) images. L'image i montre la chronologie jusqu'à t_start + (t_end − t_start) × i / (n − 1), de sorte que la première image est le début et la dernière l'image terminée. manifest.json consigne fps, duration_s, frame_count, frame_pattern (frame_%04d.svg), la taille en pixels, t_start, t_end, l'heure de mission de chaque image (frame_times), les phases, les événements et les sources. Un nouvel export dans le même répertoire supprime d'abord tous les frame_NNNN.svg déjà présents (et rien d'autre), de sorte qu'une séquence plus courte ne laisse jamais derrière elle des images d'une séquence plus longue que l'encodeur pourrait lire.
Les images sont en SVG, et non en Portable Network Graphics (PNG). Un ffmpeg compilé avec la bibliothèque librsvg les lit directement, à la cadence avec laquelle la séquence a été écrite (24 dans l'exemple ci-dessus ; le fps du manifeste) :
ffmpeg -framerate 24 -i clock-holdover.frames/frame_%04d.svg -pix_fmt yuv420p clock-holdover.mp4
Un ffmpeg sans librsvg s'arrête avec « no decoder found for: svg ». Rastérisez d'abord les images, par exemple avec rsvg-convert, et encodez les PNG :
for f in clock-holdover.frames/frame_*.svg; do rsvg-convert "$f" -o "${f%.svg}.png"; done
ffmpeg -framerate 24 -i clock-holdover.frames/frame_%04d.png -pix_fmt yuv420p clock-holdover.mp4
Accessibilité et thème#
- Schéma de couleurs. Le lecteur suit
prefers-color-schemeet se redessine lorsqu'il change ; le SVG animé porte une variante claire de sa palette sous la même requête média. Les images utilisent la palette sombre des graphiques statiques, car une vidéo n'a pas de schéma. - Mouvement réduit. Sous
prefers-reduced-motion: reduce, le SVG animé désactive chaque animation et montre l'image terminée (ses styles de base sont l'état final, de sorte que rien n'est masqué), et le lecteur s'ouvre en pause sur l'image terminée au lieu de jouer ; l'utilisateur peut toujours faire défiler ou appuyer sur Lecture. - Le SVG a un
<title>et un<desc>; les commandes du lecteur sont des boutons étiquetés, une entrée de plage avec une valeur de temps énoncée à voix haute, et une liste de sélection.
Ce qui compte comme série temporelle#
Les documents de résultats diffèrent d'un type à l'autre, de sorte que l'exportateur reconnaît les formes que le moteur émet plutôt qu'une liste de types :
- Un tableau d'enregistrements avec un champ de temps (
t,t_s,t_hours,t_min,t_days, ouksur un tableauepochs) qui croît strictement le long du tableau. Chaque autre champ numérique devient un tracé ; le même champ sous deux racines (quantum.series[].error_nsetclassical.series[].error_ns) partage un panneau. - Un objet avec un tableau de temps strictement croissant (
t_s,t,times_s, …) à côté de tableaux de même longueur : des tableaux numériques voisins, une tablechannelsd'enregistrements{unit, values}(la chronologiecampaign), un tableau d'enregistrements contenant de tels tableaux (les bandesspectrum, les traces de satellites d'une constellation), et un tableau à deux dimensions dont les lignes correspondent à l'axe du temps avec un axe de fréquence voisin*_hz(la cascadespectrum). - À côté de ce tableau de temps,
phases(name,t0_s,t1_s) deviennent la bande des phases etevents(t_s,label,alarm) deviennent les repères. Les scalaires*_t_sd'une bande (sa première perte d'accrochage, son rapport porteuse sur densité de bruit le plus bas) sont aussi marqués.
Les tracés avec une unité partagent un panneau lorsque leurs grandeurs sont dans un rapport d'au plus 100, de sorte qu'une garde de 50 ns n'aplatit pas une erreur de 2 ns. Au plus 6 panneaux de 6 tracés sont dessinés ; le reste est listé sous omitted. Les tracés de plus de 2 400 échantillons sont éclaircis par un pas régulier qui conserve le dernier échantillon, et une cascade de plus de 96 × 120 cellules est moyennée à la baisse (en puissance, pour les cellules en décibels, afin qu'un brouilleur étroit ne soit pas dilué).
Un type dont le résultat ne porte aucune de ces formes (un bilan de liaison, une géométrie à époque unique, un résumé Monte Carlo purement statistique, ou le holdover de télécommunication, dont le résultat publie l'empreinte de l'enregistrement mais non l'enregistrement) est refusé avec no time series to animate, et rien n'est écrit. Avec kshana 0.40.0, 94 des 193 fichiers de scénario exécutables (tous les fichiers sauf une suite d'étude) s'animent et 99 sont refusés. cargo test --test animation -- --nocapture affiche le recensement.
Parmi les types LEO, chaque scénario leo-pass, leo-pnt-chain et leo-ppp fourni s'anime. leo-pvt s'anime dans ses modes Doppler, positionnement conjoint et synchronisation temporelle (une exécution de synchronisation temporelle nécessite trace = true, ce qui fait rapporter à chaque ligne son erreur de temps et son sigma prédit à chaque époque) et est refusé dans son mode de couverture polaire. leo-navmsg anime sa mise à jour en milieu de passage et est refusé pour les analyses d'encodage, d'intervalle d'ajustement et de comparaison de modèles. Les résultats leo-signal et ntn-positioning ne portent aucun axe temporel et sont refusés.
Déterminisme#
La sortie est une fonction pure du document de résultats et des options : aucune horloge, aucun nombre aléatoire, aucune itération de table de hachage, aucun accès fichier ou réseau dans la bibliothèque, et aucun horodatage nulle part, de sorte que le même scénario, la même graine et les mêmes options donnent des fichiers identiques à l'octet près. Le module se compile pour WebAssembly sans changement ; seule l'interface en ligne de commande écrit des fichiers.
Utilisation en bibliothèque#
use kshana::animation::{AnimationFormat, AnimationOptions};
let anim = kshana::api::animate_toml(src, AnimationFormat::Html, &AnimationOptions::default())?;
std::fs::write("run.html", &anim.files[0].content)?;
kshana::animation::animate_result anime un document de résultats que vous avez déjà, et extract_timeline renvoie ce qui serait dessiné sans le rendre.
Limites#
- Le wheel Python et le module WebAssembly n'exposent pas encore l'exportateur ; il est accessible depuis la ligne de commande, la bibliothèque Rust et l'outil
animate_scenariodu serveur Model Context Protocol (MCP) (qui renvoie au plus 120 images dans une réponse). - Les axes sont linéaires. Une série couvrant plusieurs décades (la croissance de l'erreur d'une horloge de 0,1 ns à une microseconde) paraît plate jusqu'à tard dans l'exécution.
- Le SVG animé repose sur l'animation CSS d'un rectangle de découpe ; les moteurs actuels de Chromium, Firefox et Safari le jouent, alors qu'un visualiseur sans animation CSS montre l'image terminée.
- Les campagnes de balayage, Monte Carlo et de composition ne portent aucun axe temporel et sont refusées ; les statistiques de synthèse d'un balayage ou d'un ensemble ne sont pas une série temporelle. Une campagne enchaînée s'anime.