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

API e integracionesEditar en GitHubFuente: docs/ARCHITECTURE.md

Kshana: arquitectura

Kshana es un único motor organizado en capas sobre un núcleo compartido: los paquetes de sensores (reloj, inercial, transferencia de tiempo, híbrido); una capa de astrodinámica / numérica (SGP4/SDP4 analíticos (SGP4: Simplified General Perturbations 4; SDP4: Simplified Deep-space Perturbations 4), un propagador numérico de Cowell con su modelo de fuerzas de siete perturbaciones, diseño de maniobras, determinación de órbita a partir de distancias de estaciones terrestres y el ajuste del modelo de fuerzas frente a efemérides precisas de agencias); una capa de tiempo y marcos de referencia (escalas de tiempo del IERS (International Earth Rotation and Reference Systems Service), precesión–nutación 2006/2000A de la IAU (International Astronomical Union) y la reducción GCRS↔ITRS con CIO (Celestial Intermediate Origin) (GCRS: Geocentric Celestial Reference System; ITRS: International Terrestrial Reference System)); una capa de fusión (los estimadores GNSS/INS (GNSS: sistema global de navegación por satélite; INS: sistema de navegación inercial)); y las capas de integridad, resiliencia, PNT alternativo (PNT: posicionamiento, navegación y temporización) y lunar (RAIM/ARAIM/SBAS (RAIM: monitorización autónoma de integridad del receptor; ARAIM: monitorización autónoma avanzada de integridad del receptor; SBAS: sistema de aumentación basado en satélites), detección de jamming y de spoofing multicapa, correspondencia de mapas de gravedad/terreno/magnéticos y PNT cislunar); y las capas más recientes de LEO-PNT (PNT en órbita terrestre baja), espectro, sistema solar y diseño de constelaciones, temporización de red y campañas, con los escritores de informes, animaciones e interoperabilidad que puede usar cualquier ejecución (§1d). En todas ellas el motor no sabe nada de "cuántico" frente a "clásico": maneja modelos de error de sensores a través de un escenario de interrupción del GNSS, ejecuta un estimador y puntúa el resultado. Un dispositivo cuántico y uno clásico se comparan por tanto en el mismo escenario, y solo difieren en sus parámetros de error (publicados y citados) y en sus semillas de ruido independientes.

Este documento reúne los diagramas estructurales y de comportamiento. El §1 es el núcleo de paquetes de sensores; el §1a describe las capas de astrodinámica, fusión y PNT alternativo añadidas desde entonces; los §1b–§1d, las capas de estudio, de dominio y de salida. Para el uso, véase el README; para lo que está y no está validado, véase VALIDATION; para la tabla de madurez por capacidad, véase CAPABILITY.

Abreviaturas usadas en los diagramas y no desarrolladas donde aparecen: ADEV, desviación de Allan; BW, ancho de banda; CAI, interferómetro de átomos fríos; CZML, el Cesium Language; Δ-DOR, medición de distancia unidireccional diferencial delta; DO-229E, el estándar de receptores SBAS de RTCA (Radio Technical Commission for Aeronautics); EKF, filtro de Kalman extendido; FM, modulación de frecuencia; GSE, equipo de apoyo en tierra; HPL/VPL, nivel de protección horizontal/vertical; IMU, unidad de medición inercial; IOAG, Interagency Operations Advisory Group; IQ, muestras en fase/cuadratura; ISL, enlace entre satélites; ITU-T, el Sector de Normalización de las Telecomunicaciones de la Unión Internacional de Telecomunicaciones; J2–J6, los armónicos zonales de gravedad de la Tierra de grado 2 a 6; KIF, el Kshana Interchange Format; KML, Keyhole Markup Language; KPI, indicador clave de rendimiento; L1/L5, bandas portadoras GNSS (el L2 de las órbitas halo CR3BP es en cambio el punto de Lagrange 2 Tierra–Luna); LEO, órbita terrestre baja; LOO, dejar uno fuera; LTC, Hora Lunar Coordinada; MEO, órbita terrestre media; MTIE, error máximo de intervalo de tiempo; N2, el número de diversidad de Hill de orden 2; NED, norte-este-abajo; NTN, red no terrestre; OD, determinación de órbita; OPS-SAT, el satélite laboratorio de software en órbita de la Agencia Espacial Europea; PPP, posicionamiento de punto preciso; PSD, densidad espectral de potencia; PVT, posición, velocidad y tiempo; RINEX, Receiver Independent Exchange Format; RK4 / RK5(4), integradores de Runge–Kutta de cuarto orden y de quinto(cuarto) orden incrustado; SH, armónico esférico; SigMF, Signal Metadata Format; SIR, remuestreo por importancia de muestreo; SRIF, filtro de información de raíz cuadrada; SRP, presión de radiación solar; SSC, coeficiente de separación espectral; STK, Systems Tool Kit; SVG, Scalable Vector Graphics; TDEV, desviación de tiempo; TDM, el Tracking Data Message de CCSDS (Consultative Committee for Space Data Systems); TLE, conjunto de elementos de dos líneas; TPL, nivel de protección de temporización; UBX, el protocolo binario de u-blox; UHF, frecuencia ultraalta; VLBI, interferometría de línea de base muy larga; VRW / ARW, paseo aleatorio de velocidad / de ángulo; WASM, WebAssembly.


1. Estructura de módulos#

