panda's tech note

Advent Calendar 2020: ソフトウェア無線

注意LimeSDR などのソフトウェア無線は技術基準適合証明(通称,技適)を受けていないため,これらの機器を日本国内で無線機として利用することは電波法により禁じられています。無線機として使用するためには,実験試験局免許を取得するか電波暗室・シールドボックスなどの設備を使用する必要があります。または,アンテナの代わりにケーブルとアッテネータを用い有線接続をし電波を発しないようにすることで,無線通信ではなく有線通信とはなりますが実験することができます(この場合も電波が漏れないように注意してください)。このページを参照される方は,実験される国や地域の法令などを遵守するようにご注意ください。また,実験等はご自身の責任でお願いします。

Day 18: オリジナルプロトコルの実装 (8)

今日はこれまで実装してきたものを組み合わせてオリジナルプロトコルでの通信を実験してみます。

テスト用の送信プログラム

transmit_packet() 関数を使って以下のようにテストデータをオリジナルプロトコルで送信するプログラムを書きました。デバイスや送信ストリームのセットアップは省略しています。

    src = bitstring.BitArray(int=1, length=32)
    dst = bitstring.BitArray(int=2, length=32)
    transmit_packet(sdr, txStream, dst, src, 1, b'abcd')

この関数で送信されるデータはプリアンブル,SFDを除くと以下の通りです。受信側で demodulate() 関数で復調したデータが以下に一致すれば通信が成功していることになります(通信の終了は正しく検出できない可能性があるので,後ろにはゴミデータが付く可能性があります)。

0x010000a84c460000a80000000200000001000161626364d77a99cf

受信・復調と受信データの確認

16日目 で実装した1つ目の while ループの最後(2つ目の while ループを抜けた後)に,得られたシンボル列 packetSymbols を復調し,表示する以下の2行を追加します。

        binary = demodulate(packetSymbols)
        print(binary)

このプログラムを実行すると以下のようになります。

$ python3 myprotocol.py
linux; GNU C++ version 7.3.0; Boost_106501; UHD_003.010.003.000-0-unknown

[INFO] Make connection: 'LimeSDR-USB [USB 3.0] XXXXXXXXXXXXX'
[INFO] Reference clock 30.72 MHz
[INFO] Device name: LimeSDR-USB
[INFO] Reference: 30.72 MHz
[INFO] LMS7002M register cache: Disabled
[INFO] Filter calibrated. Filter order-4th, filter bandwidth set to 5 MHz.Real pole 1st order filter set to 2.5 MHz. Preemphasis filter not active
[INFO] TX LPF configured
[INFO] RX LPF configured
[INFO] RX LPF configured
[INFO] Tx calibration finished
[INFO] Rx calibration finished
0x010000a84c4600000000000000000000000000000000, 0b0

受信シンボル列を復調した結果は

0x010000a84c4600000000000000000000000000000000, 0b0

ですが,想定される受信データの

0x010000a84c460000a80000000200000001000161626364d77a99cf

と一致しません。途中からデータが消失しているように見えます。いろいろと試行錯誤をしたところ,送信側で正しく信号を送信出来ていないことが判明したので以下の対応をしました。

transmit_packet 関数へのポストアンブルの追加

上述の通り,データの後半が正しく送信できていなかったので,writeStream() によりサンプル列を送信する際,信号を急に止めると搬送波への影響があるのか,後半の信号が正しく送信されないという現象が発生しました.そのため,信号を急に止めないために,送信するサンプル列の後ろにポストアンブルとして128シンボル分の 0 のデータを付加しました(SoapySDR.SOAPY_SDR_END_BURST フラグなどを試しましたが,上手くいかなかったのでポストアンブルを足しました)。

具体的には以下のように numpy.ones() により 1+0j の複素シンボルを生成してフレームの後に追加しました。

"""
Transmit
"""
def transmit_packet(sdr, txStream, dst, src, seqno, data):
    # Postamble
    postamble = np.ones(128, dtype=np.complex64)
    # Build the datalink layer frame
    frame = build_datalink(dst, src, seqno, bitstring.BitArray(data))
    # Build the physical layer protocol header
    phy = build_phy(frame.size)
    # Combine the physical layer header and the data-link frame
    symbols = np.concatenate([phy, frame, postamble])

    # Get samples from symbols
    samples = np.repeat(symbols, SAMPLES_PER_SYMBOL)

    mtu = sdr.getStreamMTU(txStream)
    sent = 0
    while sent < len(samples):
        chunk = samples[sent:sent+mtu]
        status = sdr.writeStream(txStream, [chunk], chunk.size, timeoutUs=1000000)
        if status.ret != chunk.size:
            sys.stderr.write("Failed to transmit all samples in writeStream(): {}\n".format(status.ret))
            return False
        sent += status.ret

    return True

これで上記の受信プログラムを実行すると以下の通りになりました。

$ python3 myprotocol.py
linux; GNU C++ version 7.3.0; Boost_106501; UHD_003.010.003.000-0-unknown

[INFO] Make connection: 'LimeSDR-USB [USB 3.0] XXXXXXXXXXXXX'
[INFO] Reference clock 30.72 MHz
[INFO] Device name: LimeSDR-USB
[INFO] Reference: 30.72 MHz
[INFO] LMS7002M register cache: Disabled
[INFO] Filter calibrated. Filter order-4th, filter bandwidth set to 5 MHz.Real pole 1st order filter set to 2.5 MHz. Preemphasis filter not active
[INFO] TX LPF configured
[INFO] RX LPF configured
[INFO] RX LPF configured
[INFO] Tx calibration finished
[INFO] Rx calibration finished
0x010000a84c460000a80000000200000001000161626364d77a99cf00000000000000000000000000000000000000000000000, 0b00
0x010000a84c460000a80000000200000001000161626364d77a99cf00000000000000000000000000000000000000000000000, 0b00

とデータの後半にポストアンブルを含む多くの 0 ビット列が続きますが,プロトコルヘッダのフレーム長を見ることでこれらを取り除くことができるため,

0x010000a84c460000a80000000200000001000161626364d77a99cf

と送信データと同じデータが復元できます。

今日のまとめと明日の予定

これでオリジナルプロトコルでの送受信が実装できました。明日以降はまとめでオリジナルプロトコルを使った双方向通信を実装していこうと思っています。