实验一 - 利用FFT计算频谱及结果分析

数字信号处理 | 频域分析实验
南京工业大学浦江学院 | 计算机与通信工程学院 | 通信工程专业 | DSP课程实验

理论实验目的

在本实验中,我们将使用MATLAB对离散时间信号进行频域分析。本实验的主要目的是:

  • 理解并掌握离散时间傅里叶变换(DTFT)的基本概念和性质
  • 学习离散傅里叶变换(DFT)与DTFT之间的关系
  • 利用快速傅里叶变换(FFT)计算离散时间序列的频谱
  • 通过结果分析理解固定频率和时变频率(如语音信号)的数字信号频谱特点
  • 理解线性卷积和循环卷积之间的关系,掌握FFT快速计算卷积的方法
  • 培养频域分析能力,理解时域与频域的对应关系
💡 学习提示

频域分析是数字信号处理的核心内容之一。通过将时域信号变换到频域,我们可以更直观地观察信号的频率成分,这对于信号分析、滤波设计、通信系统等应用至关重要。

理论理论基础

1. 离散时间傅里叶变换(DTFT)

对于离散时间信号(DT)求其频域表达,使用DTFT,也就是离散时间傅里叶变换。此时的信号是一个离散的非周期的实数或复数序列。

DTFT分析式(正变换):

$$X(e^{j\omega}) = \sum_{n=-\infty}^{\infty} x[n]e^{-j\omega n}$$

其中 $\omega$ 为归一化角频率(弧度)

DTFT合成式(逆变换):

$$x[n] = \frac{1}{2\pi} \int_{-\pi}^{\pi} X(e^{j\omega})e^{j\omega n}d\omega$$

📌 DTFT的重要特性:
  1. 连续性:$X(e^{j\omega})$ 是关于频率 $\omega$ 的连续函数
  2. 周期性:$X(e^{j\omega})$ 是以 $2\pi$ 为周期的周期函数,即 $X(e^{j(\omega+2\pi)}) = X(e^{j\omega})$
  3. 对称性:若 $x[n]$ 为实序列,则 $X(e^{j\omega})$ 满足共轭对称性

计算机实现的限制:

在计算机系统中,想要实现一个连续的数值变量是不可能的,所以对DTFT的任何数值实现有两个要求:

  1. $x[n]$ 必须具有有限长度(序列长度有限)
  2. $X(e^{j\omega})$ 只能在连续频率变量 $\omega$ 的有限数量的样本处计算(频率采样点有限)

在满足这两条要求的前提下,我们可以通过MATLAB来计算一个DT序列的频谱。实际上,如果 $x[n]$ 是有限的,$\omega$ 的数量也是有限的,我们就把DTFT离散化了,这就引出了DFT。

2. 离散傅里叶变换(DFT)

理论上DTFT分析方程的计算是从负无穷到正无穷进行求和,在计算机中是不可实现的,我们使用DFT,也就是离散傅里叶变换来进行谱分析。

DFT与DTFT的关系:

有限长序列的DFT结果包含了N个离散频率点处的DTFT结果,这些离散频率点等间隔地分布在区间 $[0, 2\pi)$ 内。如果离散频率点数量足够多,我们就可以通过DFT近似得到DTFT的结果。

频率采样:

为了计算效率,我们将连续频率变量 $\omega$ 所在的 $0$ 到 $2\pi$ 的周期范围内,等分 N 个点:

$$\omega_k = \frac{2\pi k}{N}, \quad k = 0, 1, 2, \ldots, N-1$$

DFT正变换:

$$X[k] = \sum_{n=0}^{N-1} x[n]e^{-j\frac{2\pi kn}{N}}, \quad k = 0, 1, \ldots, N-1$$

其中 $k$ 为频率索引,对应频率 $\omega_k = 2\pi k/N$

逆离散傅里叶变换(IDFT):

$$x[n] = \frac{1}{N} \sum_{k=0}^{N-1} X[k]e^{j\frac{2\pi kn}{N}}, \quad n = 0, 1, \ldots, N-1$$

