Xilinx-Verilog-study notes (19): sine wave signal generator and DDS

Xilinx-Verilog-study notes (19): sine wave signal generator and DDS

1. Sine wave signal generator

1. Fixed-point of floating-point numbers

Here takes 2.918 as an example to realize the conversion of floating-point numbers to fixed-point numbers:

(1) Before converting floating-point to fixed-point, first determine the bit width of the integer part and the decimal part .3-digit integer width, 12-digit decimal width, The most significant sign bit is 1.
(2) The numerical range that can be represented by a 15-bit wide number is -32768 to 32767. The integer part of a 3-bit wide number can be expressed up to 8, so the maximum precision is 8/32767=0.000244140625.
(3) The process of 2.918 fixed-point is 2.918/(8/32768)=11952.128~=11952 This value is the value of 2.918 after fixed-point. The final 0.128 is that fixed-point will bring quantization errors.

2. Use matlab to generate sine waves and quantify them

Quantization processing
Quantization in the field of digital signal processing refers to the process of approximating the continuous value of a signal (or a large number of possible discrete values) to a finite number of (or fewer) discrete values.

The idea of ​​sine wave quantization
This experiment uses 256 data with a bit width of 8 to sample the sine signal to quantize a period of the sine signal. Each data bit width is 8, which is equivalent to dividing the amplitude of the sinusoidal signal from -1 to 1 at 256 equal intervals; the number of sampling points is 256, which is equivalent to sampling 256 points at equal intervals for a sine cycle.

The quantized data is composed of 256 numbers between -1 and 1, and then the floating-point value is converted into fixed-point to make it an integer between 0 and 256. (See the code for specific processing methods)

MatLab code:

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);

bysin_data = sin (2 * pi * s_p / N); It can realize the quantization of a sine cycle.
Insert picture description here

3. Design file

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 

The instantiated RAM with a depth of 256 and a bit width of 8 is generated by directly calling the IP core.

4. Testbench file

`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. Simulation waveform

Insert picture description here

The value of RAM output is expressed by analog waveform, it can be seen that it is a sinusoidal signal. The address is a sawtooth wave, because it goes from 0 to 255 and then to 0.

2. DDS Direct Frequency Synthesizer

1. Basic principles

Insert picture description here

  • fcHow many times are accumulated per second,2^nIs the maximum range that the accumulator can accumulate, sofc/2 ^nHow many times the accumulator will overflow per second is the period (resolution). Increasing the bit width n of the phase accumulator can increase the frequency resolution.
  • Stores the RAM depth of the sine or the number of quantized points in a cycle of the sine wave. The more quantized points, the lower the phase noise of the sine wave.
  • M is the control word, and different frequencies are generated through the frequency control word.

Here the bit width of the phase accumulation register is 32, and the goal is to achieve a 1Mhz signal:

(1) Control word setting: 1e6=M * 50e6/2^32, then M=1e6 * 2^32/50e6~=85899345.
(2) The phase accumulator is 32 bits, and the final output is 8 bits. Integer multiples, so take the upper 8 bits of the phase accumulator.

Insert picture description here
A sine period of 1Mhz can be obtained. Therefore, the frequency of the sinusoidal signal can be adjusted by modifying the value of M.

So we can design to increase the value of M by a certain value after a period of time to achieve continuous frequency conversion:

2. Design file

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 

At this time, through the counter, the frequency conversion is realized once in 100 clock cycles.
If it is used in high-speed circuits, do not directly use the frequency divider as a flag. You can define a div_flag as a flag.

3. Simulation waveform

Insert picture description here
It can be seen from the waveform that as M gradually increases, the clock frequency becomes higher and higher.

Three, the mixer

The main task of the mixer is to superimpose two signals of different frequencies.

1. MatLab code

(1) First define the sampling rate and the frequency of the two clocks. As can be seen from the figure, the red clock frequency is 5 times that of the blue.
Insert picture description here
(2) Then there is mixing. The signal obtained after mixing contains two frequency components, one isf1+f2,one isf1-f2, That is, a 6Mhz, a 4Mhz. It is difficult for us to see whether the result is correct from the time domain signal, so we need to perform FFT transformation on it and analyze it in the frequency domain.
Insert picture description here
The first 1024 points represent the positive frequency domain, and the last 1024 points represent the complex frequency domain, so you only need to look at the first 1024 points.

The frequency resolution is related to the number of points N and the sampling frequency fs calculated by the FFT.Frequency resolution = fs/N
50M/2048=0.0244Mhz, this is the lowest frequency that can be distinguished in FFT, using 0.0244*1024=25Mhz, which is exactly the frequency that can be identified by the 50Mhz sampling frequency.

The points of the two peaks are 165 and 247 respectively, 0.0244 * 165 = 4Mhz, 0.0244 * 247 = 6Mhz, which are exactly the two frequency components after mixing.

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 file

This experiment is designed to mix 1Khz sine signal and 10Khz sine signal.
Through calculation:
(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 

In this module, two RAMs are instantiated to generate two sine waveforms, and a multiplier is instantiated to achieve mixing of two sine signals.

3. Testbench file

`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. Simulation waveform

Insert picture description here
It can be seen from the waveform that the following two sinusoidal signals with different frequencies are mixed to generate a signal o_wave with two frequency components.

Guess you like

Origin blog.csdn.net/qq_42826337/article/details/109613978