基于fpga的AM调制解调,有modlsim仿真,以及quartus18.1和vivado2017.4的工程文件,使用matlab设计解调需要的滤波器,fir才采用verilog实现,没有调用ip。 相关仿真如下图所示,如果板子有adc和dac,支持上板。

AM调制解调在通信系统里就像老司机必备的生存技能。咱们今天用FPGA整活这个经典方案,全程不调IP核,从Matlab滤波器设计到Verilog手撸FIR,最后还能真刀真枪上板实测。

先看发射端架构(敲黑板,重点来了)。载波直接用DDS生成,Verilog代码里这个相位累加器你品:
verilog
always @(posedge clk) begin
phase_acc <= phase_acc + 32'd42949673; //1MHz载波@50MHz时钟
end
累加值每时钟周期加(2^32 * fout)/fclk,这种定点运算比浮点香多了。调制部分更暴力------直接把基带信号和载波相乘:
verilog
assign am_wave = (carrier * (12'd2048 + baseband)) >> 11; //基带DC偏移+调幅
这里基带信号要加个直流偏移避免过调幅,移位操作相当于定点数规格化,比直接截位更稳。

接收端最骚的操作在解调。Matlab的fdatool生成FIR系数,注意导出时要做定点量化:
matlab
h = fir1(63, 0.1); % 10%截止频率
h_quant = round(h * 32767); %16位量化
生成的系数直接喂给Verilog实现的FIR滤波器。手写FIR核心是这个画风:
verilog
always @(posedge clk) begin
//移位寄存器更新
delay_line <= {delay_line[62:0], am_signal};
//乘累加操作
for(int i=0; i<64; i=i+1) begin
product[i] = $signed(delay_line[i]) * coeff[i];
end
sum = 0;
for(int j=0; j<64; j=j+1) begin
sum = sum + product[j];
end
filtered <= sum >>> 15; //数据对齐
end
这个并行结构虽然吃资源,但时序表现比串行实现强太多。注意右移15位对应Matlab的32767量化系数,信号对齐的坑踩过的人都懂。

ModelSim仿真时发现个鬼故事------当基带信号频率接近载波1/10时,解调波形会抽搐。后来发现是FIR过渡带没设计好,回Matlab把滤波器阶数从64提到128阶,立马稳如老狗。

上板实测环节,AD/DA配置要注意这个骚操作:
verilog
assign dac_data = am_wave[23:8]; //16位有效位提取
always @(posedge adc_clk) begin
demod_in <= {adc_data, 8'b0}; //左移8位提升计算精度
end
数据位宽处理不当会导致信噪比血崩,实测有效位损失超过3位时解调信号直接妈见打。

最后说个保命技巧:在Vivado里用XPMCLOCKGEN替代PLL,不同板卡移植时能少掉头发。Quartus用户当我没说,Altera的IP核脾气你们懂的。完整工程已传GitHub,自取时记得star,老铁们的三连是更新的动力!


