Xilinx-Verilog-学习笔记(19):正弦波信号发生器与DDS
Xilinx-Verilog-學習筆記(19):正弦波信號發生器與DDS
一、正弦波信號發生器
1、浮點數的定點化
這里以2.918為例,實現浮點數向定點數的轉換:
(1)在進行浮點轉定點之前,要先確定整數部分位寬和小數部分位寬。3位整數位寬,12位的小數位寬,最高位的符號位1位。
(2)15位寬的數能夠表示的數值范圍為-32768到32767。整數部分3位寬的數最大能表示到8,因此最大精度為8/32767=0.000244140625。
(3)2.918進行定點化的過程為2.918/(8/32768)=11952.128~=11952這個值就是定點后的2.918的值。而最后的0.128就是定點化會帶來量化誤差。
2、用matlab生成正弦波并進行量化處理
量化處理
量化在數字信號處理領域,是指將信號的連續取值(或者大量可能的離散取值)近似為有限多個(或較少的)離散值的過程。
正弦波量化思想
本實驗通過256個位寬為8的數據對正弦信號進行采樣,以對一個周期的正弦信號進行量化處理。每個數據位寬為8,相當于把正弦信號的幅度從-1到1進行256份等間隔劃分;采樣點數為256個,相當于對一個正弦周期等間隔地采樣了256個點。
量化后的數據由256個介于-1到1之間的數構成,之后將浮點型的數值進行定點化的轉換,使其為0~256之間的整數。(具體處理方法見代碼)
MatLab代碼:
clc; clear all; N=2^8; s_p=0:255;%正弦波一個周期的采樣點數 sin_data=sin(2*pi*s_p/N);%256個介于-1到1之間的數%打印我們的波形 % plot(sin_data,'r*'); % hold on; % plot(sin_data);%定點化 fix_p_sin_data=fix(sin_data*127);%256個介于-128到127之間的數 for i=1:Nif fix_p_sin_data(i)<0fix_p_sin_data(i)=N+fix_p_sin_data(i);%將負數搬到128到256之間(用255加即可)elsefix_p_sin_data(i)=fix_p_sin_data(i);%整數不用管end end%以下是生成mif文件,用于RAM的初始化 fid=fopen('sp_ram_256x8.mif','w+'); fprintf(fid,'WIDTH=8;\n'); fprintf(fid,'DEPTH=256;\n'); fprintf(fid,'ADDRESS_RADIX=UNS;\n'); fprintf(fid,'DATA_RADIX=UNS;\n'); fprintf(fid,'CONTENT BEGIN \n'); for i=1:Nfprintf(fid,'%d:%d; \n',i-1,fix_p_sin_data(i)); end fprintf(fid,'END; \n'); fclose(fid);通過sin_data=sin(2 * pi * s_p/N); 即可實現對一個正弦周期的量化。
3、design文件
module ex_dds(input wire sclk,input wire rst_n,output wire [7:0] o_wave );reg [7:0] addr;always @(posedge sclk or negedge rst_n)if(rst_n == 1'b0)addr <= 'd0;else addr <= addr + 1'b1;sp_ram_256x8 sp_ram_256x8_inst (.address ( addr ),.clock ( sclk ),.data ( 8'd0 ),.wren ( 1'b0 ),.q ( o_wave )); endmodule其中例化的深度256,位寬為8的RAM是直接調用IP核產生的。
4、testbench文件
`timescale 1ns/1ns module tb_ex_dds; reg sclk,rst_n; wire [7:0] o_wave; initial beginsclk =0;rst_n=0;#100 rst_n =1; endalways #10 sclk =~sclk;//50Mhzex_dds ex_dds_inst(.sclk (sclk),.rst_n (rst_n),.o_wave (o_wave) );endmodule5、仿真波形
將RAM輸出的數值用模擬波形表示出來,可以看出是正弦信號。對于地址是鋸齒波,因為是從0到255然后再到0。
二、DDS直接頻率合成器
1、基本原理
- fc為每秒鐘累加多少次,2^n為累加器能夠累加到的最大范圍,所以fc/2 ^n為每秒鐘累加器會溢出多少次,即為周期(分辨率)。提高相位累加器的位寬n可以調高頻率分辨率。
- 存儲正弦的RAM深度或者叫正弦波一個周期量化的點數,量化的點數越多生成的正弦波相位噪聲低。
- M是控制字,通過頻率控制字來產生不同的頻率。
這里相位累加寄存器的位寬為32,目標實現1Mhz的信號:
(1)控制字設置:1e6=M * 50e6/2^32,則M=1e6 * 2^32/50e6~=85899345.
(2)相位累加器為32位,而最終輸出為8位,為了取整數倍,因此取相位累加器的高8位。
可以得到1Mhz的正弦周期。因此,通過修改M的值可以調節正弦信號的頻率。
于是我們可以設計過一段時間將M的值增大一定值,即可實現頻率的連續變換:
2、design文件
module ex_dds(input wire sclk,input wire rst_n,output wire [7:0] o_wave );parameter FRQ_W=32'd85899346; //相當于M parameter FRQ_ADD=32'd85899346/2; //相當于遞增量 reg [31:0] phase_sum; wire [7:0] addr; reg [31:0] frq_word; reg [6:0] div_cnt; reg div_flag;//記100個時鐘周期,M的值遞增一次 always @(posedge sclk or negedge rst_n)if(rst_n == 1'b0)div_cnt <= 1'b0;else if(div_cnt == 7'd99)div_cnt <= 1'b0;else div_cnt <= div_cnt + 1'b1;always @(posedge sclk or negedge rst_n) if(rst_n == 1'b0)div_flag <= 1'b0;else if(div_cnt == 7'd99)div_flag <= 1'b1;elsediv_flag <= 1'b0;always @(posedge sclk or negedge rst_n)if(rst_n == 1'b0)frq_word <= FRQ_W;else if(div_flag == 1'b1)frq_word <= frq_word + FRQ_ADD;always @(posedge sclk or negedge rst_n)if(rst_n == 1'b0)phase_sum <= 'd0;else phase_sum <= phase_sum + frq_word;assign addr = phase_sum[31:24];/* always @(posedge sclk or negedge rst_n)if(rst_n == 1'b0)addr <= 'd0;else addr <= addr + 1'b1; */sp_ram_256x8 sp_ram_256x8_inst (.address ( addr ),.clock ( sclk ),.data ( 8'd0 ),.wren ( 1'b0 ),.q ( o_wave )); endmodule此時通過計數器,實現100個時鐘周期變頻一次。
如果用于高速電路的話,不要直接用分頻器作為標志,可以通過定義一個div_flag作為標志。
3、仿真波形
從波形可以看出,隨著M的逐漸增大,時鐘頻率也越來越高。
三、混頻器
混頻器的主要任務是將兩個不同頻率的信號進行疊加。
1、MatLab代碼
(1)首先定義好采樣率,兩個時鐘的頻率,從圖中可以看出,紅色的時鐘頻率是藍色的5倍。
(2)然后是混頻,混頻后的到的信號包含兩個頻率分量,一個是f1+f2,一個是f1-f2,即一個6Mhz,一個4Mhz。從時域信號中我們難以看出結果是否正確,因此需要對其進行FFT變換,從頻域分析。
前1024個點表示正頻域,后1024個點表示復頻域,因此只需要看前1024個即可。
頻率分辨率與FFT計算的點數N、采樣頻率fs都有關。頻率分辨率=fs/N
50M/2048=0.0244Mhz,這是FFT中能夠分辨出的最低的頻率,用0.0244*1024=25Mhz,正好是50Mhz采樣頻率能夠識別出來的頻率。
兩個峰的點分別是165和247,0.0244 *165=4Mhz,0.0244 * 247=6Mhz,正好是混頻后的兩個頻率分量。
clc; clear all; fs=50e6; %50Mhz采樣率 f1=1e6; %1Mhz頻率 f2=5e6; %5Mhz頻率 n=0:2047; s_1=sin(2*pi*n*f1/fs); s_2=sin(2*pi*n*f2/fs);%s_1和s_2混頻,就是相乘 s_12=s_1.*s_2; %混頻后包含兩個頻率分量,一個是f1+f2一個是f1-f2 %頻域分析 fft_out=fft(s_12,2048); fft_abs=abs(fft_out);2、design文件
本實驗設計1Khz的正弦信號和10Khz的正弦信號進行混頻。
通過計算:
(1)1Khz:M=1000 * 2^32/50e6=85899
(2)10Khz:M=10000 * 2^32/50e6=858993
該模塊中通過例化兩個RAM來生成兩個正弦波形,通過例化一個乘法器來實現兩個正弦信號的混頻。
3、testbench文件
`timescale 1ns/1ns module tb_ex_dds; reg sclk,rst_n; wire [15:0] o_wave; initial beginsclk =0;rst_n=0;#100 rst_n =1; endalways #10 sclk =~sclk;//50Mhzex_dds ex_dds_inst(.sclk (sclk),.rst_n (rst_n),.o_wave (o_wave) );endmodule4、仿真波形
從波形中可以看出,下面兩個不同頻率的正弦信號進行混頻后,生成了含兩個頻率分量的信號o_wave。
總結
以上是生活随笔為你收集整理的Xilinx-Verilog-学习笔记(19):正弦波信号发生器与DDS的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 虹科ELPRO的智能数据记录仪由Sens
- 下一篇: 十大IT网站排名 及IT论坛(技术社区)