广告

原创 第三章 3.1——基于FPGA的数控振荡器

2017-9-26 10:13 613 2 2 分类: FPGA/CPLD


一、相关背景

      软件无线电是目前和未来无线通信系统中的关键技术,它的核心思想j让数字化处理(A/D 、D/A)尽量靠近天线,从而将尽可能多的处理通过数字的方式完成。

      数控振荡器(NCO)有多种实现方法,最常用的就是基DDS于直接数字频率合成技术(DDS)的三角函数发生器。与传统的频率合成器相比,DDS具有成本低、功耗低,分辨率高和转换时间短的优点,各种三角函数都可以通过余弦函数来实现。

二、DDS的原理

         在参考时钟的驱动下,相位累加器对频率控制字进行线性累加,得到的相位码对波形存储器寻址,使之输出相应的幅度码,经过模数转换器得到相应的阶梯波,最后用LPF滤波,得到所需频率的平滑连续波形。


       相位累加器由N位加法器与N位累加寄存器级联构成,每来一个时钟脉冲,加法器将频累率控制字 K与累加寄存器输出的累加相位数据相加,把相加后的结果送给累加寄存器的数据输入端。累加寄存器将加法器在上一个时钟脉冲作用后产生的新相位数据反馈到加法器输入端,以使加法器在下一个时钟脉冲下继续与频率控制字相加。这样,相位累加器在时钟作用下不断对频率控制字进行线性相位累加。由此可以看出,相位累加器输出的数据就是合成信号的相位。相位累加器的溢出频率就是DDS输出信号的频率。用相位累加器输出的数据作为ROM的相位取样地址,这样就可以把存储在ROM内的波形抽样值(二进制编码)经查找表查出,完成相位到幅值的转换。



ROM所存储的幅度值与与余弦信号有关。余弦信号波形在一个周期内相位和幅度的变化如图所示。


      

 

  每一个点对应一个特定的幅度值,一个N位相位累加器对应着圆上 2^N 个相位点,其相位分辨率为Δφ= 2*PI / (2^N)。若N=4,则有16中相位值与16种幅度值相对应,并将相应的幅度值存储在ROM中,ROM的字节数决定了相位的量化误差。在实际的DDS中,可利用正弦波的对称性,将2Pi范围内的幅、相点减小到Pi/2内以降低所需的存储量,量化的比特数决定了幅度量化误差。

     ROM输出送到D/A转换器,LPF用于滤除不需要的取样分量。DDS在相对带宽、频率转换时间、分辨率、相位连续性、正交输出以及集成化等一系列性能指标方面远远超过了传统频率合成技术所能达到的水平。

     DDS模块的输出频率fout 是系统工作频率fclk、相位累加器比特数N 以及频率控制字K 的一个函数。

                                                fout =( fclk * K ) / 2^N

它的频率分辨率,即频率的变化间隔为

                                                                                 fclk /2^N


三、matlab生成余弦波的浮点数,并量化为8bit定点数值


x = linspace(0,2*pi,1024);   %在区间[0,6.28]之间等间隔取1024点
y1 = cos(x);
%%由于正余弦波形的值在[0,1]之间,需要量化为8bit,先将数值放大
y1 = y1 * 2^7;  %在8bit数据的基础上产生数据,所以要乘以2^7
%再将放大的浮点值量化,并写到coe文本中
fid = fopen('G:/cos_coe.coe','wt');
fprintf(fid,'%.0f,\n',y1); %在写文件时量化为 8bit
fclose(fid);


memory_initialization_radix=10;
memory_initialization_vector=


四、把coe加载到ROM

     新建一个工程,添加一个 ROM 核,深度设置为1024,位宽8比特



加载coe文件,进制为10



五、编写顶层verilog文件

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2017/09/05 14:54:28
// Design Name:
// Module Name: nco_dds
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////

module nco_dds(
        input RSTn,
        input clk_100M,
       
        output [7:0] cos_data
    );
   
reg [9:0] rom_addr;
wire [7:0] rom_data;
wire clk_5M;
assign cos_data = rom_data;
//*******************************************************************
always @(posedge clk_5M or negedge RSTn)begin
   if(!RSTn)begin
        rom_addr <= 10'd0;
   end
   else begin
   
        rom_addr <= rom_addr + 1'b1;
   end
   
   
end


 clk_wiz_0 instance_name
   (
    // Clock out ports
    .clk_5M(clk_5M),     // output clk_5M
    // Status and control signals
    .reset(!RSTn), // input reset
    .locked(locked),       // output locked
   // Clock in ports
    .clk_in1(clk_100M)
    );      // input clk_in1  
   
dist_mem_gen_0 your_instance_name (
  .a(rom_addr),      // input wire [9 : 0] a
  .spo(rom_data)  // output wire [7 : 0] spo
);
   
endmodule




六、编写测试文件

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2017/09/05 15:10:16
// Design Name:
// Module Name: simu
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////

module simu(
    );
reg RSTn;
reg clk_100M;
wire [7:0] cos_data;
initial begin
    RSTn = 0;
    clk_100M =0;
    #20;
    RSTn = 1;
       
end  
always #5 clk_100M = ~clk_100M; 
nco_dds U1
(
    .RSTn(RSTn),
    .clk_100M(clk_100M),
   
    .cos_data(cos_data)
);  
   
endmodule


仿真波形(波形有畸变,目前没有找到问题所在)




广告

文章评论 0条评论)

登录后参与讨论
相关推荐阅读
LoneSurvivor 2018-02-25 08:26
C++输入/输出流(2)
1. get()函数#include<iostream>using namespace std;int main(){    char s1[80], s2[...
LoneSurvivor 2018-02-23 12:19
C++输入/输出流(1)
1. 输入/输出流类层次 C++的输入/输出流类库是用派生方法建立起的,它有2个平行的基类,streambuf和ios。其他的流类都是从这两个基类直接或间接派生的。1.1  ...
LoneSurvivor 2018-02-19 11:36
C++多态(4)——特殊运算符重载和类类型转换
1.“++”和“--”的重载     运算符“++”和“--”的重载要区分前置和后置两种形式。如果不区分前置和后置,则使用operator++()或operator—()即可...
LoneSurvivor 2018-02-12 11:15
C++多态(3)——运算符重载
1.     运算符重载的定义     运算符重载也是实现多态的一个重要手段。运算符重载实现的是编译时的多态,即静态多态性。C++预...
LoneSurvivor 2018-02-12 10:31
C++多态(2)——纯虚函数与抽象类
   抽象类是一种特殊的类,它提供了统一的操作界面。建立抽象类是为了多态地使用抽象类的成员函数。抽象类是包含纯虚函数的类。 1.    ...
LoneSurvivor 2018-02-11 16:24
C++多态(1)
1.     多态      多态是人类思维方式的一种直接模拟,多态性是指不同对象接收到相同的消息时,根据对象类的不同而产...
我要评论
0
2
广告
关闭 热点推荐上一条 /1 下一条