flowchart TD
    main["main.rs<br/>CLI (thin wrapper)"]
    py["python.rs<br/>PyO3 (feature)"]
    wasm["wasm.rs<br/>wasm-bindgen (feature)"]
    api["api.rs<br/>run_toml: parse · dispatch by kind · json+svg+summary"]

    subgraph shared["Shared core"]
      types["types.rs<br/>Seconds · TimeGrid · ModelSpec"]
      scenario["scenario.rs<br/>GnssState · GnssTimeline · ClockCfg · Scenario"]
      allan["allan.rs<br/>overlapping Allan deviation"]
    end

    subgraph pack1["Pack 1 · Clock holdover"]
      models["models.rs<br/>ErrorModel · ClockModel (incl. flicker FM)"]
      estimator["estimator.rs<br/>HoldoverEstimator"]
      kalman["kalman.rs<br/>KalmanClock → Integrity bound"]
      security["security.rs<br/>clock-aided spoof detection → Security"]
      fom["fom.rs<br/>Sample · FoMScores · score · worst_case_holdover"]
      report["report.rs<br/>RunResult · hash · to_svg"]
      run["run.rs<br/>run / run_clock / run_orbit_clock"]
    end

    inertial["inertial/<br/>Pack 2 · AccelModel (accel + gyro + bias instability/RW) · run_inertial · quantum_imu CAI + QuantumNavBudget dead-reckoning-over-holdover"]
    timetransfer["timetransfer.rs<br/>Pack 3 · TimeTransferLink · run_timetransfer"]
    hybrid["hybrid.rs<br/>Pack 4 · run_suite · score_hybrid · run_hybrid (+ integrity/security)"]
    fusion["fusion/<br/>joint Kalman PNT estimator · run_fusion"]
    orbit["orbit.rs<br/>Propagator (Kepler | SGP4) · Walker / TLE / multi-constellation · visibility · DOP"]
    tle["tle.rs<br/>two-line element parsing (line 2 → Kepler, full TLE → SGP4)"]
    sgp4mod["sgp4.rs<br/>SGP4 / SDP4 propagator (deep-space + resonance)"]
    ensemble["ensemble.rs<br/>Monte Carlo confidence bands"]
    sweep["sweep.rs<br/>trade-study parameter sweeps"]
    spoof["spoof.rs<br/>active spoofing-attack demonstrator"]
    jamming["jamming.rs<br/>link-budget anti-jam C/N₀ (J/S · processing gain · Q)"]
    navsignal["navsignal.rs<br/>signal level: BPSK-R / BOC PSD · SSC κ · Gabor BW · DLL jitter · multipath · ranging-code (m-seq/Gold) design-trade"]
    holdover["holdover.rs<br/>GNSS-denied clock holdover: van-Loan coast → holdover-to-threshold · quantum-clock classes"]
    verification["verification.rs<br/>machine-checked requirement→module→test→oracle→status matrix"]

    main --> api
    py --> api
    wasm --> api
    api --> run
    api --> inertial
    api --> timetransfer
    api --> hybrid
    api --> ensemble
    api --> sweep
    api --> fusion
    api --> spoof
    spoof --> security
    api --> jamming
    api --> holdover
    api --> verification
    navsignal -. derives anti-jam Q (κ → Q=1/(R_c·κ)) .-> jamming
    jamming -. uses PSD / SSC .-> navsignal
    holdover -. coast-variance vs van-Loan recursion .-> kalman
    ensemble --> run
    sweep --> run
    orbit --> tle
    tle --> sgp4mod
    orbit -. SGP4 propagator .-> sgp4mod
    fusion -. composes .-> models
    fusion -. composes .-> inertial
    fusion --> kalman

    run --> models
    run --> estimator
    run --> kalman
    run --> security
    run --> fom
    run --> report
    run --> orbit
    models --> types
    scenario --> types
    inertial --> scenario
    timetransfer --> types
    orbit --> scenario
    hybrid -. composes .-> models
    hybrid -. composes .-> estimator
    hybrid -. composes .-> inertial
    hybrid -. composes .-> timetransfer
    pack1 --> shared
    inertial --> allan

La CLI (interfaz de línea de comandos) y ambos bindings confluyen en un único punto de entrada api::run_toml, de modo que nunca se desvían. Los paquetes reutilizan el núcleo compartido (types, scenario, allan); el Paquete 4 (hybrid) compone los modelos y estimadores de los Paquetes 1–3 en lugar de reimplementarlos; orbit deriva una cronología GNSS a partir de la geometría que después alimenta la ejecución del Paquete 1. El módulo navsignal se sitúa a nivel de señal entre el presupuesto de enlace y el dominio de medición: deriva el coeficiente de separación espectral κ a partir de los espectros de potencia reales de la señal y del jammer, con el que jamming calcula ahora su Q = 1/(R_c·κ) antijamming en lugar de tomar una constante representativa (contrastado en CI (integración continua)); también incluye el compromiso de diseño del código de distancia (secuencia m/Gold).

Tres módulos más forman la espina de resiliencia sin GNSS. holdover responde directamente a la pregunta operativa —¿cuánto tiempo puede un reloj funcionar libre antes de que su error de temporización supere el presupuesto?— exponiendo la forma cerrada de van Loan del error de deriva como una inversión de holdover a umbral, contrastada con la recursión de covarianza de varios pasos de clock_state. Su gemelo inercial vive en inertial::quantum_imu (QuantumNavBudget), que compone la deriva de ruido blanco del interferómetro de átomos fríos con el error de sesgo y de factor de escala en un presupuesto de deriva de posición durante el holdover (el término de sesgo contrastado con el integrador independiente AccelModel). verification genera la matriz completa del motor de requisito a módulo, a prueba, a referencia independiente y a estado, con invariantes comprobados por pruebas unitarias que prohíben una etiqueta de validado sin una referencia independiente externa, de modo que la afirmación de aseguramiento no puede desviarse del código.

1a. Capas de astrodinámica, fusión y PNT alternativo#

Más allá del núcleo de paquetes de sensores, tres subsistemas comparten el mismo núcleo compartido y alimentan a orbit (o son alimentados por él). La capa de astrodinámica / numérica añade un propagador de Cowell no analítico junto a la vía analítica SGP4/SDP4; la capa de fusión lleva los estimadores GNSS/INS; y la capa de PNT alternativo es la correspondencia de mapas de gravedad sin GPS (GPS: Global Positioning System). Son capacidades de biblioteca o de escenario (véase CAPABILITY para saber cuáles están conectadas a un tipo de escenario (kind) y cuáles son accesibles como API (interfaz de programación de aplicaciones) de Rust).

