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

TemporizaciónEditar en GitHubFuente: docs/CLOCK-LOG-FORMATS.md

Formatos de registros de reloj

src/clock_log.rs lee un registro medido de reloj y lo convierte en una única serie de fase normalizada: una cuadrícula uniforme de muestras (time_s, phase_s), con el intervalo de muestreo tau0 indicado o hallado, cada hueco contado y las unidades del registro nombradas. Se leen ocho formatos, cada uno un subconjunto documentado. Todo lo que queda fuera del subconjunto se rechaza con un error que nombra lo que se encontró, en lugar de leerse de forma aproximada.

Abreviaturas. RINEX es el Receiver Independent Exchange Format. TICC es el contador de intervalos de tiempo de TAPR (Tucson Amateur Packet Radio). ADEV es la desviación de Allan solapada, TDEV la desviación temporal y MTIE el error máximo de intervalo de tiempo. tau0 es el intervalo de muestreo en segundos.

Dónde puede usarse un registro#

  • telecom-timing: [series.clock_log] en lugar de series.samples o series.csv_path. La fase del registro, en ns, es la serie de error de tiempo que se contrasta con las máscaras, y el informe incorpora un bloque clock_log que indica cómo se leyó.
  • El tipo de escenario clock: una tabla [clock_log] añade a la ejecución un bloque measured: cómo se leyó el registro, el SHA-256 de la tabla (input_sha256; el scenario_hash de la ejecución no cubre la tabla) y de las muestras de fase, y los ADEV, TDEV y MTIE solapados con factores de promediado por octavas. Necesita runs = 1. El holdover simulado no cambia.

Sin la tabla, ambos tipos de escenario se analizan, se resumen con hash y se notifican exactamente como antes.

[clock_log]                 # or [series.clock_log] in a telecom-timing scenario
format = "ticc"             # "rinex-clk", "timelab", "ticc", "ptp4l", "phc2sys", "ts2phc",
                            # "chrony-tracking" or "chrony-statistics"
path = "logs/ticc.txt"      # or text = "..." inline (the only choice in WebAssembly)
channel = "chA"             # TICC: needed when the log holds more than one channel
gaps = "linear"             # "refuse" (default), "longest" or "linear"
# clock = "G08"             # RINEX, linuxptp, chrony: needed when the log holds more than one clock or source
# tau0_s = 1.0              # overrides a header and the detected spacing
# units = "ns"              # TimeLab phase units: s (default), ms, us, ns, ps
# data = "phase"            # TimeLab: phase (default) or frequency

Los formatos#

rinex-clk: archivos de reloj RINEX, versiones 2,00 y 3,00 a 3,04 (incluido el campo de nombre de nueve caracteres de 3,04). Se comprueba el registro RINEX VERSION / TYPE y cualquier otra versión se rechaza, indicando la versión encontrada: IGS publica el formato de reloj (rinex_clock300.txt, 302, 304) hasta 3,04, y los documentos de RINEX 4,00, 4,01 y 4,02 definen solo archivos de observación, de navegación y meteorológicos, por lo que no existe una versión 4,00 del archivo de reloj que leer. De la cabecera solo se lee TIME SYSTEM ID y se omite hasta END OF HEADER. De los registros de datos, solo se conservan los registros AS (satélite) y AR (receptor o estación) de un reloj, seleccionado por nombre. Su primer campo de valor, el sesgo del reloj en segundos, es la fase. Se omiten las líneas de continuación y los registros CR, DR y MS. Las épocas son los campos de calendario del registro, como segundos desde 1980-01-06 00:00:00 en el propio sistema de tiempo del archivo, sin conversión.

timelab: registros ASCII de fase o de frecuencia de estilo TimeLab, la forma de texto plano que exporta TimeLab y que leen su importación ASCII y Stable32. Hay una lectura por línea: o bien una sola columna con un tau0 uniforme, o bien dos columnas time value. Las columnas pueden separarse por espacios en blanco, comas o punto y coma.

  • Las líneas que empiezan por #, ; o % son comentarios. Un comentario de la forma key = value (o key: value) establece tau0 (s), units (s, ms, us, ns o ps, para fase), data (phase o frequency) o time_units (s o mjd, para la primera de dos columnas).
  • Una línea inicial no numérica se toma como cabecera de columnas.
  • Los datos de frecuencia (frecuencia fraccionaria) se aceptan solo como una única columna. Se integran a fase como x[i+1] = x[i] + y[i]·tau0 (NIST SP 1065, 2008, §4,1).
  • Los archivos de proyecto binarios y .tim de TimeLab no se leen.

