[SDR] OFDM RX 详解 📅 2026/6/24 8:56:12 效果展示系列项目主页GNU Radio 教程一、定时同步、细频率补偿与载荷提取这部分流程图展示了一个完整的 OFDM 接收机物理层同步与解复用网络。它的核心任务是将天线接收到的连续复采样信号变成一个个整齐的、频率校准过的、区分了“报头”和“载荷”的数据包。在无线传输中信号会经历频率偏移由于多径或晶振误差和时间上的不确定性。这个电路的作用就像是一个自动对焦自动裁剪的相机自动对焦修正频率偏移让星座图不再旋转自动裁剪在一长串噪声和信号中精准地把属于数据包的那一段“剪”出来并分给后续的解码器1.1 同步与频率估算层 (Schmidl Cox OFDM synch)1功能概述这是整个系统的“眼睛”Schmidl Cox 模块利用特定的训练序列前导码。它在信号流中寻找两个完全相同的半周期。Output 0 (freq_offset)计算出信号偏了多少 Hz输出一个比例值。Output 1 (detect)一旦抓到同步序列的结尾发出一声“哨响”触发脉冲。Delay (延时器)数值为80即 64 FFT 16 CP。原理SC 模块需要处理完一整个符号才能给出结果。为了让后面校正频率时“校正信号”能对准“原始信号”的开头必须把原始信号拉后 80 个采样点。2原理详解首先我们参考《[30]. GNU Radio 系列教程三十—— OFDM TX 详解1.1.2 总结该块的功能》了解到实际发送时先在 64 个子载波上发送 Sync Words 1然后再发送 Sync Words 2然后再将 448 字节数据按照 Occupied Carriers 的顺序分配到每个子载波上不足 48 的整数倍进行补 0。Schmidl Cox 算法的本质是寻找时域上的重复性条目细则巧妙的同步字设计我们在发送端设计的sync_word1 [0., 0., ..., 1.414, 0., -1.414, 0., ...]在频域上是每隔一个子载波填充一个值奇数位置全是 0。根据 IFFT 的特性频域上的这种“空位填充”在时域上会产生两个完全相同的半周期如果在频域每隔一个点取一个值中间补0那么在时域就会产生两个完全一样的重复周期。定时同步模块维护一个滑动窗口计算当前半个符号与后半个符号的互相关 P(d)和能量 R(d)-度量函数M(d)M(d)|P(d)|2(R(d))2。-表现当窗口滑到 sync_word1 时M(d) 会出现一个明显的“平台区”由于循环前缀 CP 的存在平台宽度等于 CP 长度。该模块通过检测这个平台的下降沿或中心点在 detect 端口输出触发脉冲。频率偏移估算-原理由于频率偏移的存在时域上本应完全相同的两部分会产生相位差 ϕ。-计算ϕangle(P(d))。-范围这种方法细频偏只能检测到 ±1 子载波间隔内的偏移。如果偏移太大比如偏了 2 个子载波相位会发生 2π 翻转导致失效这就是为什么还需要 sync_word2 来做粗频偏补偿的原因但在本模块中主要输出的是细频偏。备注假设 L 是半个 OFDM 符号的长度在我们 OFDM 的设置中fft_len64所以 L32。接收到的采样序列为 r(n)。P(d)互相关项 (Correlation)它计算的是“当前窗口”与“L 个采样前的窗口”之间的相似性P(d)L−1∑m0(r∗dm⋅rdmL)直观理解把接收到的信号复制一份往后推 32 个点然后把重叠的部分对应相乘并累加。物理意义如果正好收到了 sync_word1因为前 32 点和后 32 点是一样的P(d) 就会产生一个巨大的复数向量。这个向量的相位Angle就代表了频偏。R(d)能量归一化项 (Energy)它计算的是窗口内信号的总能量用来给 P(d) 做分母R(d)L−1∑m0|rdmL|2注意在 GNU Radio 文档中为了防范突发信号结束时的伪触发它改进为计算整个符号两个半段的平均能量。3块参数详解参数名我们的设置值详细说明FFT length64决定了处理窗口的大小。CP length16决定了定时度量函数 M(d) 平台的长度。Threshold0.9当 M(d)0.9 时认为抓到了包。我们的sync_word1功率较大且结构清晰0.9 是合理的。Use Even CarriersTrue必须设为 True。因为我们的的sync_word1确实只占用了偶数载波。1.2 频率校正层 (Freq Mod Multiply)1功能概述这是系统的“修正器”Frequency Mod将 SC 算出的频偏数值转换成一个不断旋转的复数波形相控信号。Multiply将延时后的原始信号与这个反向旋转的波形相乘。效果抵消频偏输出频率已经“放正”的基带信号。2原理详解a. 为什么要进行频率校正在无线传输中由于发射端和接收端的晶振Oscillator不可能完全同步或者由于移动产生的多普勒频移接收到的信号会带有一个频率偏移 foff。在时域上这意味着每一个采样点 n 都会比前一个采样点多出一个相位旋转r(n)s(n)⋅ej(2πfofffsnθ0)其中 s(n) 是理想信号r(n) 是我们收到的带偏信号。如果不校正进入 FFT 后子载波之间会发生严重的正交性破坏ICI导致星座图变成一圈圆环无法解调。b. Frequency Mod 模块产生“纠偏波”这个模块的作用是将 SC 输出的一个标量频率值转换成一个随时间旋转的复正弦波。该模块的核心是一个相位累加器它将输入的标量频偏值 x[n] 积分还原为随时间演进的相位y[n]exp(j⋅Sensitivity⋅n∑k0x[k])在工程实现中通常采用更高效的迭代形式ϕ(n)(ϕ(n−1)x[n]⋅Sensitivity)(mod2π)输出补偿波为w(n)ejϕ(n)。在当前系统fft_len 64中Sensitivity 设为 -31.25m (即 −2/64)其逻辑如下缩放因子SC 模块输出的细频偏 x[n] 是归一化值。为了将其还原为每个采样点的弧度增量需要乘以校正系数。负号的物理意义SC 测量的是信号“偏离”的方向校正层必须产生反向相位。例如信号向逆时针偏 10°校正层需产生顺时针 10° 的旋转。计算推导对于 64 点 FFT其归一化增益常数定义为 −2/N−2/64−0.03125。c. 要加 Delay 80同步计算需要时间同步模块必须看满一整个符号64 FFT 16 CP 80点才能算出频偏。时间对齐为了让计算出的纠偏参数能准确作用在这个符号的“开头”必须让原始信号在 Delay 模块里等 80 个采样点确保“药方”和“病人”同时到达。d. Multiply相乘/混频将 Delay 模块输出的带偏信号与 Frequency Mod 输出的纠偏波逐点相乘。数学结果信号⋅ejϕ(n)×e−jϕ(n)信号⋅1频率立正1.3 帧分割与解复用层 (Header/Payload Demux)1功能概述这是系统的“分拣员”。这个模块是一个状态机它有三个主要阶段等待触发 (IDLE)平时它不输出任何数据直到trigger端口收到同步信号。提取包头 (Header)收到触发后它会截取指定长度的符号送往out_hdr。提取载荷 (Payload)它会等待反馈通过header_data端口告知包的具体长度然后将剩余数据送往out_payload。备注在默认配置下如果 Header 解析出错且没有处理机制这个模块确实会“卡死”或导致后续所有数据包错位。防止这种的处理方式有header 调制更保守CRC 校验失败返回一个长度为 0 的消息2参数详细解读参数名称这里设置的值深度解析Header Length (Symbols)3定义包头的长度。在收到触发信号后接下来的 3 个符号Symbol会被认为是包头并送入out_hdr通常包含包长度信息sync_word1sync_word2真正的 Header (报头数据))Header Padding0这是一个容错参数。由于 Schmidl Cox 算法探测到的同步位置平台区可能会有几个采样点的抖动不一定次次都卡在最完美的那个点所以我们需要在这个位置留一点余量。这里设置的 0 表示收到触发后立即开始切 Header没有任何缓冲Items per symbol64对应fft_len告诉模块一个完整的符号包含 64 个有效采样点。Guard Interval (items)16对应cp_len模块知道每个符号前有 16 点的 CP它会自动将其剥离。Length tag keypacket_len极其关键。模块在out_payload输出时会给数据流打上一个标签告诉后面的模块“这个包总共有多长”。Output FormatSymbols选择输出的是原始采样点还是已经去除了 CP 的符号数据。这里设为 Symbolsitem 选项是 CPFFTsymbols 选项是 FFT。Timing tag keyrx_time当trigger端口收到同步信号的一瞬间Demux 模块会在输出的第一个采样点上贴一个名为rx_time的标签Sampling Rate50k当前系统的采样率为 50 kHz。总结数据流的生命周期信号进入一路去算频偏一路在 Delay 里排队。SC 算出结果指挥 Freq Mod 产生校正波。校正波与排队信号相遇在 Multiply 里完成脱偏。校正后的干净信号进入 Demux被精准地切成“头”和“尾”两部分送往虚拟接收槽Virtual Sink。