探索 DDS 和 EDA 工具

本文介绍如何使用SignalTap和ModelSim生成并分析500kHz正弦波信号,通过Matlab进行频谱分析,验证信号频率,并讨论频谱泄露及改进方法。

1、Signal Tap 和 Matlab


1.1 signal tap

  • 合成500kHz的正弦波,其signaltap图如下:

  • signaltap


1.2 Matlab分析

1.2.1 测试代码

  • 首先写出一个测试代码:生成一个频率为1kHz的正弦波,用该测试代码分析其频谱是否正确,若正确,则可以用来分析DDS生成的正弦波。

  • 代码如下:test_1kHz.m

%/////////////////////////////////////////////////////////////////////////////////////////////////////////
% function : 
%           draw 1kHz sine signal
%           DFT analyse
%/////////////////////////////////////////////////////////////////////////////////////////////////////////
N   = 64                ; % vector length
idx = [0:N-1].'         ; % index column vector
f0 = 1E3                ; % sine signal freq, in Hz
fs = 32E3               ; % sample rate, in Hz
x1 = sin(2*pi*f0/fs*idx); % sampled sine signal

max_abs_x = max(abs(x1));
% normalize x to (-1,1)
x1 = x1 / max_abs_x;

figure                  ; % open new figure
subplot(2,2,1:2)        ;
set(gca,'fontsize',14)  ;
stem(x1)                ; % plot(x1)
grid on                 ; % draw grid on figure
title1_str = sprintf(...
  'Sampled Sine Signal, Frequency %dHz, Sample rate %dHz', f0, fs);
title(title1_str, 'fontsize',14);
axis([0 N 1.1*min(x1) 1.1*max(x1)]);%设定坐标轴范围
xlabel('n');ylabel('Magnitude');

y1     = fft(x1)        ;
% shift zero frequency to the data center
% fftshift的作用正是让正半轴部分和负半轴部分的图像分别关于各自的中心对称。
% 因为直接用fft得出的数据与频率不是对应的,fftshift可以纠正过来
y1     = fftshift(y1)   ;
y1_abs = abs(y1)        ;
%idx_f = linspace(-(fs/2),(fs/2), N);
idx_f = (-length(y1)/2: length(y1)/2-1)'*fs/length(y1);%频率轴
subplot(2,2,3); stem(idx_f,y1_abs,'LineWidth',1,'MarkerSize',6)   ;
xlim([-(fs/2) (fs/2)]);%设定x坐标轴范围
grid on; set(gca,'fontsize',12)                             ;
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)                  ; 
stem(idx_f,y1_abs_dB, 'LineWidth',1,'MarkerSize',6,'BaseValue',min_y1); 
xlim([-(fs/2) (fs/2)]);%设定x坐标轴范围
grid on; set(gca,'fontsize',12)                     ;
title('DFT Amplitude in dB scale', 'fontsize',14)   ;
xlabel('Frequency/Hz');ylabel('Magnitude/dB');
  • 运行之后的图片如下:
  • test_1kHz
  • 由图可知可以用此代码分析频谱。

1.2.2 分析 DDS 生成的正弦信号频率

  • Signaltap的数据导入到Matlab,分析频域结果

  • 选中signal tap里的SINOUT行-右键-create signal tapⅡ list file,将该文件中的代码放到sublime中,shift+右键选中SINOUT一列的数据,放到SINOUT_500k.m文件的数组中,该文件包含一个数组,可用来调用。

  • 分析其频域结果的代码如下:FFT_500k.m
clear;
SINOUT_500k; %调用SINOUT_500k.m文件
x=transpose(SINOUT); %矩阵转置

max_abs_x = max(abs(x));
% normalize x to (-1,1)
x = x / max_abs_x;

N   = 1024                ; % vector length
idx = [0:N-1].'         ; % index column vector
f0 = 500E3              ; % sine signal freq, in Hz
fs = 50E6               ; % sample rate, in Hz

figure                  ; % open new figure
subplot(3,1,1)        ;
set(gca,'fontsize',14)  ;
plot(x)            ; % plot(x)
grid on                 ; % draw grid on figure
title1_str = sprintf(...
  'Sine Signal, Frequency %dkHz, Sample rate %dMHz', f0/1E3, fs/1E6);
title(title1_str, 'fontsize',14);
axis([0 N 1.1*min(x) 1.1*max(x)]);%设定坐标轴范围
xlabel('n');ylabel('Magnitude');

