计算任意信号的DFT

时间:2018-10-22 19:58:30

标签: matlab fft dft frequency-analysis

作为大学信号处理课程的一部分,我们被要求在Matlab中编写一种算法,以使用DFT计算信号的单面频谱,而无需使用Matlab内置的fft()函数。这不是课程的评估部分,我只是想为自己争取这种“正确”。我目前正在使用Matlab的2018b版本,如果有人觉得有用的话。

我建立了一个1 KHz和2KHz正弦信号,相移了135度(2 * pi / 3 rad)。

然后使用离散时间信号处理(Allan V. Oppenheim) 9.1中的方程式和Euler公式简化指数,我生成此代码:

%%DFT(currently buggy)
n=0;m=0;
for m=1:DFT_N-1 %DFT_Fmin;DFT_Fmax; %scrolls through DFT m values (K in text.)
    for n=1:DFT_N-1;%;(DFT_N-1);%<<redundant code? from Oppenheim eqn. 9.1 % eulers identity, K=m and n=n
        X(m)=x(n)*(cos((2*pi*n*m)/DFT_N)-j*sin((2*pi*n*m)/DFT_N));
        n=n+1;
    end
    %m=m+1; %redundant code?
end

这将x作为输入(在这种情况下为前面提到的信号)以及已由DFT_N表示的转换分辨率(已初始化为100)。此函数X的输出应为在频域中有一些变化,但是绘制X会产生一个圆图,该圆图略大于单位圆,并且在左侧边缘有一个缝隙。

我正在努力查看如何将其转换为内置DFT算法给出的stem()图。

非常感谢,J。

2 个答案:

答案 0 :(得分:3)

这是您的错误:

X(m)=x(n)*(cos..替换为X(m)=X(m)+x(n)*(cos..

对于给定的m,它不对变量n进行积分,而是仅对n = DFT_N-1的最后一次计算覆盖X(m)。

请注意,对n=1:DFT_N-1进行积分会忽略一个谐波,即第一个谐波exp(-j * 2 * pi)。更换 n=1:DFT_N-1n=1:DFT_N包括在内。我也将m=1:DFT_N-1替换为m=1:DFT_N以便进行关注。

也用2*pi*n*m替换任何2*pi*(n-1)*(m-1)以得到正确的相位,因为X的第一项应该对应于零频率,从而产生sum_n x(n)*(cos(0)+ j sin(0))= sum_n x(n)。如果您的信号x是实值,则零频率分量X(1)应该是实值,即angle(X(1))= 0。

最后,不要忘了将零频分量移到频谱的中心,以获得更好的可见性,X = circshift(X,floor(size(X)/2));

答案 1 :(得分:1)

如果您仅对单边频谱感兴趣,则只需计算X(m)for m=1:DFT_N/2,因为X在m = DFT_N / 2周围是共轭对称的,即X(DFT_N/2+m) = X(DFT_N/2-m)',由于exp(-j*(pi*n+2*pi/DFT_N*m)) = exp(-j*(pi*n-2*pi/DFT_N*m))'

请注意,对于给定的m,该程序计算x数组与另一个复指数数组(即exp(-j*2*pi/DFT_N*m*n)之间的内积,其中n = 0,1,...,N- 1。 MATLAB语法对于此类计算非常方便,您可以通过以下命令避免这种内部循环

exp(-j*2*pi/DFT_N*m*(0:DFT_N-1)) * x

其中x是列向量。同样,您也可以通过每m逐行扩展复杂的指数矢量来避免第一个循环,即构建矩阵exp(-j*2*pi/DFT_N*(0:DFT_N-1)'*(0:DFT_N-1))。然后,您的DFT就是

X = exp(-j*2*pi/DFT_N*(0:DFT_N-1)'*(0:DFT_N-1)) * x

对于单面光谱,请改用

X = exp(-j*2*pi/DFT_N*(0:floor((DFT_N-1)/2))'*(0:DFT_N-1)) * x