Traducción automática, no revisada por un hablante nativo. El inglés es la referencia.

Salidas y exportacionesEditar en GitHubFuente: docs/ANIMATION.md

Exportación de animaciones

--animate convierte la serie temporal de una ejecución en algo que se mueve: un archivo Scalable Vector Graphics (SVG) animado, un único reproductor HyperText Markup Language (HTML) autónomo o una secuencia numerada de fotogramas SVG para un codificador de vídeo. Una campaña se reproduce como sus fases (jamming, spoofing, holdover, alarma de integridad) con sus alarmas marcadas; una ejecución de espectro reproduce su cascada fila a fila; una pasada en órbita terrestre baja (LEO) reproduce su enlace por banda y, con un spoofer, las estadísticas del monitor época a época.

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

Código: src/animation.rs. Pruebas: tests/animation.rs.

Qué es y qué no es#

El exportador lee el documento de resultados que la ejecución ya escribió. No vuelve a ejecutar la física, no remuestrea, suaviza ni interpola entre muestras (salvo el tramo rectilíneo que cierra una traza en el cursor), y no añade ninguna cifra propia. Por tanto, una animación es exactamente tan buena como la ejecución que hay detrás. Su nivel es MODELLED, coherencia interna: es una representación, nunca evidencia, y no lleva ninguna fila propia de la matriz de verificación.

Salidas#

Cada formato se escribe junto al escenario, además de los habituales result.json, chart.svg y report.html:

Formato Se escribe como Qué contiene
svg <scenario>.animation.svg Un SVG animado con fotogramas clave de Cascading Style Sheets (CSS) y sin script: las trazas se dibujan detrás de un cursor de tiempo móvil, los eventos aparecen en su instante y las filas de la cascada se revelan en orden temporal. Se repite en bucle, con una pausa de 1,5 s sobre la imagen terminada.
html <scenario>.animation.html Un archivo con script y estilo en línea y sin ningún recurso externo: reproducir y pausar, un control de desplazamiento, velocidad (0.25x a 4x), todos los paneles con un único cursor sincronizado, un valor en vivo por traza, la franja de fases y una lista de eventos que salta al hacer clic. La barra espaciadora reproduce o pausa, las teclas de flecha avanzan, Inicio y Fin saltan.
frames <scenario>.frames/ frame_0000.svg, frame_0001.svg, … y manifest.json.

--animate es repetible y admite una lista separada por comas (--animate svg,html) o all. --animate-fps (1 a 60, por defecto 12) y --animate-duration (0,5 s a 600 s, por defecto 8 s) fijan la reproducción; la secuencia de fotogramas está limitada a 7.200 fotogramas.

Cuando --export se ejecuta en el mismo comando, el reproductor HTML enumera los archivos de exportación escritos junto a él (CZML, KML, GeoJSON, STK, SigMF) como enlaces relativos a esos archivos hermanos; solo se escribe un enlace para un nombre de archivo simple, de modo que ninguno puede salir de la carpeta ni llegar a la red. El informe avanzado (report.html) incrusta el dibujo animado siempre que el resultado tiene una serie temporal, se haya ejecutado o no --animate.

Cuando se ejecuta --animate, result.json gana un bloque animation: los formatos, los fotogramas por segundo (fps), la duración, el número de fotogramas, el intervalo de tiempo, los títulos de los paneles, las rutas JSON de las que se leyó cada traza (sources) y cualquier serie encontrada pero no dibujada (omitted). Sin --animate el resultado es idéntico byte a byte al de una ejecución normal.

La secuencia de fotogramas#

La secuencia tiene exactamente round(duration × fps) fotogramas. El fotograma i muestra la línea de tiempo hasta t_start + (t_end − t_start) × i / (n − 1), de modo que el primer fotograma es el inicio y el último es la imagen terminada. manifest.json registra fps, duration_s, frame_count, frame_pattern (frame_%04d.svg), el tamaño en píxeles, t_start, t_end, la hora de misión de cada fotograma (frame_times), las fases, los eventos y las fuentes. Una reexportación en el mismo directorio elimina primero todos los frame_NNNN.svg que ya hubiera allí (y nada más), de modo que una secuencia más corta nunca deja fotogramas de una más larga para que los lea el codificador.

Los fotogramas son SVG, no Portable Network Graphics (PNG). Un ffmpeg compilado con la biblioteca librsvg los lee directamente, a la frecuencia con la que se escribió la secuencia (24 en el ejemplo de arriba; el fps del manifiesto):

ffmpeg -framerate 24 -i clock-holdover.frames/frame_%04d.svg -pix_fmt yuv420p clock-holdover.mp4

Un ffmpeg sin librsvg se detiene con "no decoder found for: svg". Rasterice primero los fotogramas, por ejemplo con rsvg-convert, y codifique los 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

