USRP N310,Gnuradio初探

kunn4938發表於2020-09-25

近期實驗需要搭建一個軟體無線電環境平臺,在琢磨一段時間後,以下是對之前的實驗總結一下。

實驗平臺

  • 硬體:筆記本2臺,USRP N310兩臺,及輔助天線等
  • 軟體:在Ubuntu系統下安裝Gnuradio3.7
    實驗前提,USRP能與電腦建立收發通訊

USRP-OFDM傳送端框架

在這裡插入圖片描述
​利用Socket PDU模組與外部程式建立TCP連線,通過外部程式向9090埠傳送資料從而寫入傳送端,經PDU to Tagged Stream將協議資料轉換為byte格式資料,再經過CRC32給資料加上迴圈冗餘校驗碼,再分兩路生成資料頭部和資料載荷部分,分別進行BPSK與QPSK對映,通過Tagged Stream Mux模組組裝在一起,然後經過OFDM調製部分,分別進行載頻子波分配、加入導頻系列、加入同步字與迴圈字首,再通過Multiply Const進行約束,防止波形發生非線性失真,Tag Gate模組抑制標記符號向下傳遞,最後通過UHD:USRP Sink 模組連線硬體裝置,對資料進行DAC轉換,數字變頻傳送到環境空間。

傳送端模組簡介

Socket PDU:與外部程式建立socket連線,對整個流圖進行資料輸入。

PDU to Tagged Stream:將協議資料轉化為固定長度byte型別資料,並給資料加上長度標記。

Stream CRC32:給資料尾部加上32位(4位元組)迴圈冗餘校驗-----通道編碼。

Protocol Formatter:利用資料頭生成物件建立一個6位元組的資料頭,包含資料幀長度,當前資料幀號等。

Repack Bits:對資料進行重新打包,8bits一組轉換為2bits一組或者1bit一組的資料,為後續進行BPSK、 QPSK對映,此過程不存在資料bit丟失。

Chunks to Symbols:根據Symbol Table將byte資料進行浮點數或者複數對映,byte型資料轉換為複數型數 據。

Tagged Stream Mux:將頭部BPSK符號與載荷QPSK符號組裝在一起進行OFDM調製。

OFDM Carrier Allocator:OFDM子載波分配,分配資料子載波,導頻子載波,同步子載波,直流子載波。

FFT:對分配後的子載波進行傅立葉變換,完成OFDM調製。

OFDM Cyclic Prefixer:給OFDM加入迴圈字首,防止ofdm符號間干擾(ISI)。

Multiply Const:乘常數模組,乘以小於1的值,限制幅度,防止傳送非線性失真。

Tag Gate:阻止標記符號向後延續。

其他引數:

protocol parser: 協議分析器

FEC: 前向糾錯編碼,送入傳輸通道之前

MSB: 最高位有效

Becimation: 抽取,轉變頻率

OFDM符號結構

  • ofdm輸出標籤:載波偏移,通道均衡係數,資料幀,接收時間

  • ofdm子載波: 左6個子載波[-32,-27],右5個子載波[26,31]為虛擬子載波

​ 不使用載波為0,———減少帶外功率,抑制ACI(相鄰通道干擾)

  • 一個OFDM符號:包含 虛擬子載波直流子載波射頻子載波有效資料子載波

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-CfNVPpsv-1601025338052)(D:\實驗作圖記錄\OFDM符號結構.jpg)]

​ 以進行64FFT變換為例,總載波個數為64,除去虛擬子載波,直流子載波,射頻子載波,剩餘有效資料子載波48個,資料頭部Head採用BPSK調製,(6 * 8)/1一個符號用一位位元表示,資料載荷加上校驗碼Payload部分採用QBSK調製,((96+4 )* 8)/2,一個符號用兩個位元位表示。資料生成頭部載入荷總共需要OFDM符號個數:
( 6 ∗ 8 ) / 1 + ( 96 + 4 ) ∗ 8 / 2 = 448 (6*8)/1 + (96 + 4 )*8 / 2 = 448 68/19648/2=448

448 / 48 ≈ 10 個 O F D M 符 號 448 / 48 ≈ 10 個OFDM符號 448/4810OFDM

​ 加上2個OFDM符號同步字,傳送一次資料共需要 12 個OFDM符號週期。

傳送端外部TCP客戶端程式

import socket
import time

"""
    tcp 客戶端,輸入傳送內容,從檔案讀出資料,按照每次96位元組方式傳送

"""

