信号处理基础:信号处理概述_(6).信号处理基础:离散傅里叶变换与快速傅里叶变换
信号处理基础:离散傅里叶变换与快速傅里叶变换

离散傅里叶变换 (DFT)
原理
离散傅里叶变换(Discrete Fourier Transform, DFT)代表一种形式,在工程与科学领域中用于分析离散时间信号的基本特征。它所描述的核心思想是一个有限长度的离散序列如何被分解为一系列复指数之和这一过程。数学上,则可表述为此种变换通过求和这些复指数来实现对原始信号的重新表达
X[k] = \sum_{n=0}^{N-1} x[n] e^{-j \frac{2\pi}{N} k n}
其中,x[n] 是时域信号,X[k] 是频域信号,N 是信号的长度,j 是虚数单位。
DFT的反变换(IDFT)其作用在于将频域信号还原为时域信号
x[n] = \frac{1}{N} \sum_{k=0}^{N-1} X[k] e^{j \frac{2\pi}{N} k n}
内容
离散傅里叶变换(DFT)作为一种重要的数字信号处理工具,在各个领域都展现出其广泛的应用潜力。它不仅能够有效地进行时域与频域之间的转换,在通信系统设计、图像处理以及音频工程等领域都有着不可替代的作用。掌握DFT的基本原理及其在实际中的应用对于深入理解数字信号处理技术具有重要意义。
1. DFT 的数学基础
DFT 转换为频域表示的是离散信号 x[n]。每个频域样本 X[k] 都对应于频率为 k \frac{f_s}{N} 的幅度与相位信息。其中用于计算这些参数的采样频率则被称为f_s。
2. DFT 的计算
DFT 的计算可通过直接求和的方式来实现,在理论上其时间复杂度达到了 O(N^2) 的水平。当处理较长的信号时(即 N 值较大),所需的时间也会显著增加。
3. 应用实例
为了更好地理解这一过程,请您参考以下示例:我们可以通过编写一个简单的Python程序来演示离散傅里叶变换(DFT)的计算过程,并详细解释其在频谱分析中的应用。
import numpy as np
import matplotlib.pyplot as plt
# 生成一个简单的离散信号
fs = 1000 # 采样频率
T = 1/fs # 采样周期
t = np.arange(0, 1, T) # 时间向量
f1 = 50 # 信号频率1
f2 = 120 # 信号频率2
x = 0.7 * np.sin(2 * np.pi * f1 * t) + np.sin(2 * np.pi * f2 * t) # 信号
# 计算DFT
N = len(x)
X = np.zeros(N, dtype=complex)
for k in range(N):
for n in range(N):
X[k] += x[n] * np.exp(-1j * 2 * np.pi * k * n / N)
# 计算频率轴
frequencies = np.arange(0, fs, fs/N)
# 绘制时域信号
plt.figure(figsize=(12, 6))
plt.subplot(2, 1, 1)
plt.plot(t, x)
plt.title('时域信号')
plt.xlabel('时间 (s)')
plt.ylabel('幅度')
# 绘制频域信号
plt.subplot(2, 1, 2)
plt.stem(frequencies, np.abs(X), 'b', markerfmt=" ", basefmt="-b")
plt.title('频域信号')
plt.xlabel('频率 (Hz)')
plt.ylabel('幅度')
plt.show()
代码解析
- 生成离散信号 :我们通过合成方法得到一个由两个正弦波组成的离散信号 x[n]。
- 计算 DFT :每个频域样本 X[k] 的计算值通过双重循环过程被确定下来。
- 绘制时域和频域信号 :我们分别使用 Matplotlib 绘制了时域信号及其频域幅度谱。
快速傅里叶变换 (FFT)
原理
快速傅里叶变换(Fast Fourier Transform, FFT)作为高效的计算工具,在数字信号处理领域发挥着重要作用。该方法的核心原理在于充分利用信号的对称性和周期性特性,并通过巧妙的数学处理实现了对离散傅里叶变换(Discrete Fourier Transform, DFT)的高效计算。其主要优势在于将传统的O(N^2)复杂度优化至O(N \log N)水平,并广泛应用于频域分析、数据压缩以及滤波等关键领域。其中应用最为广泛的算法是库利-图基算法(Cooley-Tukey algorithm),该方法通过递归地分解问题规模并结合快速傅里叶变换的基本思路,在实际应用中展现出显著的优势
内容
在工程实践中,FFT 应用极为广泛。其计算效率显著优于直接计算离散傅里叶变换(DFT)。掌握FFT的工作原理及其实现对进行频谱分析、滤波等信号处理任务具有重要意义。
在工程实践中
1. FFT 的基本思想
FFT的核心理念在于将一个规模为N的DFT拆分为两个规模分别为N/2的DFT,并通过递归地不断分割来完成整个过程。这一方法充分利用了DFT的对称性和周期性特点,在此基础上显著降低了运算量。
2. FFT 的计算
Python 的 NumPy 库支持快速傅里叶变换算法的实现,并且允许直接调用 np.fft.fft 函数来完成运算。
3. 应用实例
我们沿用上一节介绍的离散信号,并借助 NumPy 的 Fast Fourier Transform (FFT)函数进行频谱计算。
import numpy as np
import matplotlib.pyplot as plt
# 生成一个简单的离散信号
fs = 1000 # 采样频率
T = 1/fs # 采样周期
t = np.arange(0, 1, T) # 时间向量
f1 = 50 # 信号频率1
f2 = 120 # 信号频率2
x = 0.7 * np.sin(2 * np.pi * f1 * t) + np.sin(2 * np.pi * f2 * t) # 信号
# 计算FFT
N = len(x)
X = np.fft.fft(x)
# 计算频率轴
frequencies = np.fft.fftfreq(N, T)
# 绘制时域信号
plt.figure(figsize=(12, 6))
plt.subplot(2, 1, 1)
plt.plot(t, x)
plt.title('时域信号')
plt.xlabel('时间 (s)')
plt.ylabel('幅度')
# 绘制频域信号
plt.subplot(2, 1, 2)
plt.stem(frequencies, np.abs(X), 'b', markerfmt=" ", basefmt="-b")
plt.title('频域信号')
plt.xlabel('频率 (Hz)')
plt.ylabel('幅度')
plt.show()
代码解析
- 创建离散时间序列 :如同上一节所述,我们创建了一个由两个正弦波组成的离散时间序列 x[n]。
- 执行快速傅里叶变换(FFT) :通过调用 numpy 库中的 fft 函数来完成对信号的快速傅里叶变换(FFT)。
- 确定频率分辨率 :利用 numpy 的 fftfreq 函数来确定相应的频率分辨率。
- 展示时域序列及其频谱特性 :借助 matplotlib 库进行可视化展示,分别呈现时域序列及其频谱特性的图形表示。
离散傅里叶变换与快速傅里叶变换的比较
原理
DFT 和 FFT 都是处理时域信号到频域转换的工具,在运算方式上存在显著差异且影响效率水平。DFT 主要依赖直接求和法完成运算任务,在数据规模较大时容易导致冗余运算;而 FFT 则采用了递归分治策略,在保证精确度的前提下显著降低了整体运算复杂度
内容
掌握DFT与FFT之间的异同有助于合理选择相应的工具来进行信号处理工作。在处理短信号时,DFT能够实现频谱分析;而在处理长信号时,FFT则能够高效地完成计算任务
1. 计算复杂度
- DFT 的计算复杂度为 O(N^2)。
- FFT 的计算复杂度为 O(N \log N)。
2. 应用场景
- DFT:常用于短信号的频域分析,在处理数据时计算资源并非瓶颈问题。
- FFT:常用于长信号的频域分析、滤波与卷积操作,在处理大量数据时效率更高。
3. 比较实例
我们通过一个例子来比较 DFT 和 FFT 的计算时间。
import numpy as np
import matplotlib.pyplot as plt
import time
# 生成一个简单的离散信号
fs = 1000 # 采样频率
T = 1/fs # 采样周期
t = np.arange(0, 1, T) # 时间向量
f1 = 50 # 信号频率1
f2 = 120 # 信号频率2
x = 0.7 * np.sin(2 * np.pi * f1 * t) + np.sin(2 * np.pi * f2 * t) # 信号
# 计算DFT的时间
start_time = time.time()
N = len(x)
X_dft = np.zeros(N, dtype=complex)
for k in range(N):
for n in range(N):
X_dft[k] += x[n] * np.exp(-1j * 2 * np.pi * k * n / N)
dft_time = time.time() - start_time
# 计算FFT的时间
start_time = time.time()
X_fft = np.fft.fft(x)
fft_time = time.time() - start_time
# 计算频率轴
frequencies = np.fft.fftfreq(N, T)
# 绘制时域信号
plt.figure(figsize=(12, 6))
plt.subplot(2, 1, 1)
plt.plot(t, x)
plt.title('时域信号')
plt.xlabel('时间 (s)')
plt.ylabel('幅度')
# 绘制频域信号
plt.subplot(2, 1, 2)
plt.stem(frequencies, np.abs(X_dft), 'r', markerfmt=" ", basefmt="-r", label='DFT')
plt.stem(frequencies, np.abs(X_fft), 'b', markerfmt=" ", basefmt="-b", label='FFT')
plt.title('频域信号')
plt.xlabel('频率 (Hz)')
plt.ylabel('幅度')
plt.legend()
plt.show()
# 输出计算时间
print(f"DFT 计算时间: {dft_time:.6f} 秒")
print(f"FFT 计算时间: {fft_time:.6f} 秒")
代码解析
- 生成离散序列:如同之前的案例所述,在本研究中我们生成了一个由两个正弦波组成的离散序列 x[n]。
- 评估 DFT 所需的时间:通过直接求和法(即暴力方法)来评估 DFT 所需的时间,并记录所需的时间。
- 调用 np.fft.fft 函数:为了提高效率,在实际应用中我们调用 np.fft.fft 函数来实现 FFT 算法,并记录所需的时间。
- 借助 Matplotlib 绘制时域及频域信号的幅度谱图:通过Matplotlib工具软件绘制了时域及频域信号的幅度谱图,并在 freq-domain 图上展示了两种算法的结果对比。
- 对比分析了两种方法所需的时间:通过对实验数据进行统计分析后发现, 采用快速傅里叶变换算法相比直接求和的方法, 能够显著减少运算时间.
离散傅里叶变换和快速傅里叶变换的应用
信号频谱分析
频谱分析是信号处理中的核心内容,在信息处理领域具有重要价值;借助DFT或FFT技术能够将时域信号映射到频域,并通过分析频域特性来研究信号的基本组成成分。
例子
假设给定一个带噪声的信号序列,我们可以先对其应用 Fast Fourier Transform(FFT)来计算频谱,并随后对其进行滤波处理。
import numpy as np
import matplotlib.pyplot as plt
import scipy.signal as signal
# 生成一个包含噪声的信号
fs = 1000 # 采样频率
T = 1/fs # 采样周期
t = np.arange(0, 1, T) # 时间向量
f1 = 50 # 信号频率1
f2 = 120 # 信号频率2
x = 0.7 * np.sin(2 * np.pi * f1 * t) + np.sin(2 * np.pi * f2 * t) + 0.5 * np.random.normal(size=len(t)) # 信号加噪声
# 计算FFT
N = len(x)
X_fft = np.fft.fft(x)
# 计算频率轴
frequencies = np.fft.fftfreq(N, T)
# 绘制时域信号
plt.figure(figsize=(12, 6))
plt.subplot(2, 1, 1)
plt.plot(t, x)
plt.title('时域信号 (含噪声)')
plt.xlabel('时间 (s)')
plt.ylabel('幅度')
# 绘制频域信号
plt.subplot(2, 1, 2)
plt.stem(frequencies, np.abs(X_fft), 'b', markerfmt=" ", basefmt="-b")
plt.title('频域信号 (含噪声)')
plt.xlabel('频率 (Hz)')
plt.ylabel('幅度')
plt.show()
# 滤波处理
# 设定滤波器参数
f_cutoff = 100 # 截止频率
b, a = signal.butter(5, f_cutoff, btype='low', fs=fs) # 低通滤波器
# 应用滤波器
x_filtered = signal.filtfilt(b, a, x)
# 计算滤波后的FFT
X_fft_filtered = np.fft.fft(x_filtered)
# 绘制滤波后的时域信号
plt.figure(figsize=(12, 6))
plt.subplot(2, 1, 1)
plt.plot(t, x_filtered)
plt.title('时域信号 (滤波后)')
plt.xlabel('时间 (s)')
plt.ylabel('幅度')
# 绘制滤波后的频域信号
plt.subplot(2, 1, 2)
plt.stem(frequencies, np.abs(X_fft_filtered), 'b', markerfmt=" ", basefmt="-b")
plt.title('频域信号 (滤波后)')
plt.xlabel('频率 (Hz)')
plt.ylabel('幅度')
plt.show()
代码解析
- 生成带噪声的信号样本:我们使用numpy库生成了一个包含两个正弦波和高斯噪声的离散时间序列。
- 执行快速傅里叶变换(FFT):通过调用
np.fft.fft函数对信号进行快速傅里叶变换算法计算。 - 生成频率轴向量:利用
np.fft.fftfreq函数参数化设置采样频率参数值范围得到频率轴向量。 - 分别绘制原始信号的时间域图形及其频域幅度谱:使用Matplotlib库先绘制原始时序数据点分布图,并在同一窗口中绘制其对应的频谱幅值分布曲线。
- 应用数字滤波器进行低通滤波处理:借助SciPy工具包中的
signal.butter函数设计截止频率适当的低通Butterworth滤波器,并用signal.filtfilt函数对其进行零相位前向后向滤波处理。 - 分别绘制经过滤波处理后的原始信号的时间域图形及其频域幅度谱:再次使用Matplotlib库完成处理后的时序数据点分布图以及其对应的频谱幅值分布曲线绘图工作。
信号卷积
在信号处理领域中,信号卷积被视为一个基础操作,在这一领域内具有重要的应用价值。借助卷积运算的方法,则可实现对信号进行滤波与平滑等处理。快速傅里叶变换(FFT)则是一种高效计算卷积运算的技术手段。
例子
假设我们有两个信号 x[n] 和 h[n],我们可以通过 FFT 计算它们的卷积。
import numpy as np
import matplotlib.pyplot as plt
# 生成两个离散信号
fs = 1000 # 采样频率
T = 1/fs # 采样周期
t = np.arange(0, 1, T) # 时间向量
f1 = 50 # 信号频率1
f2 = 120 # 信号频率2
x = 0.7 * np.sin(2 * np.pi * f1 * t) + np.sin(2 * np.pi * f2 * t) # 信号1
h = np.ones(100) / 100 # 信号2,一个简单的平滑滤波器
# 计算卷积
y = np.convolve(x, h, mode='same')
# 计算FFT
N = len(x)
X_fft = np.fft.fft(x, N)
H_fft = np.fft.fft(h, N)
Y_fft = X_fft * H_fft
y_fft = np.fft.ifft(Y_fft).real
# 绘制时域信号
plt.figure(figsize=(12, 6))
plt.subplot(3, 1, 1)
plt.plot(t, x)
plt.title('时域信号1')
plt.xlabel('时间 (s)')
plt.ylabel('幅度')
plt.subplot(3, 1, 2)
plt.plot(t, h)
plt.title('时域信号2 (平滑滤波器)')
plt.xlabel('时间 (s)')
plt.ylabel('幅度')
plt.subplot(3, 1, 3)
plt.plot(t, y, label='直接卷积')
plt.plot(t, y_fft, label='FFT 卷积', linestyle='--')
plt.title('卷积结果')
plt.xlabel('时间 (s)')
plt.ylabel('幅度')
plt.legend()
plt.show()
代码解析
- 生成两个离散时间信号:我们生成了由两个调制正弦波组成的离散时间信号x[n]以及一个低通滤波器h[n]。
- 完成卷积运算:利用
np.convolve函数完成了直接域中的卷积运算。 - 进行快速傅里叶变换(FFT):分别对x[n]和h[n]进行了快速傅里叶变换(FFT)。
- 在频域中完成卷积操作:通过在频域中执行卷积操作,并结合逆FFT将结果转换回时域。
- 展示原始信号、滤波器及其卷积结果的时间序列图:我们使用Matplotlib展示了原始信号、滤波器及其在时域中的卷积结果的时间序列图。
实际应用案例
音频信号处理
在音频信号处理领域中,Fast Fourier Transform (FFT) 常被用于分析音频信号的频谱特征,并应用于降噪、压缩等操作。通过将音频信号从时域转换到频域空间进行分析与处理,则能够更加便捷地识别与处理声音中的噪声及有用信息。
例子
假设给定一个音频信号,则该音频信号的频谱可通过FFT进行分析,并进而实现降噪处理。
import numpy as np
import matplotlib.pyplot as plt
import scipy.io.wavfile as wavfile
import scipy.signal as signal
# 读取音频信号
fs, x = wavfile.read('example.wav')
# 归一化信号
x = x / np.max(np.abs(x))
# 计算FFT
N = len(x)
X_fft = np.fft.fft(x)
# 计算频率轴
frequencies = np.fft.fftfreq(N, 1/fs)
# 绘制时域信号
plt.figure(figsize=(12, 6))
plt.subplot(2, 1, 1)
plt.plot(x)
plt.title('时域信号 (原始音频)')
plt.xlabel('样本点')
plt.ylabel('幅度')
# 绘制频域信号
plt.subplot(2, 1, 2)
plt.stem(frequencies, np.abs(X_fft), 'b', markerfmt=" ", basefmt="-b")
plt.title('频域信号 (原始音频)')
plt.xlabel('频率 (Hz)')
plt.ylabel('幅度')
plt.show()
# 设定滤波器参数
f_cutoff = 500 # 截止频率
b, a = signal.butter(5, f_cutoff, btype='low', fs=fs) # 低通滤波器
# 应用滤波器
x_filtered = signal.filtfilt(b, a, x)
# 计算滤波后的FFT
X_fft_filtered = np.fft.fft(x_filtered)
# 绘制滤波后的时域信号
plt.figure(figsize=(12, 6))
plt.subplot(2, 1, 1)
plt.plot(x_filtered)
plt.title('时域信号 (滤波后音频)')
plt.xlabel('样本点')
plt.ylabel('幅度')
# 绘制滤波后的频域信号
plt.subplot(2, 1, 2)
plt.stem(frequencies, np.abs(X_fft_filtered), 'b', markerfmt=" ", basefmt="-b")
plt.title('频域信号 (滤波后音频)')
plt.xlabel('频率 (Hz)')
plt.ylabel('幅度')
plt.show()
代码解析
- 获取音频样本:通过调用
scipy.io.wavfile.read函数读取音频文件内容,并获取其中的采样频率fs和对应的音频样本x。
2. 执行归一化处理:采用适当的方法对原始音频样本进行归一化处理操作。
3. 应用快速傅里叶变换算法:通过调用np.fft.fft函数执行快速傅里叶变换算法运算。
4. 生成频率轴向量:利用np.fft.fftfreq函数生成与频谱相对应的频率轴向量。
5. 创建时间序列图表:利用 Matplotlib 绘制原始音频样本的时间序列图表。
6. 绘制频谱图:通过 Matplotlib 绘制经过 FFT 处理后的频谱图。
7. 设计低通滤波器原型:利用scipy.signal.butter函数设计一个截止频率设定为500Hz的低通滤波器原型。
8. 执行去噪处理:采用scipy.signal.filtfilt方法对手机率数据执行去噪处理操作。
9. 再次执行FFT分析:针对去噪后的数据片段再次运行FFT分析过程。
10. 生成更新图表集合:利用 Matplotlib 创建包含去噪后时间序列图表及其对应的频谱图的一组新的图表集合展示结果信息。
图像信号处理
在图像信号处理领域中,DFT与FFT也被广泛应用于图像的频谱分析技术以及滤波器的设计当中.通过将图像的空间域信号转换为频域信号,能够更加容易地识别并有效地处理图像中的噪声干扰以及高频细节信息.
例子
假设我们有一张图像,我们可以通过 FFT 分析其频谱,并进行滤波处理。
import numpy as np
import matplotlib.pyplot as plt
import cv2
# 读取图像
image = cv2.imread('example.jpg', cv2.IMREAD_GRAYSCALE)
# 计算FFT
f = np.fft.fft2(image)
fshift = np.fft.fftshift(f)
magnitude_spectrum = 20 * np.log(np.abs(fshift))
# 绘制原始图像
plt.figure(figsize=(12, 6))
plt.subplot(2, 2, 1)
plt.imshow(image, cmap='gray')
plt.title('原始图像')
plt.axis('off')
# 绘制频域图像
plt.subplot(2, 2, 2)
plt.imshow(magnitude_spectrum, cmap='gray')
plt.title('频域图像')
plt.axis('off')
# 设定滤波器参数
rows, cols = image.shape
crow, ccol = rows // 2, cols // 2
mask = np.zeros((rows, cols), np.uint8)
r = 30
mask[crow - r:crow + r, ccol - r:ccol + r] = 1
# 应用滤波器
fshift_filtered = fshift * mask
f_ishift_filtered = np.fft.ifftshift(fshift_filtered)
img_back = np.fft.ifft2(f_ishift_filtered)
img_back = np.abs(img_back)
# 绘制滤波后的频域图像
plt.subplot(2, 2, 3)
plt.imshow(20 * np.log(np.abs(fshift_filtered) + 1), cmap='gray')
plt.title('滤波后的频域图像')
plt.axis('off')
# 绘制滤波后的空间域图像
plt.subplot(2, 2, 4)
plt.imshow(img_back, cmap='gray')
plt.title('滤波后的空间域图像')
plt.axis('off')
plt.show()
代码解析
获取灰度图像:通过调用 cv2.imread 函数获取一张灰度制的数字图像。
执行二维傅里叶变换:利用 np.fft.fft2 函数对获取到的灰度图像进行二维傅里叶变换。
绘制原始图像:利用 Matplotlib 绘图模块生成原始灰度图像的可视化展示。
显示频域幅度谱:通过调用 np.fft.fftshift 实现频谱中心化的操作后,并结合 Matplotlib 绘制频域幅度谱图形。
设计高斯低通滤波器:创建一个二维高斯低通滤波器模板矩阵,在中心区域赋值为 1,在外围区域赋值为 0。
应用滤波器至频域图:将设计好的高斯低通滤波器与之前计算得到的频域幅度谱进行乘积运算。
恢复空间域图像:通过调用 np.fft.ifftshift 和 np.fft.ifft2 函数对滤波后的频域数据进行逆变换操作,并生成空间域图像结果。
展示滤波后空间域图:利用 Matplotlib 绘制滤波后空间域图的幅度分布情况,并对其进行可视化展示。
总结
离散傅里叶变换(DFT)与快速傅里叶变换(FFT)是信号处理领域中的核心技术。DFT采用数学求和方法将时域信号转换至频域空间进行分析与研究;而FFT则运用分而治之的方法显著降低了计算复杂度,在工程实践中发挥着重要作用。该技术体系不仅涵盖了频谱分析这一基础领域,在滤波器设计与卷积运算等方面也展现出独特优势;此外,在图像编码压缩等应用场景中展现出显著价值;通过对实际案例的深入研究与探讨能够帮助我们更加深入地理解这些数字信号处理技术的具体实现方式及应用价值;从而为选择合适的算法框架提供理论支持