flowchart TD
    subgraph astro["Astrodynamics & numerical"]
      orbit2["orbit · sgp4 · tle · walker<br/>analytic SGP4/SDP4 · Walker design"]
      prop["propagator<br/>Cowell driver (accel_at / accel_rv)"]
      forces["forces<br/>two-body · J2–J6 · EGM2008 d/o-70 · 3rd-body · SRP · drag · Schwarzschild + Lense–Thirring · tides"]
      integ["integrator<br/>RK4 step-doubling · Dormand–Prince RK5(4)"]
      ephem["ephem<br/>low-precision Sun & Moon"]
      man["maneuver<br/>impulsive/finite burns · Izzo Lambert · porkchop"]
      od["orbit_determination<br/>Gauss–Newton batch (batch_ls) · sequential UKF"]
    end
    subgraph fusion["Fusion (GNSS/INS)"]
      ekf["fusion/gnss_ins_ekf · closed_loop · pack<br/>15-state loosely-coupled EKF"]
      tc["fusion/tightly_coupled (8-state)<br/>fusion/tightly_coupled17 (17-state, quantum-CAI)"]
      ukf["fusion/ukf — sigma-point core"]
      coup["fusion/coupled — clock+position cross-covariance"]
    end
    subgraph alt["Alt-PNT (GPS-denied)"]
      grav["gravimeter<br/>cold-atom model + SH anomaly field + mascons"]
      pf["particle_filter — SIR"]
      mm["mapmatch — field-match likelihood"]
    end
    prop --> forces
    prop --> integ
    forces --> ephem
    man --> integ
    od --> forces
    od --> integ
    od --> ukf
    tc --> ukf
    tc -. coasts on .-> forces
    grav --> pf
    mm --> pf
    grav --> mm
    ekf -. drives .-> strap["inertial/ strapdown (quaternion · NED · IMU errors)"]
    tc -. drives .-> strap
    grav -. CAI floor .-> strap

Los términos de fuerza del propagador numérico están desactivados por defecto, de modo que activarlos nunca perturba los goldens publicados. El filtro de Kalman unscented (UKF) de 17 estados y acoplamiento fuerte recorre una interrupción del GNSS con el paseo aleatorio de velocidad derivado del acelerómetro cuántico CAI; la determinación de órbita reutiliza los mismos forces/integrator para propagar un estado candidato a lo largo del arco de seguimiento.

El mismo núcleo compartido lleva además cuatro subsistemas más no dibujados arriba (sus paquetes aparecen en el despacho del §4): una capa de tiempo y marcos de referencia (timescales, jd2, precession, nutation, cio, frames, eop) que reduce TEME↔GCRS↔ITRS (TEME: ecuador verdadero, equinoccio medio) y alimenta el paquete de ephemeris y traza en tierra; una capa de integridad (raim, sbas) para RAIM/ARAIM/SBAS; una capa de resiliencia (jamming, spoof, spoof_detect, spoof_monitors, detection) para la detección de jamming y de spoofing multicapa, con una capa de señal de navegación (navsignal) a nivel de señal —densidades espectrales de potencia BPSK-R (BPSK: modulación por desplazamiento de fase binaria) / BOC (BOC: portadora de desplazamiento binario) senoidal, el coeficiente de separación espectral κ que ahora deriva el Q antijamming de jamming, el ancho de banda de distancia RMS (Gabor), el jitter de seguimiento de código del DLL (lazo de enganche de retardo) coherente temprano–tardío y la envolvente del error de multitrayecto (análisis de prestaciones de señal, no diseño de hardware de carga útil de RF (RF: radiofrecuencia) / antena, que es el papel de un socio de carga útil)—; y una capa lunar / cislunar (lunar, lunar_frame, lunar_od, cr3bp) para la dinámica CR3BP (problema circular restringido de tres cuerpos) —incluida la matriz de transición de estado de 6×6 y un corrector diferencial de disparo único (cr3bp_jacobian, propagate_state_stm, differential_correct_halo) que produce órbitas halo/NRHO (NRHO: órbita halo casi rectilínea) genuinamente periódicas, reproduciendo la NRHO sur L2 9:2 publicada (la órbita de Gateway) con período ≈ 6,57 d / periselenio ≈ 3.250 km (publicado ≈ 6,56 d / ≈ 3.370 km); la transformación selenocéntrica MCI/MCMF (MCI: inercial centrado en la Luna; MCMF: centrado en la Luna y fijo a ella) de una órbita corregida y la continuación de familias siguen pendientes, y la NRHO es una solución CR3BP (circular, sin Sol), no validada frente a una efeméride real de LANS/Gateway (LANS: Lunar Augmented Navigation Service)— e integridad de LunaNet. El ajuste del modelo de fuerzas a efemérides de agencias (precise_od, lunar_od, tides, gravity_sh) y el conjunto completo de campos de PNT alternativo (igrf, altpnt/terrain, gravimeter) completan la lista de módulos; véase CAPABILITY para la madurez por módulo.

1b. Estudios de resiliencia, evaluación de aprendizaje automático y artefactos reproducibles#

Cinco grupos más de módulos forman la capa de estudios abiertos y reproducibles que respalda los artículos de investigación del proyecto. A diferencia de los tipos de escenario (kind), a estos se llega como generadores cargo run --example / --bin que escriben artefactos deterministas byte a byte (semillas fijas, versión del motor y hash de configuración registrados). Todos son MODELLED (calibración sintética o de conjuntos de datos públicos) y llevan etiquetas de validación honestas; ninguno es una certificación.

