Animatie-export
--animate zet de tijdreeks van een run om in iets dat beweegt: een geanimeerd SVG-bestand (Scalable Vector Graphics), één op zichzelf staande HTML-speler (HyperText Markup Language) of een genummerde reeks SVG-frames voor een video-encoder. Een campagne wordt afgespeeld als zijn fasen (jamming, spoofing, holdover, integriteitsalarm) met de alarmen gemarkeerd; een spectrumrun speelt zijn waterfall rij voor rij af; een overpassing in een lage baan om de aarde (LEO) speelt zijn verbinding per band af en, met een spoofer, de monitorstatistieken epoch voor epoch.
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.
Wat het is, en wat het niet is#
De exporter leest het resultaatdocument dat de run al heeft geschreven. Hij voert de fysica niet opnieuw uit, hij resamplet, egaliseert of interpoleert niet tussen samples (afgezien van het ene rechte lijnsegment waarmee een trace bij de cursor eindigt) en voegt geen eigen getal toe. Een animatie is dus precies zo goed als de run erachter. Het niveau ervan is MODELLED, interne consistentie: het is een weergave, nooit bewijs, en het draagt geen eigen rij in de verificatiematrix.
Uitvoer#
Elk formaat wordt naast het scenario geschreven, naast de gebruikelijke result.json, chart.svg en report.html:
| Formaat | Geschreven als | Wat het bevat |
|---|---|---|
svg |
<scenario>.animation.svg |
Eén SVG geanimeerd met CSS-keyframes (Cascading Style Sheets) en zonder script: de traces tekenen zich achter een bewegende tijdcursor, gebeurtenissen verschijnen op hun tijdstip, waterfallrijen onthullen zich in tijdsvolgorde. Het loopt in een lus, met een pauze van 1,5 s op het voltooide beeld. |
html |
<scenario>.animation.html |
Eén bestand met inline script en stijl en zonder extern bestand: afspelen en pauzeren, een scrubber, snelheid (0.25x tot 4x), elk paneel op één gesynchroniseerde cursor, een live waarde per trace, de fasebalk en een gebeurtenissenlijst die bij een klik naar de plek springt. Spatie speelt af of pauzeert, de pijltoetsen stappen, Home en End springen. |
frames |
<scenario>.frames/ |
frame_0000.svg, frame_0001.svg, … en manifest.json. |
--animate is herhaalbaar en neemt een kommalijst (--animate svg,html) of all. --animate-fps (1 tot 60, standaard 12) en --animate-duration (0,5 s tot 600 s, standaard 8 s) bepalen het afspelen; de framereeks is begrensd op 7.200 frames.
Wanneer --export in dezelfde opdracht draait, vermeldt de HTML-speler de exportbestanden die ernaast zijn geschreven (CZML, KML, GeoJSON, STK, SigMF) als relatieve links naar die naastgelegen bestanden; een link wordt alleen geschreven voor een kale bestandsnaam, zodat er geen uit de map kan wijzen of het netwerk kan bereiken. Het geavanceerde rapport (report.html) bevat de geanimeerde tekening telkens wanneer het resultaat een tijdreeks heeft, ongeacht of --animate heeft gedraaid.
Wanneer --animate draait, krijgt result.json een blok animation: de formaten, frames per seconde (fps), duur, aantal frames, de tijdspanne, de paneeltitels, de JSON-paden waaruit elke trace is gelezen (sources) en elke reeks die is gevonden maar niet getekend (omitted). Zonder --animate is het resultaat byte-identiek aan een gewone run.
De framereeks#
De reeks heeft precies round(duration × fps) frames. Frame i toont de tijdlijn tot t_start + (t_end − t_start) × i / (n − 1), dus het eerste frame is het begin en het laatste is het voltooide beeld. manifest.json legt fps, duration_s, frame_count, frame_pattern (frame_%04d.svg), de pixelgrootte, t_start, t_end, de missietijd van elk frame (frame_times), de fasen, de gebeurtenissen en de bronnen vast. Een nieuwe export naar dezelfde map verwijdert eerst elke frame_NNNN.svg die er al staat (en niets anders), zodat een kortere reeks nooit frames van een langere achterlaat die de encoder zou lezen.
De frames zijn SVG, geen Portable Network Graphics (PNG). Een ffmpeg die met de bibliotheek librsvg is gebouwd leest ze rechtstreeks, met de framesnelheid waarmee de reeks is geschreven (24 in het voorbeeld hierboven; de fps van het manifest):
ffmpeg -framerate 24 -i clock-holdover.frames/frame_%04d.svg -pix_fmt yuv420p clock-holdover.mp4
Een ffmpeg zonder librsvg stopt met „no decoder found for: svg”. Rasteriseer de frames eerst, bijvoorbeeld met rsvg-convert, en encodeer de PNG's:
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
Toegankelijkheid en thema#
- Kleurenschema. De speler volgt
prefers-color-schemeen tekent opnieuw wanneer die verandert; de geanimeerde SVG bevat onder dezelfde mediaquery een lichte variant van zijn palet. De frames gebruiken het donkere palet van de statische grafieken, omdat een video geen schema heeft. - Verminderde beweging. Onder
prefers-reduced-motion: reduceschakelt de geanimeerde SVG elke animatie uit en toont het voltooide beeld (de basisstijlen zijn de eindtoestand, dus niets is verborgen), en de speler opent gepauzeerd op het voltooide beeld in plaats van af te spelen; de gebruiker kan nog steeds scrubben of op Play drukken. - De SVG heeft een
<title>en<desc>; de bediening van de speler bestaat uit gelabelde knoppen, een bereikinvoer met een uitgesproken tijdwaarde en een keuzelijst.
Wat als tijdreeks telt#
De resultaatdocumenten verschillen per soort, dus de exporter herkent de vormen die de engine uitgeeft in plaats van een lijst van soorten:
- Een array van records met een tijdveld (
t,t_s,t_hours,t_min,t_days, ofkop eenepochs-array) dat strikt toeneemt langs de array. Elk ander numeriek veld wordt een trace; hetzelfde veld onder twee wortels (quantum.series[].error_nsenclassical.series[].error_ns) deelt een paneel. - Een object met een strikt toenemende tijdarray (
t_s,t,times_s, …) naast arrays van dezelfde lengte: naastliggende numerieke arrays, eenchannels-map van{unit, values}-records (decampaign-tijdlijn), een array van records die zulke arrays bevatten (despectrum-banden, de satellietsporen van een constellatie) en een tweedimensionale array waarvan de rijen overeenkomen met de tijdas met een naastliggende frequentieas*_hz(despectrum-waterfall). - Naast die tijdarray worden
phases(name,t0_s,t1_s) de fasebalk enevents(t_s,label,alarm) de markeringen. De scalars*_t_svan een band (het eerste verlies van lock, de laagste draaggolf-ruisdichtheidsverhouding) worden ook gemarkeerd.
Traces met een eenheid delen een paneel wanneer hun grootte binnen een factor 100 ligt, zodat een guard van 50 ns een fout van 2 ns niet afvlakt. Er worden hoogstens 6 panelen van 6 traces getekend; de rest staat onder omitted. Traces van meer dan 2.400 samples worden uitgedund met een gelijkmatige stap die de laatste sample behoudt, en een waterfall van meer dan 96 × 120 cellen wordt gemiddeld verkleind (in vermogen, voor decibelcellen, zodat een smalle jammer niet wordt verdund).
Een soort waarvan het resultaat geen van deze vormen bevat (een linkbudget, een geometrie voor één epoche, een Monte Carlo-samenvatting met alleen statistiek, of de telecom-holdover, waarvan het resultaat de hash van de opname publiceert maar niet de opname zelf) wordt geweigerd met no time series to animate, en er wordt niets geschreven. Met kshana 0.40.0 worden 94 van de 193 uitvoerbare scenariobestanden (elk bestand behalve een studiesuite) geanimeerd en worden 99 geweigerd. cargo test --test animation -- --nocapture drukt de telling af.
Onder de LEO-soorten animeert elk meegeleverd scenario leo-pass, leo-pnt-chain en leo-ppp. leo-pvt animeert in zijn modi Doppler, gezamenlijke positiebepaling en tijdsynchronisatie (een tijdsynchronisatierun heeft trace = true nodig, waardoor elke rij bij elke epoch zijn tijdfout en voorspelde sigma rapporteert) en wordt geweigerd in zijn modus poolbedekking. leo-navmsg animeert zijn update halverwege de overpassing en wordt geweigerd voor de analyses van codering, fitinterval en modelvergelijking. Resultaten van leo-signal en ntn-positioning hebben geen tijdas en worden geweigerd.
Determinisme#
De uitvoer is een zuivere functie van het resultaatdocument en de opties: geen klok, geen willekeurig getal, geen iteratie over een hashmap, geen bestands- of netwerktoegang in de bibliotheek en nergens een tijdstempel, dus hetzelfde scenario, dezelfde seed en dezelfde opties geven byte-identieke bestanden. De module bouwt ongewijzigd voor WebAssembly; alleen de opdrachtregelinterface schrijft bestanden.
Gebruik als bibliotheek#
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 animeert een resultaatdocument dat u al hebt, en extract_timeline geeft terug wat er getekend zou worden zonder het te renderen.
Beperkingen#
- Het Python-wheel en de WebAssembly-module bieden de exporter nog niet aan; hij is bereikbaar via de opdrachtregel, de Rust-bibliotheek en het hulpmiddel
animate_scenariovan de Model Context Protocol-server (MCP) (dat in één antwoord hoogstens 120 frames teruggeeft). - De assen zijn lineair. Een reeks die vele decaden overspant (de foutgroei van een klok van 0,1 ns tot een microseconde) oogt vlak tot laat in de run.
- De geanimeerde SVG steunt op CSS-animatie van een knipvierkant; de huidige engines van Chromium, Firefox en Safari spelen hem af, terwijl een viewer zonder CSS-animatie het voltooide beeld toont.
- Sweep-, Monte Carlo- en compose-campagnes hebben geen tijdas en worden geweigerd; de samenvattende statistieken van een sweep of een ensemble zijn geen tijdreeks. Een geketende campagne animeert wel.