当前位置: 首页 > news >正文

用verilog模拟DDS产生正弦波信号

用verilog模拟DDS产生正弦波信号

前言:

DDS:直接数字频率合成,正弦波0-2pi周期内,相位到幅度是一一对应的(这里我们使用放大后的整数幅度)。

主要思路:

个人理解,FPGA不擅长直接做数字信号计算,那样太占用片上逻辑资源,所以需要事先建立 正弦波相位-幅度 表,然后在时钟下,通过相位累加并用相位作为地址索引来查询正弦波信号表。

正弦波相位-幅度 表:
存储的是量化的正弦波在一个周期的幅度信息(幅度的地址即相位)。
幅度的地址数目决定了相位量化的误差。
而存储每一个幅度的比特数决定了幅度的量化误差。
可以通过matlab以及Xilinx的IP核向导创建。

Verilog编写的DDS模块主要由三部分组成,

  • 相位累加器,用于决定输出信号频率的范围和精度;
  • 正弦函数模块,用于存储经量化和离散后的正弦函数的幅值;
  • 查表模块,对相位累加器的输出地址查表。

两种方法可以改变输出信号的频率:

  • 改变查表寻址的时钟频率,从而改变输出波形的频率。
  • 改变寻址的步长来改变输出信号的频率。
    步长即为相位增量。
    由累加器对相位增量进行累加,
    累加器的值作为查表地址。

相位累加器是 DDS 的核心所在,前面在低于时钟频率的任意频率生成(相位累加器)中我们已经进行了叙述。
正弦函数模块包含一个周期正弦波的数字幅度信息,每个地址对应正弦波中0-2pi范围的一个相位点。查表模块把输入的地址相位信息映射成正弦波幅度的数字量信号。相位寄存器每经过 2^N/K 个时钟后回到初始状态,相应地正弦查询表经过一个循环回到初始位置,输出一个正弦波。

输出正弦波周期为fo=fc* K/2^N ,最小分辨率为f=fc/2^N。(通过fc和K控制正弦波频率精度) 其中,N 为累加器位宽,K 为步长,fc 为时钟频率。计数模(最大值):M=2^N。

一般正弦波表幅度地址位宽与累加的查表地址位宽不同,按前者位宽取后者对应高位的位宽即可。(具体见实例)

先用matlab生成1024点的正弦波数据:

clc;clear;
N = 10;                     %储存单元地址线
depth=2^N;                 %存储单元;
widths=N;                    %数据宽度为8位;
index = linspace(0,pi*2,depth);              
sin_value = sin(index);                
sin_value = sin_value * (depth/2 -1);  %扩大正弦幅度值    
sin_value = fix((sin_value)+0.5);
plot(sin_value);
number = [0:depth];
fid=fopen('sin_table.coe','w+');
fprintf(fid,'memory_initialization_radix=10;\n');
fprintf(fid,'memory_initialization_vector=\n');
for i = 1 : depth - 1  
    fprintf(fid, '%d,\n', sin_value(i));
end
fprintf(fid, '%d;', sin_value(depth));
fclose(fid);

Verilog程序

1、adder.v文件,相位累加模块

`timescale 1ns/1ps
/***************************************
晶振频率 fc = 100MHz
输出频率 fo = 1kHz(根据需要可以设为任意值)
控制参数 K  = (fo*2^N)/fc = 42950
参数 N = 2^32,(32为计数器的位宽)
****************************************/
module PHASE_ADDER(
    input clk,
    input rst,
    output reg [31:0] cnt,
    output reg clk_out
    );

always @(posedge clk or posedge rst) 
    if(rst)
        cnt <= 0;
    else
        cnt <= cnt + 32'd42950;  //计数器步长K

always @(posedge clk or posedge rst)
    if(rst)
        clk_out <= 1'b0;
    else if(cnt < 32'h7FFF_FFFF)
        clk_out <= 1'b0;
    else
        clk_out <= 1'b1;

endmodule

2、dds_top.v顶层设计

`timescale 10ns /1ns