ticc: registros del contador TAPR TICC (TICC Operation Manual, revisiones del 23 de noviembre de 2016 y del 15 de diciembre de 2025, «measurement modes»). Cada campo de datos son segundos con 12 decimales (11 por defecto desde el firmware 20251101: se lee cualquier cantidad hasta 15). Una marca de tiempo se lee de su texto decimal como un número entero de femtosegundos, no como un flotante binario, de modo que la fase de un registro tomado días después de arrancar el contador conserva la resolución propia del contador: una marca de tiempo f64 a 3.0e5 s tiene una separación de 5.8e-11 s, unos 60 ps del contador.

  • Las líneas del modo de marca de tiempo (<seconds> chA, <seconds> chB) y el canal de seudomarca de tiempo del modo TimeLab (chC) son marcas de tiempo de sucesos. La fase del canal seleccionado es su marca de tiempo menos el tic nominal: x[k] = t[k] − t[0] − n[k]·tau0, donde n[k] es el número entero de tau0 desde el primer suceso. Un suceso perdido es un hueco.
  • Las líneas del modo de intervalo (<seconds> TI(A->B), o cualquier etiqueta que empiece por TI) se leen directamente como fase, una lectura por tau0. El escenario debe indicar tau0_s, porque la línea no lleva tiempo.
  • El modo Paired Timestamp imprime las mismas líneas en orden de canal y se lee como modo Timestamp; el modo 3-Corner Hat añade el chC sintetizado, que se lee como arriba.
  • La salida en modo Period y en modo Debug se rechaza. Un canal cuyas lecturas no aumentan se informa como modo Period. El modo Binary Timestamp no es texto, y un archivo de ese modo se rechaza con un mensaje que lo indica.
  • Las líneas que empiezan por # y las que no son <number> <label> (como el menú de arranque) se omiten y se cuentan.

Registros de linuxptp y chrony#

Estos cinco formatos leen lo que escribe un demonio de tiempo en ejecución sobre su propio reloj. Sirven para comprobar a posteriori una cadena de temporización (un reloj de frontera, el PHC de un grandmaster, un cliente chrony) con los mismos estimadores que los demás registros. No leen la configuración de un demonio, y nada aquí se comunica con un demonio.

ptp4l, phc2sys, ts2phc: las líneas del servo de linuxptp; cada formato lee solo las líneas de su propio programa. Una lectura es una línea de la forma

ptp4l[5003.000]: master offset         40 s2 freq   +1480 path delay       497
phc2sys[7000.000]: CLOCK_REALTIME phc offset       -30 s2 freq    +100 delay   1200
ts2phc[8000.000]: /dev/ptp0 offset          3 s2 freq         -2
  • La marca de tiempo es el primer [seconds.fraction] de la línea (el reloj monotónico del demonio). También se lee tras un prefijo de syslog, donde un identificador de proceso como ptp4l[812]: no tiene fracción y no se toma.
  • La fase es el offset registrado, en nanosegundos, convertido a segundos. Es el error de tiempo medido por el demonio de su reloj esclavo respecto a su referencia, tal como se registra: positivo cuando el esclavo va adelantado. Es el error que queda bajo control del servo, no la deriva de un reloj en marcha libre.
  • Las palabras entre la marca de tiempo y offset nombran la fuente (master, eth0 master para un prefijo [eth0], CLOCK_REALTIME phc, /dev/ptp0). Un registro con más de una fuente necesita clock = "<that text>"; el error las enumera.
  • Las lecturas anteriores a que el servo informe por primera vez de s2 (enganchado) se dejan fuera y se cuentan en n_skipped_lines: s0 y s1 son los estados desenganchado y de salto, cuyos desfases son transitorios de captura. Un servo que nunca alcanza s2 se rechaza. Una línea sin campo de estado se lee tal cual.
  • Las líneas de resumen (rms ... max ...), los mensajes delay y selected best master y las líneas de otros programas se omiten y se cuentan.
  • Las marcas de tiempo que retroceden (un demonio reiniciado) se rechazan; divida el registro.