💡 理解要点

频率分辨率:DFT的频率分辨率为 $\Delta f = F_s/N$,其中 $F_s$ 为采样频率。增加 $N$ 可以提高频率分辨率,使频谱更加精细。

零填充(Zero Padding):在信号末尾补零可以增加DFT的计算点数 $N$,从而提高频率分辨率,使DFT结果更接近真实的DTFT。但需要注意,零填充并不增加新的信息,只是对DTFT进行更密集的采样。

3. 快速傅里叶变换(FFT)

FFT(Fast Fourier Transform)是计算DFT的一种高效算法,它将DFT的计算复杂度从 $O(N^2)$ 降低到 $O(N \log N)$。

MATLAB中的FFT函数:

% 如果 x 是包含 x[n] 的向量,0 ≤ n ≤ M-1 X = fft(x, N); % 计算N点DFT % 计算x的DTFT的N个均匀间隔的样本,并存储在向量X中

重要说明:

  • 零填充:如果 $N > M$(序列长度),fft 会自动在序列末尾补零
  • 截断:如果 $N < M$,fft 会截取前 $N$ 个元素进行计算
  • 频率范围:fft 函数计算区间 $[0, 2\pi)$ 中的DFT。要在区间 $[-\pi, \pi]$ 中计算,可以使用 fftshift 函数进行移位
  • 逆变换ifft 函数可用于高效地计算IDFT
📌 FFT算法优势

对于 $N=1024$ 点的DFT,直接计算需要约100万次复数乘法,而FFT只需要约1万次,计算效率提高约100倍!这使得实时信号处理成为可能。

4. 卷积定理

卷积定理是连接时域和频域的重要桥梁,在信号处理中有广泛应用。

时域卷积 ⟷ 频域相乘:

$$y[n] = x[n] * h[n] \quad \Longleftrightarrow \quad Y[k] = X[k] \cdot H[k]$$

其中 $*$ 表示卷积,$\cdot$ 表示点乘

线性卷积 vs 循环卷积:

特性 线性卷积 循环卷积
定义 两个有限长序列的卷积 DFT域的点乘对应的时域操作
结果长度 $L_1 + L_2 - 1$ $\max(L_1, L_2)$
MATLAB函数 conv(x, h) ifft(fft(x) .* fft(h))
关系 补零到 $L_1 + L_2 - 1$ 后,循环卷积等于线性卷积
⚠️ 注意

直接使用FFT计算的是循环卷积,而非线性卷积。要使循环卷积等于线性卷积,必须对两个序列都补零至少到长度 $L_1 + L_2 - 1$。

实践交互式信号频谱分析

实时信号生成器与频谱分析器

调整参数观察时域信号与其频谱的关系

💡 观察要点
  • 正弦/余弦波的频谱是单一频率分量(冲激)
  • 方波包含基频和奇次谐波分量
  • 增加DFT点数 $N$ 可以提高频率分辨率,使频谱更平滑
  • 注意观察频谱的对称性(实信号的频谱共轭对称)

实践示例讲解

例题:单位脉冲信号的频谱分析

问题:有信号 $x[n] = \delta[n]$(单位脉冲信号),回答以下问题。

问题 1:手动计算 $x[n]$ 所对应的DTFT

解:

根据DTFT定义:

$$X(e^{j\omega}) = \sum_{n=-\infty}^{\infty} x[n]e^{-j\omega n}$$

对于单位脉冲 $\delta[n]$:

$$X(e^{j\omega}) = \sum_{n=-\infty}^{\infty} \delta[n]e^{-j\omega n} = e^{-j\omega \cdot 0} = 1$$

结论:单位脉冲信号的DTFT恒等于1(幅度为1,相位为0),这意味着它包含所有频率成分,且各频率分量幅度相等。

问题 2:使用fft计算出8点DFT结果并画图显示