y1     = fft(x)        ;
% shift zero frequency to the data center
% fftshift的作用正是让正半轴部分和负半轴部分的图像分别关于各自的中心对称。
% 因为直接用fft得出的数据与频率不是对应的,fftshift可以纠正过来
y1     = fftshift(y1)   ;
y1_abs = abs(y1)        ;
idx_f = (-length(y1)/2: length(y1)/2-1)'*fs/length(y1);%频率轴
subplot(3,1,2); 
plot(idx_f,y1_abs,'LineWidth',1,'MarkerSize',6)   ;
xlim([-(fs/2) (fs/2)]);%设定x坐标轴范围
grid on; set(gca,'fontsize',12)                             ;
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(3,1,3)                  ; 
plot(idx_f,y1_abs_dB, 'LineWidth',1,'MarkerSize',6); 
axis([-(fs/2) (fs/2) -10 60]);%设定坐标轴范围
grid on; set(gca,'fontsize',12)                     ;
title('DFT Amplitude in dB scale', 'fontsize',14)   ;
xlabel('Frequency/Hz');ylabel('Magnitude/dB');
  • 频谱图如下:
  • 500k_1024
  • 频率分辨率为:fs / N = 50M / 1024 , 降低采样频率和增大采样数据的点数都可以提高频率分辨率。

1.2.3 给信号加Kaiser窗

  • 代码:FFT_kaiser_500k.m
clear;
SINOUT_500k; %调用SINOUT_500k.m文件
x = reshape(SINOUT , 1024, 1);

max_abs_x = max(abs(x));
% normalize x to (-1,1)
x = x / max_abs_x;

N   = 1024              ; % vector length
idx = [0:N-1].'         ; % index column vector
f0 = 500E3              ; % sine signal freq, in Hz
fs = 50E6               ; % sample rate, in Hz

% get window function data
kaiser_beta = 10         ;  % beta of kaiser win
win = kaiser(N,kaiser_beta);
win_x       =  win .* x;

figure                  ; % open new figure
subplot(3,1,1)          ;
set(gca,'fontsize',14)  ;
plot(win_x)                 ; % plot(x)
grid on                 ; % draw grid on figure
title1_str = sprintf(...
  'Sine Signal, Frequency %dkHz, Sample rate %dMHz, Kaiser window,β=%d', f0/1E3, fs/1E6, kaiser_beta);
title(title1_str, 'fontsize',14);
axis([0 N 1.1*min(win_x) 1.1*max(win_x)]);%设定坐标轴范围
xlabel('n');ylabel('Magnitude');

y1     = fft(win_x)        ;
% shift zero frequency to the data center
% fftshift的作用正是让正半轴部分和负半轴部分的图像分别关于各自的中心对称。
% 因为直接用fft得出的数据与频率不是对应的,fftshift可以纠正过来
y1     = fftshift(y1)   ;
y1_abs = abs(y1)        ;
idx_f = (-length(y1)/2: length(y1)/2-1)'*fs/length(y1);%频率轴
subplot(3,1,2); 
plot(idx_f,y1_abs,'LineWidth',1,'MarkerSize',6)   ;
xlim([-(fs/2) (fs/2)]);%设定x坐标轴范围
grid on; set(gca,'fontsize',12)                             ;
title1_str = sprintf(...
  'DFT Amplitude in Linear scale, Kaiser window,β=%d', kaiser_beta);
title(title1_str, 'fontsize',14);
xlabel('Frequency/Hz');ylabel('Magnitude');

y1_abs_dB = 20*log10(y1_abs)    ;
min_y1 = min(y1_abs_dB)         ;
subplot(3,1,3)                  ; 
plot(idx_f,y1_abs_dB, 'LineWidth',1,'MarkerSize',6); 
axis([-(fs/2) (fs/2) -60 60]);%设定坐标轴范围
grid on; set(gca,'fontsize',12)                     ;
title1_str = sprintf(...
  'DFT Amplitude in dB scale, Kaiser window,β=%d', kaiser_beta);
title(title1_str, 'fontsize',14);
xlabel('Frequency/Hz');ylabel('Magnitude/dB');
  • 频谱图:
  • β=0,相当于矩形窗
  • 矩形窗
  • β=7,相当于布莱克曼窗
  • 布莱克曼窗
  • 对于固定长度为N的凯泽窗,调节β值可以得到不同的主瓣和旁瓣特征。凯泽窗可以压制旁瓣,代价是主瓣变宽。

2、ModelSim 和 Matlab


2.1 Modelsim

  • 上次DDS作业中,是用bdf原理图的方法将各个模块连起来,这里新建一个dds_top.v文件连接各个模块,方便用modelsim仿真。

  • dds_top.v文件:

module dds_top(
    CLK ,
    RST ,
    FWEN    ,
    SWFW    ,
    SINOUT);

input CLK , RST;
input FWEN;
input  [3-1:0] SWFW;
output [11 :0] SINOUT;

wire [32-1:0] fqwd_W;
wire [32-1:0] cntval_W;
wire [10-1:0] addr_W;
wire [12-1:0] romout_W;

cnt_fre_words u_cfw(
    .CLK    (CLK)   ,
    .RST    (RST) ,
    .FWEN   (FWEN),
    .SWFW   (SWFW),
    .FQWD   (fqwd_W),
    .CNTVAL (cntval_W)
    );

DDS_CORE_ROM u_sinrom(
    .CLK    (CLK      ),  // clock
    .RA     (addr_W   ),  // read address
    .RD     (SINOUT)); // read data

assign addr_W = cntval_W[31:22];

endmodule
  • 一个最基本的Testbench包含三个部分,信号定义、模块接口和功能代码。自动生成testbench有两种方法,我采用第二种,自动生成的只是信号的定义,仍需要自己往testbench里添加模块接口和功能代码。

  • 接着要给给被测试设计的输入接口添加激励:CLK 和 RST;参考博客:FPGA攻略之Testbench篇

  • 最后,要把输出数据导出到文本文件中,用到的语句有:

    $fopen()
    $fdisplay()
    $fclose()

  • dds_top_tb.v文件如下:可观测信号输出波形,并将输出数据导出到文本文件SINOUT_data.txt中。

`timescale 1ns/1ns
module dds_top_tb  ; 

  reg    FWEN   ; 
  reg    RST   ; 
  wire signed  [11:0]  SINOUT   ; //define signed , when exported , the txt data is signed , or default unsigned
  reg    CLK   ; 
  reg  [2:0]  SWFW   ; 
  dds_top  
   DUT  ( 
       .FWEN (FWEN ) ,
      .RST (RST ) ,
      .SINOUT (SINOUT ) ,
      .CLK (CLK ) ,
      .SWFW (SWFW ) ); 

/*----------------------------------------------
  pumping signal : clock
  generate the system clock : CLK
  assign an initial value to CLK
  value reversal by 10ns , repeat
  generate a square wave signal
  T = 20 ns , fclk = 50MHz
----------------------------------------------*/
  initial
    CLK = 0;
  always
    #10 CLK = ~CLK ;

/*----------------------------------------------
  pumping signal : reset
  RST : asynchronous reset
----------------------------------------------*/
  initial begin
    RST = 0 ;       // RST , active high
    #100 RST = 1 ;  // delay 100 ns
    #500 RST = 0 ;  // delay 500 ns
  end

/*----------------------------------------------
  FWEN : frequency word update enable
  SWFW : switch frequency word
----------------------------------------------*/
  initial begin
    FWEN = 1 ;
    SWFW = 3'b001 ; //select 500kHz SINOUT
  end

/*----------------------------------------------
  generate SINOUT_data.txt
  export SINOUT waveform data to txt file
----------------------------------------------*/
  integer i ;
  integer write_out_file ;
  initial begin
    write_out_file = $fopen("SINOUT_data.txt") ;//opend file
    for(i = 0; i < 1054 ; i = i+1) begin
      #20;
      $fdisplay(write_out_file,"%d", SINOUT);   //write date , %d : Decimal , %h Hexadecimal
      if(i == 1054)
        $fclose(write_out_file);                //close file
    end
  end

endmodule


  • modelsim仿真:

    • Lbirary 窗格,simulate 测试文件(右键–>simulate)

    • Objects 框:选中信号(Ctrl多选),右键–>Add to–>Wave–>Selected Signals

    • 运行后,将输出信号的 format 改成 Analog (automatic)

    • 输出波形如下图所示:1024个时钟周期得到10.25个输出波形

    • modelsim

    • 输出波形周期: 105429×20ns10.25=2000ns

    • 输出频率: 12000ns=500kHz

2.2 Matlab验证

  • 将modelsim生成的文本文件数据导入到Matlab,得到频谱图如下:

  • modelsim_tb

  • 与signaltap的数据导入MATLAB后生成的波形图进行对比,二者在频率上一致,均为 488.3 kHz。

  • 本设计中采样1024个数据,截取10.25个周期,不是周期截断,因而在最终的频谱图中将含有除原始频率成分以外的其它频率,即发生频谱泄露。改善频谱泄露的方法有:增大 FFT 变换的点数或选择合适的窗函数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值