flowchart TD
    gen["study generators<br/>examples/ · bin/ (cargo run) → byte-deterministic artifacts"]

    subgraph timing["Timing integrity"]
      tplm["tpl<br/>conditional Timing Protection Level: k-σ floor · van-Loan coast · CUSUM"]
    end
    subgraph resilm["Resilience scoring & decision-instability"]
      arch["resilience/arch · score<br/>architecture model + RPCF-aligned scoring"]
      stats["resilience/stats<br/>Dirichlet · Kendall-τ · flip-rate · bootstrap"]
      div["resilience/diversity · timeline<br/>Hill-N2 common-mode collapse · KPIs"]
      study["resilience/study · report · panel<br/>instability study + integrity-hashed assurance report"]
    end
    subgraph aiml["RF-impairment optimism-gap (Machine learning)"]
      ie["impairment_eval<br/>labelled synthetic corpus · ROC/AUC harness"]
      is["impairment_study<br/>13-detector panel · scaling laws · LOO predictor"]
      ml["impairment_ml<br/>logistic-regression + one-hidden-layer MLP"]
      es["eval_stats<br/>bootstrap CI · DeLong · Spearman · ridge"]
      sdrm["sdr · realdata<br/>IQ/IF → E/P/L taps → SQM + ingest adapters"]
    end
    subgraph trade["Quantum-vs-classical"]
      cross["crossover<br/>resilience crossover map under parameter uncertainty"]
      qt["quantum_trade<br/>measured-ADEV holdover benefit vs classical"]
    end

    gen --> timing
    gen --> resilm
    gen --> aiml
    gen --> trade
    tplm -. cross-checked vs .-> recursion["holdover · clock_state · allan"]
    is --> ie
    is --> ml
    is --> es
    ie -. real recordings via .-> sdrm
    cross -. composes .-> packs2["clock · inertial packs"]
  • tpl: el nivel de protección de temporización condicional, un límite limitado por el holdover sobre el error de tiempo no detectado bajo spoofing, que compone un suelo de monitor de k sigmas, la varianza de deriva de van Loan sobre la latencia de detección y un tiempo hasta la alarma de CUSUM (suma acumulada); calibrado con un spoofing real grabado (JammerTest 2024). No existe un límite incondicional finito: el TPL es condicional a que una comprobación cruzada independiente detecte el ataque.
  • resilience/: un motor de puntuación de resiliencia PNT alineado con marcos (categorías del RPCF (Resilient PNT Conformance Framework) del DHS (Departamento de Seguridad Nacional)) más un estudio de inestabilidad de decisión: un símplex de ponderación de Dirichlet, inestabilidad de rango de Kendall-τ, tasa de cambio del ganador top-1 y colapso de diversidad de modo común (Hill-N2), con un informe de aseguramiento con hash de integridad y 35 pruebas de referencia independiente derivadas a mano. Véase RESILIENCE-CROSSWALK. Arquitecturas sintéticas alineadas con RPCF v2.0: una autoevaluación, no una certificación.
  • impairment_eval / impairment_study / impairment_ml / eval_stats: el estudio de la brecha de optimismo ante deterioros de RF: un corpus sintético etiquetado y un arnés de ROC/AUC (ROC: característica operativa del receptor; AUC: área bajo la curva) independiente del detector, un panel de 13 detectores (energía/AGC/SQM/paridad (AGC: control automático de ganancia; SQM: monitorización de calidad de señal) más detectores de regresión logística con semilla y de MLP (MLP: perceptrón multicapa) de una capa oculta), leyes de escala dentro y fuera de distribución con una hipótesis nula de permutación, y un predictor de dejar uno fuera de la degradación fuera de distribución. Las métricas de evaluación se validan bit a bit frente a scikit-learn.
  • sdr / realdata: un front end de receptor definido por software (IQ/IF en bruto (IQ: fase/cuadratura; IF: frecuencia intermedia) → tomas de correlador temprana/puntual/tardía → SQM) y adaptadores de ingesta (RINEX, u-blox UBX, GnssLogger, JammerTest, Yunnan, SatGrid) que permiten ejecutar los mismos detectores sobre grabaciones suministradas localmente; no se confirma ningún conjunto de datos en el repositorio.
  • crossover / quantum_trade: el mapa de cruce de resiliencia cuántico frente a clásico bajo incertidumbre de parámetros, y el compromiso del beneficio de holdover con ADEV medido; los núcleos numéricos del compromiso se validan frente a scipy.

1c. Capas de integridad, GNSS, espacio profundo, lunares y de misión#

Los dominios restantes se conectan al mismo despacho api y reutilizan el núcleo compartido, los marcos y la geometría. Todo lo de aquí es MODELLED salvo que una fila de la matriz verification cite una referencia independiente externa (núcleo de RAIM frente a SciPy, SBAS frente al fork de RTKLIB (una biblioteca abierta de posicionamiento cinemático en tiempo real), el núcleo de DOP (dilución de la precisión) de gnss_lib_py, la evaluación de OPS-SAT, el núcleo de nivel de protección de ARAIM lunar, la coherencia de efemérides lunares entre proveedores); el resto de la suite lunar y el demostrador cuántico son modelados, ilustrativos, de fuente pública, y no llevan ninguna afirmación de TRL (nivel de madurez tecnológica) / herencia / aval de una agencia.

flowchart TD
    api["api.rs — run_toml / run_scenario · 92 kinds"]

    subgraph gnss["Integrity & GNSS measurement"]
      raim["raim — RAIM/ARAIM · HPL/VPL (kernel vs SciPy)"]
      sbas["sbas — DO-229E PL · L1/L5 (vs RTKLIB fork)"]
      meas["gnss_sim · ionex · pvt · glonass — pseudorange · iono maps · single-point PVT"]
      imp["integrity_impact · frugal — miss→integrity · cost-per-coverage"]
    end

    subgraph deep["Deep-space & Mars"]
      core2["body · ephem_provider · clock_state — multi-body · ephemeris seam · onboard clock"]
      radio["radiometric · ccsds_tdm — light-time · Doppler/range · Δ-DOR · TDM"]
      mars["deepspace_od · mars_frame · mars_atmos · mars_pnt · linkbudget · gse_sim — SRIF OD · Mars frame · relay-PNT · GSE sim"]
    end

    subgraph lunar["Lunar PNT suite (evidence tier per piece in the matrix · illustrative public-source)"]
      cis["cr3bp · lunar · lunar_frame · lunar_od — CR3BP · halo/NRHO · cislunar ARAIM · MCI↔MCMF"]
      suite["lunar_time · lunar_vlbi · lunar_combination · lunar_frame_realise — LTC time · VLBI · joint OD+clock · frame realisation"]
      suite2["lunar_service · lunar_dpnt · lunar_interop — Moonlight service-volume · differential PNT · LunaNet/IOAG interop"]
    end

    subgraph quantum["Quantum-Enabled PNT demonstrator (MODELLED)"]
      qd["quantum_devices · quantum_faults · quantum_nav_od — device error models · fault catalogue · GNSS-free OD"]
      qt["qtrade · timetransfer_chain · representativeness — unified trade · time-transfer chain · gaps-to-flight ledger"]
    end

    subgraph mission["Mission analysis, environment & interop"]
      ma["launch · reentry · eo_payload · attitude_budget · passes · linkbudget — first-order budgets"]
      env["space_weather — Jacchia-71 density"]
      iop["rinex · rinex_obs · sp3 · oem · omm · ccsds_tdm · space_packet · interchange · permalink — interop formats + KIF"]
      ver["verification — requirement→module→test→oracle→status matrix"]
    end

    api --> gnss & deep & lunar & quantum & mission
    raim -. reuses .-> meas
    suite -. reuses validated DOP / SBAS kernels .-> gnss
    qt -. rides validated kernels (scipy / sklearn) .-> quantum

1d. LEO PNT, espectro, sistema solar, temporización de red, campañas y salidas#

Las capas más recientes siguen el mismo patrón: cada una es uno o más tipos de escenario (kind) despachados desde api, construidos sobre el núcleo compartido, y MODELLED salvo que una fila de la matriz nombre una referencia independiente externa.