module dds_top(
    input rst,
    input clk,
    output signed [15:0] sine_o
    );

    wire [31:0] phase;   //32bit内部连接线,传递相位增量
    wire clk_out;
    wire [9:0] addr;   //10bit相位信息

    PHASE_ADDER U_PHASE_ADDER(
        .clk    (clk    ),
        .rst    (rst    ),
        .cnt    (phase  ),
        .clk_out(clk_out)
        );
     
    assign addr = phase[31:22];//addr 10bit
    
    DDS_Table U_DDS_Table(
        .clka(clk),    // input wire clka
        .addra(addr),  // input wire [9 : 0] addra
        .douta(sine_o)  // output wire [15 : 0] douta
        );
endmodule

3、仿真测试文件

`timescale 1ns/1ps

module TB;
    
    reg clk;
    reg rst;
    wire clk_out;
    dds_top U_dds_top(
        .clk    (clk    ),
        .rst    (rst    )
    );

    initial begin
        clk = 0;
        rst = 0;
        #4 rst = 1;
        #3 rst = 0;
    end

    always #5 clk = ~clk;
endmodule 

matlab生成正弦数据:

sin_table

vivado和Modelsim联合仿真结果:

仿真结果

posted on 2016-05-28 17:03 christ0127 阅读( ...) 评论( ...) 编辑 收藏

转载于:https://www.cnblogs.com/christsong/p/5536995.html

相关文章:

  • 第k个元素(模板)
  • 景德镇特色的部门级别与权限
  • swift 字符串创建类
  • push 和pop的区别
  • linux命令行模式下实现代理上网 专题
  • tab.js分享及浏览器兼容性问题汇总
  • linux----进度条程序
  • Eclipse:The superclass javax.servlet.http.HttpServlet was not found on the Java Build Path
  • 运行TestCase时,提示:Element is not currently visible and so may not be interacted with
  • iOS开发之UITextField的使用详解
  • 使用生成器展平异步回调结构,JS篇
  • IPv4 地址分类
  • find命令无效处理记录
  • raft 分布式协议 -- mongodb
  • 把redis安装到ubuntu-14.04.1-server
  • 【node学习】协程
  • 【技术性】Search知识
  • CentOS 7 修改主机名
  • HTTP那些事
  • k个最大的数及变种小结
  • laravel5.5 视图共享数据
  • Material Design
  • Object.assign方法不能实现深复制
  • PHP CLI应用的调试原理
  • Python 反序列化安全问题(二)
  • SAP云平台里Global Account和Sub Account的关系
  • 初识 beanstalkd
  • 高性能JavaScript阅读简记(三)
  • 精益 React 学习指南 (Lean React)- 1.5 React 与 DOM
  • 深入浅出Node.js
  • 学习笔记:对象,原型和继承(1)
  • - 转 Ext2.0 form使用实例
  • 走向全栈之MongoDB的使用
  • ​LeetCode解法汇总307. 区域和检索 - 数组可修改
  • ​创新驱动,边缘计算领袖:亚马逊云科技海外服务器服务再进化
  • #{}和${}的区别?
  • ${ }的特别功能
  • (1)安装hadoop之虚拟机准备(配置IP与主机名)
  • (AtCoder Beginner Contest 340) -- F - S = 1 -- 题解
  • (NSDate) 时间 (time )比较
  • (Redis使用系列) SpringBoot 中对应2.0.x版本的Redis配置 一
  • (动手学习深度学习)第13章 计算机视觉---图像增广与微调
  • (附源码)spring boot智能服药提醒app 毕业设计 102151
  • (切换多语言)vantUI+vue-i18n进行国际化配置及新增没有的语言包
  • (原)Matlab的svmtrain和svmclassify
  • ./mysql.server: 没有那个文件或目录_Linux下安装MySQL出现“ls: /var/lib/mysql/*.pid: 没有那个文件或目录”...
  • .Net Core webapi RestFul 统一接口数据返回格式
  • .NET 表达式计算:Expression Evaluator
  • .Net开发笔记(二十)创建一个需要授权的第三方组件
  • [ Linux 长征路第二篇] 基本指令head,tail,date,cal,find,grep,zip,tar,bc,unname
  • [Android]创建TabBar
  • [bzoj1324]Exca王者之剑_最小割
  • [C#]C# winform部署yolov8目标检测的openvino模型
  • [CC2642R1][VSCODE+Embedded IDE+IAR Build+Cortex-Debug] TI CC2642R1基于VsCode的开发环境
  • [CISCN 2023 初赛]go_session