Vivado 2019.2平台下的Verilog开发OFDM调制解调系统:含编译码、FFT、I...
重点观察约束长度和生成多项式,这里用的是(171,133)八进制编码。先说核心架构,整个系统分为三大金刚:编码模块负责卷积码+交织,IFFT/FFT这对冤家处理频域时域转换,CP模块就是循环前缀的装卸工。CP长度设置为符号长度的1/4时,用Vivado的ILA抓波形发现符号边界错位了3个周期,后来发现是FFT核的latency没算进去。vivado2019.2平台使用verilog开发的OFDM调
vivado2019.2平台使用verilog开发的OFDM调制解调系统,包括编译码,FFT,IFFT,CP等,包含testbench,有视频指导怎么使用
直接开撸!最近在Vivado2019.2上折腾了个OFDM调制解调系统,从编码到FFT/IFFT再到循环前缀,全程Verilog硬刚。这玩意儿虽然网上资料不少,但真自己动手还是踩了不少坑,今天就给大家扒一扒实现细节。

先说核心架构,整个系统分为三大金刚:编码模块负责卷积码+交织,IFFT/FFT这对冤家处理频域时域转换,CP模块就是循环前缀的装卸工。重点看IFFT实现,Vivado自带的FFT IP核真香但得调教:
// IFFT模块实例化
xfft_0 your_fft (
.aclk(clk_122M), // 122MHz时钟
.s_axis_config_tdata(0), // 0-15为FFT点数,16位控制正反变换
.s_axis_data_tvalid(data_valid),
.m_axis_data_tlast(last_flag) // 标记符号边界
);
注意第16位控制正/逆变换,这里有个骚操作——在同一个FFT核上实现OFDM符号生成和解调,通过动态切换配置参数实现硬件复用。实测发现配置切换需要至少3个时钟周期稳定,否则会出现频谱泄漏。
CP添加模块比想象中简单粗暴,直接搬运时域信号尾部:
always @(posedge clk) begin
if(cp_state == COPY_TAIL) begin
cp_buffer[0:CP_LEN-1] <= ifft_out[SYMBOL_LEN-CP_LEN:SYMBOL_LEN-1];
end
else begin
tx_data <= cp_buffer; // 输出CP+OFDM符号
end
end
重点注意时序对齐!CP长度设置为符号长度的1/4时,用Vivado的ILA抓波形发现符号边界错位了3个周期,后来发现是FFT核的latency没算进去。这里建议在testbench里加个自动校准模块:
// 自动时延校准
reg [15:0] delay_counter;
always @(posedge clk) begin
if(tb_start) delay_counter <= 0;
else if(!tb_done) delay_counter <= delay_counter + 1;
end
编码部分用了咬尾卷积码,这个实现起来有点意思。Verilog直接写状态转移比用IP核更灵活:
// 卷积编码器
reg [5:0] shift_reg;
always @(posedge clk) begin
if(rst) shift_reg <= 6'b0;
else begin
shift_reg <= {shift_reg[4:0], input_bit};
coded_bit[0] = input_bit ^ shift_reg[1] ^ shift_reg[2] ^ shift_reg[4] ^ shift_reg[5];
coded_bit[1] = input_bit ^ shift_reg[0] ^ shift_reg[1] ^ shift_reg[3] ^ shift_reg[5];
end
end
重点观察约束长度和生成多项式,这里用的是(171,133)八进制编码。仿真时发现编码器输出和Matlab参考代码对不上,最后发现是MSB和LSB顺序问题——Verilog的位序和常规算法描述相反,这个坑至少浪费了我两包烟。

vivado2019.2平台使用verilog开发的OFDM调制解调系统,包括编译码,FFT,IFFT,CP等,包含testbench,有视频指导怎么使用
测试平台搭建是另一个重头戏。建议用系统任务生成标准OFDM符号作为激励:
// 生成QPSK调制数据
initial begin
for(int i=0; i<SYMBOL_NUM; i++) begin
for(int j=0; j<SUBCARRIER_NUM; j++) begin
din = $random % 4;
case(din)
0: {I, Q} = {16'h7FFF, 16'h7FFF}; // 00
1: {I, Q} = {16'h8001, 16'h7FFF}; // 01
2: {I, Q} = {16'h7FFF, 16'h8001}; // 10
3: {I, Q} = {16'h8001, 16'h8001}; // 11
endcase
#SYMBOL_PERIOD;
end
end
end
调试时强烈推荐用Vivado的波形调试功能,尤其是观察FFT输出频谱是否对称,CP区间是否完整覆盖多径时延。有个邪门现象——当FFT点数设置为1024时,偶尔会出现中间子载波失真,后来发现是溢出问题,把数据位宽从16bit扩展到20bit后解决。

资源消耗方面,整个系统在Zynq7020上跑,FFT核占了大头:
- Slice LUTs: 23%
- Block RAM: 35%
- DSP48E1: 62%
建议做定点化优化时,先拿FFT输出做误差分析。有个偷懒技巧:在Matlab里做浮点仿真生成golden数据,用$fwrite直接写到文件,然后在testbench里用$readmemh读取做对比验证。
最后说下视频教程的事,整个工程文件连带三个小时的实操视频(包括Vivado工程配置、约束文件编写、上板测试)已经传到GitHub,需要的老铁直接搜"OFDM-Zynq-Lab",记得点个star再白嫖~
更多推荐
所有评论(0)