こんにちは、ドルフィンシステムの笹生です。
今日の記事は「ドルフィンシステム RF キャプチャのファイルを SigMF 形式と相互変換するPython Scriptを作成してみた」というタイトルでお送りします。
前回、「NI RF Data Recording APIって何?」という記事で登場した SigMF という標準化されたデータセットのお話があったかと思います。
実は弊社ドルフィンシステムの RF キャプチャのファイルも従来からバイナリの IQ データと共にメタ情報を ini ファイルという形で保存することになっております。
SigMF は弊社の従来からの収録データの扱い方法とかなり近しい管理方法だったので、割と簡単に相互変換できるのではないかということで、今回相互変換するPython Scriptを作成してみました。
SigMF の github はこちらです。
https://github.com/sigmf/SigMF
SigMFとは?
まずは、SigMFとはなにか? についてAI にまとめさせてみました。
無線通信の世界では、受信した電波をデジタルデータとして保存し、後で解析したりAIの学習に利用したりすることが不可欠です。しかし、データの保存方法が独自フォーマットだと、数年後に「このデータはどうやって録音したのか?」が分からなくなったり(データの腐敗:Bitrot)、特定のソフトウェアでしか開けなかったりという問題が発生します。
無線通信の世界では、受信した電波をデジタルデータとして保存し、後で解析したりAIの学習に利用したりすることが不可欠です。しかし、データの保存方法が独自フォーマットだと、数年後に「このデータはどうやって録音したのか?」が分からなくなったり(データの腐敗:Bitrot)、特定のソフトウェアでしか開けなかったりという問題が発生します。
これを解決するのが、SigMF (Signal Metadata Format) です。
SigMFの定義 デジタル化された信号サンプル(時間軸データ)のセットと、それに関連するメタデータをJSON形式で記述するためのオープン標準規格。
SigMFは、単一のファイルではなく、役割の異なる「2つのファイル」をペアとして扱います。まずは、SigMFがどのように電波を「保存」しているのか、その物理的な構成から見ていきましょう。
ファイル拡張子 | 役割 | 中身の構造とルール |
|---|---|---|
.sigmf-data | データセット | 録音された電波そのもの(バイナリ)。複素数(C)の場合、実数部(I)と虚数部(Q)が I[0], Q[0], I[1], Q[1]... と交互に並ぶ「インターリーブ」形式で保存されます。 |
.sigmf-meta | メタデータ | 録音設定や信号の意味を記した JSON形式 のテキスト。必ずUTF-8でエンコードされ、データファイルと同じディレクトリに配置されます。 |
この標準化によって、ツール間での互換性が保たれ、過去のデータも「生きた情報」として再利用できるという大きなメリットが生まれます。
メタデータの詳細についてはこの記事で扱いませんが、「NI RF Data Recording API」では通常の SigMF のメタデータに追加で独自フィールド、拡張メタを追加して使用していました。
ドルフィン .dat と .sigmf-data は同じ
ドルフィンの .dat は SigMFでいう ci16_le(complex int16 little-endian)で保存されています。
並びは I,Q,I,Q,...
I/Q各要素は signed 16-bit int(little-endian)
SigMF側の .sigmf-data も同じく ci16_le に対応しているので、バイナリデータの変換は不要になります。
なので相互変換ではコピーするだけとなります。
ドルフィン → SigMF: .dat を .sigmf-data に コピー
SigMF → ドルフィン : .sigmf-data を .dat に コピー
やるべきことの本質は メタデータの変換となります。
ドルフィン .ini と .sigmf-meta の相互変換
まずはドルフォン .ini のメタ情報と、.sigmf-meta の対応表をつくってみました。この関係で相互変換を作成しました。
対応表
| INIキー | INI値 | 意味 | SigMF格納先 | SigMFキー | 値(例/式) | 備考 |
|---|---|---|---|---|---|---|
| Start time | "2026/04/20 16:38:38" | 収録開始時刻(ローカル表記の可能性) | captures[0] | SigMFFile.DATETIME_KEY | start_time → ISO8601(UTC) + 'Z' | SigMFはISO8601推奨。タイムゾーンが不明なら注記(例: local_time)を拡張メタに残すと安全。 |
| End time | "2026/04/20 16:48:37" | 収録終了時刻 | captures[0] (拡張) | capture_details.end_datetime | end_time → ISO8601(UTC) + 'Z' | SigMF標準には終了時刻キーが一般的に無いので拡張メタで保持。 |
| Data file path | /data/rx/220260420-163838//20260420-163838/-ch0.dat | IQデータ実体パス | 運用情報(拡張) | source.data_file_path | string | SigMFでは `.sigmf-data` が実体。元データの出所として残す用途。 |
| Ini file path | /data/rx/20260420-163838/20260420-163838/ch0.ini | メタ(INI)パス | 運用情報(拡張) | source.ini_file_path | string | |
| IQ Rate (S/s) | 5000000 | サンプルレート | global | SigMFFile.SAMPLE_RATE_KEY | 5000000 | |
| Carrier Freq (Hz) | 2400000000 | 中心周波数(RF) | captures[0] | SigMFFile.FREQUENCY_KEY | 2402000000 | |
| Gain/Ref Level (dB/dBm) | 50.000000 | 受信ゲイン、または基準レベル(定義は機器依存) | captures[0] (拡張) | capture_details.gain_db | 60.0 | SigMF標準に gain の共通キーはないため拡張メタ推奨。単位(dB? dBm?)を明示。 |
| LO Frequency (Hz) | 0 | LO周波数(もし0なら未使用/不明の可能性) | captures[0] (拡張) | capture_details.lo_frequency_hz | 0 | |
| BW | 0.000000 | 帯域(0なら未設定) | captures[0] (拡張) | capture_details.bandwidth_hz | 0.0 | SigMFはFLO/FHI(annotation)で周波数範囲を持てる。帯域値を別途保持したい場合は拡張が無難。 |
| Scale gain | 0.0000305175781250 | 整数IQを実数へ戻すスケール係数(例: ci16→float) | global (拡張) | conversion.iq_scale | 0.000030517578125 (= 1/32768) | `ci16_le` の“係数”はSigMF標準に固定キーが無いので、拡張で明示するのが実務的。 |
| Acquisition type | "IQ" | 取得タイプ(IQ) | global (拡張) | acquisition.type | "IQ" | |
| Read size (bytes) | 10000 | 取り込み/読み出しのチャンクサイズ | global (拡張) | acquisition.read_size_bytes | 10000 | |
| ADC_Bits | 12 | ADC量子化ビット数 | global (拡張) | hardware.adc_bits | 12 | |
| DAC_Bits | 12 | DAC量子化ビット数 | global (拡張) | hardware.dac_bits | 12 | |
| Device_Name | B-Series Device | デバイス名(製品ファミリ等) | global | SigMFFile.HW_KEY (または拡張) | "B-Series Device" | `hw` は自由文字列なので入れられる。より構造化したいなら `hardware.device_name` を拡張で。 |
| Mboard_Name | B200 | マザーボード名(例: B200) | global (拡張) | hardware.mboard_name | "B200" | |
| IQデータ型 | (INIに明示なしだがci16_le) | IQサンプルの格納型(例: ci16_le / cf32_le) | global | SigMFFile.DATATYPE_KEY | "ci16_le" など | INIの Scale gain が 1/32768 なので、実体が int16 IQ(ci16) |
上記対応表に従って、dolphin_sigmf_convert.py を作成しました。
一般の公開は未定ですしまだきちんとした検証が出来ておりませんが、既に弊社の収録アプリ等ををお使いの方でご興味がおありでしたら、直接メール等でお問い合わせ頂ければお送りします。(以前からの全ての弊社 ini に対応している動作の補償は一切できませんのでご了承ください。)
コマンド(Dolphin → SigMF)
python tools/dolphin_sigmf_convert.py dat-ini-to-sigmf ^
--dat dolphin/20260116-133838-ch0.dat ^
--ini dolphin/20260116-133838-ch0.ini ^
--out-base out/20260116-133838-ch0
生成物:
out/20260116-133838-ch0.sigmf-data(.dat のコピー)
out/20260116-133838-ch0.sigmf-meta(INIから生成)
コマンド(SigMF → Dolphin)
python tools/dolphin_sigmf_convert.py sigmf-to-dat-ini ^
--sigmf-data out/20260116-133838-ch0.sigmf-data ^
--sigmf-meta out/20260116-133838-ch0.sigmf-meta ^
--out-base out/20260116-133838-ch0-restored
生成物:
out/20260116-133838-ch0-restored.dat
out/20260116-133838-ch0-restored.ini
まとめ
前回、「NI RF Data Recording APIって何?」という記事の続きのような感じで今回、SigMF について調査をしておりまして、従来からの弊社のメタデータと基本的な思想が一致していたので、折角なら相互で変換出来たらいいなと思い作成しました。
0 件のコメント :
コメントを投稿