4、OFDM与SC-FDMA:IFFT/FFT的流水线设计、循环前缀插入、峰均比抑制

各位同学,今天我们来聊聊物理层里两个绕不开的模块——OFDM和SC-FDMA。说实话,这两个东西在4G/5G里几乎是天天见。我当年刚入行时,觉得IFFT不就是个数学变换嘛,有啥难的?结果第一次做芯片实现时,被流水线时序和面积折腾得够呛。嗯,今天就把这些坑和经验一并讲清楚。

4.1 OFDM与SC-FDMA的核心差异

先理清一个基本概念。OFDM是正交频分复用,SC-FDMA是单载波频分多址。说白了,OFDM是多个子载波并行发数据,SC-FDMA是先做一次DFT再映射到子载波上。

为什么要搞SC-FDMA?因为OFDM的峰均比(PAPR)太高了。我记得在LTE项目里,终端发射功率本来就受限,OFDM信号一上去,功放效率直接掉到20%以下。SC-FDMA相当于把时域信号先“摊平”了,PAPR能低3-4dB。你想想看,这对电池续航意味着什么。

特性 OFDM SC-FDMA
PAPR 高(约10-12dB) 低(约6-8dB)
实现复杂度 低(单次IFFT) 高(DFT + IFFT)
适用场景 下行(基站发射) 上行(终端发射)
频域均衡 简单 简单

4.2 IFFT/FFT的流水线设计

做芯片实现时,IFFT/FFT是核心计算单元。我见过很多新手直接拿教科书上的蝶形运算图去写RTL,结果综合出来面积大得吓人。为什么?因为没有考虑流水线结构。

我个人习惯用基-2 流水线FFT架构。以128点FFT为例,需要7级蝶形运算。每一级包含一个蝶形处理单元(BFU)和一个旋转因子乘法器。关键是怎么安排流水线。

核心设计原则:

  • 每级流水线深度控制在2-3个时钟周期
  • 旋转因子用ROM存储,地址由级数和当前索引生成
  • 数据采用乒乓RAM缓冲,避免读写冲突

我曾经在一个项目里,为了省面积把流水线深度压到1个周期,结果时序收敛不了。后来老老实实加了2级寄存器,面积只多了5%,时序却轻松过了。所以啊,流水线深度不是越浅越好。

下面是一个简化的流水线控制代码示例,我用Verilog描述一下核心思路:

// 流水线FFT控制逻辑(简化版)
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        stage_cnt <= 0;
        data_valid <= 0;
    end else begin
        // 每级流水线延迟2个时钟
        if (stage_cnt == N_FFT_POINTS-1) begin
            stage_cnt <= 0;
            data_valid <= 1;
        end else begin
            stage_cnt <= stage_cnt + 1;
            data_valid <= 0;
        end
    end
end

// 蝶形运算单元
always @(posedge clk) begin
    if (data_valid) begin
        // 从RAM读取a和b
        // 计算 a + b * W, a - b * W
        // 写回RAM
    end
end

小技巧:旋转因子的精度很关键。我建议用16位量化,其中1位符号位、1位整数位、14位小数位。这样在128点FFT下,信噪比损失可以控制在0.1dB以内。

4.3 循环前缀插入

循环前缀(CP)的作用是消除符号间干扰(ISI)。原理很简单:把OFDM符号末尾的一段数据复制到开头。但实现时有个细节——CP长度是动态可配的。

在LTE里,常规CP是4.69μs,扩展CP是16.67μs。5G NR更灵活,CP长度跟子载波间隔有关。所以芯片设计时,CP插入模块必须支持参数化配置。

我建议用双指针RAM控制法

  • 写指针:IFFT输出数据按顺序写入RAM
  • 读指针:先读末尾CP长度的数据,再从头读到尾

这样做的好处是,不需要额外的存储空间。我曾经看到有人专门开一块RAM存CP数据,白白浪费了面积。