flowchart TD
    api["api.rs — run_toml / run_scenario"]

    subgraph leo["LEO PNT (low Earth orbit positioning, navigation and timing)"]
      lsig["leo_signal — signal design: acquisition, code tracking, GNSS compatibility, band trade"]
      lpass["leo_pass · leo_link (geometry · antenna · itu · iono · energy · spoof · presets) — pass and per-band link budget"]
      lnav["leo_navmsg (elements · fit · codec · sisre · services · text) — broadcast ephemeris and clock message"]
      lfus["leo_fusion (doppler · joint_pvt · ppp · ntn · timing · polar · presets) — fused MEO+LEO PVT · PPP · 5G NTN"]
      lchain["leo_pnt_chain — one system end to end, each stage handing its output to the next"]
    end

    subgraph rf["Spectrum"]
      spec["spectrum · navsignal — L-band (and UHF/S/C) PSD waterfall under a jammer timeline"]
      sig["sigmf — SigMF recording read/write · Welch PSD of complex IQ"]
    end

    subgraph sky["Solar system & constellations"]
      ss["solar_system · body · ephem · ephem_provider — bodies, constants, light time at one epoch"]
      bp["body_pnt — positioning around any body with a local constellation"]
      cd["constellation · walker — Walker delta/star, multi-shell, published GNSS slots, coverage/DOP maps"]
    end

    subgraph net["Network timing"]
      tel["telecom_timing — time error, MTIE, TDEV vs ITU-T masks"]
      slot["slot_timing — seconds until a free-running clock leaves a slot guard"]
    end

    subgraph comp["Composition & outputs"]
      camp["campaign · study · suite — chained phases, sweeps, Monte Carlo, shared conditions"]
      rep["advanced_report — report.html + report.json with a reproducibility record"]
      anim["animation — SVG / HTML / frame animations"]
      iop["interop (czml · kml · geojson · stk) · sigmf — exchange files for --export"]
    end

    api --> leo & rf & sky & net & comp
    lchain -. composes .-> lsig & lpass & lnav & lfus
    lsig -. SSC chain .-> spec
    lfus -. GNSS presets .-> cd
    bp -. reuses .-> ss
    camp -. runs other kinds through .-> api

El detalle por tipo de escenario está en LEO-PNT, LEO-SIGNAL, LEO-PASS, LEO-NAVMSG, LEO-PNT-FUSION, SPECTRUM, CONSTELLATION-DESIGN, TELECOM-TIMING, SLOT-TIMING, CAMPAIGNS, REPORTS, ANIMATION e INTEROP.

1e. Capas de confianza del receptor, evidencias, telemetría, formación y compliance (0,35)#

Estas capas leen el propio registro de un receptor o escriben archivos para otras herramientas; ninguna de ellas sintetiza ni transmite una señal de radiofrecuencia. Se sitúan junto a api y no bajo los tipos de escenario, salvo receiver-trust en sí, que es un tipo de escenario. Todas son MODELLED salvo que una fila de la matriz nombre una referencia independiente externa, y las salidas marítimas son de carácter consultivo, no un equipo de navegación homologado.

Módulo Qué hace Documentado en
receiver_trust puntúa un registro de receptor época a época con los monitores de confianza; una plataforma de buque añade los monitores marítimos y la puntuación de 0 a 100 con motivos RECEIVER-TRUST, MARITIME-TRUST
receiver_trust::live la misma puntuación sobre un flujo a medida que llega (stdin, un archivo al que se añade, TCP o UDP), la sentencia $PKSHT y la puerta opcional; LiveEngine es el conjunto completo, sin entrada ni salida MARITIME-TRUST
evidence un paquete firmado y encadenado por hashes de una ventana de registro, su configuración y el resultado del motor, verificable sin conexión; token de marca de tiempo RFC 3161 opcional EVIDENCE-PACKS
telemetry el flujo de confianza como métricas de Prometheus, eventos de syslog (CEF o LEEF) y, opcionalmente, OpenTelemetry (función otlp, desactivada por defecto) TRUST-TELEMETRY
nmea_synth NMEA 0183 de puente sintético con eventos programados de jamming, arrastre, spoofing de tiempo y reproducción, y un registro del instructor, para la formación de tripulaciones (solo texto) NMEA-TRAINING
interference_map mapas agregados de navegación degradada a partir de informes de aeronaves y buques con licencia abierta, y la exposición de una ruta a ellos; solo archivos locales INTERFERENCE-MAP
osnma un verificador del lado del receptor para Galileo OSNMA: lee páginas I/NAV (páginas sin formato, CSV de vectores, un flujo UBX), comprueba la clave firmada, la cadena TESLA y los MAC, e informa por satélite de si los datos de navegación están autenticados; osnma::cli::verify_report es la única ruta que comparten la línea de comandos, Python y WebAssembly; solo estado de autenticación, no un servicio de integridad OSNMA
compliance asigna los resultados de Kshana a marcos públicos de resiliencia y rellena la asignación a partir de documentos de resultados; run_from_text y assess_texts reciben textos, no rutas compliance/
interop::testbench el movimiento del vehículo y los eventos de un escenario como un CSV de movimiento, NMEA, texto de puntos de ruta y archivos de eventos para un simulador GNSS de laboratorio; no se escribe ninguna señal TEST-BENCH

Las integraciones para embarcaciones (el complemento de Signal K, el modo de puerta de OpenCPN y la compilación de referencia) llaman a la herramienta de línea de comandos; consulte MARINE-INTEGRATIONS.

2. Canalización del motor (por ejecución)#

Cada ejecución hace avanzar un único modelo de sensor por la rejilla temporal, disciplinándolo siempre que el GNSS es nominal y dejándolo en funcionamiento libre (holdover / navegación por estima) durante la interrupción.

flowchart TD
    A["for each time step t"] --> B{"i &gt; 0 ?"}
    B -- yes --> C["model.step(dt, rng)<br/>evolve noise state"]
    B -- no --> D
    C --> D{"GNSS state at t ?"}
    D -- "Nominal" --> E["discipline to truth<br/>(estimator sync / dead-reckoning reset)<br/>error = 0"]
    D -- "Denied/Degraded" --> F["estimator predicts;<br/>error = truth − prediction"]
    E --> G["record Sample(t, error, gnss)"]
    F --> G
    G --> A
    A -. after loop .-> H["score(series, spec)<br/>→ figures of merit"]
    H --> I["assemble Result<br/>(specs · series · FoM · scenario hash)"]