def main1():
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect(('192.168.10.3', 9090))
    while True:
        tmp = input('請輸入您要傳送的內容:')
        if tmp != 'exit':
            s.send('{}\n'.format(tmp).encode('utf-8'))
            print('{}\n'.format(tmp).encode())
        else:
            break


def main():
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect(('192.168.10.3', 9090))

    with open('./SendData', 'r', encoding='utf-8') as R_file:
        while True:
            content = R_file.read(96)
            if content != '':
                s.send('{}'.format(content).encode('utf-8'))
                print(content, end='')
                time.sleep(0.01)

            else:
                print('資料傳送結束!!!')
                s.close()
                break


if __name__ == '__main__':
    main()
    # main1()

USRP-OFDM接收端框架

在這裡插入圖片描述
​ 通過UHD:USRP Source模組接收空間中的電磁資料,通過去頻偏,同步去資料頭分離出載荷,OFDM解調,IFFT變換,解符號對映,CRC32校驗,再通過Socket PDU與外部TCP伺服器連線,解碼恢復出傳送的資料。

接收端模組簡介

UHD USRP Source:與硬體USRP N310 連線,接收空間中電磁資料,實現數字下變頻,ADC變換,轉換為基 帶訊號輸入給Gunradio軟體款圖。

Schmidl & Cox OFDM Synch​:實現符號定時同步,除去小數部分載波頻偏​。

Delay:延時模組,延遲一個ofdm符號週期,fft_len + 迴圈字首(64+16)。

Frequency Mod:頻率調製模組,產生一個和載波頻偏對應的序列,與接收資料流相乘,達到去載波頻偏。

Multiply:兩資料相乘,去除小數載波頻偏,消除ACI干擾。

Head/Payload Demux:根據定時資訊與幀頭資訊,將資料頭與載荷部分分開,輸入訊號分別為去除載波頻偏 的資料流,觸發資訊,解碼後的幀頭資訊。輸出為幀頭部資料,載荷資料。

FFT:進行逆傅立葉變換。

OFDM Channel Estimation:通道評估模組,得到整數倍頻偏和系統頻域響應。

OFDM Frame Equalizer:OFDM幀均衡模組,糾正整數倍頻偏,對接收訊號進行均衡。

OFDM Serializer:逆OFDM子載波分配,與傳送端OFDM Carrier Allocator 相逆的過程,找到攜帶資料的48 個子載波,並提取出其資訊。

Constellation Decoder:解符號對映,分別進行逆BPSK,QPSK對映,轉化為byte型別資料。

Repack Bits:與傳送端相逆的過程,位元組重新組合,不丟失位元資訊。

Stream CRC32:迴圈冗餘校驗,校驗資料是否出錯並輸出。

Tagged Stream to PDU:byte型別資料轉換為協議資料。

Socket PDU:與外部程式建立socket連線。

接收端外部TCP服務端程式

import socket

"""
    tcp 服務端,接收客戶端傳送的資料

"""

def main():
    host = '192.168.10.1'
    port = 9090
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server_socket.bind((host, port))
    server_socket.listen(1)
    client_socket, client_add = server_socket.accept()
    while True:
        data = client_socket.recv(1024)
        data = data.decode('utf-8')
        print(data)
        # client_socket.close()


if __name__ == '__main__':
    main()

TCP客戶端伺服器注意事項

  • TCP伺服器端需要先繫結IP與埠,等待客戶端連線,客戶端則不需要
  • TCP客戶端需先與伺服器端建立連線才能通訊
  • TCP 三次握手

輸入資料編碼選擇

  • ASCII:128個字元,單位元組編碼,目前只使用低7位二進位制表示,保留最高位,A-65,a-97,0-48

  • UTF-8:可變長位元組編碼,1-4位元組:

    • US-ASCII:1位元組
    • 拉丁文,希臘字母,阿拉伯文:2位元組
    • 中日韓,東南亞文字:3位元組
    • 少數語言字元:4位元組
  • GBK:漢字編碼字符集

IP資料幀傳輸效率

IP資料幀:MTU,包含頭部資訊14個位元組,尾部校驗和FCS 4個位元組,乙太網資料幀的傳輸效率:
α = ( T − 14 − 4 ) / T α=(T-14-4)/T α=(T144)/T

參考資料

1.USRP—OFDM通訊實驗報告.
2.GNU Radio教程.
3.Linux系統下搭建USRP + GNU Radio開發環境.
4.OFDM調製理解.
5.PDU(協議資料單元).
6.Python學習筆記——網路-TCP.