注意:CP插入后,符号长度会变化。后续的加窗、上变频模块都要同步调整时序。我吃过这个亏,CP长度配错了,导致整个发射链路时序错位,查了两天才找到原因。

4.4 峰均比抑制技术

PAPR抑制是OFDM系统里绕不开的话题。高PAPR意味着功放需要很大的回退,效率低得可怜。常用的方法有几种:

  1. 限幅(Clipping):最简单粗暴,但会引入带外辐射
  2. 压扩变换(Companding):对信号做非线性变换,PAPR能降2-3dB
  3. 选择性映射(SLM):生成多个候选信号,选PAPR最低的
  4. 部分传输序列(PTS):把子载波分块,优化相位

我个人在项目中用得最多的是限幅+滤波的组合方案。限幅把峰值砍掉,再用滤波器把带外噪声滤除。实现起来不复杂,效果也还行。

下面是一个限幅的数学表达:

// 限幅处理
if (|x[n]| > A_th) then
    y[n] = A_th * exp(j * angle(x[n]))
else
    y[n] = x[n]
end

其中A_th是限幅门限,通常设为信号均方根的3-4倍。门限设低了,PAPR降得多但EVM恶化;设高了,PAPR改善不明显。这个平衡点需要根据系统要求来调。

经验值参考:

  • 限幅门限 = 3.5倍RMS:PAPR降低约2.5dB,EVM恶化约1%
  • 限幅门限 = 4.0倍RMS:PAPR降低约1.8dB,EVM恶化约0.5%

对于SC-FDMA,PAPR本来就低,一般不需要额外抑制。但如果你做的是NB-IoT或者Cat-M这类窄带系统,终端发射功率极小,PAPR哪怕高1dB都会影响覆盖。这时候建议加一个简单的压扩变换,实现成本很低。

4.5 整体架构图

下面我用一张SVG图来展示OFDM/SC-FDMA发射链路的整体流程。这张图里包含了我们今天讲的所有模块:

OFDM/SC-FDMA发射链路架构图 数据输入 调制映射 DFT (SC-FDMA) 子载波映射 IFFT CP插入 PAPR抑制 DAC/上变频 图例说明 数据输入:比特流或符号流 调制映射:QPSK/16QAM/64QAM DFT:仅SC-FDMA使用,OFDM跳过 IFFT:核心变换模块,流水线实现 CP插入:循环前缀,消除ISI PAPR抑制:限幅/压扩/SLM/PTS

从这张图可以看到,OFDM和SC-FDMA的主要区别就在DFT那块。OFDM直接走子载波映射,SC-FDMA先做DFT再映射。后面的IFFT、CP插入、PAPR抑制都是共用的。

4.6 实现中的常见陷阱

最后,我总结几个实际项目中容易踩的坑:

  • IFFT/FFT的位宽选择:输入位宽和输出位宽要匹配。我见过有人输入用16位,输出截成12位,结果EVM直接炸了。建议每级流水线保留1-2位增长,最后再截断。
  • CP插入的时序:CP插入后,数据率会变化。比如128点IFFT加32点CP,输出数据率是输入数据率的(128+32)/128=1.25倍。后续模块的时钟或使能信号要相应调整。
  • PAPR抑制的EVM代价:限幅虽然简单,但会引入EVM恶化。3GPP对EVM有严格要求(比如64QAM要求EVM<8%),所以限幅门限不能设太低。

我的建议:在做芯片验证时,一定要用真实的信道模型去测PAPR和EVM。我曾经在仿真环境里PAPR降了3dB,结果拿到信道模拟器上一测,EVM超标了。后来发现是限幅后的滤波没做好,带外噪声串回来了。

好了,关于OFDM和SC-FDMA的物理层实现,今天就讲到这里。这些内容都是我在项目里一点点试出来的,希望能帮大家少走弯路。


公众号:蓝海资料掘金营,微信deep3321