博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
用verilog模拟DDS产生正弦波信号
阅读量:7081 次
发布时间:2019-06-28

本文共 2992 字,大约阅读时间需要 9 分钟。

前言:

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));endfprintf(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;  //计数器步长Kalways @(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 /1nsmodule 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/1psmodule 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 阅读(
...) 评论(
...)

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

你可能感兴趣的文章
Windows Phone 8 SDK RC 版推出
查看>>
Database2Sharp代码生成工具使用心得
查看>>
稀疏矩阵的十字链表存储
查看>>
【算法导论第13章】红黑树
查看>>
对PostgreSQL中bufmgr.c 中 bufs_to_lap的初步理解
查看>>
Windows 内存分析之路 --How to use Resource Monitor
查看>>
文件上传
查看>>
理解maven的核心概念
查看>>
一个简单的名片管理程序(C#)
查看>>
max tablename length limit in MySQL is 64
查看>>
Ubuntu 12.04 中国科学技术大学源
查看>>
(转)c#实现WinRAR解压缩
查看>>
MIME
查看>>
NetworkInterface的使用
查看>>
http://daffodil.codeplex.com/
查看>>
反码符号-128有8位二进制表示的原码、反码和补码
查看>>
编程输出完美之星编程大赛 复赛第二场 24点
查看>>
最大连续子序列
查看>>
iPhone loadView 和 viewDidLoad的区别
查看>>
Netfilter/iptables的一些新进展
查看>>