Un escenario ejecuta esta canalización dos veces, una para el sensor cuántico y otra para el sensor clásico, con semillas independientes (classical_seed = seed + 0x9e3779b97f4a7c15) para que las dos realizaciones de ruido no estén correlacionadas.

3. La interfaz del modelo de error (el punto de extensión)#

Todo sensor implementa la misma idea: un objeto con estado cuyo step() hace avanzar su error estocástico interno y cuyo estado acumulado se lee en cada paso. Los relojes exponen la fase acumulada; los acelerómetros, la posición integrada dos veces; los enlaces, el jitter por medición.

classDiagram
    class ErrorModel {
      <<trait>>
      +step(dt, rng)
      +spec() ModelSpec
    }
    class ClockModel {
      +y0, q_wf, q_rw, drift, flicker
      +phase() s
      +det_freq()  +drift_rate()
    }
    class AccelModel {
      +bias, q_va, gyro_bias, q_arw
      +pos() m  +theta() rad
      +reset()
    }
    class TimeTransferLink {
      +sigma_j
      +sample(rng) s
    }
    ErrorModel <|.. ClockModel
    ClockModel : white FM + random-walk FM + flicker FM + aging
    AccelModel : accel bias + VRW + gyro bias + ARW (gravity-tilt)
    TimeTransferLink : white timing jitter

ModelSpec { id, kind, provenance, params } pasa al resultado, de modo que cada cifra de la salida es trazable hasta la fuente publicada que se nombra en provenance.

Junto al HoldoverEstimator analítico, el paquete de reloj ejecuta un filtro de Kalman de dos estados (fase, frecuencia) (KalmanClock) cuyo ruido de proceso coincide con el del modelo de verdad. Al avanzar por inercia durante una interrupción, la varianza de su error de fase crece exactamente hasta q_wf·T + q_rw·T³/3, la relación analítica de holdover, y su cota de 1-σ en línea se usa para obtener la cifra de mérito de integridad (fracción de muestras de la interrupción cuyo error permanece dentro de la cota de k-σ).

4. Despacho (CLI y enlaces)#

api::run_toml(src) es el único punto de entrada: examina el kind de nivel superior, deserializa el escenario correspondiente, ejecuta el paquete y devuelve { json, svg, summary, csv } (csv solo está presente en los tipos de escenario que publican una tabla de reproducibilidad). La CLI escribe esos resultados en archivos, además del informe (report.html, report.json) y cualquier salida de --export / --animate; los enlaces de Python y WebAssembly los devuelven al anfitrión. Un solo despacho, sin divergencias.

flowchart TD
    F["api::run_toml(src) · run_scenario(src)"] --> K{"ScenarioKind::classify<br/>typed · exhaustive · 92 kinds<br/>(absent kind → clock; unknown kind → InvalidInput)"}
    K --> G1["Timing<br/>clock · timetransfer · quantum-time-transfer · telecom-timing · slot-timing"]
    K --> G2["Inertial & fusion<br/>inertial · hybrid · hybrid-ukf · fusion · gnss-ins · quantum-gnss-free-nav · ins-trn-coast · hybrid-optical-rf"]
    K --> G3["Orbit, geometry & positioning<br/>orbit · ephemeris · constellation-design · gnss-sim · pvt"]
    K --> G4["Integrity<br/>integrity · lunar-integrity · araim-reference-check"]
    K --> G5["Resilience & spectrum<br/>jamming · spoof · spoof-detect · quantum-anomaly-detect · tracking-loop · spectrum · conflict-resilience"]
    K --> G6["Alt-PNT (GPS-denied)<br/>gravity-map · terrain-nav · terrain-slam · combined-altpnt"]
    K --> G7["LEO PNT<br/>leo-signal · leo-pass · leo-navmsg · leo-pvt · leo-ppp · ntn-positioning · leo-pnt-chain"]
    K --> G8["Lunar / cislunar suite (MODELLED)<br/>lunar-time-offset · lunar-time-budget · lunar-vlbi · lunar-vlbi-fim · lunar-joint-od-clock<br/>lunar-frame-realisation · lunar-frame-campaign · lunar-llr-datum · realtime-frame-eop<br/>moonlight-service-volume · lunar-differential-pnt · lunar-interop-export · lunar-beacon<br/>lunar-jamming · lunar-attack-surface · earth-gnss-lunar · cislunar-observability · cislunar-arc-recovery"]
    K --> G9["Deep space & solar system<br/>mars-pnt · solar-system · body-pnt"]
    K --> G10["Machine learning & trade<br/>impairment-eval · quantum-trade"]
    K --> G11["Mission analysis & environment<br/>launch-window · reentry · eo-coverage · attitude-budget · aperture-duty-cycle<br/>passes · link-budget · space-packet · space-weather"]
    K --> G12["Trade studies, campaigns & interop<br/>sweep · sweep-nd · campaign · oem-interop"]
    G1 & G2 & G3 & G4 & G5 & G6 & G7 & G8 & G9 & G10 & G11 & G12 --> W["RunOutput { json, svg, summary, csv }<br/>+ SHA-256 scenario_hash"]

El despacho se hace sobre una enumeración ScenarioKind tipada, con coincidencia exhaustiva (véase la subsección siguiente), de modo que añadir un paquete es un cambio verificado en compilación. Si falta kind, se recurre al paquete clock, así que los escenarios existentes de un solo tipo de escenario se deserializan sin cambios (serde ignora el campo kind en cada estructura de escenario). Un kind no reconocido se rechaza con KshanaError::InvalidInput, que nombra el tipo de escenario integrado más cercano cuando el nombre parece una errata.

Despacho tipado y la API estructurada#

El despacho se hace sobre una enumeración ScenarioKind tipada, no sobre una comparación de cadenas sin formato: ScenarioKind::classify(src) resuelve el campo kind a una variante y el despachador hace coincidencia exhaustiva sobre ella, de modo que añadir un paquete es un cambio verificado en compilación, no una errata de cadena. Dos superficies tipadas conviven con run_toml, que devuelve cadenas (se mantiene para la CLI y los enlaces existentes):

  • run_scenario(src) -> Result<RunOutput, KshanaError>: la entrada tipada, con una taxonomía de errores estructurada (InvalidInput, NonConvergence, Unsupported, IoError). Cada error lleva un kind_tag() estable para que quien llama pueda bifurcar según la categoría del fallo en lugar de analizar el mensaje. Los enlaces lo exponen como error_kind(toml).
  • list_scenario_kinds() -> Vec<ScenarioMeta> (y list_scenario_kinds_json(), expuesta en los enlaces como list_kinds()): introspección programática con el nombre, la descripción y los campos obligatorios y opcionales de cada tipo de escenario, para la interfaz de usuario (UI) y el autocompletado en cuadernos.

Ampliar Kshana con un paquete externo#

Un paquete de terceros implementa dos rasgos (traits) pequeños y estables según semver de api:

use kshana::api::{ExternalPack, KshanaError, RunOutput, Scenario, ScenarioMeta};

struct MyPack {
    threshold: f64, // the deserialized scenario fields
}

impl Scenario for MyPack {
    fn run(&self) -> Result<RunOutput, KshanaError> {
        // Run the model, then build the unified output envelope.
        Ok(RunOutput {
            json: format!("{{\"threshold\": {}}}", self.threshold),
            svg: String::from("<svg xmlns=\"http://www.w3.org/2000/svg\"/>"),
            summary: format!("my-pack | threshold {}", self.threshold),
            csv: None,
        })
    }
}

impl ExternalPack for MyPack {
    fn kind_name(&self) -> &'static str {
        "my-pack"
    }
    fn meta(&self) -> ScenarioMeta {
        ScenarioMeta {
            name: "my-pack",
            description: "An out-of-tree example pack.",
            required_fields: &["threshold"],
            optional_fields: &[],
        }
    }
}

ExternalPack también tiene un método register_into(&mut PackRegistry) por defecto, que no hace nada salvo que un paquete opte por el punto de despacho del registro en src/registry.rs. El paquete jamming integrado se conecta mediante Scenario como ejemplo resuelto; los paquetes externos al árbol siguen el mismo contrato sin bifurcar el núcleo (reflejando el punto de extensión de ErrorModel en el §3, que usa la capa privada de resiliencia).

Por tanto, Kshana tiene dos puntos de extensión estables: añadir un sensor implementando ErrorModel (§3), o añadir un tipo de escenario completo implementando Scenario + ExternalPack; ambos son estables según semver y ninguno exige bifurcar el núcleo:

classDiagram
    class ErrorModel {
      <<trait — sensor seam>>
      +step(dt, rng)
      +spec() ModelSpec
    }
    class Scenario {
      <<trait — pack seam>>
      +run() RunOutput
    }
    class ExternalPack {
      <<trait : Scenario>>
      +kind_name() str
      +meta() ScenarioMeta
    }
    ErrorModel <|.. ClockModel
    ErrorModel <|.. AccelModel
    ErrorModel <|.. TimeTransferLink
    Scenario <|.. ExternalPack
    Scenario <|.. JammingPack : worked example
    ExternalPack <|.. ThirdPartyPack : out-of-tree, no core fork

5. El cierre híbrido#

El paquete híbrido ejecuta una suite (un reloj y un sensor inercial) y exige que tanto la temporización como la posición se mantengan dentro de la especificación; pnt_holdover es el tiempo hasta que una de las dos la incumple. Opcionalmente, un enlace óptico entre satélites vuelve a sincronizar el reloj durante la interrupción: solo ayuda a la hora; la posición no se vuelve a sincronizar, porque la transferencia de tiempo da tiempo, no posición. Esto es lo que aísla al sensor inercial como factor limitante.

flowchart LR
    subgraph suite["PNT suite (per technology)"]
      clk["clock → timing error"]
      acc["inertial sensor → position error"]
      isl["optical ISL<br/>re-sync clock at interval"] -. aids .-> clk
    end
    clk --> J["both within spec ?"]
    acc --> J
    J --> P["pnt_holdover = first breach<br/>(timing OR position)"]

6. Disponibilidad GNSS derivada de la geometría#

orbit.rs es una capa de geometría determinista y sin dependencias. Un Propagator es o bien el Orbit kepleriano analítico (dos cuerpos, opcionalmente con J2 secular) o bien un propagador Sgp4 completo construido a partir de un conjunto completo de elementos de dos líneas; un generador Walker-delta produce constelaciones sintéticas, y la visibilidad en línea de visión = oclusión terrestre + máscara de elevación. El número de satélites visibles se asigna a un estado GNSS (≥4 = nominal, 1–3 = degradado, 0 = denegado), y build_timeline lo convierte en la línea temporal de disponibilidad que impulsa la ejecución estándar de holdover del reloj. Por tanto, la disponibilidad está derivada de la geometría en lugar de escrita a mano, mientras que la ejecución, el estimador y la puntuación no cambian.

Una constelación suministrada como TLE completos se propaga con el modelo SGP4/SDP4 de sgp4.rs (validado con los vectores AIAA (American Institute of Aeronautics and Astronautics) 2006-6753); los elementos de solo la línea 2 mantienen la ruta analítica de dos cuerpos. Ambos pueden mezclarse dentro de un mismo bloque de constelación.

flowchart LR
    U["user orbit"] --> V
    C["Walker constellation"] --> V["visible_count(t)<br/>occultation + mask"]
    V --> S["gnss_state: ≥4 / 1–3 / 0"]
    S --> T["build_timeline → GnssTimeline"]
    T --> R["run_orbit_clock → clock holdover"]

7. Enlaces#

