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);
通過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 begin
sclk =0;
rst_n=0;
#100
rst_n =1;
end
always #10 sclk =~sclk;//50Mhz
ex_dds ex_dds_inst(
.sclk (sclk),
.rst_n (rst_n),
.o_wave (o_wave)
);
endmodule
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
此時通過計數器,實作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
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
該模塊中通過例化兩個RAM來生成兩個正弦波形,通過例化一個乘法器來實作兩個正弦信號的混頻,
3、testbench檔案
`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;//50Mhz
ex_dds ex_dds_inst(
.sclk (sclk),
.rst_n (rst_n),
.o_wave (o_wave)
);
endmodule
4、仿真波形

從波形中可以看出,下面兩個不同頻率的正弦信號進行混頻后,生成了含兩個頻率分量的信號o_wave,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/214343.html
標籤:其他
上一篇:Arm Keil MDK V5.32版本更新,米爾官網高速下載通道
下一篇:unity3D開發
