首页天道酬勤相位调制原理,相位比较法数据处理

相位调制原理,相位比较法数据处理

张世龙 05-13 06:14 37次浏览

1、理论DDS技术是一种新型的频率合成方法,具有低成本、低功耗、高分辨率和快速转换时间等优点,对数字信号处理及其硬件的实现具有重要作用。 ds的基本结构主要由相位累加器、相位调制器、波形数据表ROM、D/A转换器等四种结构组成,其中数模转换器后增加低通滤波器的设计也很多。 ds结构的示意图如下。

现在看这张图可能不太清楚,没关系。 有印象就好了。

2、DDS的实现将逐步实现正弦波发生器。

2.1、相位累加器首先使用上位机软件生成正弦波的MIF文件。 我在这里正点原子的上位机WaveToMif:

位宽设定为8,深度设定为4096。 这样,我们将一个正弦波形分解为4096个数据。 每个数据的大小是当前位的值。 然后,生成宽8位、深4096的ROM,并将此MIF文件保存在ROM中。 到时候读出他,就会构成完整的正弦波。

首先,为了输出正弦波,写以下的Verilog代码。

模块DDS (inputsys _ clk,//系统时钟,50MHz input sys_rst_n,//复位信号,低电平有效output(7:0 ) data_out/////参数定义parameter FREQ_CTRL=12'd1; //相位累加器一次累积值//reg定义reg[11:0]rom_addr; //ROM地址reg [11:0]fre_adder; //累加器//相位累加器赋值always @ (posedge sys _ clkornegedgesys _ rst _ n ) beginif(sys_rst_n==1'B0 ) fre _ end//ROM读取地址赋值always @ (posedge sys _ clkornegedgesys _ rst _ n ) beginif(sys_rst_n==1'B0 ) rom _ addr=end------------------------------------ -模块化------------------- -。

第一个always块将值指派给定义的相位累加器,每时钟周期(20ns )累积FREQ_CTRL ),由此设定的第一个always块将相位累加器的值读取到ROM ROM的值在每个时钟周期内递增1,到地址溢出(4096 )后再开始循环。 就这样,我们每次都

使用以下测试bench进行模拟(仅实例化了此模块,在后续模拟中仍使用此测试bench ) :

