04 DDS信号发生器

DDS信号发生器

DDS信号发生器结构

DDS信号发生器如上图所示,大致可分为4个部分:相位累加器、相位量化器、波形ROM表、 D/A 转换器构成。

相位累加器:宽度为N位,它在系统时钟的控制下按相位步进K进行累加运算,并向相位量化器输出结果(相位步进在有些地方又被称之为频率控制字)。

相位量化器:对相位累加器输出的N位相位控制字在进行截断,输出M位结果到波形ROM表。

波形ROM表:一共存储有2^M个波形参数,它根据相位量化器输出的值从ROM中取出数据,并输出到DA转换器。

D/A 转换器:将数字量转换为模拟量输出。

DDS信号发生器输出频率

相位累加器每来一个时钟就会按相位步进(K)进行一次累加运算,溢出后又从零开始进行累加,如此往复;相位累加器完成一次溢出便对应着的完成了一次波形ROM的遍历,所以相位累加器的溢出频率就是DDS信号发生器的输出频率:

当K=1时便是DDS信号发生器的最小输出频率,又称DDS信号发生器的分辨率

DDS信号发生器优化

上面的DDS信号发生器在相位量化器中只进行了截断操作(直接舍弃低位),将截断的高位作为地址查表,虽然节省了大量ROM资源,但是会导致波形精度降低,甚至明显的出现台阶。

这里可以将截断操作后得到的ROM地址和余数同时输出到波形ROM模块,波形ROM模块根据地址取出当前数据和下一个数据,然后再根据余数进行信息化,以减小误差(波形ROM可以采用双口ROM设计,以便同时读出两个数据)。

混频

混频就是对信号进行频谱搬移,如将低频信号搬移到高频或者将高频信号搬移到低频,在数字信号处理中,频谱的搬移就是将一个本震信号和一个输入信号相乘,这样就可以得到一个复合的信号,相应的公式如下:

通过公式可以看出这个复合信号中包含一个高频信号和一个低频信号,对这个信号进行低通滤波就可以将输入信号从高频信号搬移到低频,相应的进行高通滤波可以将输入信号从低频搬移到高频。

上图中输出的复合信号fout由两个信号组成,分别是f1+f2和f1-f2,后面通过滤波器可以选择出f1+f2(高频)或f1-f2(低频)。

ROM IP核

COE文件格式

Xilinx的RAM/ROM IP核可以通过COE文件初始化其中内容,COE文件格式如下:

MEMORY_INITIALIZATION_RADIX用于描述进制,10表示10进制,16表示16进制,2表示二进制

MEMORY_INITIALIZATION_VECTOR为数据向量,每个数据以","隔开,采用";"结尾

下面是一个COE文件范例:

c 复制代码
MEMORY_INITIALIZATION_RADIX=10; 
MEMORY_INITIALIZATION_VECTOR= 
0 ,
3 ,
6 ,
9 ,
12 ,
15 ,
18 ;

在实际工作中可以使用matlab等工具生成COE文件,如下是生成128个正弦波和余弦波COE文件的matlab程序,正弦波和余弦波的幅值为-127~+127:

c 复制代码
clc;
close all;
clear;

% 生成采样点t,范围从0~(1-1/128),步进为1/128,共计128个元素,表示对在一个周期进行128等分采样
t = 0:(1/128):(1-1/128);
% 对一个周期的信号采样128个点
sin_data = 127 * sin(2.0 * pi * t);
cos_data = 127 * cos(2.0 * pi * t);
% 四舍五入
sin_data = round(sin_data);
cos_data = round(cos_data);

% 画图
figure(1);
plot(sin_data);
hold on;
plot(cos_data);

% sin_data写入文件
file = fopen('sin_data.coe', 'w+');
fprintf(file, 'MEMORY_INITIALIZATION_RADIX=10;\r\n');
fprintf(file, 'MEMORY_INITIALIZATION_VECTOR=\r\n');
fprintf(file, '%d ,\r\n', sin_data(1:127));
fprintf(file, '%d ;', sin_data(128));
fclose(file);

