用DDS求角度的正弦值

  • 1 DDS原理
    • 1.1 书上的解释
    • 1.2 自己的理解
  • 2 DDS IP的参数设置
  • 3 Vivado实现
    • 3.1 编写源文件
    • 3.2 编写testbench文件
    • 3.3 仿真结果
  • 4 通过DDS计算得到权值

1 DDS原理

1.1 书上的解释

DDS(Direct Digital Synthesizer)技术是一种全新的频率合成方法,是从相位概念出发直接合成所需波形的一种频率合成技术,通过控制相位的变化速度,直接产生各种不同频率、不同波形信号的一种频率合成方法。

系统的核心是相位累加器,其内容会在每个时钟周期(system clock)更新。相位累加器每次更新时,存储在Δ相位寄存器中的数字字M就会累加至相位寄存器中的数字。假设Δ相位寄存器中的数字为00…01(即M=1),相位累加器中的初始内容为00…00。相位累加器每个时钟周期都会按00…01(M=1)更新。如果累加器为32位宽,则在相位累加器返回至00…00前需要2^32(超过40亿)个时钟周期,周期会不断重复。

相位累加器的截断输出用作正弦(或余弦)查找表的地址。查找表中的每个地址均对应正弦
波的从0°到360°的一个相位点。查找表包括一个完整正弦波周期的相应数字幅度信息。
(实际上,只需要90°的数据,因为两个MSB中包含了正交数据)。因此,查找表可将相位
累加器的相位信息映射至数字幅度字,进而驱动DAC。图3用图形化的“相位轮”显示了这
一情况。
考虑n = 32,M = 1的情况。相位累加器会逐步执行2^ 32 (2^n/M)个可能的输出中的每一个,直至溢出并重新开始。相应的输出正弦波频率等于输入时钟频率 2 ^ 32分频。若M=2,相位累加器寄存器就会以两倍的速度“滚动”计算,输出频率也会增加一倍。以上内容可总结如下:

1.2 自己的理解

DDS系统主要由相位累加器、波形存储器、数模(D/A)转换器和低通滤波器等四个大的结构组成,其结构框图如下图所示。

参考时钟:
图中,参考频率f_clk为固定值,一般我们选择系统时钟(system clock),这里设置的是100MHz。
频率控制字:
用来调整输出信号的频率。如何根据参考频率得到输出频率,DDS IP的官方文档给出了相应公式。


相位控制字:

相位累加器:
由N位加法器与N位累加寄存器构成,它根据频率控制字k,完成相位值的累加,并将此累加值输入到波形存储器中。
波形存储器:
将相位累积器的值作为当地址,查找与相位值对应的信号数据,输出到D/A转换器。
D/A转换器:
将波形存储器输出的数字量转换为与之对应的模拟量。
低通滤波器:
由于D/A转换器存在量化误差,输出波形中存在混叠,需要在输出端使用低通滤波器进行滤波,提高信号的输出性能。

2 DDS IP的参数设置


3 Vivado实现

3.1 编写源文件

PI的值如何确定的,在后面解释