`时间比例1 ns/1 ns module TB _ DDS (; //wiredefinewire [ 7:0 ] data _ out; //reg definereg sys_clk; reg sys_rst_n; initial begin sys_clk=1'b0; sys_rst_n=1'b0; #200; sys_rst_n=1'b1; endalways #10 sys_clk=~sys_clk; //----------top _ DDS _ inst------------ DD sdds _ inst-------- sys _ clk (,//) (这里的误差来源于不能正确放置基准线。 以下相同) ) )。

当输出以上波形的正弦波时,20ns4096=81920ns; 20ns是采样时钟Fclk的倒数1/Fclk,81920ns是输出时钟的周期,也是输出频率Fout的倒数1/Fout,4

096是相位累加器(12位宽:N)的最大值,所以有:1/Fclk✖(2的N次方)= 1/Fout----公式(1)

那么在这个频率的基础上怎么进行调节?

这个波形是每个时钟周期ROM的读取地址+1,假设我们每隔两个时钟周期,才将ROM的地址+1,那么输出波形的周期不就变成之前的两倍,频率变为一半了嘛(6100Hz)!

稍微更改Verilog文件:把相位累加器的位宽从12位改为13位,但是将相位累加器的值赋值给ROM地址的时候只使用高12位;这样相位累加器的低1位每隔2才会向高12位进位,高12位每隔两个时钟周期才会+1,从而实现了每隔两个时钟周期ROM的读取地址+1。

module dds( input sys_clk , //系统时钟,50MHz input sys_rst_n , //复位信号,低电平有效 output [7:0] data_out //波形输出);//parameter定义parameter FREQ_CTRL = 12'd1;//相位累加器单次累加值//reg 定义reg[11:0]rom_addr;//ROM地址reg [12:0]fre_adder;//累加器//相位累加器赋值always@(posedge sys_clk or negedge sys_rst_n)begin if(sys_rst_n == 1'b0) fre_adder <= 12'd0; elsefre_adder <= fre_adder + FREQ_CTRL;end//ROM读地址赋值always@(posedge sys_clk or negedge sys_rst_n)begin if(sys_rst_n == 1'b0)rom_addr <= 12'd0;elserom_addr <= fre_adder[12:1];end//------------------------- 模块例化------------------------//例化ROM模块rom_ddsrom_dds_inst (.address ( rom_addr ),//ROM读地址.clock ( sys_clk ), //读时钟.rden ( 1'b1 ), //读使能.q ( data_out ) //读出波形数据);endmodule

 使用modelsim进行联合仿真,结果如下:

 可以看到将相位累加器的位宽增加就可以将频率相应的缩小了。如果使用20位宽的相位累加器,并使用高12位(因为ROM地址位宽是12位)对ROM地址赋值,且每个时钟周期低8位累加1,那么低8位需要2的8次方(256)个时钟周期才会向高12位进位(高12位+1,ROM地址+1),那么输出信号的频率应该就是12位位宽相位累加器输出频率(12207Hz)的256分之一,即47.68Hz,更改Verilog,并进行仿真,仿真结果如下,与推论的一致:

module dds( input sys_clk , //系统时钟,50MHz input sys_rst_n , //复位信号,低电平有效 output [7:0] data_out //波形输出);//parameter定义parameter FREQ_CTRL = 12'd1;//相位累加器单次累加值//reg 定义reg[11:0]rom_addr;//ROM地址reg [19:0]fre_adder;//累加器//相位累加器赋值always@(posedge sys_clk or negedge sys_rst_n)begin if(sys_rst_n == 1'b0) fre_adder <= 12'd0; elsefre_adder <= fre_adder + FREQ_CTRL;end//ROM读地址赋值always@(posedge sys_clk or negedge sys_rst_n)begin if(sys_rst_n == 1'b0)rom_addr <= 12'd0;elserom_addr <= fre_adder[19:8];end//------------------------- 模块例化------------------------//例化ROM模块rom_ddsrom_dds_inst (.address ( rom_addr ),//ROM读地址.clock ( sys_clk ), //读时钟.rden ( 1'b1 ), //读使能.q ( data_out ) //读出波形数据);endmodule

 到这里看似通过改变相位累加器的位宽从而实现了控制波形的输出频率,但是在实际模块调用中,相位累加器的位宽都是固定的,那么我们位宽被BAN了,应该怎么办呢?

这里我们编写Verilog模块时候,每次相位累加器的值都是每个时钟周期+1,这个1还是用参数FREQ_CTRL 定义的,之所以用参数定义,就是为了方便更改。

设想一下,一个20位宽的相位累加器,并使用高12位(因为ROM地址位宽是12位)对ROM地址赋值,如果每个时钟周期加的不是1,而是其他值(比如2的4次方16),那么低8位是不是只要2的4次方=16(2的8次方/2的4次方)就会溢出,向高12位进位?所以在这种情况下,输出频率应该是赏赐47.68Hz的16倍,即762.93Hz.

照例更改代码,进行仿真:

module dds( input sys_clk , //系统时钟,50MHz input sys_rst_n , //复位信号,低电平有效 output [7:0] data_out //波形输出);//parameter定义parameter FREQ_CTRL = 12'd16;//相位累加器单次累加值//reg 定义reg[11:0]rom_addr;//ROM地址reg [19:0]fre_adder;//累加器//相位累加器赋值always@(posedge sys_clk or negedge sys_rst_n)begin if(sys_rst_n == 1'b0) fre_adder <= 12'd0; elsefre_adder <= fre_adder + FREQ_CTRL;end//ROM读地址赋值always@(posedge sys_clk or negedge sys_rst_n)begin if(sys_rst_n == 1'b0)rom_addr <= 12'd0;elserom_addr <= fre_adder[19:8];end//------------------------- 模块例化------------------------//例化ROM模块rom_ddsrom_dds_inst (.address ( rom_addr ),//ROM读地址.clock ( sys_clk ), //读时钟.rden ( 1'b1 ), //读使能.q ( data_out ) //读出波形数据);endmodule

 这样在公式(1)----1/Fclk✖(2的N次方)= 1/Fout的基础上,将频率控制字K加进去    1/Fclk✖(2的N次方)/K= 1/Fout,即公式(2)----K = 2的N次方 * fOUT / fCLK  ,这样我们就得到了DDS的频率控制字的算法

2.2、相位调制器

从上面的分析可以知道,从ROM里面读取数据(地址从0到最大)就可以输出一个完整的波形,那么一个周期就是2的N次(N表示ROM地址位宽)个点,假如我们在读取ROM地址的时候赋一个值初值PHASE_CTRL,那么波形的相位就一定会发生变化。

可以推出如下对应关系:一个周期2π = 4096(2的位宽次方),那么 PHASE_CTRL = 相位偏移量 / 2π ✖ 2的位宽次方。

在上条仿真的基础上,增加一个 π/2(90度)相位的偏移,可以算出PHASE_CTRL应该设置为 π/2/2π ✖ 2的8方=1024。

重新编写Verilog文件,并进行仿真:

module dds( input sys_clk , //系统时钟,50MHz input sys_rst_n , //复位信号,低电平有效 output [7:0] data_out //波形输出);//parameter定义parameter FREQ_CTRL = 12'd16;//相位累加器单次累加值parameter PHASE_CTRL = 12'd1024;//相位偏移量 //reg 定义reg[11:0]rom_addr;//ROM地址reg [19:0]fre_adder;//累加器//相位累加器赋值always@(posedge sys_clk or negedge sys_rst_n)begin if(sys_rst_n == 1'b0) fre_adder <= 12'd0; elsefre_adder <= fre_adder + FREQ_CTRL;end//ROM读地址赋值always@(posedge sys_clk or negedge sys_rst_n)begin if(sys_rst_n == 1'b0)rom_addr <= 12'd0;elserom_addr <= fre_adder[19:8] + PHASE_CTRL; //读取地址还要加上相位偏移量end//------------------------- 模块例化------------------------//例化ROM模块rom_ddsrom_dds_inst (.address ( rom_addr ),//ROM读地址.clock ( sys_clk ), //读时钟.rden ( 1'b1 ), //读使能.q ( data_out ) //读出波形数据);endmodule

可以看到最新输出的波形频率仍然是764赫兹,但是初始相位与之前的相差了90度。

 3、总结

        通过改变频率控制字的大小,可以改变相位累加器的累加速度,间接控制ROM读取速度,从而控制输出波形频率;

        通过改变相位控制字的大小,可以改变相位调制器,间接控制ROM读取的初值,从而控制输出波形的初值;

        假设存储波形的ROM地址位宽为N,设定的相位累加器的位宽为M,采样时钟Fclk,想要输出的时钟为Fout,初始相位为θ,则有如下等式:

                频率控制字:

                相位控制字:

rs485串口,细说linux基础知识pdf 张飞搞笑语录,主角是张飞的小说