機械翻訳であり、ネイティブスピーカーによる確認は行われていません。英語版が基準です。

タイミングGitHub で編集出典:docs/CLOCK-LOG-FORMATS.md

クロックログの形式

src/clock_log.rsは、測定したクロックログを、正規化した一つの位相系列に読み込みます。(time_s, phase_s)サンプルの一様な格子で、サンプル間隔tau0は明記されているか、検出されたもので、すべての欠測が数えられ、ログの単位が明示されます。読み込める形式は八つで、それぞれ文書化された部分集合です。部分集合の外にあるものは、近似して読むのではなく、見つかった内容を示すエラーとともに拒否されます。

略語。RINEXはReceiver Independent Exchange Formatです。TICCはTAPR(Tucson Amateur Packet Radio)の時間間隔カウンターです。ADEVは重なりありアラン偏差、TDEVは時間偏差、MTIEは最大時間間隔誤差です。tau0は秒単位のサンプル間隔です。

ログを使える場所#

  • telecom-timing:series.samplesやseries.csv_pathの代わりに[series.clock_log]を使います。ログの位相(ns単位)が、マスクに対して検査される時間誤差の系列になり、レポートには、どう読み込んだかを示すclock_logブロックが加わります。
  • クロック種別:[clock_log]テーブルにより、実行にmeasuredブロックが加わります。ログをどう読み込んだか、テーブルのSHA-256(input_sha256。実行のscenario_hashはテーブルを対象としません)と位相サンプルのハッシュ、そしてオクターブの平均化係数での重なりありADEV、TDEV、MTIEです。runs = 1が必要です。シミュレーションによるホールドオーバーは変わりません。

テーブルがなければ、どちらの種別も、これまでとまったく同じようにパース、ハッシュ、報告されます。

