作为大学信号处理课程的一部分,我们被要求在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。
答案 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-1
和n=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