Kshana · क्षण · el instante preciso
Un simulador de código abierto para la resiliencia de PNT (posicionamiento, navegación y temporización).
Versión v0.40.0 176 de 401 capacidades validadas frente a referencias independientes externas Cerca del 95% de cobertura de líneas, con un mínimo del 85% exigido en la integración continua Licencia: AGPL-3.0-only, o una licencia comercial DOI 10.5281/zenodo.20528627
Ensaye el minuto en que el GNSS se apaga#
Kshana reproduce jamming, spoofing y holdover de reloj cuando fallan las señales GNSS (Sistema Global de Navegación por Satélite), y le dice cuánto tiempo mantiene un sistema la hora y la posición dentro de su presupuesto, y qué reloj o sensor aporta más margen. Este es el paquete WebAssembly: todo el motor en JavaScript, en el navegador o en Node.js. Cada ejecución es reproducible bit a bit a partir del escenario, la semilla y la versión del motor.
Pruébelo primero sin instalar nada: Kshana Studio ejecuta todo el motor en su navegador, compilado a WebAssembly, y no sube nada.
Evidencias#
176 de 401 capacidades validadas frente a referencias independientes externas; 221 etiquetadas con franqueza como modeladas, 4 propiedad de socios. Cada capacidad lleva una etiqueta en un registro verificado por máquina: VALIDATED (una referencia independiente externa coincide: datos reales, una implementación independiente o vectores de referencia publicados), MODELLED (internamente consistente, y dicho en voz alta) o PARTNER (un socio de hardware es su propietario). Entre las comprobaciones: los 666 vectores SGP4 (Simplified General Perturbations 4) de AIAA (American Institute of Aeronautics and Astronautics) 2006-6753 con 4,12 mm, y el modelo de fuerzas de Cowell con 0,08 m frente a Orekit 12,2.
Instalación#
npm install kshana
Uso#
El paquete es un módulo ES (ECMAScript, JavaScript estándar) con una carga WebAssembly, creado para el navegador. Inicialícelo una vez y después llame al motor de forma síncrona. La única diferencia entre el navegador y Node.js es cómo se carga el binario de WebAssembly.
En el navegador (mediante un empaquetador, o una página que sirva node_modules/kshana/), init() obtiene kshana_bg.wasm desde junto al módulo:
import init, { run, summary, chart_svg, version } from "kshana";
await init(); // fetch and compile the WebAssembly binary
En Node.js, init() falla con TypeError: fetch failed (el fetch de Node no puede leer un archivo local), así que lea el binario del disco y páselo a initSync:
import { readFileSync } from "node:fs";
import { createRequire } from "node:module";
import { initSync, run, summary, chart_svg, version } from "kshana";
const wasmPath = createRequire(import.meta.url).resolve("kshana/kshana_bg.wasm");
initSync({ module: readFileSync(wasmPath) }); // compile the WebAssembly binary
Guarde la versión de Node.js como un archivo .mjs (o establezca "type": "module" en su package.json) para que import funcione. A partir de ahí ambas son iguales:
// A complete scenario, not a sketch: scenarios/clock-holdover.toml without its comment
// lines. It runs 2 h, 10 min of GNSS then about 1.8 h with GNSS denied, and asks how long
// a strontium optical clock and a chip-scale atomic clock (CSAC) each hold time to within
// 20 ns. sigma_y(1s) is a clock's Allan deviation at an averaging time of one second;
// q_wf, the white-frequency-noise intensity, is its square.
const toml = `
seed = 42
threshold_ns = 20.0
[time]
step_s = 10.0
duration_s = 7200.0
[gnss]
windows = [
{ t0 = 0.0, t1 = 600.0, state = "nominal" },
{ t0 = 600.0, t1 = 7200.0, state = "denied" },
]
[clock_quantum]
id = "optical-sr-lattice"
provenance = "Strontium optical lattice clock, space-oriented goal sigma_y(1s)=1e-15 (Origlia/Schiller/Bongs et al., arXiv:1503.08457); q_wf=sigma_y(1s)^2; ground-demonstrator maturity, not flown; flicker/aging not modeled"
y0 = 5.0e-17
q_wf = 1.0e-30
q_rw = 0.0
[clock_classical]
id = "csac-sa45s"
provenance = "Microchip SA65 / SA.45s CSAC datasheet sigma_y(1s)=3e-10; q_wf=sigma_y(1s)^2; flicker/aging not modeled"
y0 = 5.0e-10
q_wf = 9.0e-20
q_rw = 0.0
`;
const result = JSON.parse(run(toml)); // the full result document
// timing_p95_ns: the 95th-percentile timing error over the GNSS outage, in nanoseconds
console.log(version(), result.classical.fom.timing_p95_ns);
console.log(summary(toml)); // the one-line result string
const svg = chart_svg(toml); // the same chart the command-line interface (CLI) writes
TypeScript ve resultados tipados: run_typed(toml) devuelve un RunOutput (json, svg, summary, csv: string | null, data: ResultDocument), scenario_kinds() devuelve un KindMeta[] cuyo name es la unión ScenarioKind de todos los tipos, y error_kind() devuelve un ErrorKind (o "" si tiene éxito). Los campos propios de cada documento de resultados varían según el tipo; ResultDocument tipa la envoltura compartida (schema_version, engine_version y el bloque units de FieldUnits).
import { run_typed, scenario_kinds, type ScenarioKind } from "kshana";
const out = run_typed(toml);
const units = out.data.units; // Record<string, FieldUnit>
const kinds: ScenarioKind[] = scenario_kinds().map((k) => k.name);
Cuatro funciones más describen el motor a una interfaz. kind_modules() devuelve un objeto JSON que asigna a cada tipo los módulos que nombran sus filas de la matriz de verificación, field_importance() otro que asigna a cada tipo los campos de resultados que responden a su pregunta (metadatos de presentación; el motor nunca los lee), iq_signals() los nombres de señal que acepta iq_run_short, y iq_run_short(fs_hz, duration_s, signal, ids, dopplers_hz, cn0_dbhz, seed) una escena IQ sintética corta, adquirida y seguida en memoria (como máximo 0,25 s, 1.000.000 muestras y 8 satélites), con la misma respuesta que la compilación nativa.
import { list_examples, get_example, export_scenario, animate_scenario } from "kshana";
const names = JSON.parse(list_examples("")).scenarios.map((s) => s.name); // the bundled scenarios
const toml = get_example("orbit-gnss-challenged"); // its TOML, byte for byte
const czml = JSON.parse(export_scenario(toml, "czml")).files[0].content; // a CZML file, in memory
const player = JSON.parse(animate_scenario(toml, "html", 0, NaN, 0)).files; // {name: html text}
En la cara WebAssembly cada punto de entrada es una llamada aparte: run (el documento de resultados como cadena JSON), summary, chart_svg, table_csv (la tabla CSV (valores separados por comas) del escenario como cadena, o undefined para los tipos que no publican tabla; lanza un error con un escenario no válido), run_all (una ejecución del motor que devuelve {json, svg, summary, csv} como cadena JSON: úsela cuando quiera más de una salida, ya que cada otra llamada ejecuta el escenario de nuevo), run_typed (las mismas salidas como un único objeto tipado, con el documento ya interpretado como data), version, list_kinds / scenario_kinds / error_kind (introspección; scenario_kinds devuelve la lista interpretada), encode_permalink / decode_permalink (el códec de enlaces compartibles (URL, localizador uniforme de recursos) que Kshana Studio usa para recorrer ida y vuelta un escenario completo por el fragmento de la barra de direcciones) y export_sp3 / export_omm / export_oem, los artefactos de efemérides SP3-c (revisión c del formato Standard Product 3) y CCSDS (Consultative Committee for Space Data Systems) que escribe la CLI (OMM, el Orbit Mean-elements Message, y OEM, el Orbit Ephemeris Message), y receiver_trust, que evalúa un registro real de receptor descrito por un escenario receiver-trust y devuelve {json, csv, svg, summary} como cadena JSON (el navegador no tiene sistema de archivos, así que el registro, y cualquier archivo de navegación, deben ir en línea en el escenario como text o base64; una tabla [platform] kind = "vessel" añade los monitores marítimos y la puntuación de confianza de 0 a 100, solo consultiva), export_formats / export_scenario (qué formatos de interoperabilidad admite un escenario, sin ejecutarlo, y una exportación en memoria: czml, kml, geojson, stk o sigmf como JSON {format, spec_url, files}, idéntica byte a byte para el mismo escenario, sin subir nada), import_route (una ruta GeoJSON escrita en un escenario de trayectoria por puntos de ruta, el --import-route de la línea de comandos), animate_scenario (la serie temporal de la ejecución como SVG animado, un único reproductor HTML o fotogramas SVG), list_examples / get_example (los escenarios de referencia incluidos y su TOML), evidence_attach_timestamp (vincula un token RFC 3161 a un paquete de evidencias en memoria; el paquete debe seguir verificándose, y no se comprueba la firma de la autoridad de sellado de tiempo), osnma_verify (qué datos de navegación de Galileo de qué satélites autentica un archivo de páginas I/NAV o un flujo UBX, con la raíz de Merkle de confianza o las claves públicas y una hora de referencia independiente opcional; autentica datos y no hace ninguna afirmación de prestaciones antispoofing; no se sube nada), receiver_trust_replay (un extracto NMEA acotado puntuado como lo puntúa el modo en vivo; sin compuerta), assess_vessel_log (el registro NMEA de un buque como ejecución por lotes), trust_telemetry (un flujo o resultado de confianza como texto Prometheus, líneas syslog CEF o LEEF, o una carga OTLP; no se envía nada), evidence_verify (comprueba un paquete de evidencias firmado; no se sube nada; los paquetes se crean con la CLI, Python o MCP), bench_export (el movimiento y los eventos de un escenario como texto para un simulador de laboratorio; no se escribe ninguna señal), compliance_report y compliance_mapping (a qué filas de requisitos de marcos públicos aportan evidencias a favor de los documentos de resultados, con la brecha de cada fila; no es una conclusión de que se alcance un marco), y interference_map (texto CSV de ADS-B o AIS a un GeoJSON kshana-interference-map/v1 por día UTC; solo agregado), route_exposure (la proporción de una ruta que atraviesa celdas degradadas de esos mapas; no es un pronóstico), nmea_training (NMEA de puente sintético y un registro del instructor para la formación de tripulaciones; solo texto, nunca para los sistemas de navegación en servicio de un buque) y las funciones de geometría del cielo sky_geometry, sky_monte_carlo, skyline_presets, skyline_profile y skyplot_svg (qué satélites ve un emplazamiento cuando edificios, muelles o terreno bloquean parte del cielo, con la dilución de la precisión, la elipse de error horizontal, una nube de Monte Carlo con semilla y un skyplot como texto SVG; la decisión de visibilidad y la elipse se comprueban frente a bibliotecas independientes, los preajustes son geometrías representativas y no levantamientos, y un horizonte elimina los satélites con línea de visión y nada más). No están en la compilación del navegador: receiver-trust live con su compuerta y su escucha TCP, el NMEA de formación en flujo y los exportadores de telemetría (Prometheus, OpenTelemetry, syslog) son procesos de red de larga duración y permanecen en la herramienta de línea de comandos; crear un paquete de evidencias requiere una clave de firma, que corresponde a la CLI o a Python. Aquí no hay una llamada única run_full; ese enlace existe solo en la wheel de Python.
Cada capacidad de la matriz de verificación se etiqueta como validada (comprobada frente a una referencia independiente externa), modelada o propiedad de un socio; las cifras de relojes ópticos son objetivos espaciales sobre hardware de tierra (ningún reloj óptico de estroncio ha volado). La madurez no es uniforme entre dominios: el PNT terrestre está validado con datos reales; la navegación del espacio profundo y de Marte está modelada, con solo sus bloques constructivos (tiempo de luz, posiciones planetarias) validados frente a referencias independientes externas; la determinación de órbita (OD) del espacio profundo en misiones reales está en la hoja de ruta.
Capacidades#
El motor tiene 92 tipos de escenario; kshana kinds los enumera con sus campos. Nuevos en 0.38.0: gnss-ssv (señales GNSS para naves por encima, alrededor y más allá de las órbitas GNSS) y lunar-infrastructure (órbita y superficie lunares como infraestructura de navegación y geodésica), ambos MODELLED, y holdover-test (un registro de error de tiempo frente a las máscaras ITU-T).
- Espectro: cómo un jammer se apodera de la banda L del GNSS, banda por banda.
- Relojes y temporización: holdover frente a un umbral, transferencia de tiempo y holdover de telecomunicaciones frente a las máscaras del sector de normalización de la Unión Internacional de Telecomunicaciones (UIT-T).
- Constelaciones alrededor de cualquier cuerpo: cobertura, dilución de la precisión y disponibilidad alrededor de la Tierra, la Luna o Marte, y el sistema solar en una época.
- Navegación en órbita terrestre baja: señal, pasada y enlace, mensaje de navegación y una posición fusionada, etapa por etapa.
- Campañas: una misión encadenada, un barrido o un conjunto de Monte Carlo en un solo escenario.
- Informes, animación y exportaciones: cada cifra con su unidad y su etiqueta; un dibujo animado de una ejecución; archivos SP3 (Standard Product 3), mensajes de órbita CCSDS (Consultative Committee for Space Data Systems), CZML (Cesium Language), KML (Keyhole Markup Language), GeoJSON, STK (Systems Tool Kit) y SigMF (Signal Metadata Format).
Arquitectura#
El mismo archivo de escenario da los mismos bytes en todas las superficies. MCP es el Model Context Protocol: kshana-mcp permite que un asistente de IA (inteligencia artificial) ejecute el motor.
Investigación#
Seis artículos en arXiv se basan en el motor abierto, cada uno con el comando que hay detrás: arXiv:2606,22054 (la brecha de optimismo de los detectores de interferencia), arXiv:2606,24210 (un nivel de protección de temporización condicional), arXiv:2607,05415 (cuán estable es una puntuación de resiliencia de PNT), arXiv:2607,02566 (observabilidad de estaciones de superficie lunar con interferometría de base muy larga), arXiv:2607,06212 (geometría del polo sur lunar y balizas de superficie) y arXiv:2610,23871 (la navegación cislunar como problema de observabilidad: longitud de arco, condicionamiento del gramiano y la palanca Doppler). Véase Investigación.
Ediciones#
Todo el motor es libre bajo la AGPL-3.0. Kshana Pro, una capa propietaria que depende del motor abierto y nunca lo bifurca, y los estudios a medida están disponibles por contrato con Ashforde® OÜ: contact@ashforde.org. No hay precios; véase docs/PRO.md.
Más información#
- El README completo → https://github.com/AshfordeOU/kshana
- Kshana Studio (el motor en su navegador, como WebAssembly) → https://kshana.dev
- Capacidades → docs/CAPABILITY.md
- Validación y procedencia → docs/VALIDATION.md · docs/PROVENANCE.md
- Matriz de verificación → docs/VERIFICATION-MATRIX.md
- Cómo citar → CITATION.cff · DOI 10.5281/zenodo.20528627
Licencia#
Software libre y de código abierto bajo la GNU AGPL-3.0-only (la Licencia Pública General de GNU Affero, solo versión 3). Hay disponible una licencia comercial de Ashforde® OÜ (una sociedad privada de responsabilidad limitada estonia; OÜ = osaühing) para integración cerrada; véase LICENSING.md. Desarrollado y mantenido profesionalmente por Ashforde® OÜ.