Tłumaczenie maszynowe, niezweryfikowane przez osobę, dla której polski jest językiem ojczystym. Wzorcem jest wersja angielska.

Synchronizacja czasuEdytuj na GitHubieŹródło: docs/CLOCK-LOG-FORMATS.md

Formaty dzienników zegara

src/clock_log.rs wczytuje zmierzony dziennik zegara do jednego znormalizowanego szeregu fazy: jednorodnej siatki próbek (time_s, phase_s), z podanym lub znalezionym interwałem próbkowania tau0, każdą przerwą policzoną i nazwanymi jednostkami dziennika. Wczytywanych jest osiem formatów, każdy jako udokumentowany podzbiór. Wszystko poza podzbiorem jest odrzucane z błędem, który nazywa to, co znaleziono, zamiast być odczytywane w przybliżeniu.

Skróty. RINEX to Receiver Independent Exchange Format. TICC to licznik interwałów czasu TAPR (Tucson Amateur Packet Radio). ADEV to overlapping odchylenie Allana, TDEV to odchylenie czasu, a MTIE to maksymalny błąd interwału czasu. tau0 to interwał próbkowania w sekundach.

Gdzie można użyć dziennika#

  • telecom-timing: [series.clock_log] zamiast series.samples lub series.csv_path. Faza dziennika, w ns, jest szeregiem błędu czasu sprawdzanym względem masek, a raport zyskuje blok clock_log mówiący, jak go odczytano.
  • Rodzaj clock: tabela [clock_log] dodaje do przebiegu blok measured: jak odczytano dziennik, SHA-256 tabeli (input_sha256; scenario_hash przebiegu nie obejmuje tabeli) i próbek fazy oraz overlapping ADEV, TDEV i MTIE przy oktawowych współczynnikach uśredniania. Wymaga runs = 1. Symulowany holdover pozostaje bez zmian.

Bez tabeli oba rodzaje są parsowane, haszowane i raportowane dokładnie tak jak dotąd.

