加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

dds、MATLAB浮点数定点化、mif文件生成

(2017-01-16 14:25:23)
分类: Matlab与FPGA联合仿真
2017年1月7日18:20:29 dds-正弦波发生器

1、
(1)将连续的正弦波信号离散化--应用MATLAB软件进行实现;
(2)1)将离散化后的正弦波一个整周期存储到ram中--将离散后的数据进行定点化:ram规格为256x8bit,数据规格为1bit符号位,7bit小数位。
--由于8bit有符号数能表示的数值范围为-128~+127(-1~0使用128份量化,0~1使用128份定点化,-1最终定点化后为-127,+1定点化后为+127),所以应让采样得到的数据全部乘以127后取整数部分得到定点化后的数据(此时还是有小数部分的)。
--使用MATLAB中的fix函数对数据去小数。
2)创建一个ram,用于存储离散的数据。
(3)将上面所得数据表示成二进制补码形式,以便在FPGA中存储--上面处理完的数据全部加256(2^8=8位二进制数所能表示的最大数据+1)所得到的十进制数,取其二进制表示的低8bit就是这个数据的二进制补码表示形式-->将前面的有符号数使用无符号数量化。新的数据0~127表示原来的复数,新的数据128~255表示原来的正数。
2、MATLAB中,在Command Window(命令行窗口中)输入clc--清空命令行窗口;输入clear--清空Workspace
3、MATLAB中,两个向量相乘使用".*",一个向量和一个实数或者两个实数相乘用"*"。
4、MATLAB中,在Command Window窗口中输入help+函数名,可得到函数的用法。
5、MATLAB中,hold on使图像保持,在此图像基础上进行编辑。
6、由于正弦波中的所有数值都在-1~+1之间,所以根据笔记12中浮点数定点化的方法,只需1bit符号位,其余都为小数位。
7、MATLAB中,floor函数是对数据进行向左取整。round函数是对数据小数部分进行四舍五入取整。fix函数是将小数点后的部分直接去掉。
8、MATLAB中数组下标是从1开始的。
9、有符号m使用n二进制补码表示方法(m<2^n,MATLAB代码中用到的方法):2^n+m(肯定是正的)的二进制码表示就是最终结果。
比如使用8bit的二进制无符号数表示 -64的补码形式:2^8=256,256-64=192(1100_0000),-->1100_0000就是-64的8bit补码表示。
比如使用8bit表示64:2^8=256,256+64=320(1_0100_0000),-->取低8位0100_0000就是64的bit有符号补码表示。
10、生成正弦波的频率是50M/256。
11、always @ (posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
addr <= 8'd0;
else
addr <= addr + 1'b1; //若为addr+8'd2;那么出来正弦波的频率将变为2倍--地址累加量称为频率控制字。改变地址的递增量,那么正弦波的频率会变化,两者成正比。addr+1'b1的时候也是频率分辨率最小的时候,也就是能达到的最小的正弦波频率。若采样时钟频率为fc,频率控制字的位宽为n,那么最小频率分辨率(最小正弦波频率)为fc/(2^n)。当采样时钟不变,但是最终正弦波频率变大--是由于每个正弦波内的采样点数变少了,所以,单位时间采样的正弦波个数变多了。
12、奈奎斯特采样定理决定:正弦信号每个周期只要采样两个或两个以上点,最终都可以恢复原来波形。
13、dds设计框图如下。图中公式中,f0是最终输出的正弦波的频率,fc是对正弦波进行采样的时钟的频率,n为频率控制字总线的位宽(也就是上面addr<=addr+1'b1;中的1'b1,可设置任意宽度,只要保证不大于采样时钟频率就好),那么要满足奈奎斯特采样定理,只需要f0大于等于25M即可(f0=M*fc/2^n=25M,由于fc=50M-->M/2^n=1/2-->若n=8,那么M=2^7=128),也就是每个周期采样两个点,这也是最低采样速率。下图公式中求得的M*fc/2^n,表示每秒叠加fc次M。
14、对于公式中所谓的频率分辨率的理解:公式中,f0=M*fc\2^n中,n为相位累加器的位宽,fc\2^n就是每次可调整的最小频率的大小,可以在这个基础上控制M来调整当前输出的正弦波频率。当M确定之后,输出正弦波的频率就确定了。M*fc\^n中M\2^n的配合最终导致的结果就是使得地址递增频率和每次递增的量值的变化,这就是所谓的采样点数的变化,最终弄表现就是输出正弦波频率的变化。
15、ram中存储的是256个采样点的幅值,图中ram地址为8bit,是截取相位累加器的高8bit得到,这样的截取不会影响频率分辨率。不一定保证每个时钟相位累加器高8bit都递增1,也就是ram地址递增1。也可能导致每个时钟累加器高8bit递增0、2、3、4...等。

16、混频器--先使用MATLAB进行验证,其次使用FPGA实现。
混频:就是两个不同频率的信号进行相乘。相乘后会产生哪些新的频率分量的信号??
17、modelsim仿真输出混频后的信号o_wave,由于是16bit位宽,所以设置模拟波形信号显示方式的时候,最大/小值应改为2^16~-2^16即-32768~32768,否则会显示溢出。
18、混频后的信号输出波形如下,含有4K和6K两个分量。若想取4K--加低通滤波器。
平滑:就是求平均,积分器能带来平滑作用。将连续的许多点累加求得平均值可起到平滑作用。累加器可以起到滤波的作用,对于一个信号如果累加长度够长,就可对一个信号进行平均。假设对于1K的正弦波进行5000个点的积分(累加)。
19、将加法器的一个输入端连在数据输入端口,另一个输入端连接在寄存器的输出端口,寄存器的输入接在加法器的输出端面积构成了一个累加器。
 

//--------------ex_dds.v-----------------------------------------------
 module ex_dds(
input wire sclk, //50M
input wire rst_n,
output wire [7:0] o_wave
);
parameter FRQ_W = 32'd85899346; //32'd85899346--1M
parameter FRQ_ADD = 32'd85899346/2;
parameter INI_PHASE = 32'd2147483648; //初始相位

reg [31:0] phase_sum; //相位累加器 
wire [7:0] addr;
reg [31:0] frq_word; //频率控制字
reg [6:0] div_cnt;
reg div_flag;

//控制频率控制字的变化
always @ (posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
div_cnt <= 7'd0;
else if(div_cnt == 7'd99)
div_cnt <= 7'd0;
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; //每过100个clk频率控制字递增一个FRQ_ADD大小

always @ (posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
phase_sum <= INI_PHASE;
else
phase_sum <= phase_sum + frq_word; //相位累加器

assign addr = phase_sum[31:24]; //ram地址位宽转换,若取低8位那么不是成比例的???

//always @ (posedge sclk or negedge rst_n)
// if(rst_n == 1'b0)
// addr <= 8'd0;
// else
// addr <= addr + 8'd125; //若为addr+2'd2;那么出来正弦波的频率将变为2倍

sp_ram_256x8 sp_ram_256x8_inst (
.address ( addr ),
.clock ( sclk ),
.data ( 8'd0 ),
.wren ( 1'b0 ),
.q ( o_wave )
);


endmodule 

//-----------tb_ex_dds.v------------------------------------------------------
`timescale 1ns / 1ns
module tb_ex_dds;
reg sclk;
reg rst_n;

wire [7:0] o_wave;

initial begin
sclk = 0;
rst_n = 0;
#100;
rst_n = 1;
end 

always #10 sclk <= ~sclk;

ex_dds ex_dds_inst(
.sclk (sclk ),
.rst_n (rst_n ),
.o_wave (o_wave )
);


endmodule  
   
//--------------run.do-------------------------------------------------
quit -sim
.main clear

vlib work 

vlog ./tb_ex_dds.v
vlog ./../design/*.v
vlog ./../quartus_prj/ipcore_dir/sp_ram_256x8.v
vlog ./altera_lib/*.v

vsim -voptargs=+acc work.tb_ex_dds

add wave tb_ex_dds/*
add wave tb_ex_dds/ex_dds_inst/*

run 10us

//-------混频器和平滑滤波的-ex_dds_org.v----------------------------------------------------
module ex_dds_org(
input wire sclk, //50M
input wire rst_n,
output wire [15:0] o_wave
);
//1kHz和10kHz混频器设计
parameter FRQ_W_1k = 32'd85899; //32'd85899346--1M
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
wire [7:0] o_wave_10k;

//积分器--累加累加器就是比加法器多一个寄存器用来存取前面加过的数据,寄存器是需要时钟驱动的。
reg [22:0] sum;
reg [15: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 == 'd24999) //ram中存储的是50M/256的正弦波,也就是每个周期采样256个点,每秒采样50M个点--50M/256个周期的数据。原始正弦波的采样频率---ram的时钟频率,为50MHz(每秒采样50M个点),正弦波的频率为1KHz(每秒显示1K个正弦波),也就是最终的1K的正弦波每个周期采样的数据点数为50M/1k=50000,每经过25000个点(25000个采样时钟)积分一次,相当于每个周期采样两次,还是可以恢复原始正弦波的。
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 == 'd24999)
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}; //由于是有符号数,所以需要进行符号位扩展,进行位宽拼接12{o_wave_1k[7]}-->把o_wave_1k[7]拼接12次
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; //此时的sum为前面25000个数据的和,也是平滑滤波后的信号
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]; //ram地址位宽转换,若取低8位那么不是成比例的???
assign addr_10k = phase_sum_10k[31:24];

sp_ram_256x8 sp_ram_256x8_1k_inst (
.address ( addr_1k ),
.clock ( sclk ),
.data ( 8'd0 ),
.wren ( 1'b0 ),
.q ( o_wave_1k )
);

sp_ram_256x8 sp_ram_256x8_10k_inst (
.address ( addr_10k ),
.clock ( sclk ),
.data ( 8'd0 ),
.wren ( 1'b0 ),
.q ( o_wave_10k )
);
//混频器
mult_8x8_sign mult_8x8_sign_inst (
.dataa ( o_wave_1k ),
.datab ( o_wave_10k ),
.result ( o_wave )
);

endmodule 

//-------------tb_ex_dds_org.v---------------------------------
`timescale 1ns / 1ns
module tb_ex_dds_org;
reg sclk;
reg rst_n;

wire [15:0] o_wave;

initial begin
sclk = 0;
rst_n = 0;
#100;
rst_n = 1;
end 

always #10 sclk <= ~sclk;

ex_dds_org ex_dds_org_inst(
.sclk (sclk ),
.rst_n (rst_n ),
.o_wave (o_wave )
);


endmodule 

//-------------run_org.do---------------------------------------------------------------
quit -sim
.main clear

vlib work 

vlog ./tb_ex_dds_org.v
vlog ./../design/*.v
vlog ./../quartus_prj/ipcore_dir/*.v
vlog ./altera_lib/*.v

vsim -voptargs=+acc work.tb_ex_dds_org

add wave tb_ex_dds_org/*
add wave tb_ex_dds_org/ex_dds_org_inst/*

run 10us


//-----------matlab-sin函数波形采样-gen_sin_wave.m---------------------------------------------------------
clc;
clear;

N=2^8; %每个周期的最大采样点数
s_p=0:2554; %正弦波一个周期的各个采样点变量
sin_data=sin(2*pi*s_p/N); %对一个正弦波在各个采样点进行采样后得到的数据-->将0-2pi分为N份,每更新一个s_p就取N份中的一份也就是对应一个数值,之后对这个数值取sin值--采样
%打印波形
%plot(sin_data,'r*');
%hold on;
%plot(sin_data);

%定点化
fix_p_sin_data=fix(sin_data*127);
for i=1:N
    if(fix_p_sin_data(i) < 0)
        fix_p_sin_data(i) = 2^8 + fix_p_sin_data(i); %这步的目的是将定点化后有符号的数据在FPGA中使用补码形式表示--应该是+
    else
        fix_p_sin_data(i) = fix_p_sin_data(i);
    end 
end 
%生成mif文件
fid=fopen('sp_ram_256x8.mif','w+');
fprintf(fid,'WIDTH=8;\n');
fprintf(fid,'DEPTH=256;\n\n');
fprintf(fid,'ADDRESS_RADIX=UNS;\n');
fprintf(fid,'DATA_RADIX=UNS;\n\n'); %注意这里数据类型选择无符号的,因为上面16行代码之后,数据的结果已经是补码的十进制数形式
fprintf(fid,'CONTENT BEGIN\n');
for i=1:N
    fprintf(fid,'   %d:%d;\n',i-1,fix_p_sin_data(i)); %单个地址不加[],matlab中的数组是从1开始的
end 
fprintf(fid,'END;\n');
fclose(fid); %fopen后最好加fclose

//--------matlab混频器仿真-------mixer.m-----------------------------------------------------
clc;
clear;

%验证混频--用到三角函数积化和差公式,产生两个正弦波->混频->使用fft验证是否产生了目标频率
fs=50e6;PM 
f1=1e6;%1M
f2=5e6;%5M
n=0:2047;
s_1=sin(2*pi*n*f1/fs); %可不用for循环--对连续正弦波sin(2*pi*f1*t)进行频率为fs的采样得到
s_2=sin(2*pi*n*f2/fs);%f(x)=sin(2*pi*f*t)-->f位三角函数频率
%plot(s_1);
%plot(s_2,'r');

%s_1和s_2混频--就是相乘
s_12=s_1.*s_2; %混频后包含两个频率分量,一个是6MHz,一个是4MHz 
%频域分析--做fft--fft处理的数据和输出的数据都是复数
fft_out=fft(s_12,2048);�t结果是复数,要看到频域波形应对复数求模得到幅值
fft_abs=abs(fft_out);
%plot(fft_abs); 
%采样频率为fs,也就是每个正弦波采样fs个点。
%频率分辨率 与fft点数N 和 采样频率fs 有关,fs/N--频率分辨率
PM/2048=0.0244140625M--fft可以分辨出的最低频率.奈奎斯特采样定理规定,每个周期至少采样两个点,也就是采样率至少是显示频率的两倍,显示频率是采样频率的1/2,上面采样率是50M,那么能显示的频率就为25M。
%得到的fft_abs频率是实数部分和虚数部分两个范围,0~1023点范围使我们需要的。
%目标频点怎么求:fs/N*n,n为目标频点的位置。频率最高峰有一个是在165位置,这个位置所对应的频率为(fs/N)*165=4MHz。另一个频率最高峰为247位置,对应的频率为fs/N*247=6MHz

%S1*S2=A1*A2*sin(w1t+a1)*sin(w2t+a2)=(A1*A2/2){cos[(w1-w2)t+(a1-a2)]-cos[(w1+w2)t+(a1+a2)]}则,结果是振幅为A1*A2/2,角频率为w1+w2,w1-w2的两个余弦波的叠加物理上,用频谱角度讲,出现振幅为A1*A2/2,频谱w1+w2,w1-w2的两个频谱
%对于连续正弦信号f(x)=sin(wt)=sin(2*pi*f*t),其中,f是这个正弦波的频率。在计算机中,必须使用离散的信号进行处理,也就是对原来的连续正弦信号进行采样得到离散的正弦波--令t=n*Ts(n为对正弦信号的采样点数,Ts为采样周期,fs=1/Ts为采样频率),得到f(n)=sin(2*pi*f*n*Ts)=sin(2*pi*f*n/fs)=sin(2*pi*n*f/fs)-->频率为f的离散正弦波信号,其中,离散正弦波是由连续正弦波sin(2*pi*f*t)进行频率为fs的采样得到的。

%--------------关于fft中频率和实际频率的关系-------------------------------------------------------------------------------------------------
%举例说,如果做了16个点的FFT分析,你原来的模拟信号的最高频率f=32kHz,采样频率是64kHz,n的范围是0,1,2...15。(卢注:这意味着已经将原来的模拟信号采样了8遍。)这时,64kHz的模拟频率被分成了16分,每一份是4kHz,这个叫频率分辨率(卢注:做FFT用的点越多,频率分辨率越高)。那么在横坐标中,n=1时对应的f是4kHz, n=2对应的是8kHz, n=15时对应的是60kHz,你的频谱是关于n=8对称的。你只需要关心n=0到7以内的频谱就足够了,因为,原来信号的最高模拟频率是32kHz。
%----------------------------------------------------------------------------------------------------------------------------

//--------------------相关图片---------------------------------------------------
dds设计框图
混频输出图
http://s2/mw690/006hC78Ezy781UosYLL61&690
平滑滤波之后的图--原始1K信号的频率已经发生改变
http://s14/mw690/006hC78Ezy781UozVcF9d&690


0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有