chrony-tracking, chrony-statistics: los archivos log tracking y log statistics de chrony, leídos por posición de columna. Una lectura es una línea con al menos 14 columnas (tracking) o 13 (statistics) que empieza por una fecha y hora UTC YYYY-MM-DD HH:MM:SS. La línea de cabecera de columnas se omite y se cuenta; la regla ==== que hay debajo se omite sin contarse.

  • Tracking: columna 7, el desfase local en la actualización del reloj, en segundos. La dirección IP o el identificador de referencia cambia con la fuente seleccionada, de modo que, sin clock, cada línea se lee como un único reloj local. clock = "<id>" conserva un único identificador de referencia.
  • Statistics: columna 5, el desfase estimado de una fuente, en segundos. Hay una serie por dirección de fuente, y el registro necesita clock = "<address>" cuando contiene más de una.
  • Las épocas son segundos desde 1980-01-06 00:00:00 UTC, sin tratamiento de segundos intercalares. Chrony escribe una línea por actualización o por muestra de fuente, de modo que el espaciado no es uniforme. tau0 es el espaciado mediano; una lectura a menos de medio tau0 de la anterior conservada se descarta y se cuenta en n_duplicates, y un espaciado mayor es un hueco, que gaps = "refuse" notifica. Indique tau0_s y gaps = "linear" para un registro con un intervalo de sondeo estable.

Las columnas de chrony y los formatos de línea de linuxptp son los de la documentación pública de los demonios. Los archivos de prueba de tests/fixtures/clock_log/linuxptp_chrony/ están escritos para Kshana con valores inventados (véase su NOTICE.md); no se leyó ningún registro real, de modo que un formato que difiera entre versiones del demonio aún puede rechazarse o leerse mal. Una línea que no coincide se omite y se cuenta, nunca se adivina.

tau0 y huecos#

Cuando el registro lleva marcas de tiempo y no se indica tau0, tau0 es el espaciado mediano de marcas de tiempo consecutivas, redondeado a cuatro cifras significativas, y la fuente se notifica como median-spacing. El espaciado de un contador difiere del nominal en el desfase de frecuencia de la referencia, partes en 10^6 o menos. Un tau0_s en el escenario siempre prevalece (fuente input), seguido de un comentario de cabecera tau0 (fuente header).

Las muestras se sitúan en la cuadrícula t0 + i·tau0, y una época ausente es un hueco. Las lecturas a más de un 1 % de tau0 fuera de la cuadrícula se descartan y se cuentan, igual que los duplicados (se conserva el primero). La política de huecos es una de estas:

  • refuse (la predeterminada): cualquier hueco es un error que cuenta los huecos;
  • longest: conservar el tramo sin huecos más largo;
  • linear: rellenar los huecos interiores por interpolación lineal e indicar el número de huecos rellenados.

Los estimadores necesitan un registro sin huecos, por lo que aquí se resuelven los huecos.

Su propio reloj#

Una tabla [clock_log] en el tipo de escenario de reloj informa de lo estable que fue su propio reloj, junto a la simulación: scenarios/clock-measured-log.toml (kshana example clock-measured-log) es clock-holdover.toml con un extracto de 96 lecturas de un reloj de satélite IGS como registro TimeLab en línea. Sustituya text por path y format para su propio archivo. El bloque measured del resultado contiene cómo se leyó el registro (formato, tau0 y su origen, cada hueco) y sus ADEV, TDEV y MTIE; no cambia la simulación.

Conducir el holdover con su propio reloj: [clock_fit]#

[clock_log]                      # the measured series, as above
format = "ticc"
path = "my-clock.txt"
channel = "chA"

[clock_fit]
replaces = "classical"           # or "quantum": the simulated clock whose noise the log replaces

El registro se ajusta con el procedimiento de ficha de dispositivo de src/clock_library/card.rs (acondicionamiento, eliminación de la parte cuadrática, identificación del ruido con retardo 1, mínimos cuadrados ponderados en PM blanco, FM blanco, FM de flicker y FM de paseo aleatorio en los tiempos de promediado con al menos 30 grados de libertad). El reloj nombrado toma entonces q_wf = h_0 / 2, q_rw = 2 pi^2 h_-2, flicker_floor = sqrt(2 ln 2 h_-1) y el drift ajustado; y0 queda como lo tiene el escenario, porque un registro contiene el desplazamiento de su referencia, no el del reloj tras la disciplina. El ruido de fase blanco se ajusta y se informa, pero no se simula. El resultado gana un bloque fitted (los coeficientes, los puntos de ajuste, los valores que usó la ejecución, lo que se dejó fuera, el SHA-256 del registro) y el reloj lleva el identificador measured:<12 hex of the phase hash>. Con runs > 1 el conjunto toma muestras del reloj ajustado (el bloque measured necesita runs = 1). Un ajuste sin ruido de frecuencia, un registro demasiado corto para ajustar y un replaces distinto de quantum o classical son errores que lo indican. scenarios/clock-fitted-log.toml es un ejemplo (6 horas de un reloj de satélite IGS).

