使用 GNU Radio Companion 驱动 USRP N320 实现 OFDM 自收自发测试。(Ubuntu20.04LTS + GNURadio 3.8 + UHD 3.15)
该模块由随机数信号源、CRC、符号映射器、FFT、循环前缀加法器、放大器组成。主要目标是传输随机信号,根据调制方式的选择对有效载荷进行重新包装。选择的调制是 QPSK,所以 2 位被重新打包在一起。然后将有效载荷和报头分别映射到 QPSK 和 BPSK 的复星座矢量中。OFDM 载波分配器分配占用载波、导频载波、导频符号和同步字。FFT(Reverse)或 IFFT采用复数值向量并计算 IFFT 它表示输出。循环前缀以 OFDM 符号作为其输入,从而产生具有循环前缀的输出符号。
Random Source:
①、变量:packet_len
②、stream to Tagged stream
①、变量:length_tag_key
②、Stream CRC32
下面举例介绍:
CRC32 之后的数据图如下所示,CRC 已经被添加到每个分组的末尾,并且分组长度标签已经从 100 字节被更新到104 字节,其中额外的 4 个字节用干 CRC
①、变量:length_tag_key
②、变量:occupied_carriers
③、变量:hdr_format
occupied_carriers
: 用于指定 OFDM 系统中被占用的载波序列。1
: 用于指定 OFDM 头部的长度length_tag_key
: 用于指定标记头部长度的 keyheader_format_ofdm C++ 实现源码如下:
header_format_ofdm::header_format_ofdm(
const std::vector<std::vector<int>>& occupied_carriers,
int n_syms,
const std::string& len_key_name,
const std::string& frame_key_name,
const std::string& num_key_name,
int bits_per_header_sym,
int bits_per_payload_sym,
bool scramble_header)
: header_format_crc(len_key_name, num_key_name),
d_frame_key_name(pmt::intern(frame_key_name)),
d_occupied_carriers(occupied_carriers),
d_bits_per_payload_sym(bits_per_payload_sym)
{
d_header_len = 0;
for (int i = 0; i < n_syms; i++) {
d_header_len += occupied_carriers[i].size();
}
d_syms_per_set = 0;
for (unsigned i = 0; i < d_occupied_carriers.size(); i++) {
d_syms_per_set += d_occupied_carriers[i].size();
}
// Init scrambler mask
d_scramble_mask = std::vector<uint8_t>(header_nbits(), 0);
if (scramble_header) {
// These are just random values which already have OK PAPR:
gr::digital::lfsr shift_reg(0x8a, 0x6f, 7);
for (size_t i = 0; i < header_nbytes(); i++) {
for (int k = 0; k < bits_per_header_sym; k++) {
d_scramble_mask[i] ^= shift_reg.next_bit() << k;
}
}
}
}
④、Protocol Formatter
①、Repack Bits
例如,假设你正在发送 8-PSK,因此在调制器之前的发送侧设置 k=8、l=3。现在假设您正在传输单个字节(8位)的数据。您的传入标记流的长度为 1(现在共 8+1=9 位,多出 1 位为标记流的长度),传出的长度为 3。但是,第三项实际上仅携带 2 位相关数据(多出来的 1 位标记流),这些位与边界不对齐
。因此,您将 Pack Alignment 设置为 Input,因为输出可能不对齐。`现在假设您正在执行相反的操作:将这三项打包为完整字节。你如何解释这三个字节?如果没有这个标志,您必须假设其中有 9 个相关位,因此最终会得到 2 个字节的输出数据。但在打包的情况下,您希望输出对齐;所有输出位都必须有用。通过断言此标志,打包算法尝试执行此操作,并且在本例中假设由于我们在 8 位之后进行了对齐,因此可以丢弃第 9 位。8PSK 星座图如下:
②、变量:occupied_carriers
③、Repack Bits
Virtual Sink:
①、变量:header_mod
②、Chunks to Symbols
Tagged Stream Mux:
①、变量:occupied_carriers
②、变量:pilot_carriers
③、变量:pilot_symbols
④、变量:sync_word1、sync_word2
[0., 0., 0., 0., 0., 0., 0., 1.41421356, 0., -1.41421356, 0., 1.41421356, 0., -1.41421356, 0., -1.41421356, 0., -1.41421356, 0., 1.41421356, 0., -1.41421356, 0., 1.41421356, 0., -1.41421356, 0., -1.41421356, 0., -1.41421356, 0., -1.41421356, 0., 1.41421356, 0., -1.41421356, 0., 1.41421356, 0., 1.41421356, 0., 1.41421356, 0., -1.41421356, 0., 1.41421356, 0., 1.41421356, 0., 1.41421356, 0., -1.41421356, 0., 1.41421356, 0., 1.41421356, 0., 1.41421356, 0., 0., 0., 0., 0., 0.]
[0, 0, 0, 0, 0, 0, -1, -1, -1, -1, 1, 1, -1, -1, -1, 1, -1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, 1, -1, -1, 1, -1, 0, 1, -1, 1, 1, 1, -1, 1, 1, 1, -1, 1, 1, 1, 1, -1, 1, -1, -1, -1, 1, -1, 1, -1, -1, -1, -1, 0, 0, 0, 0, 0]
⑤、OFDM Carrier Allocator:
①、fft_len
②、FFT:
①、变量:rolloff
②、OFDM Cyclic Prefixer
Multiply Const: 将输入流乘以标量或向量常量(如果向量,则按元素)
Tag Gate:
①、参数:address0
②、变量:samp_rate
③、参数:carrier_freq
④、参数:tx_gain
⑤、USRP Sink
OFDM 头部和有效载荷调制后组成一帧 OFDM 信息。
在 OFDM(正交频分复用)系统中,帧通常由头部(Header)和有效载荷(Payload)两部分组成。
将上面的一帧 OFDM 信号通过载波分配器,配置好数据子载波、导频子载波、导频符号、同步字,并将 OFDM 信号通过 IFFT 调制到子载波上,并添加循环前缀。
接收机主要由 OFDM同步器、频率调制器、信号混频器、FFT 和帧采集组成。来自天线的输入信号,采取的带宽对应于包含实际数据的载波数,直接发送到同步器(Schmidl & Cox OFDM synch)。该同步器负责定时同步和频率误差校正。**频率误差校正被馈送到频率调制器,以产生与同步块的频率误差成比例的信号。然后将其与接收到的数据混合以校正错误并输入到解复用器。**解复用器一旦得到数据包的开头,就开始接收数据,并输出报头和有效载荷进行解调。
Schmidl & Cox OFDM synch:
信号检测
: 首先,接收端需要检测到信号并确定接收到的信号是否包含 OFDM 数据。这可能涉及到自动增益控制(AGC)和能量检测等技术。同步序列检测
: 然后,接收端需要在接收到的信号中找到用于同步的特定序列,通常是 OFDM 帧的循环前缀(Cyclic Prefix)。频率偏移估计
: 接着,模块会估计接收信号的频率偏移,以便进行频率校正。频率偏移可能是由于发送端和接收端的本地振荡器不精确而引起的。时间同步
: 最后,模块会根据找到的同步序列进行时间同步,以确定接收到的信号的起始位置,从而进行正确的数据解调。Frequency Mod:
Delay:
Header/Payload Demux:
OFDM Channel Estimation:
OFDM Frame Equalizer:
OFDM Serializer:
Constellation Decoder:
Packet Header Parser:
符号倍解映射,重新打包和检查字节对应的头数据和发送到文件接收器。
首先不使用 USRP 进行收发,先进行仿真验证直接将发送端送给接收端,在信号源端将发送的数据保存到本地为 send_data.bin,在最后的接收端将接收的数据保存到本地为 recv_data.bin,使用 beyond compare 进行二进制对比,可以看到如下结果,两个文件一致,误码率为0。
①、在实际测试过程中发现将发送增益和接收增益都设置为 0 时,收不到数据,因此增加发送及接收增益,发送端增益设置为 20,接收端增益设置为 25,采样率为 1MHz时,对比发送和接收文件,发现存在误码情况,手动计算了一下大约 2.4e-4 的误码率量级
②、采样率为 781.25KHz 时,对比发送和接收文件,发现存在误码情况,手动计算了一下的误码率量级为 7.8e-5
③、采样率为 390.625KHz 时,对比发送和接收文件,未发现存在误码情况,误码率为 0
传输的文本本间对比,左面为发送的数据,右面为接收到的数据
发送端OFDM 时域信号
接收端及发射端OFDM 频谱图
OFDM Header 采用 BPSK 调制方式,Payload 采用 QPSK 调制方式
整体流程图: