问题

众所周知,系统的冲激响应和频率响应是一对傅里叶变换对。也就是说,只需要将系统的冲激响应进行傅里叶变换,然后再经过一些处理,即可得到系统的幅频响应曲线和相频响应曲线。在 MATLAB 中,我们可以使用 fft 函数来进行快速傅里叶变换,但也可以使用 freqz 函数来直接求解数字系统的频率响应,按照上面的分析,这俩应该做的是一件事情,可是,它们的结果好像差距有点大?

先试一下 fft

b = 0.4*sinc(0.4*(-25:25));
plot(abs(fft(b)));

通过 fft 得到的幅频响应曲线,结果是这样的:

再试一下 freqz

b = 0.4*sinc(0.4*(-25:25));
freqz(b);

通过 freqz 得到的幅频响应曲线,结果是这样的:

这差的也太大了吧?

那么,为什么?

调查一下

这个问题得从多角度进行分析。

首先,FFT 本质上是 DFT 的优化,而 DFT 在频域上是离散的。试想:数字滤波器虽然是数字的,但是它的频率响应会是离散的吗?显然不是。
因此,想要从单位冲激响应画出数字系统的频率响应,我们需要的是 DTFT 而不是 DFT ,关于这俩的转换关系, 这篇文章 讲的非常通俗易懂。

其次,对实序列进行 FFT ,其结果有一半是共轭的,可以参照 这篇文章 当中的证明,因此其得到的幅频响应必然是对称的(上面的第一张图)。

所以,freqz 到底做了些什么呢?
首先,它会使用更高点数的 fft 来逼近 DTFT (默认是 500 点)。其次,它会自动帮你砍掉变换结果中的共轭部分。另外,还有一些细节处理,比如对数坐标。

尝试自己用 fft 实现一下?

b = 0.4 * sinc(0.4 * (-25 : 25));
res = abs(fft(b, 500));
semilogy(res(1 : length(res) / 2));

这下够像了吧?