[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

Formaty#

rinex-clk: pliki zegara RINEX, wersje 2,00 oraz od 3,00 do 3,04 (w tym dziewięcioznakowe pole nazwy z 3,04). Sprawdzany jest rekord RINEX VERSION / TYPE, a każda inna wersja jest odrzucana z podaniem znalezionej wersji: IGS publikuje format zegara (rinex_clock300.txt, 302, 304) do 3,04, a dokumenty RINEX 4,00, 4,01 i 4,02 definiują tylko pliki obserwacji, nawigacji i meteorologiczne, więc nie ma wersji 4,00 pliku zegara do odczytu. Nagłówek jest czytany tylko dla TIME SYSTEM ID i pomijany do END OF HEADER. Spośród rekordów danych zachowywane są tylko rekordy AS (satelita) i AR (odbiornik lub stacja) jednego zegara, wybranego po nazwie. Ich pierwsze pole wartości, bias zegara w sekundach, jest fazą. Linie kontynuacji oraz rekordy CR, DR i MS są pomijane. Epoki to pola kalendarzowe rekordu, jako sekundy od 1980-01-06 00:00:00 we własnym systemie czasu pliku, bez konwersji.

timelab: dzienniki fazy lub częstotliwości ASCII w stylu TimeLab, czyli zwykła postać tekstowa, którą eksportuje TimeLab i którą wczytują jego import ASCII oraz Stable32. W każdej linii jest jeden odczyt: albo pojedyncza kolumna przy jednorodnym tau0, albo dwie kolumny time value. Kolumny mogą być oddzielone białymi znakami, przecinkami lub średnikami.

  • Linie zaczynające się od #, ; lub % są komentarzami. Komentarz w postaci key = value (lub key: value) ustawia tau0 (s), units (s, ms, us, ns lub ps, dla fazy), data (phase lub frequency) albo time_units (s lub mjd, dla pierwszej z dwóch kolumn).
  • Jedna początkowa linia nienumeryczna jest traktowana jako nagłówek kolumn.
  • Dane częstotliwości (częstotliwość względna) są przyjmowane tylko jako pojedyncza kolumna. Są całkowane do fazy jako x[i+1] = x[i] + y[i]·tau0 (NIST SP 1065, 2008, §4,1).
  • Binarne pliki projektów TimeLab oraz .tim nie są wczytywane.

ticc: dzienniki licznika TAPR TICC (TICC Operation Manual, wersje z 23 listopada 2016 i 15 grudnia 2025, „measurement modes”). Każde pole danych to sekundy z 12 miejscami po przecinku (domyślnie 11 od oprogramowania sprzętowego 20251101: odczytywana jest każda liczba do 15). Znacznik czasu jest odczytywany z jego tekstu dziesiętnego jako całkowita liczba femtosekund, a nie jako liczba binarna zmiennoprzecinkowa, więc faza dziennika zebranego dni po uruchomieniu licznika zachowuje własną rozdzielczość licznika: znacznik czasu f64 przy 3.0e5 s ma rozstaw 5.8e-11 s, około 60 ps licznika.

  • Linie trybu znaczników czasu (<seconds> chA, <seconds> chB) oraz kanał pseudoznacznika czasu trybu TimeLab (chC) są znacznikami czasu zdarzeń. Fazą wybranego kanału jest jego znacznik czasu minus nominalny takt: x[k] = t[k] − t[0] − n[k]·tau0, gdzie n[k] to liczba całkowita tau0 od pierwszego zdarzenia. Pominięte zdarzenie jest przerwą.
  • Linie trybu interwału (<seconds> TI(A->B) lub dowolna etykieta zaczynająca się od TI) są odczytywane bezpośrednio jako faza, jeden odczyt na tau0. Scenariusz musi podać tau0_s, ponieważ linia nie niesie czasu.
  • Tryb Paired Timestamp drukuje te same wiersze w kolejności kanałów i jest odczytywany jako tryb Timestamp; tryb 3-Corner Hat dodaje syntetyzowany chC, odczytywany jak wyżej.
  • Wyjście trybu okresu i trybu debugowania jest odrzucane. Kanał, którego odczyty nie rosną, jest zgłaszany jako tryb okresu. Binarny tryb Timestamp nie jest tekstem, a jego plik jest odrzucany z komunikatem, który to mówi.
  • Linie zaczynające się od # oraz linie niebędące <number> <label> (takie jak menu startowe) są pomijane i liczone.

dzienniki linuxptp i chrony#

Te pięć formatów wczytuje to, co działający demon czasu zapisuje o własnym zegarze. Służą do sprawdzania łańcucha czasu po fakcie (zegar graniczny, PHC grandmastera, klient chrony) tymi samymi estymatorami co inne dzienniki. Nie wczytują konfiguracji demona i nic tu nie komunikuje się z demonem.

ptp4l, phc2sys, ts2phc: linie serwa linuxptp, przy czym każdy format wczytuje tylko linie własnego programu. Odczytem jest linia w postaci

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
  • Znacznikiem czasu jest pierwsze [seconds.fraction] w linii (zegar monotoniczny demona). Jest on odczytywany także po prefiksie syslog, gdzie identyfikator procesu, taki jak ptp4l[812]:, nie ma części ułamkowej i nie jest brany.
  • Fazą jest zalogowane offset, w nanosekundach, przeliczone na sekundy. Jest to zmierzony przez demona błąd czasu jego zegara podrzędnego względem wzorca, tak jak zalogowano: dodatni, gdy zegar podrzędny wyprzedza. Jest to błąd pozostały pod kontrolą serwa, a nie dryf zegara swobodnego.
  • Słowa między znacznikiem czasu a offset nazywają źródło (master, eth0 master dla prefiksu [eth0], CLOCK_REALTIME phc, /dev/ptp0). Dziennik z więcej niż jednym źródłem wymaga clock = "<that text>"; błąd je wylicza.
  • Odczyty sprzed pierwszego zgłoszenia przez serwo s2 (zablokowany) są pomijane i liczone w n_skipped_lines: s0 i s1 to stany niezablokowany i skokowy, których przesunięcia są przejściowymi procesami wejścia. Serwo, które nigdy nie osiąga s2, jest odrzucane. Linia bez pola stanu jest odczytywana tak, jak jest.
  • Linie podsumowań (rms ... max ...), komunikaty delay i selected best master oraz linie innych programów są pomijane i liczone.
  • Znaczniki czasu cofające się (ponownie uruchomiony demon) są odrzucane; podziel dziennik.

chrony-tracking, chrony-statistics: pliki log tracking i log statistics chrony, odczytywane według położenia kolumn. Odczytem jest linia z co najmniej 14 kolumnami (tracking) lub 13 (statistics), zaczynająca się od daty i czasu UTC w postaci YYYY-MM-DD HH:MM:SS. Linia nagłówka kolumn jest pomijana i liczona; linia ==== pod nią jest pomijana bez liczenia.

  • Tracking: kolumna 7, lokalne przesunięcie przy aktualizacji zegara, w sekundach. Adres IP lub identyfikator odniesienia zmienia się wraz z wybranym źródłem, więc bez clock każda linia jest odczytywana jako jeden zegar lokalny. clock = "<id>" zachowuje jeden identyfikator odniesienia.
  • Statistics: kolumna 5, estymowane przesunięcie źródła, w sekundach. Dla każdego adresu źródła jest jeden szereg, a dziennik wymaga clock = "<address>", gdy zawiera więcej niż jeden.
  • Epoki to sekundy od 1980-01-06 00:00:00 UTC, bez obsługi sekund przestępnych. Chrony zapisuje linię na aktualizację lub na próbkę źródła, więc odstęp nie jest jednorodny. tau0 to mediana odstępu; odczyt wcześniejszy niż połowa tau0 po zachowanym poprzednim jest odrzucany i liczony w n_duplicates, a dłuższy odstęp jest przerwą, o czym informuje gaps = "refuse". Podaj tau0_s i gaps = "linear" dla dziennika ze stałym interwałem odpytywania.

Kolumny chrony i układy linii linuxptp pochodzą z publicznej dokumentacji demonów. Zestawy danych w tests/fixtures/clock_log/linuxptp_chrony/ napisano dla Kshana ze zmyślonymi wartościami (zob. jego NOTICE.md); nie wczytano żadnego prawdziwego dziennika, więc układ różniący się między wersjami demona może nadal zostać odrzucony lub źle odczytany. Linia niepasująca jest pomijana i liczona, nigdy zgadywana.

tau0 i przerwy#

Gdy dziennik niesie znaczniki czasu i nie podano tau0, tau0 jest medianą odstępu kolejnych znaczników czasu, zaokrągloną do czterech cyfr znaczących, a źródło jest zgłaszane jako median-spacing. Odstęp licznika różni się od nominalnego o przesunięcie częstotliwości wzorca, rzędu 10^6 lub mniej. tau0_s w scenariuszu zawsze wygrywa (źródło input), następnie komentarz nagłówka tau0 (źródło header).

Próbki są umieszczane na siatce t0 + i·tau0, a brakująca epoka jest przerwą. Odczyty oddalone od siatki o więcej niż 1 % tau0 są odrzucane i liczone, podobnie jak duplikaty (pierwszy jest zachowywany). Polityka przerw jest jedną z:

  • refuse (domyślnie): każda przerwa jest błędem, który liczy przerwy;
  • longest: zachowaj najdłuższy ciąg bez przerw;
  • linear: wypełnij przerwy wewnętrzne interpolacją liniową i podaj liczbę wypełnionych.

Estymatory wymagają zapisu bez przerw, dlatego przerwy są tu rozwiązywane.

Twój własny zegar#

Tabela [clock_log] w rodzaju zegara podaje, jak stabilny był Twój własny zegar, obok symulacji: scenarios/clock-measured-log.toml (kshana example clock-measured-log) to clock-holdover.toml z 96-odczytowym wyciągiem zegara satelity IGS jako wbudowanym dziennikiem TimeLab. Zastąp text przez path i format dla własnego pliku. Blok measured w wyniku zawiera sposób odczytu dziennika (format, tau0 i skąd pochodzi, każda przerwa) oraz jego ADEV, TDEV i MTIE; nie zmienia on symulacji.

Sterowanie holdover własnym zegarem: [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

Dziennik jest dopasowywany procedurą karty urządzenia z src/clock_library/card.rs (kondycjonowanie, usunięcie składowej kwadratowej, identyfikacja szumu z opóźnieniem 1, ważona metoda najmniejszych kwadratów w szumie PM białym, FM białym, FM typu flicker i FM typu błądzenie losowe w czasach uśredniania z co najmniej 30 stopniami swobody). Wskazany zegar przyjmuje wtedy q_wf = h_0 / 2, q_rw = 2 pi^2 h_-2, flicker_floor = sqrt(2 ln 2 h_-1) oraz dopasowane drift; y0 pozostaje takie, jak w scenariuszu, ponieważ dziennik niesie przesunięcie swojego wzorca, a nie zegara po dyscyplinowaniu. Szum fazy białej jest dopasowywany i podawany, ale nie symulowany. Wynik zyskuje blok fitted (współczynniki, punkty dopasowania, wartości użyte przez przebieg, co pominięto, SHA-256 dziennika), a zegar nosi identyfikator measured:<12 hex of the phase hash>. Przy runs > 1 zespół losuje z dopasowanego zegara (blok measured wymaga runs = 1). Dopasowanie bez szumu częstotliwości, dziennik zbyt krótki do dopasowania oraz replaces inne niż quantum lub classical są błędami, które o tym mówią. scenarios/clock-fitted-log.toml to przykład (6 godzin zegara satelity IGS).

Co pokazuje porównanie na znanym szumie (tests/fixtures/clock_fit/RESULTS.md) i o czym warto pamiętać:

  • Osiągnięte: poziom FM białego jest odzyskiwany z dokładnością do 5 % w każdym zapisie syntetycznym, który go ma; dopasowana karta odtwarza prawdziwe odchylenie Allana w granicach współczynnika 1,35 przy każdym czasie uśredniania, dla którego była dopasowana; wykładnik szumu identyfikowany przez dopasowanie równa się wykładnikowi allantools w każdym punkcie (w zapisie 5071A, po usunięciu także z wejścia allantools skoku fazy, który usuwa kondycjonowanie).
  • Nieosiągnięte i przypięte przez test: FM typu błądzenie losowe jest odzyskiwany tylko wtedy, gdy dominuje przy najdłuższych czasach uśredniania zapisu, a nawet wtedy w jednym z trzech zapisów serii 131 072 s z przecięciem przy 3 000 s dopasowanie przypisało go do FM typu flicker i do dryfu. Podział między FM typu błądzenie losowe a FM typu flicker nie jest wiarygodny na podstawie jednego zapisu. Przebieg odtwarza stabilność dziennika w czasach uśredniania, które dziennik obejmuje; poza nimi oba wybory się rozchodzą (FM typu flicker to stała podłoga, FM typu błądzenie losowe rośnie jak pierwiastek kwadratowy czasu uśredniania).
  • MODELLED: scenariusz „co by było, gdyby” dla szumu tego zegara, jaki pokazuje dziennik, a nie kalibracja zegara ani prognoza jego przyszłego zachowania.

Zniekształcony dziennik jest błędem, który nazywa to, co znaleziono (wiersz, wersję, brakujący selektor), a nigdy częściowym wynikiem: tests/clock_log_real_allantools.rs przypina 24 takie przypadki.

Dowody#

MODELLED. To jest parser, a jego wynik zasila estymatory sprawdzane gdzie indziej względem allantools. Testy jednostkowe w src/clock_log.rs używają małych ręcznie napisanych dzienników, a dla formatów linuxptp i chrony zestawów danych z tests/fixtures/clock_log/linuxptp_chrony/. tests/clock_log_allantools.rs uruchamia porównanie zarejestrowane wstępnie w tests/fixtures/clock_log/PREREGISTRATION.md: trzy syntetyczne dzienniki z ziarnem, po jednym na format, odczytane z powrotem przez niezależny czytnik napisany na podstawie tej strony przez tego samego autora, z ADEV, TDEV i MTIE sprawdzonymi względem allantools 2024,6; porównanie to obejmuje tylko pierwsze trzy formaty, a czytniki linuxptp i chrony mają testy parsera, lecz nie mają porównania z wyrocznią. Dzienniki tego porównania są syntetyczne, więc nic tam nie opisuje prawdziwego zegara ani licznika; porównanie na zmierzonych seriach opisano poniżej.

Na zmierzonych danych#

tests/clock_log_real_allantools.rs uruchamia porównanie zarejestrowane wstępnie w tests/fixtures/clock_log_real/PREREGISTRATION.md (zatwierdzone przed jakimkolwiek zestawem danych lub przebiegiem) na czterech zmierzonych seriach: PHASE.DAT ze Stable32, pierwsze 65 536 odczytów zegara cezowego 5071A względem masera wodorowego oraz zegary satelity IGS G01 (30 s) i stacji ABMF (300 s) z końcowego zegara IGS z 2026-08-02, jako dołączony wycinek z jego NOTICE. Dwa pierwsze nie mają przyznanego prawa redystrybucji: zapisane z nich dzienniki znajdują się w ignorowanym przez git realdata-cache/ (scripts/gen_clock_log_real_ref.py), a test o tym mówi i przechodzi, gdy ich brak, chyba że ustawiono KSHANA_REQUIRE_REALDATA=1. Każdy dziennik jest odczytywany przez silnik i przez niezależny czytnik, a ADEV, TDEV i MTIE są porównywane z allantools 2024,6. Zapisano w tests/fixtures/clock_log_real/RESULTS.md: w dostarczonym czytniku dzienniki TICC, wersja nagłówka i pięć komunikatów o błędach nie osiągnęły progów zarejestrowanych wstępnie; zostały naprawione, a porównanie uruchomiono ponownie bez zmian. Osiągnięte, z wyjątkiem jednej pary: MTIE dziennika częstotliwości różni się od MTIE allantools, ponieważ allantools całkuje częstotliwość pomniejszoną o jej średnią (przypięte jako NOT MET; porównanie jednakowe jest osiągnięte). Wiersz pozostaje MODELLED: dzienniki TICC to zmierzone dane zegara zakodowane ponownie w układzie licznika naszym skryptem (nie znaleziono żadnego rzeczywistego zapisu TICC), a czytnik wzorcowy ma tego samego autora co czytnik silnika.