Lo que muestra la comparación con ruido conocido (tests/fixtures/clock_fit/RESULTS.md), y qué tener en cuenta:

  • Alcanzado: el nivel de FM blanco se recupera dentro del 5 % en cada registro sintético que lo tiene; la ficha ajustada reproduce la desviación de Allan verdadera dentro de un factor de 1,35 en cada tiempo de promediado en que se ajustó; el exponente de ruido que identifica el ajuste es igual al de allantools en cada punto (en el registro 5071A, una vez que el salto de fase que elimina el acondicionamiento se elimina también de la entrada de allantools).
  • No alcanzado, y fijado por la prueba: el FM de paseo aleatorio solo se recupera cuando domina los tiempos de promediado más largos del registro, e incluso entonces en uno de tres registros; en una serie de 131.072 s con un cruce en 3.000 s, el ajuste se lo atribuyó al FM de flicker y a la deriva. La separación entre el FM de paseo aleatorio y el FM de flicker no es fiable a partir de un solo registro. La ejecución reproduce la estabilidad del registro en los tiempos de promediado que este cubre; más allá de ellos las dos opciones divergen (el FM de flicker es un piso constante, el FM de paseo aleatorio crece como la raíz cuadrada del tiempo de promediado).
  • MODELLED: un escenario hipotético para el ruido de ese reloj tal como lo muestra el registro, no una calibración del reloj ni una predicción de su comportamiento futuro.

Un registro malformado es un error que indica lo que se encontró (la línea, la versión, el selector que falta), nunca un resultado parcial: tests/clock_log_real_allantools.rs fija 24 casos de ese tipo.

Evidencias#

MODELLED. Esto es un analizador, y su salida alimenta estimadores que se validan en otro lugar frente a allantools. Las pruebas unitarias de src/clock_log.rs usan registros pequeños escritos a mano, y para los formatos linuxptp y chrony los archivos de prueba de tests/fixtures/clock_log/linuxptp_chrony/. tests/clock_log_allantools.rs ejecuta la comparación preregistrada en tests/fixtures/clock_log/PREREGISTRATION.md: tres registros sintéticos con semilla, uno por formato, releídos por un lector independiente escrito a partir de esta página por el mismo autor, con las ADEV, TDEV y MTIE comprobadas frente a allantools 2024,6; esa comparación cubre solo los tres primeros formatos, y los lectores de linuxptp y chrony tienen pruebas de analizador pero ninguna comparación con una referencia independiente. Los registros de esa comparación son sintéticos, de modo que nada de lo que contienen describe un reloj ni un contador reales; la comparación con series medidas se describe más abajo.

Con datos medidos#

tests/clock_log_real_allantools.rs ejecuta la comparación preregistrada en tests/fixtures/clock_log_real/PREREGISTRATION.md (confirmada antes de cualquier archivo de prueba o ejecución) sobre cuatro series medidas: el PHASE.DAT de Stable32, las primeras 65.536 lecturas de un reloj de cesio 5071A frente a un máser de hidrógeno, y los relojes del satélite IGS G01 (30 s) y de la estación ABMF (300 s) del reloj final de IGS del 2026-08-02, como un recorte incluido con su NOTICE. Los dos primeros no tienen ninguna concesión de redistribución: los registros escritos a partir de ellos están en realdata-cache/, ignorado por git (scripts/gen_clock_log_real_ref.py), y la prueba lo indica y pasa cuando faltan, salvo con KSHANA_REQUIRE_REALDATA=1. Cada registro lo leen el motor y un lector independiente, y las ADEV, TDEV y MTIE se comparan con allantools 2024,6. Registrado en tests/fixtures/clock_log_real/RESULTS.md: en el lector tal como se entregó, los registros TICC, la versión de la cabecera y cinco mensajes de error no alcanzaron los umbrales preregistrados; se corrigieron y la comparación se repitió sin cambios. Alcanzado, salvo un par: la MTIE de un registro de frecuencia difiere de la de allantools, porque allantools integra la frecuencia menos su media (fijado como NOT MET; la comparación equivalente se alcanza). La fila sigue siendo MODELLED: los registros TICC son datos de reloj medidos recodificados al formato del contador por nuestro script (no se encontró ninguna captura TICC real), y el lector de referencia tiene el mismo autor que el del motor.