N = 8; % 假设计算8点DFT n = 0:(N-1); % 时间索引:0到7 x = [1, zeros(1, 7)]; % 单位脉冲信号 δ[n] k = 0:(N-1); % 频率索引:0到7 % 计算8点DFT Xdft_8 = fft(x, N); % 计算幅度谱和相位谱 mag_Xdft_8 = abs(Xdft_8); % 幅度谱 phase_Xdft_8 = angle(Xdft_8); % 相位谱(弧度) % 绘制结果 figure; subplot(2, 1, 1); stem(k, mag_Xdft_8), grid on; title('8点DFT幅度谱'); xlabel('频率索引 k'), ylabel('|X[k]|'); xlim([-0.2, 8.2]); subplot(2, 1, 2); stem(k, phase_Xdft_8), grid on; title('8点DFT相位谱'); xlabel('频率索引 k'), ylabel('∠X[k] (弧度)'); xlim([-0.2, 8.2]);
图1:单位脉冲信号的8点DFT幅度谱和相位谱。幅度谱在所有频率点 $k=0,1,\ldots,7$ 处均为1;相位谱为0。

结果分析

  • 幅度谱在所有频率点处均为1,验证了理论结果 $|X(e^{j\omega})| = 1$
  • 相位谱为0,因为 $X(e^{j\omega}) = 1$ 是实数
  • 这说明单位脉冲信号包含所有频率成分,且各频率分量幅度相等

问题 3:通过零填充提高频率分辨率

选择 $N = 100, 500, 1000$ 进行尝试,观察DFT是否接近DTFT。

% 原始信号 x = [1, zeros(1, 7)]; % 不同的DFT点数 N_values = [8, 100, 500, 1000]; figure; for i = 1:length(N_values) N = N_values(i); k = 0:(N-1); Xdft = fft(x, N); mag_Xdft = abs(Xdft); subplot(2, 2, i); if N <= 100 stem(k, mag_Xdft), grid on; else plot(k, mag_Xdft), grid on; % N较大时用plot避免点重叠 end title(sprintf('%d点DFT幅度谱', N)); xlabel('k'), ylabel('|X[k]|'); end
图2:不同DFT点数下单位脉冲信号的幅度谱。随着 $N$ 增大,频率分辨率提高,频谱更加平滑,逐渐逼近连续的DTFT。
📌 观察结果
  • $N=8$ 时:只有8个离散频率点,频谱较粗糙
  • $N=100$ 时:频率点增加,频谱变得更平滑
  • $N=500, 1000$ 时:频谱非常平滑,逼近连续的DTFT
  • 所有情况下幅度均为1,验证了理论结果

结论:增加DFT点数(通过零填充)可以提高频率分辨率,使DFT更好地逼近DTFT。但要注意,这并不增加新的信息,只是对DTFT进行更密集的采样。

💡 深入理解

数字频率 $\omega$ 与 DFT索引 $k$ 的关系:

$$\omega_k = \frac{2\pi k}{N} \quad \text{(归一化角频率,弧度)}$$

或者用Hz表示(假设采样频率为 $F_s$):

$$f_k = \frac{kF_s}{N} \quad \text{(实际频率,Hz)}$$

因此,DFT的第 $k$ 个点对应的归一化频率为 $2\pi k/N$ 弧度。

实践练习一:指数序列的频谱分析

题目

设有离散时间序列 $x[n] = 0.7^n$,$0 \leq n \leq 7$

1 求出 $x[n]$ 所对应DTFT的解析式。

提示:利用几何级数求和公式 $\sum_{n=0}^{N-1} r^n = \frac{1-r^N}{1-r}$

2 根据例题计算出8点DFT($0 \leq k \leq 7$)并画出幅度相位谱。

3 根据例题计算出16点DFT($0 \leq k \leq 15$)并画出幅度相位谱。

4 根据例题计算出128点DFT($0 \leq k \leq 127$)并画出幅度相位谱。

注意:数据较多时使用 plot 函数代替 stem 函数。

5 观察第4题和第1题的结果,数字频率 $\omega$ 和DFT中 $k$ 的关系是什么?

实践练习二:卷积定理的验证

题目

设有两序列 $x[n] = [1, 1, 1, 1]$,$y[n] = [1, 1, 1, 1]$