[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

形式#

rinex-clk:RINEX clock ファイル、バージョン 2.00 と 3.00 から 3.04(3.04 の九文字の名前フィールドを含みます)。RINEX VERSION / TYPEレコードを検査し、それ以外のバージョンは、見つかったバージョンを示して拒否します。IGS は clock 形式(rinex_clock300.txt、302、304)を 3.04 まで公開しており、RINEX の 4.00、4.01、4.02 の文書は観測、航法、気象のファイルのみを定義しているため、読み込むべきバージョン 4.00 の clock ファイルはありません。ヘッダーはTIME SYSTEM IDのためだけに読み、END OF HEADERまでは読み飛ばします。データレコードのうち、名前で選んだ一つのクロックのAS(衛星)とAR(受信機または局)のレコードだけを保持します。その最初の値フィールドである、秒単位のクロックバイアスが位相です。継続行とCR、DR、MSのレコードは読み飛ばします。エポックは、レコードの暦のフィールドを、ファイル自身の時刻系での 1980-01-06 00:00:00 からの秒数としたもので、変換は行いません。

timelab:TimeLab形式のASCII位相または周波数ログで、TimeLabがエクスポートし、そのASCIIインポートとStable32が読み込める、プレーンテキスト形式です。一行に一つの読み取り値があり、一様なtau0の単一列か、time valueの二列のどちらかです。列は、空白、カンマ、セミコロンで区切れます。

  • #、;、%で始まる行はコメントです。key = value(またはkey: value)の形式のコメントは、tau0(s)、units(s、ms、us、ns、ps。位相用)、data(phaseまたはfrequency)、time_units(sまたはmjd。二列のうち最初の列用)を設定します。
  • 先頭にある数値でない一行は、列ヘッダーとして扱われます。
  • 周波数データ(分数周波数)は、単一列のみ受け付けます。これはx[i+1] = x[i] + y[i]·tau0として位相に積分されます(NIST SP 1065、2008、§4.1)。
  • TimeLabのバイナリと.timのプロジェクトファイルは読み込みません。

ticc:TAPR TICC カウンターのログ(TICC Operation Manual、2016 年十一月 23 日版と 2025 年十二月 15 日版、「measurement modes」)。すべてのデータフィールドは小数点以下 12 桁の秒です(ファームウェア 20251101 以降の既定は 11 桁で、15 までの桁数を読み込みます)。タイムスタンプは、二進の浮動小数点数ではなく、その 十進の文字列から整数個のフェムト秒として読み込みます。このため、カウンターの起動から数日後に取ったログの位相も、カウンター自身の分解能を保ちます。3.0e5 s でのf64のタイムスタンプは間隔が 5.8e-11 s で、カウンターの 60 ps に近い値です。

  • タイムスタンプモードの行(<seconds> chA、<seconds> chB)と、TimeLabモードの擬似タイムスタンプチャネル(chC)は、イベントのタイムスタンプです。選んだチャネルの位相は、そのタイムスタンプから公称のティックを引いたもので、x[k] = t[k] − t[0] − n[k]·tau0です。ここでn[k]は、最初のイベント以降のtau0の整数個です。取りこぼしたイベントは欠測になります。
  • インターバルモードの行(<seconds> TI(A->B)、またはTIで始まる任意のラベル)は、tau0ごとに一つの読み取り値として、位相として直接読み込まれます。行に時刻が含まれないため、シナリオでtau0_sを指定する必要があります。
  • Paired Timestamp モードは、同じ行をチャネル順に出力し、Timestamp モードとして読み込みます。3-Corner Hat モードは合成されたchCを加えますが、上と同様に読み込みます。
  • Period モードと Debug モードの出力は拒否します。読み取り値が増えないチャネルは、Period モードとして報告されます。バイナリの Timestamp モードはテキストではなく、そのファイルは、その旨を示すメッセージとともに拒否します。
  • #で始まる行と、<number> <label>ではない行(起動時のメニューなど)は、スキップして数えます。

linuxptpとchronyのログ#

これらの五つの形式は、動作中の時刻デーモンが自身のクロックについて書き出す内容を読み込みます。事後にタイミングの連鎖(バウンダリークロック、グランドマスターのPHC、chronyクライアント)を、他のログと同じ推定器で検査するためのものです。デーモンの設定は読み込まず、ここにあるものはデーモンと通信しません。

ptp4l、phc2sys、ts2phc:linuxptpのサーボ行で、各形式は自身のプログラムの行だけを読み込みます。読み取り値は、次の形式の行です

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
  • タイムスタンプは、行の中で最初の[seconds.fraction]です(デーモンの単調クロック)。syslogのプレフィックスの後にある場合も読み取られ、ptp4l[812]:のようなプロセスIDには小数部がないため、採用されません。
  • 位相は、記録されたoffset(ナノ秒)を秒に変換したものです。これは、デーモンが測定した、スレーブクロックの基準に対する時間誤差で、記録されたとおりです。スレーブが進んでいるときに正になります。これはサーボ制御のもとで残る誤差であり、自由走行するクロックのドリフトではありません。
  • タイムスタンプとoffsetの間の語が、ソースを示します(master、[eth0]プレフィックスの場合のeth0 master、CLOCK_REALTIME phc、/dev/ptp0)。複数のソースを含むログにはclock = "<that text>"が必要で、エラーにはそれらが列挙されます。
  • サーボが最初にs2(ロック)を報告するより前の読み取り値は除外され、n_skipped_linesに数えられます。s0とs1はロック前とステップの状態で、そのオフセットは引き込み時の過渡現象です。s2に到達しないサーボは拒否されます。状態フィールドのない行は、そのまま読み込まれます。
  • 要約行(rms ... max ...)、delayとselected best masterのメッセージ、他のプログラムの行は、スキップして数えます。
  • 時間をさかのぼるタイムスタンプ(デーモンの再起動)は拒否されます。ログを分割してください。

chrony-tracking、chrony-statistics:chronyのlog trackingとlog statisticsのファイルで、列の位置で読み取ります。読み取り値は、YYYY-MM-DD HH:MM:SSのUTCの日付と時刻で始まる、14列以上(tracking)または13列(statistics)の行です。列ヘッダー行はスキップして数え、その下の====の罫線は、数えずにスキップします。

  • Tracking:7列目で、クロック更新時のローカルオフセット(秒)です。IPアドレスまたは参照IDは選択されたソースによって変わるため、clockがなければ、すべての行が一つのローカルクロックとして読み込まれます。clock = "<id>"は、一つの参照IDを保持します。
  • Statistics:5列目で、ソースの推定オフセット(秒)です。ソースのアドレスごとに一つの系列があり、ログに複数が含まれる場合はclock = "<address>"が必要です。
  • エポックは1980-01-06 00:00:00 UTCからの秒数で、うるう秒の処理はありません。chronyは、更新ごと、またはソースのサンプルごとに一行を書くため、間隔は一様ではありません。tau0は間隔の中央値です。保持された直前の読み取り値の後、tau0の半分未満で現れた読み取り値は破棄されてn_duplicatesに数えられ、それより長い間隔は欠測であり、gaps = "refuse"が報告します。ポーリング間隔が一定のログには、tau0_sとgaps = "linear"を指定してください。

chronyの列とlinuxptpの行のレイアウトは、各デーモンの公開ドキュメントに記載されているものです。tests/fixtures/clock_log/linuxptp_chrony/のフィクスチャーは、Kshanaのために架空の値で書いたものです(そのNOTICE.mdを参照)。実際のログは読み込んでいないため、デーモンのバージョン間で異なるレイアウトは、拒否されたり、誤って読み取られたりする可能性があります。一致しない行はスキップして数え、推測することはありません。

tau0と欠測#

ログにタイムスタンプがあり、tau0が指定されていない場合、tau0は連続するタイムスタンプの間隔の中央値を有効数字四桁に丸めたものとなり、ソースはmedian-spacingとして報告されます。カウンターの間隔は、基準の周波数オフセット(10^6分の一以下)の分だけ公称値と異なります。シナリオのtau0_sが常に優先され(ソースはinput)、その次がtau0ヘッダーコメントです(ソースはheader)。

サンプルは格子t0 + i·tau0に配置され、存在しないエポックは欠測です。格子からtau0の1 %を超えてずれた読み取り値は、重複(最初のものを残す)と同様に、破棄されて数えられます。欠測の扱い方は次のいずれかです。

  • refuse(既定):どの欠測もエラーとなり、欠測の数を示します。
  • longest:欠測のない最長の連続区間を残します。
  • linear:内部の欠測を線形補間で埋め、埋めた数を報告します。

推定器は欠測のない記録を必要とするため、欠測はここで解決されます。

自分のクロック#

クロック kind の[clock_log]テーブルは、シミュレーションと並べて、自分のクロックがどれだけ安定していたかを報告します。scenarios/clock-measured-log.toml(kshana example clock-measured-log)は、IGS 衛星クロックの 96 個の読み取り値の抜粋を、インラインの TimeLab ログとして持つclock-holdover.tomlです。自分のファイルを使うには、textをpathとformatに置き換えます。結果のmeasuredブロックには、ログをどう読み込んだか(形式、tau0、出所、すべての欠測)と、その ADEV、TDEV、MTIE が入ります。シミュレーションは変わりません。

自分のクロックでホールドオーバーを駆動する:[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

ログは、src/clock_library/card.rsのデバイスカードの手順で当てはめます(調整、二次成分の除去、ラグ 1 のノイズ識別、自由度が 30 以上の平均化時間での、白色 PM、白色 FM、フリッカー FM、ランダムウォーク FM の重み付き最小二乗)。指定したクロックは、q_wf = h_0 / 2、q_rw = 2 pi^2 h_-2、flicker_floor = sqrt(2 ln 2 h_-1)と、当てはめたdriftを取り込みます。y0はシナリオの指定のままです。ログが持つのは参照のオフセットであり、規律後のクロックのオフセットではないためです。白色位相ノイズは当てはめて報告しますが、シミュレートはしません。結果にはfittedブロック(係数、当てはめの点、実行で使った値、除外したもの、ログの SHA-256)が加わり、クロックは IDmeasured:<12 hex of the phase hash>を持ちます。runs > 1のとき、アンサンブルは当てはめたクロックから抽出します(measuredブロックにはruns = 1が必要です)。周波数ノイズのない当てはめ、当てはめるには短すぎるログ、quantumでもclassicalでもないreplacesはエラーとなり、その旨を示します。scenarios/clock-fitted-log.tomlは例です(IGS 衛星クロックの 6 時間分)。

既知のノイズに対する比較(tests/fixtures/clock_fit/RESULTS.md)が示すこと、そして心に留めておくべきこと:

  • 達成:白色 FM の水準は、それを含むすべての合成レコードで 5 % 以内に復元されます。当てはめたカードは、当てはめたすべての平均化時間で、真のアラン偏差を 1.35 倍以内で再現します。当てはめが識別するノイズの指数は、すべての点で allantools のものと一致します(5071A のレコードでは、調整が除く位相ステップを allantools の入力からも除いた場合)。
  • 未達で、テストにより固定されています:ランダムウォーク FM が復元されるのは、それがレコードの最長の平均化時間で支配的な場合に限られ、その場合でも、131,072 s の系列で、交差が 3,000 s にある三つのレコードのうち一つにとどまり、当てはめはそれをフリッカー FM とドリフトに割り当てました。ランダムウォーク FM とフリッカー FM の切り分けは、一つのレコードからは信頼できません。実行は、ログが覆う平均化時間の範囲でログの安定度を再現します。その範囲を超えると、二つの選択は分かれます(フリッカー FM は一定のフロアで、ランダムウォーク FM は平均化時間の平方根で増大します)。
  • MODELLED:ログが示すとおりのそのクロックのノイズについての仮定の試算であり、クロックの較正でも、将来の挙動の予測でもありません。

不正な形式のログは、見つかった内容(行、バージョン、欠けているセレクター)を示すエラーとなり、部分的な結果になることはありません。tests/clock_log_real_allantools.rsはそのような 24 件のケースを固定しています。

エビデンス#

MODELLED。これはパーサーであり、その出力は、他の場所で allantools と照合して検証される推定器に渡されます。src/clock_log.rsの単体テストは、手書きの小さなログを使い、linuxptp と chrony の形式ではtests/fixtures/clock_log/linuxptp_chrony/のフィクスチャーを使います。tests/clock_log_allantools.rsは、tests/fixtures/clock_log/PREREGISTRATION.mdで事前登録した比較を実行します。形式ごとに一つ、シード付きの合成ログ三つを、同じ作者がこのページから書いた独立したリーダーで読み戻し、ADEV、TDEV、MTIE を allantools 2024.6 と照合します。この比較の対象は最初の三つの形式だけで、linuxptp と chrony のリーダーにはパーサーテストはありますが、オラクルとの比較はありません。この比較のログは合成なので、実際のクロックやカウンターについては何も表していません。測定した系列での比較は、下で説明します。

測定データについて#

tests/clock_log_real_allantools.rsは、tests/fixtures/clock_log_real/PREREGISTRATION.mdで事前登録した比較(フィクスチャーや実行の前にコミット済み)を、測定した四つの系列で実行します。Stable32 のPHASE.DAT、水素メーザーに対する 5071A セシウムクロックの最初の 65,536 個の読み取り値、そして 2026-08-02 の IGS 最終クロックにある IGS 衛星 G01(30 s)と局 ABMF(300 s)のクロックで、NOTICE を添えた切り出しを同梱しています。最初の二つには再配布の許諾がないため、そこから書いたログは git 管理外のrealdata-cache/(scripts/gen_clock_log_real_ref.py)にあり、テストはその旨を述べ、それらがなければ、KSHANA_REQUIRE_REALDATA=1でない限り合格します。各ログはエンジンと独立したリーダーで読み、ADEV、TDEV、MTIE を allantools 2024.6 と比較します。tests/fixtures/clock_log_real/RESULTS.mdに記録:出荷時のリーダーでは、TICC のログ、ヘッダーのバージョン、五つのエラーメッセージが事前登録した合格基準に届きませんでした。これらを修正し、比較を変更せずに再実行しました。一組を除いて達成しています。周波数ログの MTIE は allantools のものと異なります。allantools が周波数からその平均を引いたものを積分するためです(NOT MET として固定。同じ条件での比較は達成)。この行は MODELLED のままです。TICC のログは、測定したクロックデータを私たちのスクリプトでカウンターのレイアウトに再エンコードしたもの(実際の TICC の取得データは見つかりませんでした)であり、参照リーダーはエンジンのリーダーと同じ作者によるものだからです。