DDS-正弦-SignalTap和MATLAB

##方案描述:

  • 设计一个DDS,50MHz的时钟速率,输出波形频率为1MHz,输出数据格式为2补码
  • 波表ROM由MATLAB生成,8bit地址,10bit量化
  • 相位累加器为32bit
  • 首先在SignalTap里面观察波形的正确性,然后把SignalTap的数据导入至MATLAB进行分析

##DDS原理:


其中fo为输出频率,fc为时钟频率,N为相位累加器的位数,K为频率控制字。其中频率控制字作为相位累加器的输入,相位累加器的高P位输出作为ROM表的输入,输出为相位对应的幅值。从未达到频率对应幅值的效果,产生数字的正弦信号。
这里写图片描述
这里写图片描述

##Verilog代码及输出文件:
###顶层文件

/*-----------------------------------------------------
Author           :   madezhuang Communication University of China
Technology blogs :   http://blog.csdn.net/proton_boke
Email address    :   mdz800@cuc.edu.cn
module function  :     
       Simulate the function of dds to generate a sine wave
Data             :   2017-04-01
Version          :   1.0
-----------------------------------------------------*/
module Top
(
CLK ,    // Global clock 50MHz
RST ,    // Global reset
FWEN,    // inputfrequency word update enable
RD  ,    // read data
CLKOUT   // Accumulator overflow flag
);
input  CLK;
input  RST;
input  FWEN;
output CLKOUT;
output [9:0] RD;

reg [9:0] RA;
            
wire  [31:0]   FQWD;       // output frequency word
reg   [32-1:0] FWIN;

wire  [7 :0]   ADD_R;      // ROM_dress

//--------------------------------------------
//generate_freq_word
generate_freq_word u_generate_freq_word
(
FQWD,
FWEN
);
//--------------------------------------------

always @(FQWD)
begin
 FWIN <= FQWD;
end

//--------------------------------------------
//phase_adder
phase_adder u_phase_adder
(
CLK   ,
RST   ,
FWIN  ,
ADD_R ,
CLKOUT
);
//--------------------------------------------

always @(ADD_R)
begin
 RA <= ADD_R;
end

//--------------------------------------------
//Output discrete sine waveforms
DDS_CORE_ROM u_DDS_CORE_ROM
(
CLK  ,
RA   ,
RD     
);
//--------------------------------------------

endmodule

###产生频率控制字

module generate_freq_word(
  FQWD      ,   // output frequency word
  FWEN      );  // input frequency word update enable

parameter VAL_FREQ = 32'h051E_B851;     
// 50MHz clock, 1MHz out wave freqword value
      
output [31:0] FQWD;      
input FWEN;   
    
reg [31:0] FQWD;      
always @(FWEN) 
begin
 if(FWEN)
  FQWD <= VAL_FREQ;
 else
  FQWD <= 0;
end    
  
endmodule

###相位累加器

module phase_adder(
  CLK   ,   // clock, posedge valid
  RST   ,   // reset, high level reset
  FWIN  ,   // input frequency word
  ADD_R ,   // output ROM_dress
  CLKOUT    // output clock
); 

input           CLK;
input           RST;
input [32-1:0]  FWIN;
output[8 -1:0]  ADD_R;
output          CLKOUT;

reg   [32 -1:0]  fwin_R;     // freq word DFF
reg   [32 -1:0]  acc_R;      // phase ACC DFF
reg   [8 -1:0]  ADD_R;      // ROM_dress
reg              CLKOUT;

always @ (posedge CLK or posedge RST) begin
  if(RST) begin
    fwin_R   <= 0;
    acc_R    <= 0;
  end
  else begin
   // update fwin_R DFF
     fwin_R <= FWIN;
   
   // update acc_R
   acc_R <= fwin_R + acc_R;
    
   // update addr_R, the acc_R high RA_WL is rom address
   ADD_R <= acc_R[32-1:24];  
  end
end
    
