FPGA 上的 OFDM 同步:从 S&C 到残差 CFO 的工程化实现

FPGA 上的 OFDM 同步:从 S&C 到残差 CFO 的工程化实现

1. 背景与目标

在软件仿真(MATLAB)中,我们可以用"全数据可见"的方式做同步:

  • 通过 S&C 训练块做粗定时粗 CFO

  • 以二维代价面 J(τ,ϵ)J(\tau,\epsilon)J(τ,ϵ) 做精同步

  • 用 NCO 校正 CFO,并在CP 边界附近做微调;

  • 通过均衡 + 去数据相位 得到每符号 CPE ,拟合其斜率评估残差 CFO

在 FPGA 上,必须把这些步骤改造成 流式、定点、有限资源 的架构:

  • 滑窗/环形缓冲实现相关累加;

  • 局部搜索 + 控制器 FSM 代替"全二维并行";

  • CORDIC/LUT 计算相位与旋转;

  • BRAM 对齐 + AXI-Stream 握手串接后级 FFT/均衡链路。

本文给出一套可综合的模块化实现验证闭环 ,适配 N=256, Ncp=32 等常见参数,易扩展到更大 FFT。

2. 顶层数据流与接口

2.1 处理链路(时序)

复制代码
I/Q流 → S&C延迟自相关(粗τ0, εc) → 精同步半符号局部搜索(τ̂, ε̂)
    → NCO CFO校正 → CP边界扫描(起点微调)
    → (可选) FFT → 均衡 → 逐符号CPE → 线性拟合(残差CFO)

2.2 AXI-Stream 风格接口

  • 输入:s_axis_*(I/Q 定点、valid/ready)

  • 输出:m_axis_*(CFO 校正后的 I/Q 流,交给 FFT 核或后续处理)

  • 关键估计量:tau0, eps_coarse, tau_hat, eps_hat(寄存器导出,PS 可读)

3. S&C 粗同步(延迟自相关)

3.1 数学回顾

训练块由两段相同的长度 L=N/2L = N/2L=N/2 子块构成,定义:
P(i)=∑k=0L−1r[i+k]r∗[i+k+L], γ(i)=∣P(i)∣∑k=0L−1∣r[i+k]∣2⋅∑k=0L−1∣r[i+L+k]∣2. \begin{aligned} P(i) &= \sum_{k=0}^{L-1} r[i+k] r^*[i+k+L],\ \gamma(i) &= \frac{|P(i)|}{\sqrt{\sum_{k=0}^{L-1}|r[i+k]|^2 \cdot \sum_{k=0}^{L-1}|r[i+L+k]|^2}}. \end{aligned} P(i)=k=0∑L−1r[i+k]r∗[i+k+L], γ(i)=∑k=0L−1∣r[i+k]∣2⋅∑k=0L−1∣r[i+L+k]∣2 ∣P(i)∣.

触发点 τ0\tau_0τ0 在 γ(i)\gamma(i)γ(i) 超阈值后附近取峰值位置;

粗 CFO 取自 P(τ0)P(\tau_0)P(τ0) 的相位:
ϵcoarse≈∠P(τ0)2π⋅NL \epsilon_{\text{coarse}} \approx \frac{\angle P(\tau_0)}{2\pi}\cdot\frac{N}{L} ϵcoarse≈2π∠P(τ0)⋅LN

3.2 RTL 设计要点

  • 环形延迟线 (深度 LLL)获取 (s,sdelayed)(s,s_{\text{delayed}})(s,sdelayed)。

  • 逐拍乘加 累加 P(i)P(i)P(i)、能量项(用 FIFO 退出项做真滑窗,或 IIR 近似)。

  • 阈值/滞回:建议"双阈值 + 最小间隔"抑制虚警。

  • 相位求取CORDIC-atan2(P_im, P_re) 输出相位 → 粗 CFO 定点换算。

3.3 可综合骨架(节选)

verilog 复制代码
// 延迟自相关 (S&C) 粗同步,输出 tau0 与 eps_coarse
delay_corr_sc #(
  .IQW(16), .ACCW(40), .LWIN(N/2), .PHW(24)
) u_sc (/* ... AXI-Stream + outputs ... */);

工程建议:滑窗能量的开方可省略,用比较/比例近似代替;相位必须用 CORDIC 或 LUT/差值,确保过采样/量化误差在预算内。