Accesibilidad y tema#

  • Esquema de color. El reproductor sigue prefers-color-scheme y se redibuja cuando cambia; el SVG animado lleva una variante clara de su paleta bajo la misma media query. Los fotogramas usan la paleta oscura de los gráficos estáticos, porque un vídeo no tiene esquema.
  • Movimiento reducido. Bajo prefers-reduced-motion: reduce el SVG animado desactiva toda animación y muestra la imagen terminada (sus estilos base son el estado final, de modo que no se oculta nada), y el reproductor se abre en pausa sobre la imagen terminada en lugar de reproducirse; el usuario aún puede desplazarse o pulsar Reproducir.
  • El SVG tiene un <title> y un <desc>; los controles del reproductor son botones etiquetados, una entrada de rango con un valor de tiempo hablado y un selector.

Qué cuenta como serie temporal#

Los documentos de resultados difieren de un tipo de escenario a otro, de modo que el exportador reconoce las formas que emite el motor en lugar de una lista de tipos de escenario:

  1. Una matriz de registros con un campo de tiempo (t, t_s, t_hours, t_min, t_days, o k en una matriz epochs) que crece estrictamente a lo largo de la matriz. Cada otro campo numérico se convierte en una traza; el mismo campo bajo dos raíces (quantum.series[].error_ns y classical.series[].error_ns) comparte un panel.
  2. Un objeto con una matriz de tiempo estrictamente creciente (t_s, t, times_s, …) junto a matrices de la misma longitud: matrices numéricas hermanas, un mapa channels de registros {unit, values} (la línea de tiempo de campaign), una matriz de registros que contienen tales matrices (las bandas de spectrum, las trazas de satélites de una constelación) y una matriz bidimensional cuyas filas coinciden con el eje de tiempo con un eje de frecuencia *_hz hermano (la cascada de spectrum).
  3. Junto a esa matriz de tiempo, phases (name, t0_s, t1_s) se convierten en la franja de fases y events (t_s, label, alarm) en los marcadores. Los escalares *_t_s de una banda (su primera pérdida de enganche, su relación portadora-ruido más baja) también se marcan.

Las trazas con unidad comparten un panel cuando sus magnitudes están dentro de un factor de 100, de modo que una guarda de 50 ns no aplana un error de 2 ns. Se dibujan como máximo 6 paneles de 6 trazas; el resto se enumera en omitted. Las trazas de más de 2.400 muestras se aclaran con un paso uniforme que conserva la última muestra, y una cascada de más de 96 × 120 celdas se promedia a la baja (en potencia, para celdas en decibelios, de modo que un jammer estrecho no se diluya).

Un tipo de escenario cuyo resultado no lleva ninguna de estas formas (un balance de enlace, una geometría de una sola época, un resumen Monte Carlo solo de estadísticas, o el holdover de telecomunicaciones, cuyo resultado publica el hash del registro pero no el registro) se rechaza con no time series to animate, y no se escribe nada. Con kshana 0.40.0, 94 de los 193 archivos de escenario ejecutables (todos salvo un conjunto de estudio) se animan y 99 se rechazan. cargo test --test animation -- --nocapture imprime el censo.

Entre los tipos de escenario LEO, todo escenario leo-pass, leo-pnt-chain y leo-ppp incluido se anima. leo-pvt se anima en sus modos de Doppler, de posicionamiento conjunto y de temporización (una ejecución de temporización necesita trace = true, que hace que cada fila informe de su error de tiempo y de su sigma previsto en cada época) y se rechaza en su modo de cobertura polar. leo-navmsg anima su actualización a mitad de pasada y se rechaza para los análisis de codificación, de intervalo de ajuste y de comparación de modelos. Los resultados de leo-signal y ntn-positioning no llevan eje de tiempo y se rechazan.

Determinismo#

La salida es una función pura del documento de resultados y de las opciones: sin reloj, sin números aleatorios, sin iteración de mapas hash, sin acceso a archivos ni a la red en la biblioteca, y sin marca de tiempo en ningún sitio, de modo que el mismo escenario, la misma semilla y las mismas opciones dan archivos idénticos byte a byte. El módulo se compila para WebAssembly sin cambios; solo la interfaz de línea de comandos escribe archivos.

Uso como biblioteca#

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 anima un documento de resultados que usted ya tiene, y extract_timeline devuelve lo que se dibujaría sin renderizarlo.

Límites#

  • El wheel de Python y el módulo WebAssembly todavía no exponen el exportador; se llega a él desde la línea de comandos, la biblioteca de Rust y la herramienta animate_scenario del servidor Model Context Protocol (MCP) (que devuelve como máximo 120 fotogramas en una respuesta).
  • Los ejes son lineales. Una serie que abarca muchas décadas (el crecimiento del error de un reloj de 0,1 ns a un microsegundo) se ve plana hasta tarde en la ejecución.
  • El SVG animado se apoya en la animación CSS de un rectángulo de recorte; los motores actuales de Chromium, Firefox y Safari lo reproducen, mientras que un visor sin animación CSS muestra la imagen terminada.
  • Las campañas de barrido, Monte Carlo y composición no llevan eje de tiempo y se rechazan; las estadísticas de resumen de un barrido o de un conjunto no son una serie temporal. Una campaña encadenada se anima.