always @(posedge CLK or posedge RST) begin
  if(RST)
    CLKOUT <= 1'b0;
  else if(acc_R < 32'h7FFF_FFFF)
    CLKOUT <= 1'b0;
  else
    CLKOUT <= 1'b1;
end
    
endmodule 

###DDS波表ROM

module DDS_CORE_ROM(
  CLK    ,           // clock
  RA     ,           // read address
  RD     );          // read data
input          CLK;
input  [7  :0] RA;
output [9  :0] RD;
reg    [9  :0] RD;
always @ (posedge CLK)
  case(RA)
     8 'd 0     :RD = #1 10'b 0000000000; //      0 0x0 
     8 'd 1     :RD = #1 10'b 0000001100; //     12 0xC 
     8 'd 2     :RD = #1 10'b 0000011001; //     25 0x19 
     8 'd 3     :RD = #1 10'b 0000100101; //     37 0x25 
     8 'd 4     :RD = #1 10'b 0000110010; //     50 0x32 
     8 'd 5     :RD = #1 10'b 0000111110; //     62 0x3E 
     8 'd 6     :RD = #1 10'b 0001001010; //     74 0x4A 
     8 'd 7     :RD = #1 10'b 0001010111; //     87 0x57
     ...............//省略了
     8 'd 169   :RD = #1 10'b 1001010001; //   -431 0x251 
     8 'd 170   :RD = #1 10'b 1001001010; //   -438 0x24A 
     8 'd 171   :RD = #1 10'b 1001000100; //   -444 0x244 
     8 'd 172   :RD = #1 10'b 1000111110; //   -450 0x23E 
     8 'd 173   :RD = #1 10'b 1000111000; //   -456 0x238 
     8 'd 174   :RD = #1 10'b 1000110011; //   -461 0x233 
     8 'd 175   :RD = #1 10'b 1000101101; //   -467 0x22D  
     ...............//省略了
     8 'd 249   :RD = #1 10'b 1110101001; //    -87 0x3A9 
     8 'd 250   :RD = #1 10'b 1110110110; //    -74 0x3B6 
     8 'd 251   :RD = #1 10'b 1111000010; //    -62 0x3C2 
     8 'd 252   :RD = #1 10'b 1111001110; //    -50 0x3CE 
     8 'd 253   :RD = #1 10'b 1111011011; //    -37 0x3DB 
     8 'd 254   :RD = #1 10'b 1111100111; //    -25 0x3E7 
     8 'd 255   :RD = #1 10'b 1111110100; //    -12 0x3F4 
  default : RD = #1 0;
  endcase
  
endmodule 

###Block Diagram File
这里写图片描述

###SignalTap
这里写图片描述
##将SignalTap中的数据导入至MATLAB分析:
在SignalTap文件sin_wave_out位置单击鼠标右键选择Create signal tapⅡ list file,生成如下图所示的数据
这里写图片描述
利用文件编辑器Utradit文件编辑器,选择需要的数据,保存为.m文件。之后就可以在matlab中对此文件进行调用。

##通用正弦信号频谱分析的MATLAB代码:

  • 生成一个1k的标准正弦信号,然后由32k去采样,采样点数为64
  • 此时包含 64/(32kHz/1kHz) = 2个周期的样点
  • 结果非常之好,好的接近理想程度了,现实世界中的电子热运动噪声才-180dB,案例1中的噪声被压制到了-300dB以下,已经非常满足工程上面的测量需求了。
%/
%用途:正确的正弦信号频谱分析的matlab代码
%方案,设计生成一个标准的正弦信号,对其作fft变换分析频谱,若与实际情况一致,则证明matlab代码可用
%作者:中国传媒大学 马德壮  PS:几乎未改动的来自杜伟韬杜老师
%/
clc;
clear all;
fc = 1e3;     %正弦信号频率
fs = 32e3;   %采样频率
N = 64;        %采样点数,则此时采样点数共包含N/(fs/fc) = 2 个周期正弦信号
idx = [0:N-1];  
x1 = sin(2*pi*fc/fs*idx);  %t = 1/fs*[0:N-1]

figure;
subplot(2,2,1:2);  %将绘图窗口分为两行两列的,其中第一幅图占据第一行的第一、二列
stem(x1);  %将以火柴柱状图画出
grid on;  %添加网格线
title('Sampled Sine Signal', 'fontsize',14);  %改变标题字体的大小至14

%频谱实现左右对称,横轴为频率,纵轴为幅度值
y1 = fftshift ( fft(x1) );
y1_abs = abs(y1);
subplot(2,2,3);
f = linspace(-(fs/2),(fs/2), N);
stem(f,y1_abs,'LineWidth',1,'MarkerSize',6);
xlim([-(fs/2) (fs/2)]);
grid on;
title('DFT Amplitude in Linear scale', 'fontsize',14);
xlabel('Frequency(Hz)');
ylabel('Magnitude');

y1_abs_dB = 20*log10(y1_abs);
min_y1 = min(y1_abs_dB);
subplot(2,2,4);
% f = linspace(-(fs/2),(fs/2), N);
stem(f,y1_abs_dB, 'LineWidth',1,'MarkerSize',6,'BaseValue',min_y1); 
xlim([-(fs/2) (fs/2)]);
grid on;
title('DFT Amplitude in dB scale','fontsize',14);
xlabel('Frequency(Hz)');
ylabel('Magnitude(dB)');


% %频谱未搬移,即频谱不对称
% y1 = fft(x1);
% y1_abs = abs(y1);
% subplot(2,2,3);
% stem(y1_abs);
% grid on;
% title('DFT Amplitude in Linear scale', 'fontsize',14);
% 
% %纵轴以分贝显示,频谱未搬移,即频谱不对称
% y1_abs_dB = 20*log10(y1_abs);
% min_y1 = min(y1_abs_dB);
% subplot(2,2,4); 
% stem(y1_abs_dB, 'LineWidth',1,'MarkerSize',6,'BaseValue',min_y1); 
% % stem(y1_abs_dB);  采用这条代码时会发生错误,错误原因暂不去查明
% grid on;
% title('DFT Amplitude in dB scale', 'fontsize',14);

这里写图片描述
##将上述代码稍加改动的分析来自SignalTap中的数据:

###第一次代码

%/
%用途:对DDS产生的正弦信号进行FFT变换,频谱分析
%作者:中国传媒大学 马德壮
%/
clc;
clear all;
sin_wave_out;  %调用sin_wave_out里面的数据
signal = reshape(sin_wave_data, 1024, 1)/512;
fc = 1e6;     %正弦信号频率
fs = 50e6;   %采样频率
N = 1024;        %采样点数,则此时采样点数共包含N/(fs/fc) = 10.24 个周期正弦信号

figure; subplot(4,4,1:4);  %将绘图窗口分为两行两列的,其中第一幅图占据第一行的第一、二、三、四列
plot([0:N-1],signal);  
title('Sine Signal', 'fontsize',14);  %改变标题字体的大小至14
subplot(4,4,5:8);
stem(signal);
xlim([100,200]);
grid on;  %添加网格线
title('Sampled Sine Signal(Partially displayed)', 'fontsize',14);  %改变标题字体的大小至14

%频谱实现左右对称,横轴为频率,纵轴为幅度值
y1 = fftshift ( fft(signal) );
y1_abs = abs(y1);
subplot(4,4,9:12);
f = linspace(-(fs/2),(fs/2), N);
plot(f,y1_abs);
grid on;
title('DFT Amplitude in Linear scale', 'fontsize',14);
xlabel('Frequency(Hz)');  ylabel('Magnitude');

y1_abs_dB = 20*log10(y1_abs);
subplot(4,4,13:16);
plot(f,y1_abs_dB,'linewidth',1);
grid on;
title('DFT Amplitude in dB scale','fontsize',14);
xlabel('Frequency(Hz)'); ylabel('Magnitude(dB)');

###第一次波形

这里写图片描述

###第一波小分析

%///
%结果显示:(单一频率正弦波,强度适中)噪声太大,即频谱泄露严重
%结果分析:采样点数不是整数个周期造成频谱泄露
%改进方法:不管是否乐意,我们拿过来一段有限长序列,等价于对序列在时域乘了一个矩形窗,于是等价于在频域对信号的频谱与矩形窗的频谱做卷积。而我们知道,矩形窗的频域即为抽样函数,这就导致正弦信号的尖峰在整个频域扩展开来。因此,可以选择一个合适的窗,以改进频谱泄露。
%///

###第二次代码(加kaiser窗)

clc;
clear all;
sin_wave_out;  %调用sin_wave_out里面的数据
signal = reshape(sin_wave_data, 1024, 1)/512;
kaiser_Beta = 12;
N = 1024;      %采样点数,则此时采样点数共包含N/(fs/fc) = 20.48 个周期正弦信号
win = kaiser(N,kaiser_Beta);  %凯撒窗
x1 = signal.*win;
fc = 1e6;     %正弦信号频率
fs = 50e6;   %采样频率

figure; subplot(3,3,1:3);  
 plot([0:N-1],x1);
grid on;  %添加网格线
title('Sine Signal(Kaiser window,Beta 14)', 'fontsize',10);  %改变标题字体的大小至14

%频谱实现左右对称,横轴为频率,纵轴为幅度值
y1 = fftshift ( fft(x1) );
y1_abs = abs(y1);
subplot(3,3,4:6);
f = linspace(-(fs/2),(fs/2), N);
plot(f,y1_abs);
xlim([-(fs/2) (fs/2)]);
grid on;
title('DFT Amplitude in Linear scale', 'fontsize',14);
xlabel('Frequency(Hz)');  ylabel('Magnitude');

y1_abs_dB = 20*log10(y1_abs);
subplot(3,3,7:9);
f = linspace(-(fs/2),(fs/2), N);
plot(f,y1_abs_dB); 
xlim([-(fs/2) (fs/2)]);
grid on;
title('DFT Amplitude in dB scale','fontsize',14);
xlabel('Frequency(Hz)'); ylabel('Magnitude(dB)');

###第二次波形

这里写图片描述
###第二波小分析

%///
%结果显示:(单一频率正弦波,强度适中)噪声仍然很大
%结果分析:采用的是kaiser窗,Beta为14,比较第一次波形虽有改善,但噪声仍未被压制到-40dB以下,不明白原因
%///
  • 2
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值