4. 精同步:半符号相关 + 局部二维搜索

4.1 思路替换"全二维并行"

MATLAB 里的 J(τ,ϵ)J(\tau,\epsilon)J(τ,ϵ) 全面网格搜索在 FPGA 上成本过高。我们改为局部搜索

  1. 在 τ0\tau_0τ0 周围 [τ0−Δ, τ0+Δ][\tau_0-\Delta,\ \tau_0+\Delta][τ0−Δ, τ0+Δ] 枚举 τ\tauτ。

  2. 对每个 τ\tauτ,先累加
    P0(τ)=∑k=0N/2−1r[τ+k]⋅r∗[τ+N/2+k], P_0(\tau) = \sum_{k=0}^{N/2-1} r[\tau+k]\cdot r^*[\tau+N/2+k], P0(τ)=k=0∑N/2−1r[τ+k]⋅r∗[τ+N/2+k],

    再扫描离散 ϵ\epsilonϵ 网格,用
    J(τ,ϵ)=ℜ ⁣{ P0(τ) ejπϵ} J(\tau,\epsilon)=\Re\!\left\{\,P_0(\tau)\,e^{j\pi\epsilon}\right\} J(τ,ϵ)=ℜ{P0(τ)ejπϵ}

    取最大点。归一化 ∣s1∣,∣s2∣|s_1|,|s_2|∣s1∣,∣s2∣ 可选做(硬件中常略去或统一门限)。

4.2 控制器 FSM

  • LOAD_TAU:从 BRAM 读出窗口数据;

  • ACCUM:NH 次乘加得 P0,E1,E2P_0, E_1, E_2P0,E1,E2;

  • SWEEP_EPS:查表 ejπϵe^{j\pi\epsilon}ejπϵ 与 P0P_0P0 做一次复乘取实部;

  • UPDATE_BEST:比较并记录 (τ∗,ϵ∗)(\tau^*,\epsilon^*)(τ∗,ϵ∗);

  • NEXT_TAU / DONE

4.3 实现片段(节选)

verilog 复制代码
fine_sync_halfcorr_ctrl #(
  .N(256), .IQW(16), .ACCW(40), .PHW(24), .TAU_SPAN(10)
) u_fine (/* tau0/epsc in, tau_hat/eps_hat out */);

工程建议:把 ϵ\epsilonϵ 网格中心放在 eps_coarse 附近,步长按 SNR/残差设为 0.005∼0.020.005\sim0.020.005∼0.02 子载波;NEPS≈33~65 足够多数场景。

5. NCO CFO 校正与相位累加可视化

5.1 相位步进

phase_step=−2π⋅ϵhatN \text{phase\step} = -2\pi \cdot \frac{\epsilon{\text{hat}}}{N} phase_step=−2π⋅Nϵhat

采用 PHW 位 相位累加器(2π↦2PHW2\pi \mapsto 2^{\text{PHW}}2π↦2PHW),步进由 eps_hat 定点换算得到。

5.2 旋转实现

  • CORDICsin/cos LUT 取 cos⁡θ, sin⁡θ\cos\theta,\ \sin\thetacosθ, sinθ;

  • 复乘:(I+jQ)⋅(cos⁡+jsin⁡)(I+jQ)\cdot(\cos+j\sin)(I+jQ)⋅(cos+jsin);

  • 位宽回切与饱和。

verilog 复制代码
nco_rotator #(.IQW(16), .PHW(24)) u_nco (/* s_axis → m_axis */);

6. CP 边界细化(只向右微调)

6.1 指标

对偏移 o=0,...,omax⁡o=0,\ldots,o_{\max}o=0,...,omax:
val(o)=∣ ℜ ⁣{⟨CP(o), tail(o)⟩∥CP(o)∥ ∥tail(o)∥}∣ \mathrm{val}(o) = \left|\,\Re\!\left\{\frac{\langle \mathrm{CP}(o),\,\mathrm{tail}(o)\rangle}{\|\mathrm{CP}(o)\|\,\|\mathrm{tail}(o)\|}\right\}\right| val(o)= ℜ{∥CP(o)∥∥tail(o)∥⟨CP(o),tail(o)⟩}

取最大 ⇒\Rightarrow⇒ start_refined = start_coarse + o^\*。实践中只允许正向小步,避免回跳到训练块。

