1. 产生调制信号和载波信号
调用 ROM IP 核在 FPGA 内部产生两路余弦信号, 其中一路信号用于模拟外部输入的调制信号, 另一路用作载波信号.
在配置 ROM IP 核之前, 需要用 Matlab 生. coe 文件, 存放在 ROM 核里.
Matlab 生成. coe 文件:
%---------------------------------%
width=8; % 设置 rom 的位宽
depth=1024; % 设置 rom 的深度
%---------------------------------%
x=linspace(0,2*pi,depth); % 在一个周期内产生 depth 个采样点
y_cos=cos(x); % 生成余弦函数
%y_cos=sin(x); % 生成正弦函数
%y_cos=round(y_cos*(2^(width-1)-1))+2^(width-1)-1; % 将数据转化成整数, 生成无符号数
y_cos=round(y_cos*(2^(width-1)-1)); % 将数据转化成整数, 生成有符号数
plot(x,y_cos); % 绘图
fid = fopen('E:\Workspace\DDS\Design\IP_Core\cos.coe','wt');
fprintf(fid,'memory_initialization_radix = 10;\nmemory_initialization_vector =');
for i = 1 : depth
if mod(i-1,8) == 0
fprintf(fid,'\n');
end
fprintf(fid,'m,',y_cos(i));
end
fclose(fid); % 关闭文件
生成. coe 文件后就可以进行 IP 核的配置了.
ROM 核具体配置:
配置完 IP 核后, 编写控制模块, 产生两路信号. 其中, 调制信号上叠加的直流分量的大小为调制信号的峰值, 这样将得到调制度为 100% 的已调信号. 如果要得到不同的调制度, 则需要叠加不同大小的直流分量, 同时需要注意定义的数据位宽, 防止数据溢出.
产生载波和带有直流分量的调制信号:
module cos_make(
input clk,
input rst_n,
output reg [7:0] cos_s,
output reg signed [7:0] cos_c
);
//------------------------------------//
parameter freq_s = 32'd429497; // 调制信号频率 10k
parameter freq_c = 32'd42949673; // 载波频率 1M
parameter cnt_width = 8'd32;
//------------------------------------//
//------------------------------------//
reg [cnt_width-1:0] cnt_s = 0;
reg [cnt_width-1:0] cnt_c = 0;
wire [9:0] addr_s;
wire [9:0] addr_c;
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
cnt_s <= 0;
cnt_c <= 0;
end
else begin
cnt_s <= cnt_s + freq_s;
cnt_c <= cnt_c + freq_c;
end
end
assign addr_s = cnt_s[cnt_width-1:cnt_width-10];
assign addr_c = cnt_c[cnt_width-1:cnt_width-10];
//------------------------------------//
//------------ 调用 ROM 核 ----------------//
wire signed [7:0] cos_s_r;
wire signed [7:0] cos_c_r;
ROM ROM_inst(
.clka (clk),
.addra (addr_s),
.douta (cos_s_r),
.clkb (clk),
.addrb (addr_c),
.doutb (cos_c_r)
);
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
cos_s <= 0;
cos_c <= 0;
end
else begin
cos_s <= cos_s_r + 8 'd128; // 加上大小为峰值的直流分量
cos_c <= cos_c_r;
end
end
endmodule
2. 生成 AM 调制信号
得到两路信号后就可以用乘法器将两路信号相乘, 得到已调信号.
乘法器具体配置:
AM 调制的顶层模块:
module modulate(
input clk,
input rst_n,
output signed [15:0] AM_mod
);
wire [7:0] cos_s;
wire signed [7:0] cos_c;
//------------ 调用出波模块 ------------//
cos_make cos_make_inst0(
.clk (clk),
.rst_n (rst_n),
.cos_s (cos_s),
.cos_c (cos_c)
);
//-----------------------------------//
//------------ 调用乘法器 --------------//
MULT MULT_inst1(
.CLK (clk),
.A (cos_s),
.B (cos_c),
.P (AM_mod)
);
endmodule
3. 仿真调制结果
以上 AM 调制过程基本完成, 但是正确与否还需要通过仿真来确定, 接下来编写仿真用的测试模块.
TestBeach 的编写:
`timescale 1ns/1ps
module tb_AM();
//--------- 接口设置 ----------//
reg sclk;
reg rst_n;
wire signed [15:0] AM_mod;
//--------------------------//
initial sclk = 1;
always #5 sclk = ~sclk; //100M 时钟
initial begin
rst_n = 0;
#500
rst_n = 1;
end
//--------------------------//
modulate modulate_inst0(
.clk (sclk),
.rst_n (rst_n),
.AM_mod (AM_mod)
);
endmodule
在 Vivado 中将各个文件添加进工程后, 运行仿真.
仿真结果如下:
已调信号能明显看到包络, 并且包络的频率同调制信号一致, 表明 AM 调制正确.
来源: https://www.cnblogs.com/HOOKNET/p/8407749.html