Advent Calendar 2020: ソフトウェア無線
注意:LimeSDR などのソフトウェア無線は技術基準適合証明(通称,技適)を受けていないため,これらの機器を日本国内で無線機として利用することは電波法により禁じられています。無線機として使用するためには,実験試験局免許を取得するか電波暗室・シールドボックスなどの設備を使用する必要があります。または,アンテナの代わりにケーブルとアッテネータを用い有線接続をし電波を発しないようにすることで,無線通信ではなく有線通信とはなりますが実験することができます(この場合も電波が漏れないように注意してください)。このページを参照される方は,実験される国や地域の法令などを遵守するようにご注意ください。また,実験等はご自身の責任でお願いします。
Day 19: 双方向通信のための準備
今日から数日間で双方向通信を実装します。
受信シンボルのフレーム構造分析
17日目 で実装した demodulate()
関数で変調したデータを物理層・データリンク層のフレームとして処理します(データが受信・復調できて忘れてました)。
以下の物理層の定義のうち, demodulate()
関数により得られるシンボル列はプリアンブル・SFD以降なので,48ビット分が物理層のフレームとしてシンボル列に含まれます。
+------------+------------+-------------+------------+------------+-----------+
| Preamble | Preamble | Modulation/ | Reserved | Length | CRC16 |
| (SYNC) | (SFD) | Code rate | | | |
+------------+------------+-------------+------------+------------+-----------+
128 symbols 16 symbols 8 bits 8 bits 16 bits 16 bits
上記の物理層の信号に以下のようなデータリンク層のフレームが続きます。
+-------+---------+-------------+-------------+----------+---...---+-------+
| Frame | Symbols | Destination | Source | Sequence | Data | FCS |
| type | | address | address | number | | |
+-------+---------+-------------+-------------+----------+---...---+-------+
1 byte 2 bytes 4 bytes 4 bytes 2 bytes 4 bytes
このデータ構造を Python のクラスとして以下のように定義し,シンボル列からフレームの各パラメータを取り出す parse()
メソッドを実装します。物理層のModulcation/Code rateにより,データリンク層の処理を変更できるように設計していますが,今回は簡単のため物理層とデータリンク層を同じクラスに実装しました。
"""
PHysical & data link layer protocol class
"""
class MyProtocol:
"""
Constructor
"""
def __init__(self):
self.modulation = None
self.length = 0
"""
Parse symbols to get a frame
"""
def parse(self, data):
# Physical layer
self.modulation = data[0:8].int
self.length = data[16:32].int
# Check the checksum∫
if not crc16_check(data[0:48].bytes):
return False
# Data-link layer
self.frame_type = data[48:56].int
self.symbols = data[56:72].int
self.destination = data[72:104].int
self.source = data[104:136].int
self.sequence_number = data[136:152].int
if data.len - 48 < self.symbols:
return False
self.payload = data[152:16 + self.symbols].bytes
# Check the checksum
if not crc32_check(data[48:48 + self.symbols].bytes):
return False
return True
18日目 までに実装した
0x010000a84c460000a80000000200000001000161626364d77a99cf
を以下のように使用します(上記 MyProtocol
クラスの定義と crc16/32
関係の関数(11日目を参照)は省略しています)。
import bitstring
import crcmod
# Class定義
# crc16, crc16_check, crc32, crc32_check の実装
data = bitstring.BitArray(hex='010000a84c460000a80000000200000001000161626364d77a99cf')
protocol = MyProtocol()
if not protocol.parse(data):
print("Failed to parse the protocol data")
print(protocol.payload)
上記を実行すると以下のように送信されたデータが復元できます。
b'abcd'
今日のまとめと明日の予定
今日はオリジナルプロトコルの構造を解析するために,MyProtocol
クラスを実装しました。明日はSDR機器を無線インターフェイスとして扱うためのクラスを実装します。