6.2 实现提示

  • 与精同步类似,用 FSM 顺序累加;

  • 归一化可用能量近似或统一门限;

  • OFF_MAX = min(Ncp/2, 16) 一般足够。

7. 残差 CFO 观测(CPE 斜率)

7.1 流程

  1. CFO 校正后 → FFT (IP 核) → 均衡 (HkH_kHk 估计或导频)

  2. 用已知发端数据去相位,得到每符号公共相位 ϕs\phi_sϕs

  3. 对 ϕs\phi_sϕs 做 unwrap 后最小二乘直线拟合:斜率 a^\hat{a}a^(rad/符号)

  4. 换算残差 CFO(单位:子载波/符号):
    rescfo=a^2π(1+NcpN). res_{cfo} = \frac{\hat{a}}{2\pi\left(1+\dfrac{N_{cp}}{N}\right)}. rescfo=2π(1+NNcp)a^.

7.2 FPGA/PS 分工

  • FFT/均衡 → 建议 IP/PS;

  • 逐符号累计 ∑ϕ, ∑kϕ, ∑k, ∑k2\sum \phi,\ \sum k\phi,\ \sum k,\ \sum k^2∑ϕ, ∑kϕ, ∑k, ∑k2 → 可在 PL 做;

  • 最终除法/换算 → PS 完成,写回寄存器或监控面板。

8. 定点化与资源规划

位宽/资源建议:

模块 主要运算 建议位宽 备注
I/Q 数据 加/乘 IQW=14~16(Q1.(IQW-1)) 基带固定点
P、能量累加 乘加 ACCW ≥ IQW + log2(win) + margin,如 40 位 防溢出
相位/NCO 加法/查表 PHW=24(2π→2242\pi \to 2^{24}2π→224) 相位累加
CORDIC 旋转/atan2 迭代 12~16 级 角误差 < 10−310^{-3}10−3 rad
ε 网格 LUT sin/cos 16 位输出 配合缩放/舍入

门限与滞回 :建议使用 2 级阈值 + 最小保持长度,抑制短促噪声峰值。
时钟与吞吐:各乘法/累加上管线;核心链路 100~200 MHz 对 Zynq/7 系常见配置足够。

9. 关键 RTL 片段(可直接嵌入)

9.1 NCO 旋转(节选)

verilog 复制代码
wire [PHW-1:0] phase_step_q = /* round(-eps_hat/N * 2^PHW) */;
reg  [PHW-1:0] phase_acc;

always @(posedge clk) if (rstn && valid && ready && enable)
  phase_acc <= phase_acc + phase_step_q;

// cos_q/sin_q → LUT or CORDIC;I'Q' = 复数乘法后截位

9.2 精同步控制器(伪代码)

verilog 复制代码
for (tau = tau0-TAU_SPAN; tau <= tau0+TAU_SPAN; tau++) begin
  P0 = Σ s1 * conj(s2);  // NH 次
  for (eps in eps_grid) begin
    J = Re{ P0 * e^{jπeps} };  // LUT给cos/sin
    if (J > Jbest) begin
      Jbest   = J;
      tau_hat = tau;
      eps_hat = eps;
    end
  end
end

10. 缓存与对齐:把"估计"落地到"流"

  • 在 S&C 之后引入一个环形缓冲区(BRAM);

  • 精同步得到 tau_hat 后,把读取指针对齐到 tau_hat,再把后续样点送入 NCO;

  • CP 扫描使用同一缓冲窗口,避免 DDR 往返。

小技巧:对齐时可以在 stream 中插入"时间戳/样点计数",方便调试与波形对比。

11. 仿真与上板验证

11.1 仿真(Modelsim/VCS/Verilator)

  • 激励 :用 MATLAB 生成 I/Q .bin(含 S&C 训练 + 数据 + CFO + 噪声),在 testbench 中喂入;

  • 观测 :dump tau0, eps_coarse, tau_hat, eps_hat 与 NCO 输出波形;

  • 指标

    • 定时误差 ∣τhat−τtrue∣\lvert \tau_{\text{hat}}-\tau_{\text{true}}\rvert∣τhat−τtrue∣;

    • CFO 误差 ∣ϵhat−ϵtrue∣\lvert \epsilon_{\text{hat}}-\epsilon_{\text{true}}\rvert∣ϵhat−ϵtrue∣;

    • CP 扫描偏移量对齐到 [0,,Ncp/2][0,,N_{cp}/2][0,,Ncp/2] 内的局部最大;

    • 残差 CFO 的斜率接近 0(或在预算内)。

