記録の項目
アプリが書く frames.jsonl(生フレーム)と events.jsonl(通話)の、すべてのキーの意味です。1 行が 1 件の JSON です。メイン画面のログ欄と、TCP で送る行も、同じ形です。
ファイルの置き場所と名前は出力ファイルにあります。
共通のキー
frames.jsonl と events.jsonl の両方の行が持つキーです。
| キー | 型 | 内容 |
|---|---|---|
ts | 文字列 | 時刻(ISO 8601、ローカル時刻とオフセット)。枠の時刻を、チャンクが届いた時刻から逆算した近似です。順序は si で見てください |
radio | 文字列 | 受けた無線機の ID。同じチャンネルを 2 台で受けたときも 1 ファイルに書き、これで区別します |
ch | 文字列 | チャンネルの ID(プリセットの channels[].id。例 t102_399131250、t61t_399068750、t61c_399062500) |
standard | 文字列 | 方式。t102(T102 強化秘話, AMBE+2)か t61(ARIB STD-T61 EL-CELP) |
si | 整数 | 受信を始めてからの絶対位置。T102 はシンボル番号(2400 シンボル/秒)、T61 はビット位置(9600 bit/秒)。無線機を開き直すと 0 に戻ります |
kind | 文字列 | 行の種別。方式とファイルごとに下の表のとおりです |
frames.jsonl(T102)
同期した枠を 1 行ずつ書きます。同期語の誤りが 0 の枠が、直近 4 秒の窓に 2 枚以上ある間だけ書きます(雑音から行を作らないためです)。1 枠は 80 ms です。
{"ts":"2026-10-26T09:02:17.312+09:00","radio":"r1","ch":"t102_399131250","standard":"t102","freq_hz":399131250,"si":1234567,"kind":"voice","sync_errors":0,"sacch":{"info":33554437,"crc_ok":true,"s":2,"user":0},"voice_errors":[3,0,1,2],"uncorrectable":0}
{"ts":"2026-10-26T09:02:17.392+09:00","radio":"r1","ch":"t102_399131250","standard":"t102","freq_hz":399131250,"si":1234759,"kind":"facch","sync_errors":0,"sacch":{"info":0,"crc_ok":false,"s":0,"user":0},"facch_hex":"e10500004e22000b5800e10500004e22000b5800"}
| キー | 型 | 内容 |
|---|---|---|
freq_hz | 整数 | チャンネルの周波数(Hz) |
kind | 文字列 | voice(音声枠)、facch(制御の枠)、idle(空きの制御の枠。CRC が通った片がどれも 00 05 で始まる)、unknown(RICH のパリティが合わない枠、または種別を読めない枠) |
sync_errors | 整数 | 同期語(10 シンボル)の誤りビット数 |
sacch | オブジェクト | 枠ごとの SACCH の 1 片。下の表 |
facch_hex | 文字列 | facch と idle の枠だけ。CRC が通った FACCH の片(1 片 10 バイト = 20 桁)を、枠の中の順に連ねた hex。1 片なら 20 桁、2 片なら 40 桁。CRC が通った片が無ければキーごと無い |
voice_errors | 整数 4 つの配列 | voice の枠だけ。4 語(1 語 20 ms)それぞれの、情報ビットの訂正数 |
uncorrectable | 整数 | voice の枠だけ。訂正できなかった語の数(0〜4) |
sacch:
| キー | 型 | 内容 |
|---|---|---|
info | 整数 | SACCH の 1 片の 26 bit(上位から S 2 bit、ユーザー 6 bit、本体 18 bit) |
crc_ok | 真偽 | SACCH の片の CRC が通ったか |
s | 整数 | info の上位 2 bit。4 片で 1 通の制御メッセージになるときの片の番号(3 → 0 の順に送られる) |
user | 整数 | info の次の 6 bit |
SACCH の制御メッセージ(72 bit)は 4 片をつないで作ります。受信中は 4 片を組み立て、結果を events.jsonl の control 行(detail.channel が sacch)に書きます。
frames.jsonl(T61)
通話波で同期した枠を 1 行ずつ書きます。同期語の硬判定の誤りが 3 bit 以上の枠は書きません。1 枠は 40 ms です。制御波の枠は書きません(信号だけを出します)。
{"ts":"2026-10-26T09:02:17.312+09:00","radio":"r1","ch":"t61t_399068750","standard":"t61","freq_hz":399068750,"si":1234567,"kind":"traffic","sw_hd":0,"rich":{"mode":1,"crc_ok":true,"raw_hex":"<14 桁>"},"tch_hex":"<64 桁>","elcelp":{"ok":true,"hex":"<35 桁>","corrected":3}}
| キー | 型 | 内容 |
|---|---|---|
freq_hz | 整数 | チャンネルの周波数(Hz) |
kind | 文字列 | traffic(RICH の CRC が通った枠)、unknown(同期したが RICH の CRC が通らなかった枠) |
sw_hd | 整数 | 同期語の硬判定の誤りビット数(0〜2) |
rich | オブジェクト | RICH(56 bit)。下の表 |
tch_hex | 文字列 | TCH の 256 bit(PN9 を剥がしたもの)。64 桁の hex |
elcelp | オブジェクト | EL-CELP の伝送路符号を復号した結果。下の表。次の枠(40 ms 後)がそろった枠だけに付くので、行は 1 枠遅れて書かれます。次の枠が来なかった枠にはキーごと無い |
rich:
| キー | 型 | 内容 |
|---|---|---|
mode | 整数か null | 通信モード M。CRC が通らなければ null |
crc_ok | 真偽 | RICH の CRC が通ったか |
raw_hex | 文字列 | RICH の 56 bit。14 桁の hex |
elcelp:
| キー | 型 | 内容 |
|---|---|---|
ok | 真偽 | FEC が合格したか。入力 116 bit の末尾 3 bit の従属検査(u113 = u110⊕u112、u114 = u110⊕u111、u115 = u111⊕u112)が成り立ち、corrected が 12 以下なら合格 |
hex | 文字列 | 音声ビット 137 bit。35 桁の hex(末尾 3 bit は 0 詰め) |
corrected | 整数 | 復号結果を符号化し直したものと、受けた硬判定との不一致ビット数 |
hex はどれも、ビットの並びの先頭を上位にして 4 bit ずつ小文字の 16 進にしたものです。
EL-CELP の符号語と 137 bit の並び
- 符号語(256 bit)は、枠 n の TCH の偶数位置と、枠 n+1 の TCH の奇数位置から作ります。結果は枠 n の行に付きます。
- 符号語は、14 列のブロックインタリーブを戻してから、テイルバイティングの畳み込み符号(レート 1/2、拘束長 7、生成多項式 (133,171)₈)を軟判定の Viterbi で復号し、入力 116 bit を得ます。
hexの 137 bit は、入力のu0〜u112(113 bit)の後に、無保護の 24 bit を並べたものです。- 無保護の 24 bit は、符号語の中の位置
[16,17,34,35,36,53,54,71,72,73,90,91,108,109,128,145,146,165,182,183,218,219,254,255]にあります。hexでの並びは、この昇順ではありません。研究側のビット地図(codec137.npzのunp)と同じ順です。誤りのない実データ 6,093 語で、この順なら全語が研究側のビット列と一致することを確かめています。 - コーデック側の欄の配置と符号帳は分かっていないので、この版では音にしません。
events.jsonl(T102)
T102 の通話の始まりと終わりと、制御メッセージを書きます。T61 は events.jsonl を書きません。
{"ts":"2026-10-26T09:02:15.040+09:00","radio":"r1","ch":"t102_399131250","standard":"t102","si":1229000,"kind":"call_start","summary":"移動162 → 宛先11(秘話 鍵24)","detail":{"caller":20002,"caller_name":"移動162","caller_tag":"a1b2c3d4","destination":11,"cipher_mode":1,"key_number":24,"key_known":true}}
{"ts":"2026-10-26T09:02:27.360+09:00","radio":"r1","ch":"t102_399131250","standard":"t102","si":1258568,"kind":"call_end","summary":"通話終了 発信者20002 12.3 秒","detail":{"caller":20002,"caller_name":"移動162","caller_tag":"a1b2c3d4","destination":11,"duration_s":12.32,"voice_words":614,"gap_words":2,"inferred_phase_words":0,"mean_errors":1.8,"uncorrectable_words":0,"wav":"2026-10-26_T102_399.13125_voice_090215_c20002-d11.wav"}}
{"ts":"2026-10-26T09:02:27.360+09:00","radio":"r1","ch":"t102_399131250","standard":"t102","si":1258568,"kind":"unit_name","summary":"ユニット名 20002 = 移動162","detail":{"caller":20002,"name":"移動162","tag":"a1b2c3d4"}}
{"ts":"2026-10-26T09:02:30.000+09:00","radio":"r1","ch":"t102_399131250","standard":"t102","si":1265000,"kind":"control","summary":"制御 e3 05 …","detail":{"channel":"facch","raw_hex":"e3050000000000000000"}}
| キー | 型 | 内容 |
|---|---|---|
kind | 文字列 | call_start(通話の始まり)、call_end(通話の終わり)、unit_name(発信者とコールサイン名を初めて結び付けた)、control(そのほかの制御メッセージ) |
summary | 文字列 | 画面の通話の欄に出す 1 行の要約 |
detail | オブジェクト | 種別ごとの中身。下の表 |
ts と si は、call_start は通話の始まり、call_end は通話の終わり、unit_name はそれを出した通話の始まりか終わり、control はそのメッセージを運んだ枠の時刻です。
通話の区切り方
通話は、音声の語の流れで区切ります。制御メッセージの通話開始(0xE1)が運ぶ発信者・宛先・秘話の値を、その後の音声に当てます。音声が 2 秒途切れたときと、語の発信者が変わったときに閉じます(通話終了 0xE8 を受けると発信者が分からなくなるので、次の語で閉じます)。音声の語が 50 に満たない通話は捨てます(call_start も出しません)。call_start は語が 50 に達したときに出すので、行が出るのは通話が始まって 1 秒ほど後です。ts と si は通話の始まりの時刻です。
call_start
| キー | 型 | 内容 |
|---|---|---|
caller | 整数か null | 発信者の ID。通話開始のメッセージを受けていなければ null |
caller_name | 文字列か null | 発信者のコールサイン名(例「移動162」「基地11」)。まだ結び付いていなければ null |
caller_tag | 文字列か null | 発信者の 4 バイトの固有タグ(8 桁の hex)。意味は分かっておらず、見分けるための値です |
destination | 整数か null | 宛先の ID |
cipher_mode | 整数か null | 暗号モード。0 は秘話なし |
key_number | 整数か null | 秘話の鍵番号 |
key_known | 真偽 | 秘話を外して合成できる鍵か。鍵番号が分かっていて、アプリが持つ鍵と違えば false(暗号モードは見ないので、平文の通話でも鍵番号で決まります)。false で秘話が掛かっている通話は、秘話が掛かったまま合成するので聞き取れません |
summary は、発信者の名前(無ければ 発信者<ID>)と宛先(宛先<ID>)を「→」でつなぎ、秘話の括弧((平文)、(秘話 鍵<n>)、鍵が分からなければ (秘話 鍵<n> 未知))を付けたものです。値が無いところは 不明 と書きます。
call_end
caller、caller_name、caller_tag、destination は call_start と同じです。コールサイン名は通話の途中で結び付くことが多いので、call_start では null でも call_end では埋まっていることがあります。
| キー | 型 | 内容 |
|---|---|---|
duration_s | 数 | 通話の長さ(秒) |
voice_words | 整数 | 受けた音声の語の数(1 語 20 ms) |
gap_words | 整数 | 取れなかった語の数。合成では前の語からの補間か無音で埋めます |
inferred_phase_words | 整数 | SACCH の CRC が通らず、語の位相を前後から推定した数 |
mean_errors | 数 | 訂正できた語の、情報ビットの訂正数の平均(訂正できなかった語は除く) |
uncorrectable_words | 整数 | 訂正できなかった語の数 |
wav | 文字列 | この通話を録音した WAV のファイル名。WAV を書かなかった通話(WAV の録音を切っているときなど)ではキーが無い |
summary は 通話終了 発信者<ID> <秒数> 秒 です(名前があっても ID で書きます)。
unit_name
コールサイン名の制御メッセージ(0xE7)は、自分の発信者 ID を持ちません。アプリは直近の通話開始の発信者に結び付け、何度か受けた値の多数決で名前とタグを決めます。(発信者, 名前) の組を初めて決めたときに 1 行出します。
| キー | 型 | 内容 |
|---|---|---|
caller | 整数 | 発信者の ID |
name | 文字列 | コールサイン名(Shift-JIS を読んだもの) |
tag | 文字列か null | 4 バイトの固有タグ(8 桁の hex) |
control
通話開始(0xE1)、通話終了(0xE8)、コールサイン名(0xE7)以外の制御メッセージで、CRC が通ったものです。FACCH の空き(00 05 で始まる片)は書きません。画面の通話の欄では、最初は表示から外してあります。
| キー | 型 | 内容 |
|---|---|---|
channel | 文字列 | 運んだチャネル。facch か sacch |
raw_hex | 文字列 | メッセージのバイト列の hex。FACCH は 10 バイト(20 桁)、SACCH は 4 片をつないだ 9 バイト(18 桁) |
ライセンスが未認証のとき
未認証の間は、frames.jsonl と events.jsonl を書かず、TCP でも送りません。画面に出す行では、次の値を伏せます。
| 行 | 見せるもの | 伏せるもの |
|---|---|---|
call_start・call_end | detail の caller、caller_name、destination | detail のほかの値(caller_tag、cipher_mode、key_number、key_known、duration_s、wav など)は ***。null は null のまま、無いキーは足しません |
unit_name | summary と detail の全部 | なし |
control | なし | summary と detail の値は *** |
| T102 の枠 | 受信品質の値(sync_errors、sacch、voice_errors、uncorrectable) | facch_hex は同じ文字数の * |
| T61 の枠 | 受信品質の値(sw_hd、rich.mode、rich.crc_ok、elcelp.ok、elcelp.corrected) | rich.raw_hex・tch_hex・elcelp.hex は同じ文字数の * |
未認証の summary は、秘話の括弧と通話の長さを含みません。call_start は <名前> → 宛先<ID>、call_end は 通話終了 <名前> です。名前は caller_name があればそれ、無ければ 発信者<ID> で、値が無いところは 不明 と書きます(例「移動162 → 宛先11」「通話終了 発信者20002」)。音声は流さず、WAV も作りません。