西安电子科技大学西电实验室
直播中

蓝e

10年用户 53经验值
擅长:可编程逻辑 电源/新能源 MEMS/传感技术 测量仪表 嵌入式技术 制造/封装 模拟技术 连接器 EMC/EMI设计 光电显示 存储技术 EDA/IC设计 处理器/DSP 接口/总线/驱动 控制/MCU RF/无线
私信 关注
[项目进行中]

用Verilog通过DDS合成正弦波信号

本帖最后由 蓝e 于 2016-7-12 22:32 编辑

Verilog通过DDS合成正弦波信号
主要原理:
      DDS:直接数字合成,正弦波0-2pi周期内,相位到幅度是一一对应的。首先需要的将正弦波查询表存储起来,然后在时钟下,通过相位累加模块和地址查询模块实现正弦波信号。
正弦波查询表:存储的是量化的正弦波在一个周期的幅度信息(幅度的“地址”也蕴含相位)。幅度的地址数目决定了相位量化的误差。而存储每一个幅度的比特数决定了幅度的量化误差。可以通过Quartus IIIP核资源创建。
Verilog编写的DDS模块主要由三部分组成,
一、相位累加器,用于决定输出信号频率的范围和精度;
二、正弦函数功能表(波形存储器),用于存储经量化和离散后的正弦函数的幅值;
三、查表模块,相位累加器的输出地址查表。
两种方法可以改变输出信号的频率:
(1)改变查表寻址的时钟频率,可以改变输出波形的频率。
(2)改变寻址的步长来改变输出信号的频率。步长即为对数字波形查表的相位增量。由累加器对相位增量进行累加,累加器的值作为查表地址。
       相位累加器是DDS 的核心所在,它由一个加法器和一个位相位寄存器组成,每来一个时钟,相位寄存器以步长K累加,相位寄存器的输出与相位控制字相加,然后输入到正弦查询表地址上。正弦查询表包含一个周期正弦波的数字幅度信息,每个地址对应正弦波中0-2pi范围的一个相位点。查询表把输入的地址相位信息映射成正弦波幅度的数字量信号。相位寄存器每经过2^N/K 个fc 时钟后回到初始状态,相应地正弦查询表经过一个循环回到初始位置,输出一个正弦波。
输出正弦波周期为fo=fc* K/2^N,最小分辨率为f=fc/2^N。(通过fc和K控制正弦波频率精度) 其中,N 为累加器位宽,K 为步长,fc 为时钟频率。计数模(最大值):M=2^N。
       一般正弦波表幅度地址位宽与累加的查表地址位宽不同,按前者位宽取后者对应高位的位宽即可。(具体见实例)

Verilog程序
1、sine_top.v顶层设计
`timescale 10ns /1ns       //时延:时间单位/时间精度
module sine_top(//采用直接数字合成(Direct Digital Synthesis)
    sine,
    clk,
        rst_n
    );
        
       output[7:0]sine;   //输出叠加的正弦波
       input rst_n;
       input clk;
           
       wire [15:0] rom_ad;   //16bit内部连接线,传递相位增量(频率控制字的整数倍)
       wire [9:0] address;   //10bit
       wire signed [7:0] sine1; //8位大小的存储器阵列
      
       assign sine=sine1;
//M=2^N=2^16=65536N控制频率分辨率,fc/M,通过相位增量K(频率控制字)控制输出频率。fout=K*fclk/M
//通过查表输出正弦波,一个周期内,102410位)点 X 8bit(幅度量化精度)
//fclk=100MHz(10ns)
//10MHz         //带参数的模块实例化
       adder #(.fcw(6554)) uut0(  //10MHz-->6554(频率控制字),实例化adder模块,uut0
       .clk(clk),
       .rst(rst_n),
       .sum(rom_ad)      //rom_ad,16bit大小内部连接线
       );
        assign address=rom_ad [15:6];//address,10bitrom_ad10位作为地址,与表中1024个值一一对应。
      
        rom_sine0 rom0(     //IP
       .address(address),//输入10位的地址,查出正弦波表对应的幅度值
       .clock(clk),         
       .q(sine1)        //输出结果
       );
endmodule

2adder.v文件,累加模块
module adder#(parameter fcw=16'd10000)(  //参数为16位大小 默认参数(10000
   sum,
       clk,
       rst
       );
      
       output [15:0] sum;   //输出地址
       input         clk;
       input         rst;
      
   reg [15:0] sum;      //初值  
       always @(posedge clk)//正沿触发
         begin
              if(!rst)            //复位0有效
                 sum<=16'd0;
               else
                 sum<=sum+fcw; //求和
              end
            
endmodule  

3sine_stimulate.v仿真测试文件
//sine_stimulate.v,my testbench
`timescale 1ns/1ns
modulesine_stimulate; //
   reg rst_n;        //复位信号
       reg clk;         //时钟信号
       wire signed[7:0]sine;
   sine_top uut0(
    .sine(sine),
        .clk(clk),
        .rst_n(rst_n)
    );
        
  initial      //过程语句,只执行一次(与always不同)
       begin
       clk=0;
       rst_n=0;
       #50;            //延迟50ns
       rst_n=1;
       end
      
       always #5 clk=~clk;
      
       endmodule

Quartus II 13.0 ModelsimSE 10.1a联合仿真结果
仿真输出的正弦波:

                              
插值后的正弦波图形:

这就是我用Verilog编程,采用DDS合成正弦波的所有流程。

-----------------------------------------------------------------------------------------------------------------
赶紧动手开始探索你的神奇之旅吧,学习FPGA开发,享受Verilog编程、仿真带来的乐趣!!!
版主刚开始做教程,如有不足,敬请原谅!祝好!

附:
正弦查询表(.mif文件)



附件: 您需要登录才可以下载或查看附件。没有帐号?注册

回帖(92)

董平

2014-3-24 23:31:56
谢谢楼主  问一下怎么进行插值处理  要用什么 求解
举报

蓝e

2014-3-25 15:26:27
引用: low-keking 发表于 2014-3-24 23:31
谢谢楼主  问一下怎么进行插值处理  要用什么 求解

我是用的Modelsim 中自带的插值功能。
举报

董平

2014-3-25 17:58:52
哦 这样啊 我试试看 谢谢楼主
举报

2014-7-21 10:36:48
谢谢
楼主
分享
举报

更多回帖

发帖
×
20
完善资料,
赚取积分