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; // 输出CPOFDM符号 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 6b0; 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 i0; iSYMBOL_NUM; i) begin for(int j0; jSUBCARRIER_NUM; j) begin din $random % 4; case(din) 0: {I, Q} {16h7FFF, 16h7FFF}; // 00 1: {I, Q} {16h8001, 16h7FFF}; // 01 2: {I, Q} {16h7FFF, 16h8001}; // 10 3: {I, Q} {16h8001, 16h8001}; // 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再白嫖~
Vivado 2019.2平台下的Verilog开发OFDM调制解调系统:含编译码、FFT、I...
发布时间:2026/5/25 23:16:03
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; // 输出CPOFDM符号 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 6b0; 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 i0; iSYMBOL_NUM; i) begin for(int j0; jSUBCARRIER_NUM; j) begin din $random % 4; case(din) 0: {I, Q} {16h7FFF, 16h7FFF}; // 00 1: {I, Q} {16h8001, 16h7FFF}; // 01 2: {I, Q} {16h7FFF, 16h8001}; // 10 3: {I, Q} {16h8001, 16h8001}; // 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再白嫖~