`timescale 1ns / 1psmodule top(input           sys_clk     ,input           rst_n       );reg [15:0] angle;
always@(posedge sys_clk or negedge rst_n)
beginif(!rst_n)angle=16'd0;elseangle=angle+3;
end// 例化求正弦值的ip核
wire    [15:0]     sin_value;
dds_sin dds_sin_inst (.aclk(sys_clk),                               // input wire aclk.s_axis_phase_tvalid(1'b1),                   // input wire s_axis_phase_tvalid.s_axis_phase_tdata(angle),                   // input wire [15 : 0] s_axis_phase_tdata.m_axis_data_tvalid(),                        // output wire m_axis_data_tvalid.m_axis_data_tdata(sin_value)                 // output wire [15 : 0] m_axis_data_tdata
);    wire    [15:0]     theta;
wire    [15:0]     sin_theta;
wire    [15:0]     PI  ;
assign PI=32750;    // sin(pi/2)=1,找到最大值对应的横坐标即为pi/2
assign theta = PI/2;    // 例化求正弦值的ip核
dds_sin dds_sin_1_inst (.aclk(sys_clk),                               // input wire aclk.s_axis_phase_tvalid(1'b1 ),                   // input wire s_axis_phase_tvalid.s_axis_phase_tdata(theta ),                   // input wire [15 : 0] s_axis_phase_tdata.m_axis_data_tvalid(      ),                        // output wire m_axis_data_tvalid.m_axis_data_tdata(sin_theta)                 // output wire [15 : 0] m_axis_data_tdata);    endmodule

3.2 编写testbench文件

`timescale 1ns / 1psmodule sim_top;//inputreg sys_clk;reg rst_n;// 初始化//例化源文件top top_inst(.sys_clk    (sys_clk    ),.rst_n      (rst_n      )     );initialbegin//初始化输入sys_clk=0;rst_n=0;#100;rst_n=1;end// create clock;always #5 sys_clk=~sys_clk;endmodule

3.3 仿真结果

图中,s_axis_phase_tdata对应的就是theta
m_axis_data_tdata对应的就是sin_theta。可以看出,PI的定义的正确的。

PI的值如何确定的?
*parameter PI=32768; //PI的值如何确定?
利用DDS IP 得到每一个数值(1~100000)下的正弦值,找到正弦最大值(1)所对应的下标。根据sin(pi/2)=1。从而得到PI的值。需要注意的是,不同的位宽得到的PI的值是不一样的。

4 通过DDS计算得到权值

`timescale 1ns / 1psmodule top(input    sys_clk,input    rst_n    );reg  [15:0]  angle =0;
wire [15:0]  sin_angle ;
// 产生均匀变化的angle
always@(posedge sys_clk)
begin   if(rst_n==0)beginangle=0;end    else if (angle==65536-1)beginangle=0;endelse beginangle=angle+1'b1;end end // sin_angle dds_sin dds_sin_angle_inst (.aclk(sys_clk),                               // input wire aclk.s_axis_phase_tvalid(1'b1),                   // input wire s_axis_phase_tvalid.s_axis_phase_tdata(angle),                   // input wire [15 : 0] s_axis_phase_tdata.m_axis_data_tvalid(),                        // output wire m_axis_data_tvalid.m_axis_data_tdata(sin_angle)                 // output wire [15 : 0] m_axis_data_tdata); wire [15:0]   theta=90; //子波束i的指向角度
wire [15:0]   fine =30;
wire [15:0]   W_1I ;//权值的第1个元素的实部、虚部
wire [15:0]   W_1Q ;
wire [15:0]   W_2I ;//权值的第2个元素的实部、虚部
wire [15:0]   W_2Q ;
parameter PI=32768;  // 根据每个角度的正弦值的曲线仿真得到(pi/2对应的正弦值最大,PI/2=max_下标)
wire  [15:0]  theta1    ;//子波束i的指向角度
wire  [15:0]  fine1     ;assign theta1= theta*PI/180;assign fine1= fine*PI/180;wire [15:0]  sin_theta;wire [15:0]  sin_fine;wire [15:0]  cos_fine;// sin_theta dds_sin dds_sin_theta_inst (.aclk(sys_clk),                               // input wire aclk.s_axis_phase_tvalid(1'b1),                   // input wire s_axis_phase_tvalid.s_axis_phase_tdata(theta1),                   // input wire [15 : 0] s_axis_phase_tdata.m_axis_data_tvalid(),                        // output wire m_axis_data_tvalid.m_axis_data_tdata(sin_theta)                 // output wire [15 : 0] m_axis_data_tdata); // sin_fine dds_sin dds_sin_fine_inst (.aclk(sys_clk),                               // input wire aclk.s_axis_phase_tvalid(1'b1),                   // input wire s_axis_phase_tvalid.s_axis_phase_tdata(fine1),                   // input wire [15 : 0] s_axis_phase_tdata.m_axis_data_tvalid(),                        // output wire m_axis_data_tvalid.m_axis_data_tdata(sin_fine)                 // output wire [15 : 0] m_axis_data_tdata);   // cos_fine dds_cos dds_cos_fine_inst (.aclk(sys_clk),                               // input wire aclk.s_axis_phase_tvalid(1'b1),                   // input wire s_axis_phase_tvalid.s_axis_phase_tdata(fine1),                   // input wire [15 : 0] s_axis_phase_tdata.m_axis_data_tvalid(),                        // output wire m_axis_data_tvalid.m_axis_data_tdata(cos_fine)                 // output wire [15 : 0] m_axis_data_tdata);       wire [31:0] sin_theta_mul_sin_fine1; wire [31:0] sin_theta_mul_cos_fine1;wire [31:0] sin_theta_mul_cos_fine_add_sin_theta_mul_sin_fine1;wire [15:0] sin_theta_mul_sin_fine;//sin(theta)*sin(fine)wire [15:0] sin_theta_mul_cos_fine; //sin(theta)*cos(fine)wire [15:0] sin_theta_mul_cos_fine_add_sin_theta_mul_sin_fine; //sin(theta)*cos(fine)+sin(theta)*sin(fine)// 乘法计算//sin(theta)*sin(fine)mult_16x16 inst_sin_theta_mul_sin_fine (.CLK(sys_clk),  // input wire CLK.A(sin_theta),      // input wire [15 : 0] A.B(sin_fine),      // input wire [15 : 0] B.P(sin_theta_mul_sin_fine1)      // output wire [31 : 0] P);//sin(theta)*cos(fine)mult_16x16 inst_sin_theta_mul_cos_fine (.CLK(sys_clk),  // input wire CLK.A(sin_theta),      // input wire [15 : 0] A.B(cos_fine),      // input wire [15 : 0] B.P(sin_theta_mul_cos_fine1)      // output wire [31 : 0] P);//sin(theta)*cos(fine)+sin(theta)*sin(fine)assign sin_theta_mul_cos_fine_add_sin_theta_mul_sin_fine1=sin_theta_mul_cos_fine1+sin_theta_mul_sin_fine1;// 截位,保留高16位assign sin_theta_mul_sin_fine=sin_theta_mul_sin_fine1[31:16];assign sin_theta_mul_cos_fine=sin_theta_mul_cos_fine1[31:16];assign sin_theta_mul_cos_fine_add_sin_theta_mul_sin_fine=sin_theta_mul_cos_fine_add_sin_theta_mul_sin_fine1[31:16];wire [31:0] PI_mul_sin_theta_mul_sin_fine1;wire [31:0] PI_mul_sin_theta_mul_cos_fine1;wire [31:0] PI_mul_sin_theta_mul_cos_fine_add_sin_theta_mul_sin_fine1;wire [15:0] PI_mul_sin_theta_mul_sin_fine; //PI*sin(theta)*sin(fine)wire [15:0] PI_mul_sin_theta_mul_cos_fine; //PI*sin(theta)*cos(fine)wire [15:0] PI_mul_sin_theta_mul_cos_fine_add_sin_theta_mul_sin_fine; //PI*(sin(theta)*cos(fine)+sin(theta)*sin(fine))//PI*sin(theta)*sin(fine)mult_16x16 inst_PI_mul_sin_theta_mul_sin_fine (.CLK(sys_clk),  // input wire CLK.A(PI),      // input wire [15 : 0] A.B(sin_theta_mul_sin_fine),      // input wire [15 : 0] B.P(PI_mul_sin_theta_mul_sin_fine1)      // output wire [31 : 0] P);//PI*sin(theta)*cos(fine)mult_16x16 inst_PI_mul_sin_theta_mul_cos_fine (.CLK(sys_clk),  // input wire CLK.A(PI),      // input wire [15 : 0] A.B(sin_theta_mul_cos_fine),      // input wire [15 : 0] B.P(PI_mul_sin_theta_mul_cos_fine1)      // output wire [31 : 0] P);//PI*(sin(theta)*cos(fine)+sin(theta)*sin(fine))mult_16x16 inst_PI_mul_sin_theta_mul_cos_fine_add_sin_theta_mul_sin_fine(.CLK(sys_clk),  // input wire CLK.A(PI),      // input wire [15 : 0] A.B(sin_theta_mul_cos_fine_add_sin_theta_mul_sin_fine),      // input wire [15 : 0] B.P(PI_mul_sin_theta_mul_cos_fine_add_sin_theta_mul_sin_fine1)      // output wire [31 : 0] P);// 截位assign PI_mul_sin_theta_mul_sin_fine=PI_mul_sin_theta_mul_sin_fine1[31:16];assign PI_mul_sin_theta_mul_cos_fine=PI_mul_sin_theta_mul_cos_fine1[31:16];assign PI_mul_sin_theta_mul_cos_fine_add_sin_theta_mul_sin_fine=PI_mul_sin_theta_mul_cos_fine_add_sin_theta_mul_sin_fine1[31:16];/*函数功能:DDS计算某角度所对应的权值*/     assign  W_1I =16'b0111_1111_1111_1111;assign  W_1Q =16'b0000_0000_0000_0000;// W_2I  cos(PI*(sin(theta)*sin(fine)))dds_cos dds_W_2I_inst (.aclk(sys_clk),                               // input wire aclk.s_axis_phase_tvalid(1'b1),                   // input wire s_axis_phase_tvalid.s_axis_phase_tdata(PI_mul_sin_theta_mul_sin_fine),                   // input wire [15 : 0] s_axis_phase_tdata.m_axis_data_tvalid(),                        // output wire m_axis_data_tvalid.m_axis_data_tdata(W_2I)                 // output wire [15 : 0] m_axis_data_tdata);  // W_2Q  sin(-PI*(sin(theta)*sin(fine)))dds_sin dds_W_2Q_inst (.aclk(sys_clk),                               // input wire aclk.s_axis_phase_tvalid(1'b1),                   // input wire s_axis_phase_tvalid.s_axis_phase_tdata(-PI_mul_sin_theta_mul_sin_fine),                   // input wire [15 : 0] s_axis_phase_tdata.m_axis_data_tvalid(),                        // output wire m_axis_data_tvalid.m_axis_data_tdata(W_2Q)                 // output wire [15 : 0] m_axis_data_tdata);  ila_0 ila_0_inst (.clk(sys_clk), // input wire clk.probe0(theta), // input wire [15:0]  probe0  .probe1(fine ), // input wire [15:0]  probe1 .probe2(W_1I ), // input wire [15:0]  probe2 .probe3(W_1Q ), // input wire [15:0]  probe3 .probe4(W_2I ), // input wire [15:0]  probe4 .probe5(W_2Q ) // input wire [15:0]  probe5
);endmodule

基于FPGA的DDS 信号发生器(一)相关推荐

  1. 基于FPGA的DDS信号发生器

    基于FPGA的DDS信号发生器     两个礼拜前就像写这个文档了,但是一直鸽到现在,主要是人摆了.还有个技术上的原因是,我想用串口屏显示波形,在串口调试助手上返回的数据是对的,但是发到串口屏上啥反应 ...

  2. 【FPGA实例】基于FPGA的DDS信号发生器设计

    原文链接来源:www.runoob.com 基于FPGA的DDS信号发生器设计 DDS 原理 ------DDS(直接频率合成) 技术是根据奈奎斯特抽样定理及数字处理技术,把一系列的模拟信号进行不失真 ...

  3. CASE_05 基于FPGA的DDS信号发生器

             该系类博客序言和资源简介可浏览该博客:PREFACE FPGA经典案例序言 快速了解该系列博客的内容与可用 资源. 目录 1 简介 2 DDS原理与方案 2.1 方案一:基于CORD ...

  4. 基于FPGA的DDS信号发生器(vivado版本)

    一.设计目标 根据DDS技术原理,在vavido上编写DDS信号源硬件逻辑语言,实现频率.幅度.波形可调的信号源发生器. 频率调节分为11个档位,分别是:1Hz.10Hz.100Hz.500Hz.1k ...

  5. 基于FPGA的DDS 信号发生器(三)

    控制正弦波的频率和相位(频率控制字+相位控制字) 1 DDS原理 1.1 书上的解释 1.2 自己的理解 2 DDS IP的参数设置 3 源码 3.1 顶层文件 3.2 频率控制字模块 3.3 相位控 ...

  6. 基于FPGA实现DDS正弦波发生器

    名言:学无止境. 1 开发环境 操作系统:win7 开发软件:ISE14.7 硬件平台:Xilinx FPGA Spartan6 2 DDS简介 DDS(Direct Digital Synthesi ...

  7. 国产紫光FPGA实现DDS信号发生器

    前言 随着信息技术的迅速发展,FPGA作为半定制电路具有可重复编程.计算能力强等优势,进入人们的视野,并在未来将发挥出越来越重要的作用. 作为电子专业的大三学生,我们小组在老师的带领下对现有国产FPG ...

  8. 基于FPGA的DDS算法实现(可调幅值,附ISE联合Modelsim仿真结果)

    基于FPGA的DDS算法实现(附ISE联合Modelsim仿真结果) 声明:这篇博客是在充分参考前人成果的基础上写成的,如有侵权,请联系我作进一步处理.此外,这是我第一次写博客,描述不准确之处敬请指出 ...

  9. 基于FPGA的混沌信号发生器设计与实现

    提出基于FPGA设计混沌信号发生器的一种改进方法.首先,采用Euler算法,将连续混沌系统转换为离散混沌系统.其次,基于IEEE-754单精度浮点数标准和模块化设计理念,利用Quartus II软件, ...

最新文章

  1. jquery autocomplete demo
  2. KVM、QEMU和KQemu的区别:
  3. hdu4971 流-最大权闭包
  4. 本地共享映射文件夹进行删除操作_从集群建立到航测建模CC(Smart3D)实用操作教程...
  5. stm32 窗口看门狗学习(二)
  6. 有关凸集的证明例题_第1章引言题解1. 用定义验证下列各集合是凸集: (1) S={(X1 ......
  7. 自考专科计算机信息管理专业好,计算机信息管理(专科)专业介绍
  8. php模板中的数组在哪,php – Twig:从包含的模板中添加项目到数组
  9. c# Linq实现 获得某一个路径下所有文件的名(不含扩展名)
  10. Hive常用命令之MSCK REPAIR TABLE命令概述
  11. 【壁纸小程序】搭建自己的壁纸小程序-微信抖音双端
  12. 【ASE入门学习】ASE入门系列六——塞尔达扰动火焰
  13. JS特效模板精彩案例!
  14. 拍摄UFP 单一职责原则
  15. 音频wav文件格式分析
  16. 广州小学生米饭行为实验:米饭被大骂一个月会变臭
  17. elementui 按钮 表单_elementUI 学习入门之 Button 按钮
  18. 30岁的程序员,你迷惘了吗?
  19. 临床路径实施难点探讨
  20. 应用训练MNIST的CNN模型识别手写数字图片完整实例(图片来自网上)

热门文章

  1. 【自学C++】C++ cout clog cerr区别
  2. 扒一扒云服务器和VPS主机有啥不一样
  3. 如何区分云服务器和VPS
  4. SpringBoot(3) 获取后台返回字符串对象及json数据
  5. java 为什么要get,set方法
  6. 【C/C++】龙格库塔+亚当姆斯求解数值微分初值问题
  7. 计算机组成原理 — GPU 图形处理器
  8. 基于Matlab软件的视觉导航系统的仿真
  9. 基于视觉导航的自主机器人简介(一)
  10. Android Settings和SettingsProvider源码分析与修改,android开发计算器界面