1、Signal Tap 和 Matlab
1.1 signal tap
合成500kHz的正弦波,其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');
- 运行之后的图片如下:
- 由图可知可以用此代码分析频谱。
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');
- 频谱图如下:
- 频率分辨率为: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个输出波形
输出波形周期: (1054−29)×20ns10.25=2000ns
- 输出频率: 12000ns=500kHz
2.2 Matlab验证
将modelsim生成的文本文件数据导入到Matlab,得到频谱图如下:
与signaltap的数据导入MATLAB后生成的波形图进行对比,二者在频率上一致,均为 488.3 kHz。
本设计中采样1024个数据,截取10.25个周期,不是周期截断,因而在最终的频谱图中将含有除原始频率成分以外的其它频率,即发生频谱泄露。改善频谱泄露的方法有:增大 FFT 变换的点数或选择合适的窗函数。

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

被折叠的 条评论
为什么被折叠?