El núcleo se compila sin cambios a nativo, a una extensión de Python y a WebAssembly. Los módulos de Python (python.rs, PyO3 abi3) y de WebAssembly (wasm.rs, wasm-bindgen) son dependencias opcionales, controladas por funciones (--features python / --features wasm): la compilación por defecto y el conjunto de pruebas nunca las compilan, mientras que la puerta de auditoría de dependencias (cargo deny --all-features) sí inspecciona sus árboles de dependencias, porque esos crates se distribuyen dentro del wheel y del paquete npm. Ambos llaman a api::run_toml, de modo que todas las superficies devuelven resultados idénticos. El módulo de WebAssembly respalda el área de pruebas del navegador en web/ y exporta trece funciones: run, run_all (una ejecución del motor que devuelve a la vez resultado, gráfico, resumen y tabla), chart_svg, summary, table_csv, list_kinds, error_kind, version, el códec de URL (URL: dirección web) compartible encode_permalink / decode_permalink, y los tres exportadores export_sp3 / export_omm / export_oem que respaldan el menú de exportación del área de pruebas. Otras dos puertas de entrada llegan a la misma api: el servidor MCP (Model Context Protocol) (mcp/kshana-mcp, un crate rmcp excluido del workspace que expone quince herramientas: run_scenario, list_scenario_kinds, validate_scenario, list_example_scenarios, get_example_scenario, report_scenario, animate_scenario, list_export_formats, export_interop, import_route, export_sp3, export_omm, export_oem, export_table_csv, assess_receiver_log; las dos herramientas de ejemplo leen los escenarios incluidos mediante la función bundled-scenarios de la biblioteca, desactivada por defecto, que solo este servidor activa) y el complemento para el IDE (entorno de desarrollo integrado) de JetBrains (ide/jetbrains, un proyecto en Kotlin que invoca la CLI de kshana en lugar de enlazar la biblioteca).

flowchart LR
    cli["CLI · main.rs<br/>native binary"] --> api
    py["Python · python.rs (PyO3 abi3)<br/>RunOutput class + run · run_full · run_typed · scenario_kinds · list_kinds · validate_toml · error_kind · version"] --> api
    wasm["WebAssembly · wasm.rs (wasm-bindgen)<br/>run · run_all · chart_svg · summary · table_csv · list_kinds · error_kind · version · encode/decode_permalink<br/>export_sp3 · export_omm · export_oem"] --> api
    mcp["MCP server · mcp/kshana-mcp (rmcp)<br/>tools: run_scenario · list_scenario_kinds · validate_scenario<br/>list_example_scenarios · get_example_scenario<br/>report_scenario · animate_scenario<br/>list_export_formats · export_interop · import_route<br/>export_sp3 · export_omm · export_oem · export_table_csv"] --> api
    ide["JetBrains plugin · ide/jetbrains (Kotlin)"] -- spawns process --> cli
    api["api::run_toml / run_scenario / list_scenario_kinds"] --> out["identical { json, svg, summary } on every surface"]

Control por funciones: Python y WASM son --features python / --features wasm; la tabla de escenarios incluidos es --features bundled-scenarios (el único uso que le da el servidor MCP); el servidor MCP y las comprobaciones cruzadas de xval/* son crates EXCLUIDOS del workspace; el complemento del IDE no enlaza nada: ejecuta la CLI.

8. Determinismo y reproducibilidad#

  • Toda la aleatoriedad fluye por un único ChaCha8Rng con semilla por ejecución; el orden de los pasos es fijo, de modo que (scenario, seed, engine version) → identical bits.
  • El resultado lleva un scenario_hash SHA-256 (SHA: Secure Hash Algorithm); scripts/check-reproducible.sh ejecuta dos veces un escenario de referencia y comprueba que la salida sea idéntica byte a byte.
  • El mismo motor se compila a nativo, a una extensión de Python y a wasm32-unknown-unknown para ejecuciones en el navegador que producen los mismos números.

9. Estructura diferida / futura#

Las capas de astrodinámica, fusión y alt-PNT del §1a (el propagador SGP4/SDP4 completo, el propagador numérico de Cowell con su modelo de fuerzas de siete perturbaciones y dos integradores adaptativos, el diseño de maniobras y trayectorias, la determinación de órbita, los estimadores GNSS/INS de 15, 8 y 17 estados, el filtro acoplado de reloj y posición, y la correlación con mapas de gravedad) ya se han entregado, junto con la cifra de mérito de seguridad con un demostrador activo de spoofing, la geometría real de TLE y multiconstelación, las bandas de Monte Carlo, los barridos de estudios de compromiso, el informe HTML (HyperText Markup Language) imprimible con su gemelo legible por máquina, y los flujos de trabajo de publicación, wheels y páginas.

Varias capacidades que antes figuraban aquí como trabajo futuro se han entregado desde entonces y se tratan más arriba o en VALIDATION: la nutación IAU 2000A completa y la reducción GCRS↔ITRS / ITRF (International Terrestrial Reference Frame) con CIO, sin equinoccio (validada bit a bit con SOFA/ERFA (SOFA: Standards of Fundamental Astronomy; ERFA: Essential Routines for Fundamental Astronomy)), el geopotencial EGM2008 (Earth Gravitational Model 2008) hasta grado y orden 70, el término de arrastre de marco de Lense–Thirring, las mareas sólidas, oceánicas y atmosféricas, una validación cruzada de efemérides de grado DE (DE440/ANISE (DE440: Development Ephemeris 440; ANISE: Attitude, Navigation, Instrument, Spacecraft, Ephemeris, un conjunto de herramientas de geometría planetaria en Rust puro)), la validación cruzada externa con Orekit 12,2 del propagador numérico de Cowell (0,08 m en 24 h) y de la determinación de órbita por lotes y secuencial, y el navegador fuertemente acoplado de 17 estados expuesto como el tipo de escenario hybrid-ukf.

El resto de las tareas pendientes se sigue en CHANGELOG [Unreleased] y la hoja de ruta por capacidad en CAPABILITY: un valor de referencia independiente externo para el evaluador de alto grado de EGM (Earth Gravitational Model) exactamente sobre el eje polar y una comparación cercana al polo limpia con pyshtools (el evaluador hasta grado 2190 y su cargador .gfc en tiempo de ejecución ya se han entregado, MODELLED; véase xval/high-degree-gravity/), un impulsor variable en el tiempo de clima espacial para el nivel opcional de densidad de arrastre NRLMSISE-00 (NRLMSISE: Naval Research Laboratory Mass Spectrometer and Incoherent Scatter Radar Extended atmosphere model) (la densidad de arrastre por defecto es el modelo exponencial estático, y la densidad de Jacchia-71 del tipo de escenario space-weather está caracterizada frente a NRLMSISE-00 pero no se sustituye por ella), una comprobación externa de la sombra opcional con oscurecimiento del limbo solar, el acoplamiento fuerte GNSS/INS con fase de portadora, y un mapa de gravedad real EGM2008/EIGEN (EIGEN: European Improved Gravity model of the Earth by New techniques) para el correlador alt-PNT.

Un repositorio de superposición privado contiene la profundidad de resiliencia sujeta a control de exportación; se conecta mediante la misma interfaz ErrorModel (y el contrato ExternalPack del §4) sin cambiar el motor público.