Експорт анімації
--animate перетворює часовий ряд прогону на щось рухоме: анімований файл Scalable Vector Graphics (SVG), єдиний самодостатній програвач HyperText Markup Language (HTML) або пронумеровану послідовність кадрів SVG для відеокодувальника. Кампанія відтворюється за своїми фазами (глушіння, спуфінг, holdover, тривога цілісності) із позначеними тривогами; прогін спектра відтворює свій водоспад рядок за рядком; прохід на низькій навколоземній орбіті (LEO) відтворює свою лінію за діапазонами і, зі спуфером, статистики монітора епоха за епохою.
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
Код: src/animation.rs. Тести: tests/animation.rs.
Що це таке і чим воно не є#
Експортер читає документ результату, який прогін уже записав. Він не перезапускає фізику, не передискретизує, не згладжує й не інтерполює між відліками (окрім одного прямолінійного відрізка, що завершує криву на курсорі) і не додає жодного власного числа. Тому анімація настільки ж добра, наскільки добрий прогін за нею. Її рівень — MODELLED, внутрішня узгодженість: це відтворення, ніколи не докази, і вона не має власного рядка матриці верифікації.
Виходи#
Кожен формат записується поруч зі сценарієм, біля звичних result.json, chart.svg і report.html:
| Формат | Записується як | Що містить |
|---|---|---|
svg |
<scenario>.animation.svg |
Один SVG, анімований ключовими кадрами Cascading Style Sheets (CSS) без скриптів: криві домальовуються за рухомим курсором часу, події з'являються у свій момент, рядки водоспаду розкриваються в порядку часу. Він повторюється циклічно з витримкою 1,5 с на готовій картинці. |
html |
<scenario>.animation.html |
Один файл із вбудованими скриптом і стилем та без зовнішніх ресурсів: відтворення та пауза, повзунок, швидкість (від 0.25x до 4x), усі панелі на одному синхронізованому курсорі, жива величина для кожної кривої, смуга фаз і список подій, що перемотує за клацанням. Пробіл вмикає або зупиняє відтворення, стрілки роблять крок, Home і End переходять до початку й кінця. |
frames |
<scenario>.frames/ |
frame_0000.svg, frame_0001.svg, … і manifest.json. |
--animate можна повторювати, і він приймає список через кому (--animate svg,html) або all. --animate-fps (від 1 до 60, типово 12) і --animate-duration (від 0,5 с до 600 с, типово 8 с) задають відтворення; послідовність кадрів обмежено 7 200 кадрами.
Коли --export виконується в тій самій команді, програвач HTML перелічує файли експорту, записані поруч (CZML, KML, GeoJSON, STK, SigMF), як відносні посилання на ці сусідні файли; посилання записується лише для простого імені файлу, тож жодне не може вийти за межі теки чи дістатися мережі. Розширений звіт (report.html) вбудовує анімований рисунок щоразу, коли результат має часовий ряд, незалежно від того, чи запускалася --animate.
Коли --animate виконується, result.json отримує блок animation: формати, кадри за секунду (fps), тривалість, кількість кадрів, часовий інтервал, заголовки панелей, шляхи JSON, з яких прочитано кожну криву (sources), і будь-які знайдені, але не намальовані ряди (omitted). Без --animate результат побайтово ідентичний звичайному прогону.
Послідовність кадрів#
Послідовність має рівно round(duration × fps) кадрів. Кадр i показує часову шкалу до t_start + (t_end − t_start) × i / (n − 1), тож перший кадр — це початок, а останній — готова картинка. manifest.json записує fps, duration_s, frame_count, frame_pattern (frame_%04d.svg), розмір у пікселях, t_start, t_end, місійний час кожного кадру (frame_times), фази, події та джерела. Повторний експорт у ту саму теку спершу видаляє кожен frame_NNNN.svg, що вже там є (і більше нічого), тож коротша послідовність ніколи не залишає кадрів довшої для кодувальника.
Кадри — це SVG, а не Portable Network Graphics (PNG). ffmpeg, зібраний із бібліотекою librsvg, читає їх напряму з частотою, з якою записано послідовність (24 у прикладі вище; fps маніфесту):
ffmpeg -framerate 24 -i clock-holdover.frames/frame_%04d.svg -pix_fmt yuv420p clock-holdover.mp4
ffmpeg без librsvg зупиняється з повідомленням «no decoder found for: svg». Спершу растеризуйте кадри, наприклад за допомогою rsvg-convert, і закодуйте 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
Доступність і тема#
- Колірна схема. Програвач слідує за
prefers-color-schemeі перемальовується, коли вона змінюється; анімований SVG містить світлий варіант своєї палітри під тим самим медіазапитом. Кадри використовують темну палітру статичних діаграм, бо відео не має схеми. - Зменшений рух. За
prefers-reduced-motion: reduceанімований SVG вимикає всі анімації й показує готову картинку (його базові стилі — це кінцевий стан, тож нічого не приховано), а програвач відкривається на паузі на готовій картинці замість відтворення; користувач усе одно може перемотати або натиснути Play. - SVG має
<title>і<desc>; елементи керування програвача — це підписані кнопки, поле діапазону з озвучуваним значенням часу та select.
Що вважається часовим рядом#
Документи результатів різняться від виду до виду, тож експортер розпізнає форми, які видає рушій, а не список видів:
- Масив записів із полем часу (
t,t_s,t_hours,t_min,t_daysабоkу масивіepochs), що строго зростає вздовж масиву. Кожне інше числове поле стає кривою; те саме поле під двома коренями (quantum.series[].error_nsіclassical.series[].error_ns) ділить одну панель. - Об'єкт зі строго зростаючим масивом часу (
t_s,t,times_s, …) поряд із масивами тієї самої довжини: сусідні числові масиви, мапаchannelsіз записів{unit, values}(часова шкалаcampaign), масив записів, що містять такі масиви (діапазониspectrum, треки супутників орбітального угруповання), і двовимірний масив, рядки якого відповідають осі часу, із сусідньою віссю частот*_hz(водоспадspectrum). - Поряд із цим масивом часу
phases(name,t0_s,t1_s) стають смугою фаз, аevents(t_s,label,alarm) — маркерами. Скаляри*_t_sдіапазону (його перша втрата захоплення, його найнижче відношення несівної до густини шуму) також позначаються.
Криві з одиницею виміру ділять панель, коли їхні величини відрізняються не більше ніж у 100 раз, тож охоронний інтервал 50 нс не сплющує похибку 2 нс. Малюється щонайбільше 6 панелей по 6 кривих; решту перелічено під omitted. Криві понад 2 400 відліків проріджуються рівномірним кроком, що зберігає останній відлік, а водоспад понад 96 × 120 комірок усереднюється (за потужністю, для децибельних комірок, щоб вузький глушник не розбавлявся).
Тип, результат якого не містить жодної з цих форм (бюджет лінії зв'язку, геометрія за одну епоху, підсумок Монте-Карло лише зі статистик або телекомунікаційний holdover, чий результат публікує хеш запису, але не сам запис), відхиляється з повідомленням no time series to animate, і нічого не записується. У kshana 0.40.0 94 зі 193 придатних до запуску файлів сценаріїв (усі файли, крім набору досліджень) анімуються, а 99 відхиляються. cargo test --test animation -- --nocapture друкує перепис.
Серед видів LEO кожен вбудований сценарій leo-pass, leo-pnt-chain і leo-ppp анімується. leo-pvt анімується в режимах Доплера, спільного позиціонування та синхронізації часу (прогін синхронізації потребує trace = true, що змушує кожен рядок повідомляти похибку часу й прогнозовану сигму в кожній епосі) і відхиляється в режимі полярного покриття. leo-navmsg анімує своє оновлення посеред проходу й відхиляється для аналізів кодування, інтервалу підгонки та порівняння моделей. Результати leo-signal і ntn-positioning не мають осі часу й відхиляються.
Детермінованість#
Вихід — це чиста функція документа результату та параметрів: без годинника, без випадкових чисел, без обходу хеш-мап, без доступу до файлів чи мережі в бібліотеці й без позначок часу будь-де, тож той самий сценарій, зерно (seed) і параметри дають побайтово ідентичні файли. Модуль збирається для WebAssembly без змін; файли записує лише інтерфейс командного рядка.
Використання як бібліотеки#
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 анімує документ результату, який у вас уже є, а extract_timeline повертає те, що було б намальовано, без відтворення.
Обмеження#
- Колесо Python і модуль WebAssembly ще не надають експортер; він доступний з командного рядка, з бібліотеки Rust і з інструмента
animate_scenarioсервера Model Context Protocol (MCP) (що повертає не більше 120 кадрів в одній відповіді). - Осі лінійні. Ряд, що охоплює багато порядків (зростання похибки годинника від 0,1 нс до мікросекунди), виглядає плоским до пізнього етапу прогону.
- Анімований SVG спирається на CSS-анімацію прямокутника обрізання; сучасні рушії Chromium, Firefox і Safari його відтворюють, а засіб перегляду без CSS-анімації показує готову картинку.
- Кампанії перебору, Монте-Карло та compose не мають осі часу й відхиляються; підсумкові статистики перебору чи ансамблю не є часовим рядом. Ланцюгова кампанія анімується.