% cos_data写入文件
file = fopen('cos_data.coe', 'w+');
fprintf(file, 'MEMORY_INITIALIZATION_RADIX=10;\r\n');
fprintf(file, 'MEMORY_INITIALIZATION_VECTOR=\r\n');
fprintf(file, '%d ,\r\n', cos_data(1:127));
fprintf(file, '%d ;', cos_data(128));
fclose(file);

ROM IP核配置

Xilinx的Block Memory Generator IP可以生成单口RAM(只有一个读写端口、伪双口RAM(一个读端口一个写端口)、真双口RAM(两个端口均可读写)、单口ROM(只有一个读端口)、双口ROM(只有两个读端口),这些存储器本质上都是由FPGA内部的RAM生成。在此章节中需要使用到单口ROM IP和,下面将介绍使用Block Memory Generator IP生成单口ROM IP核的步骤。

  1. 开IP配置界面
  2. 基础配置
  3. A端口配置
  4. 其他配置
  5. 生成IP核

乘法IP核

  1. 打开乘法器IP配置页面
  2. 配置乘法IP核
  3. 生成IP核

DDS信号发生器和混频

通过Verilog实现DDS信号发生器,然后将DDS信号发生器例化两次输出不同频率,然后对输出频率进行混频。

  1. 按照上面的步骤配置ROM IP核,并用COE文件进行初始化,这里选用cos_data.coe初始化ROM IP
  2. 按照上面的步骤配置乘法IP核
  3. 编写DDS信号发生器代码
c 复制代码
`timescale 1ns / 1ps

module dds(
    input  wire        sclk             ,
    input  wire        resetn           ,
    
    input  wire [31:0] fcw              ,//频率控制字或相位步进
    output wire [7:0]  cos_data          //dds输出信号
);

//相位累加器
reg  [31:0] phase_accum = 32'd0;
//截断后的相位累加器
wire [6:0]  phase_key;


//相位累加器递增
always @(posedge sclk) begin
    if(!resetn)
        phase_accum <= 32'd0;
    else
        phase_accum <= phase_accum + fcw;
end

//将相位截断
assign phase_key = carrier_phase_accum[31:25];

//例化ROM模块
single_rom_8x128 u_single_rom_8x128_inst0 (
    .clka(sclk),            // input wire clka
    .addra(phase_key),      // input wire [6 : 0] addra
    .douta(cos_data)        // output wire [7 : 0] douta
);

endmodule
  1. 编写混频代码
c 复制代码
`timescale 1ns / 1ps

module mixer(
    input  wire        sclk			,
    input  wire        resetn		,
	
    input  wire [7:0]  signal_a		,//输入信号A
    input  wire [7:0]  signal_b		,//输入信号B
    output wire [15:0] mixer_out	 //混频输出
);

mult_i8xi8 u_mult_i8xi8_inst0 (
	.CLK(sclk),  		// input wire CLK
	
	.A(signal_a),      	// input wire [7 : 0] A
	.B(signal_b),      	// input wire [7 : 0] B
	.P(mixer_out)      	// output wire [15 : 0] P
);

endmodule
  1. 编写顶层代码
c 复制代码
`timescale 1ns / 1ps

module mixer_top(
    input  wire        sclk         ,
    input  wire        resetn       ,
    
    input  wire [31:0] fcw_a        ,//DDS A频率控制器
    input  wire [31:0] fcw_b        ,//DDS B频率控制器
    output wire [7:0]  cos_a        ,//DDS A输出
    output wire [7:0]  cos_b        ,//DDS B输出
    output wire [15:0] mixer_out     //混频输出
);


//DDS信号发生器A
dds u_dds_inst0(
    .sclk             (sclk    ),
    .resetn           (resetn  ),
                       
    .fcw              (fcw_a   ),//频率控制字或相位步进
    .cos_data         (cos_a   ) //dds输出信号
);

//DDS信号发生器B
dds u_dds_inst1(
    .sclk             (sclk    ),
    .resetn           (resetn  ),
                       
    .fcw              (fcw_b   ),//频率控制字或相位步进
    .cos_data         (cos_b   ) //dds输出信号
);

//混频
mixer u_mixer_inst0(
    .sclk           (sclk     ),
    .resetn         (resetn   ),
    
    .signal_a       (cos_a    ),//输入信号A
    .signal_b       (cos_b    ),//输入信号B
    .mixer_out      (mixer_out) //混频输出
);

endmodule
  1. 编写仿真激励文件
c 复制代码
`timescale 1ns / 1ps

module tb_mixer_top( );

reg         sclk         ;
reg         resetn       ;

reg  [31:0] fcw_a        ;//DDS A频率控制器
reg  [31:0] fcw_b        ;//DDS B频率控制器
wire [7:0]  cos_a        ;//DDS A输出
wire [7:0]  cos_b        ;//DDS B输出
wire [15:0] mixer_out    ;//混频输出


//产生激励时钟,50M
initial begin
    sclk = 1'b0;
end
always #10 sclk = ~sclk;

//产生复位信号
initial begin
    resetn = 1'b0;
    repeat(100) @(posedge sclk);
    resetn = 1'b1;
end

//设置频率控制字
initial begin
    fcw_a = 32'd0;
    fcw_b = 32'd0;
    repeat(200) @(posedge sclk);
    fcw_a = 32'd42949673;	//0.5M,fcw_a = (0.5M * 4294967296)/50M = 42949672.96
    fcw_b = 32'd257698038;	//3.0M,fcw_b = (3.0M * 4294967296)/50M = 257698037.76
end


//例化仿真模块
mixer_top tb_mixer_top_inst0(
    .sclk         (sclk     ),
    .resetn       (resetn   ),

    .fcw_a        (fcw_a    ),//DDS A频率控制器
    .fcw_b        (fcw_b    ),//DDS B频率控制器
    .cos_a        (cos_a    ),//DDS A输出
    .cos_b        (cos_b    ),//DDS B输出
    .mixer_out    (mixer_out) //混频输出
);

endmodule
  1. 进行仿真测试,仿真输出结果如下:
相关推荐
szxinmai主板定制专家3 小时前
基于 STM32 + FPGA 船舶电站控制器设计与实现
arm开发·人工智能·stm32·嵌入式硬件·fpga开发·架构
ARM+FPGA+AI工业主板定制专家13 小时前
基于ARM+FPGA+AI的船舶状态智能监测系统(二)软硬件设计,模拟量,温度等采集与分析
arm开发·人工智能·目标检测·fpga开发
szxinmai主板定制专家15 小时前
基于ZYNQ MPSOC船舶数据采集仪器设计(一)总体设计方案,包括振动、压力、温度、流量等参数
arm开发·人工智能·嵌入式硬件·fpga开发
FPGA小迷弟19 小时前
高频时钟设计:FPGA 多时钟域同步与时序收敛实战方案
前端·学习·fpga开发·verilog·fpga
szxinmai主板定制专家20 小时前
基于ZYNQ MPSOC船舶数据采集仪器设计(三)振动,流量,功耗,EMC,可靠性测试
arm开发·人工智能·嵌入式硬件·fpga开发
hoiii1871 天前
Vivado下Verilog交通灯控制器设计
fpga开发
嵌入式-老费1 天前
vivado hls的应用(开篇)
fpga开发
ARM+FPGA+AI工业主板定制专家1 天前
基于ARM+FPGA+AI的船舶状态智能监测系统(一)总体设计
网络·arm开发·人工智能·机器学习·fpga开发·自动驾驶
Eidolon_li1 天前
ARINC429模块规格书(V1.1)
fpga开发