本模块中涉及到fft频谱分析,所以增加了一些端口,fft的按键控制、输出有效、持续、标志等。
本文产生载波频率为50k,频偏3k
1.模块分析
模块输入:时钟、复位、调制信号
模块输出:FM调制信号
载波信号的产生是基于ROM读取进行产生的,深度是1024 宽度是8位。基础时钟是50mhz,所以如果正常读取信号的话,这个频率是50m/1024=48.8khz左右。通过这个基础的变化进行其他频率信号的产生。
本文要产生一个50k的载波信号,因此50k/48.8k=1.024左右,得出来这个系数之后怎么获取频率字?首先这个系数是一个小数,FPGA本身是处理不了小数的,因此我们需要进行放大,本文选择放大2的22次方倍,1.024*2^22=4294967,得到了频率字,同时因为1024和放大倍数,频率字的位宽是10+22=32。
频偏控制,首先确定范围是3k,因此按照上面的方法算出来3k的频率控制字:255852,其次通过调用一个乘法器ip核将调制信号与3k频率字进行想乘,进而得到随调制信号变化的频偏数值,最后将这个频偏数值作用到载波频率上,就完成了FM的调制工作。
本篇文章的大致实现方法参考了:FM调制讲解DDS
module FM_Mod(
input clk,
input rst_n,
input signed [7:0] adc_data,
input key_fft,
output reg last,
output reg s_axis_data_tvalid,
output reg fft_flag,
output signed [7:0] FM_Mod
);
parameter signed Freq_I = 32'd4294967; // 1.024 * 2的22次方
parameter signed Freq_Word = 20'd255852; // 0.061 * 2的22次方
wire signed [27:0] mult_data; //0.061*adc_data
wire signed [20:0] Freq_Offset;
reg [14:0] count;
MULT b2v_inst6(
.CLK(clk),
.A(adc_data),
.B(Freq_Word),
.P(mult_data)
);
assign Freq_Offset = mult_data[27:7]; //移位 除法 2的7次方
reg signed [31:0] cnt_I;//22+10
wire [9:0] addr_I;
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
cnt_I <= 0;
end
else begin
cnt_I <= cnt_I + Freq_I + Freq_Offset;
end
end
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
fft_flag <= 1'b0;
end
else if(key_fft==1'b0) begin
fft_flag <= ~fft_flag;
end
else begin
fft_flag <= fft_flag;
end
end
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
count <= 15'd0;
last <=1'b0;
s_axis_data_tvalid<=1'b0;
end
else if(fft_flag && count<2048) begin
s_axis_data_tvalid <=1'b1;
count <= count + 1'b1;
last <= 1'b0;
end
else if(fft_flag && count==2048) begin
s_axis_data_tvalid= 1'b0;
count <= 15'd0;
last <=1'b1;
end
end
assign addr_I = cnt_I[31:22] ; //移位 除法 2的16次方
ROM b2v_inst(
.clka(clk),
.addra(addr_I),
.douta(FM_Mod)
);
endmodule
2.波形分析
下面是500hz 的调制信号,上面是FM调制完的信号。
3k的频偏对于50k的载波信号来说比较不明显,但是通过观看不同位置的周期能够看出明显差距,通过选取500hz信号的低谷和峰谷测量fm信号周期,能够看出明显的差距。如果需要明显的调制效果,可以将频偏增加。