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:N if fix_p_sin_data(i)<0
fix_p_sin_data(i)=N+fix_p_sin_data(i);%將負數搬到128到256之間(用255加即可) else
fix_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:N
fprintf(fid,'%d:%d; \n',i-1,fix_p_sin_data(i));end
fprintf(fid,'END; \n');fclose(fid);123456789101112131415161718192021222324252627282930313233
透過
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
12345678910111213141516171819202122
其中例化的深度256,位寬為8的RAM是直接呼叫IP核產生的。
4、testbenc h 檔案
`timescale 1ns/1ns
module tb_ex_dds;reg sclk,rst_n;wire [7:0] o_wave;initial begin
sclk =0;
rst_n=0;
#100
rst_n =1;end
always #10 sclk =~sclk;//50Mhzex_dds ex_dds_inst(
.sclk (sclk),
.rst_n (rst_n),
.o_wave (o_wave));endmodule1234567891011121314151617181920
5、模擬波形
將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;
else
div_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
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859
此時透過計數器,實現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取樣頻率能夠識別出來的頻率。
/lanzhou/
兩個峰的點分別是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);1234567891011121314
2、design檔案
本實驗設計1Khz的正弦訊號和10Khz的正弦訊號進行混頻。
透過計算:
(1)1Khz:M=1000 * 2^32/50e6=85899
(2)10Khz:M=10000 * 2^32/50e6=858993
module ex_dds(
input wire sclk,//50Mhz
input wire rst_n,
output wire [15:0] o_wave);parameter FRQ_W_1k=32'd85899;
parameter FRQ_W_10k=32'd858993;reg [31:0] phase_sum_1k,phase_sum_10k;wire [7:0] addr_1k,addr_10k;wire [7:0] o_wave_1k;wire [7:0] o_wave_10k;//
reg [22:0] sum;reg [14:0] sum_cnt;reg sum_flag;reg [22:0] sum_r;always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
sum_cnt <= 'd0;
else if(sum_cnt == 'd29999)
sum_cnt <='d0;
else
sum_cnt <= sum_cnt + 1'b1;
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
sum_flag<= 1'b0;
else if(sum_cnt == 'd29999)
sum_flag <= 1'b1;
else
sum_flag <= 1'b0;always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
sum <= 'd0;
else if(sum_flag == 1'b1)
sum <= {{15{o_wave_1k[7]}},o_wave_1k};
else
sum <= sum + {{15{o_wave_1k[7]}},o_wave_1k};
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
sum_r <= 'd0;
else if(sum_flag == 1'b1)
sum_r <= sum;always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
phase_sum_1k<='d0;
else
phase_sum_1k <= phase_sum_1k + FRQ_W_1k ;
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
phase_sum_10k<='d0;
else
phase_sum_10k <= phase_sum_10k + FRQ_W_10k ;assign addr_1k=phase_sum_1k[31:24];assign addr_10k=phase_sum_10k[31:24];//混頻器
mult_8x8_l0 mult_8x8_l0_inst (
.dataa ( o_wave_1k ),
.datab ( o_wave_10k ),
.result ( o_wave )
);sp_ram_256x8 sp_ram_256x8_inst (
.address ( addr_1k ),
.clock ( sclk ),
.data ( 8'd0 ),
.wren ( 1'b0 ),
.q ( o_wave_1k )
);sp_ram_256x8 sp_ram_256x8_inst_1 (
.address ( addr_10k ),
.clock ( sclk ),
.data ( 8'd0 ),
.wren ( 1'b0 ),
.q ( o_wave_10k )
);endmodule
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
該模組中透過例化兩個RAM來生成兩個正弦波形,透過例化一個乘法器來實現兩個正弦訊號的混頻。
3、testbench 檔案
/petitmal/
`timescale 1ns/1ns
module tb_ex_dds;reg sclk,rst_n;wire [15:0] o_wave;initial begin
sclk =0;
rst_n=0;
#100
rst_n =1;end
always #10 sclk =~sclk;//50Mhzex_dds ex_dds_inst(
.sclk (sclk),
.rst_n (rst_n),
.o_wave (o_wave));endmodule1234567891011121314151617181920
4、模擬波形
從波形中可以看出,下面兩個不同頻率的正弦訊號進行混頻後,生成了含兩個頻率分量的訊號o_wave。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/30239065/viewspace-2734214/,如需轉載,請註明出處,否則將追究法律責任。