赞
踩
DDS(Direct Digital Synthesis)是一种把一系列数字信号通过D/A转换器转换成模拟信号的数字合成技术。它有查表法和计算法两种基本合成方法。由于ROM查询法结构简单,只需要在ROM中存放不同相位对应的幅度序列,然后通过相位累加器的输出对其寻址,经过数/模转换和低通滤波(LPF)输出便可以得到所需要的模拟信号。
ROM查表法。DDS技术实质上是实现了一个数字分频器的功能。对于一个周期的正弦波连续信号,可以沿其相位轴方向,以等量的相位间隔对其进行相位/幅度采样,得到一个周期性的正弦信号的离散相位的幅度序列,对模拟幅度进行量化后的幅值采用二进制数据编码,这样就把一个周期的正弦波连续信号转换成一系列离散的二进制数字量,然后存入存储器RAM中,每个存储器单元的地址即是相位取样地址,存储单元的内容是已经量化了的正弦波幅值。一个这样的只读存储器构成了一个与2π周期相位取样对应的正弦波函数表。DDS的基本原理主要由标准参考频率源、相位累加器、波形存储器和数/模转换器构成。
在时钟脉冲的控制下,频率控制字K由累加器得到相应的相码。相码寻址波形存储器进行相码—幅码变换输出不同的幅度编码,经过数/模变换器得到相应的阶梯波,最后经过低通滤波器对阶梯波进行平滑,即得到由频率控制字K决定的连续变化的输出波形。相位累加器是实现DDS的核心,它由一个N位字长的二进制加法器和一个由固定时钟脉冲取样的N位相位寄存器组成,在每个时钟脉冲到达时,相位寄存器采用上个时钟周期内相位寄存器的值与频率控制字K之和,并作为相位累加器在这一时钟周期的输出。fpga系统框图如图:
利用matalab产生.mif。.mif文件格式
WIDTH=8;//mif数据的深度,8代表每个数据都是8bit;
DEPTH=512;//数据的宽度,512代表总共有512的数据;
ADDRESS_RADIX=HEX;//地址的格式 HEX即代表以16进制来寻址 (uns–十进制,bin–二进制,hex–十六进制)
DATA_RADIX=HEX;//数据存储的格式,同上
CONTENT BEGIN//
0 : 80;
1 : 86;
2 : 8C;
3 : 92;
4 : 98;
END;//在content begin和end之间就是存储的数据
采用matlab生成.mif
MATALB程序:
clc; clear all; close all; width = 8; %位宽 depth = 2 ^9; %深度(采样点个数) x = linspace(0, 2 * pi, depth); y = sin(x); y = round(y * (2 ^ (width - 1) - 1) + 2 ^ (width - 1) - 1);%量化 plot(y); fid = fopen('dds_sin.mif','w');//生成的.mif文件在.m所在路径 fprintf(fid,'DEPTH=%d;\n',depth); fprintf(fid,'WIDTH=%d;\n',width); fprintf(fid, 'ADDRESS_RADIX = UNS;\n'); %% 指定地址为十进制 fprintf(fid, 'DATA_RADIX = DEC;\n'); fprintf(fid, 'CONTENT\t'); fprintf(fid, 'BEGIN\n'); for i = 0 : depth-1 fprintf(fid, '\t%d\t:\t%d;\n',i,y(i+1)); end fprintf(fid, 'END;\n'); fclose(fid);
1、生成的.mif
记事本打开.mif正弦波数据:
quartus打开.mif文件可以直观看到数据:
2、利用quartusii生成ROM表导入.mif文件
使用的quartus是15版本的,创建好工程,选择tools–>IP catalog
操作完成后,注意屏幕右侧,在搜索框中,搜索rom,选择ROM:1-PORRT
page1:根据自己设置的位宽和深度配置,我自己生成的.mif文件中,位宽为8,深度为512然后next,所有如图
page2:配置如图,此处没有选择rden信号:
page3:要导入.mif文件,利用其初始化rom,所以需要选择yes,选择browse,找到.mif文件所在位置,导入即可(ps:建议把.mif文件放在工程文件下)
page4,page5:选择finsh,IP核就生成好了,在左侧project navigator处,找到IP Components,可以看到我们所生成的ip核,同时想要编辑此ip核,鼠标右键选择EdIT in Parameter Editor,就可以进入ip核配置界面。
**思路:**在时钟控制下,每次相位累加器累加一次频率字,rom的地址由频率累加字的高9位[只要高于]与相位字的和决定;利用传参改变相位累加器位宽、产生的波形频率、输入时钟,初始相位。
频率字F_WORD=需要波形的频率2^N/输入时钟频率(相位N为累加器的位宽)
如:需要10k的正弦波,带入公式F_WORD=100002^N/50000000=13.1频率字约等于13;
P_WORD:相位字,决定正弦波初始相位
module dds_ip ( input sys_rst_n, input sys_clock,//50Mhz时钟 output [7:0] wave_out//波形输出 ); //传参改变他们的值 parameter PHASE_SUM_N=5'd16;//相位累加器位宽 parameter wave_fre =10'd1000;//1khz parameter iclock_fre = 26'd50000000;//50mhz模块工作时钟 parameter P_WORD = 9'd0;//默认初始相位为0 //reg reg [15:0]PHASE_SUM;//16位相位累加器 reg [31:0]F_WORD;//频率字F_WORD=需要波形的频率*2^N/输入时钟频率(相位N为累加器的位宽), //wire wire [8:0] rom_addr;//rom地址 //初始化F_WORD initial begin F_WORD =(wave_fre<<PHASE_SUM_N)/iclock_fre; end always@(posedge sys_clock or negedge sys_rst_n) begin if(!sys_rst_n) PHASE_SUM <=16'd0; else if(PHASE_SUM <16'b1111_1111_1111_1111) begin PHASE_SUM <= PHASE_SUM + F_WORD;//累加 end else PHASE_SUM <= 16'd0; end assign rom_addr =P_WORD+PHASE_SUM[15:7];//取高九位+初始相位,得rom地址 sin_ip u_sin_ip ( .address(rom_addr), .clock(sys_clock), .q(wave_out) ); endmodule
如何查看IP核的传参入口,调用IP核,如下图
quartus与Modelsim联合仿真Tb文件编写(利用quartus生成的tb程序框架)
切记,信号一定要初始化
`timescale 1 ns/ 1 ns module dds_ip_vlg_tst(); // constants // general purpose registers // test vector input registers reg sys_clock; reg sys_rst_n; // wires wire [7:0] wave_out; // assign statements (if any) dds_ip #(.wave_fre(14'd10000),.P_WORD(6'd20))i1_inst ( // port map - connection between master ports and signals/registers .wave_out(wave_out), .sys_clock(sys_clock), .sys_rst_n(sys_rst_n) ); initial begin sys_clock=1'b0; sys_rst_n=1'b0; #200 sys_rst_n = 1'b1; $display("Running testbench"); end always #10 sys_clock=~sys_clock;//50MHZ时钟 endmodule
仿真结果如图 ,wave_out是16进制的数,我们需要看波形,还需要进行设置;
wave_out上右键先选择Radix->unsigned;再选择Format->Analog(automatic)。实当缩小,波形就出来了
此文章,作为本人学习记录,同时希望能够给向我一样的初学者提供一些帮助;后续会优化细节。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。