11.2 上板(Zynq + AD9361 为例)

  • PS 负责:参数下发、LUT/寄存器配置、状态读取、残差 CFO 拟合;

  • PL 负责:S&C、精同步、NCO、CP 扫描、FFT(可用 IP)等;

  • 采集链路:DMA 抓取 NCO 前/后的数据做 A/B 对比;

  • UI 面板:实时显示 γ(d)\gamma(d)γ(d) 峰值、J(τ,ϵ)J(\tau,\epsilon)J(τ,ϵ) 最优点、CPE 趋势线。

12. 常见坑位与调参建议

  1. 阈值过敏 :噪声峰值触发 → 加双阈值与最小长度;movmean 在硬件用 IIR 或真滑窗替代。

  2. 定点溢出:累加器不够 → 提前估算动态范围,宁宽勿窄;乘法后适当右移保留 SNR。

  3. CORDIC 迭代不足 :角度量化误差导致 ϵ\epsilonϵ 偏差 → 迭代 14~16 级 + 相位缩放校正。

  4. 网格过稀 :精同步 ϵ\epsilonϵ 网格步长过大 → 先粗后细(两轮搜索或自适应步长)。

  5. 对齐错误tau_hat 未正确对齐到输出流 → 用样点计数/戳确认边界。

  6. CP 扫描回跳:允许负向微调可能跳回训练块 → 仅向右扫描(正向小幅微调)。

  7. 残差 CFO 偏差:未做 unwrap 或符号选择不纯 → 做相位展开 & 仅用导频/已知数据。

13. 资源与时序(估算模板)

N=256, IQW=16, PHW=24, TAU_SPAN=10, NEPS=41 为例(不同器件略有差异):

  • 乘法器:S&C(2~4 个复乘/拍,管线摊销)、精同步(1 个复乘 + 1 复旋转/拍);

  • BRAM:环形缓冲 ≥ N + (N+Ncp) * 若干符号

  • LUT/FF:控制器 FSM + CORDIC/LUT;

  • Fmax:> 150 MHz(7 系/US+ 常见约束);AXIS 满速 1 样点/拍。

实际请以综合/实现报表与时序分析为准。

14. 与 MATLAB 结果对照的清单

  • 在同一输入 .bin 上,比较 tau_hat/eps_hat 与 MATLAB 的 τ/ϵ\tau/\epsilonτ/ϵ;

  • 绘制 NCO phase stepphase accum(前 500 样点)对齐;

  • CP 扫描曲线峰值位置一致;

  • CPE 曲线斜率与脚本拟合一致,残差 CFO 换算公式一致:
    rescfo=a^2π(1+NcpN). res_{cfo}=\dfrac{\hat{a}}{2\pi\left(1+\dfrac{N_{cp}}{N}\right)}. rescfo=2π(1+NNcp)a^.

相关推荐
hahaha601613 小时前
高层次综合基础-vivado hls第三章
算法·fpga开发
国际学术会议-杨老师2 天前
2025年计算机网络与信号处理国际会议(CNSP 2025)
计算机网络·信号处理
菜鸟‍2 天前
【实验报告】华东理工大学随机信号处理实验报告
信号处理
青草地溪水旁2 天前
从“快递签收规则”看 sigaction:信号处理的“总开关”
linux·信号处理
XINVRY-FPGA3 天前
XCVU9P-2FLGA2104E Xilinx AMD Virtex UltraScale+ FPGA
人工智能·嵌入式硬件·fpga开发·硬件工程·dsp开发·射频工程·fpga
Zevalin爱灰灰3 天前
数字信号处理 第二章(z变换与LSI系统频域分析)【下】
信号处理
范纹杉想快点毕业3 天前
ZYNQ7045芯片中UART实现RS422通信详解,50000字解析,C语言,嵌入式开发,软件开发
c语言·笔记·stm32·单片机·嵌入式硬件·mcu·fpga开发
Zevalin爱灰灰4 天前
数字信号处理 第一章(离散时间信号与系统)【下】
信号处理
千宇宙航5 天前
闲庭信步使用图像验证平台加速FPGA的开发:第三十课——车牌识别的FPGA实现(2)实现车牌定位
图像处理·计算机视觉·fpga开发·车牌识别