1 对 $x$ 和 $y$ 做线性卷积(使用 conv 函数),把卷积结果用 stem 函数画出来。

2 手动计算 $x$ 和 $y$ 之间的圆周卷积结果。

提示:圆周卷积定义为 $z[n] = \sum_{m=0}^{N-1} x[m]y[(n-m) \bmod N]$,$n = 0, 1, 2, 3$

3 分别计算 $x$ 和 $y$ 的DFT,结果保存在 Xk 和 Yk 中。对结果做点乘,也就是计算 $Zk = Xk .* Yk$。对 Zk 求逆离散傅里叶变换(使用 ifft 函数)。如果你得到复数结果,使用 real 函数提取实数部分。确认你的结果与第2题获得的结果一致。使用 stem 函数绘制结果,观察结果中有多少个样本数和第1题中的结果一致?

4 对 $x$ 和 $y$ 尾部填零。首先对 $x$ 和 $y$ 分别添加一个零,重复第2题和第3题。有多少个样本和第1题的结果是一致的?需要补充多少零才能使结果和第1题中的完全一致,画图验证。

5 有两个新的序列 $u[n] = [-3, 5, 8, 6, 2, 2]$,$v[n] = [1, 1, 4, 2]$,重复以上问题并回答:对 $u$ 和 $v$ 各补充多少零可使得 $u$ 和 $v$ 之间的线性卷积结果等于循环卷积结果?

实践练习三:实际信号的频谱分析

题目

运行以下代码将 'tones.mat' 文件中的信号数据读取到MATLAB中,这个信号里面包含了多个不同频率的声音。

s = load('tones.mat'); x = s.y1;

变量 $x$ 现在就是声音信号。

1 计算 $x$ 所对应的DFT,假设 $N=25$。用 stem 函数画出幅度谱,你观察到了多少个主要频率分量?

2 对 $x$ 补零(调整 $N$ 值)并重新计算DFT的结果,你是否观察到了更多的频率分量?它们具体的频率是多少?尝试画出 $x$ 的图像,思考理解为什么要将时间信号变换到频域进行分析。

实践练习四:编写自定义DFT函数

题目

写一个自定义函数 X = MyDFT(x, N) 用以计算序列 $x$ 所对应的DFT。

函数要求:

  • $N$ 的长度可能和序列真实长度 $M$ 不同
  • 如果 $N > M$,则函数应该在 $x$ 的末尾补充零
  • 如果 $N < M$,则应截取前 $N$ 段进行计算
  • 写完后可以和MATLAB自带 fft() 函数进行比较
  • 可以用 randn 函数创建随机测试向量

DFT定义:

$$X[k] = \sum_{n=0}^{N-1} x[n]e^{-j\frac{2\pi kn}{N}}, \quad k = 0, 1, \ldots, N-1$$

任务 编写 MyDFT 函数,并用多个测试用例验证其正确性(与 fft 函数比较)。比较两者的计算时间,分析效率差异。

实验总结

核心知识点

概念 关键要点 应用
DTFT 连续频率,周期 $2\pi$,理论分析工具 理解信号频率特性
DFT 离散频率,DTFT的采样版本 计算机数值计算
FFT 快速计算DFT,$O(N \log N)$ 复杂度 实时信号处理
零填充 提高频率分辨率,不增加新信息 精细频谱分析
卷积定理 时域卷积 ⟷ 频域相乘 快速卷积计算

常见问题

Q1: 为什么需要FFT,DFT不够用吗?

A: DFT和FFT计算结果相同,但FFT效率高得多。对于 $N=1024$,FFT比DFT快约100倍。在实时处理中,FFT是必需的。

Q2: 零填充会增加新的信息吗?

A: 不会。零填充只是对DTFT进行更密集的采样,使频谱看起来更平滑,但不会创造新信息。

Q3: 如何选择合适的DFT点数 $N$?

A: 一般原则:$N$ 应 $\geq$ 信号长度 $M$;若要提高频率分辨率,可增大 $N$;FFT在 $N$ 为2的幂次时最快。