2.4 :快速傅里叶变换 (FFT) Scipy 核心模块详解:2.4 :快速傅里叶变换 (FFT) 快速傅里叶变换 (FFT) 是信号处理、图像分析和科学计算中不可或缺的工具。 模块提供了高效且全面的 FFT 实现,允许用户执行离散傅里叶变换 (DFT) 及其逆变换,以及相关的操作。 本文将深入探讨 模块的核心功能、使用方法以及一些实际应用。 2.4.1 模块概述 模块旨在提供一个统一的接口,用于执行各种类型的 FFT。它包含了多个函数,涵盖了一维、二维以及多维的 FFT,实数 FFT,Hermitian FFT 等。 主要功能: 一维 FFT ( ): 计算一维离散傅里叶变换。 逆一维 FFT ( ): 计算一维离散傅里叶逆变换。 二维 FFT ( ): 计算二维离散傅里叶变换。
scipy.fft:快速傅里叶变换 (FFT)scipy.fft:快速傅里叶变换 (FFT)快速傅里叶变换 (FFT) 是信号处理、图像分析和科学计算中不可或缺的工具。scipy.fft 模块提供了高效且全面的 FFT 实现,允许用户执行离散傅里叶变换 (DFT) 及其逆变换,以及相关的操作。 本文将深入探讨 scipy.fft 模块的核心功能、使用方法以及一些实际应用。
scipy.fft 模块概述scipy.fft 模块旨在提供一个统一的接口,用于执行各种类型的 FFT。它包含了多个函数,涵盖了一维、二维以及多维的 FFT,实数 FFT,Hermitian FFT 等。
主要功能:
一维 FFT (fft): 计算一维离散傅里叶变换。
逆一维 FFT (ifft): 计算一维离散傅里叶逆变换。
二维 FFT (fft2): 计算二维离散傅里叶变换。
逆二维 FFT (ifft2): 计算二维离散傅里叶逆变换。
多维 FFT (fftn): 计算 N 维离散傅里叶变换。
逆多维 FFT (ifftn): 计算 N 维离散傅里叶逆变换。
实数 FFT (rfft): 对实数输入进行 FFT,利用对称性提高效率。
逆实数 FFT (irfft): 计算实数 FFT 的逆变换。
Hermitian FFT (hfft): 对具有 Hermitian 对称性的输入进行 FFT。
逆 Hermitian FFT (ihfft): 计算 Hermitian FFT 的逆变换。
频率生成 (fftfreq, rfftfreq): 生成 FFT 频率轴。
移频 (fftshift, ifftshift): 将零频率分量移动到频谱中心。
fft 和 ifft)fft(x, n=None, axis=-1, norm=None, overwrite_x=False, workers=None, plan=None) 函数计算输入数组 x 的一维离散傅里叶变换。
x: 输入数组。
n: 可选,指定 FFT 的长度。如果 n 小于 x 的长度,则 x 将被截断。如果 n 大于 x 的长度,则 x 将被填充零。
axis: 可选,指定进行 FFT 的轴。默认为 -1,即最后一个轴。
norm: 可选,指定规范化模式。可以是 "backward" (默认), "ortho", 或 "forward"。
overwrite_x: 可选,如果为 True,则允许修改输入数组 x。
workers: 可选,指定用于并行计算的线程数。
plan: 可选,预先计算的 FFT 计划。
ifft(x, n=None, axis=-1, norm=None, overwrite_x=False, workers=None, plan=None) 函数计算一维离散傅里叶逆变换。参数与 fft 函数类似。
代码示例:
import numpy as np from scipy.fft import fft, ifft import matplotlib.pyplot as plt # 生成一个简单的信号 N = 256 # 采样点数 T = 1.0 / 800.0 # 采样周期 x = np.linspace(0.0, N*T, N, endpoint=False) y = np.sin(2.0*np.pi*50.0*x) + 0.5*np.sin(2.0*np.pi*80.0*x) # 执行 FFT yf = fft(y) xf = np.linspace(0.0, 1.0/(2.0*T), N//2) # 绘制频谱 plt.figure(figsize=(12, 6)) plt.subplot(2, 1, 1) plt.plot(x, y) plt.title("Original Signal") plt.xlabel("Time (s)") plt.ylabel("Amplitude") plt.subplot(2, 1, 2) plt.plot(xf, 2.0/N * np.abs(yf[:N//2])) plt.title("FFT Spectrum") plt.xlabel("Frequency (Hz)") plt.ylabel("Amplitude") plt.tight_layout() plt.show() # 执行逆 FFT y_reconstructed = ifft(yf) # 验证重建信号 plt.figure(figsize=(12, 4)) plt.plot(x, y, label="Original") plt.plot(x, np.real(y_reconstructed), label="Reconstructed", linestyle="--") plt.title("Original vs. Reconstructed Signal") plt.xlabel("Time (s)") plt.ylabel("Amplitude") plt.legend() plt.tight_layout() plt.show()
这段代码首先生成一个包含两个正弦波的信号,然后使用 fft 函数计算其频谱,并绘制原始信号和频谱。接着,使用 ifft 函数对频谱进行逆变换,重建原始信号,并将其与原始信号进行比较。
fft2 和 ifft2)fft2(x, s=None, axes=(-2, -1), norm=None, overwrite_x=False, workers=None, plan=None) 函数计算输入数组 x 的二维离散傅里叶变换。
x: 输入数组。
s: 可选,指定 FFT 的形状。如果 s 小于 x 的形状,则 x 将被截断。如果 s 大于 x 的形状,则 x 将被填充零。
axes: 可选,指定进行 FFT 的轴。默认为 (-2, -1),即最后两个轴。
其他参数与 fft 函数类似。
ifft2(x, s=None, axes=(-2, -1), norm=None, overwrite_x=False, workers=None, plan=None) 函数计算二维离散傅里叶逆变换。参数与 fft2 函数类似。
代码示例:
import numpy as np from scipy.fft import fft2, ifft2 import matplotlib.pyplot as plt # 创建一个简单的二维图像 N = 64 image = np.zeros((N, N)) image[N//4:3*N//4, N//4:3*N//4] = 1 # 创建一个正方形 plt.imshow(image, cmap='gray') plt.title("Original Image") plt.show() # 执行二维 FFT fourier_image = fft2(image) # 将零频率分量移动到中心 fourier_amplitudes = np.fft.fftshift(np.abs(fourier_image)) # 显示频谱 plt.imshow(np.log(1 + fourier_amplitudes), cmap='gray') plt.title("FFT Spectrum (log scale)") plt.show() # 执行二维逆 FFT reconstructed_image = ifft2(fourier_image) # 显示重建图像 plt.imshow(np.real(reconstructed_image), cmap='gray') plt.title("Reconstructed Image") plt.show()
这段代码首先创建一个简单的二维图像(一个正方形),然后使用 fft2 函数计算其二维频谱,并使用 fftshift 函数将零频率分量移动到频谱中心。接着,使用 ifft2 函数对频谱进行逆变换,重建原始图像。
fftn 和 ifftn)fftn(x, s=None, axes=None, norm=None, overwrite_x=False, workers=None, plan=None) 函数计算输入数组 x 的 N 维离散傅里叶变换。
x: 输入数组。
s: 可选,指定 FFT 的形状。
axes: 可选,指定进行 FFT 的轴。如果为 None,则对所有轴进行 FFT。
其他参数与 fft 函数类似。
ifftn(x, s=None, axes=None, norm=None, overwrite_x=False, workers=None, plan=None) 函数计算 N 维离散傅里叶逆变换。参数与 fftn 函数类似。
代码示例:
import numpy as np from scipy.fft import fftn, ifftn # 创建一个三维数组 N = 16 data = np.random.rand(N, N, N) # 执行三维 FFT fourier_data = fftn(data) # 执行三维逆 FFT reconstructed_data = ifftn(fourier_data) # 验证重建数据 print("Max difference:", np.max(np.abs(data - np.real(reconstructed_data))))
这段代码创建一个随机的三维数组,然后使用 fftn 函数计算其三维频谱,并使用 ifftn 函数对频谱进行逆变换,重建原始数据。最后,验证重建数据的准确性。
rfft 和 irfft)由于实数信号的傅里叶变换具有 Hermitian 对称性,因此只需要存储一半的频谱信息。rfft 函数利用这一特性,可以更高效地计算实数信号的 FFT。
rfft(x, n=None, axis=-1, norm=None, overwrite_x=False, workers=None, plan=None) 函数计算实数输入数组 x 的 FFT。
irfft(x, n=None, axis=-1, norm=None, overwrite_x=False, workers=None, plan=None) 函数计算实数 FFT 的逆变换。
代码示例:
import numpy as np from scipy.fft import rfft, irfft import matplotlib.pyplot as plt # 生成一个实数信号 N = 256 T = 1.0 / 800.0 x = np.linspace(0.0, N*T, N, endpoint=False) y = np.sin(2.0*np.pi*50.0*x) + 0.5*np.sin(2.0*np.pi*80.0*x) # 执行实数 FFT yf = rfft(y) xf = np.linspace(0.0, 1.0/(2.0*T), N//2 + 1) # 绘制频谱 plt.figure(figsize=(12, 6)) plt.subplot(2, 1, 1) plt.plot(x, y) plt.title("Original Real Signal") plt.xlabel("Time (s)") plt.ylabel("Amplitude") plt.subplot(2, 1, 2) plt.plot(xf, 2.0/N * np.abs(yf)) plt.title("Real FFT Spectrum") plt.xlabel("Frequency (Hz)") plt.ylabel("Amplitude") plt.tight_layout() plt.show() # 执行逆实数 FFT y_reconstructed = irfft(yf) # 验证重建信号 plt.figure(figsize=(12, 4)) plt.plot(x, y, label="Original") plt.plot(x, np.real(y_reconstructed), label="Reconstructed", linestyle="--") plt.title("Original vs. Reconstructed Signal (Real FFT)") plt.xlabel("Time (s)") plt.ylabel("Amplitude") plt.legend() plt.tight_layout() plt.show()
fftfreq 和 rfftfreq)fftfreq(n, d=1.0, axis=0) 函数生成 FFT 频率轴。
n: 采样点数。
d: 采样周期。
rfftfreq(n, d=1.0, axis=0) 函数生成实数 FFT 的频率轴。
代码示例:
import numpy as np from scipy.fft import fftfreq, rfftfreq # 生成频率轴 N = 256 T = 1.0 / 800.0 xf = fftfreq(N, T)[:N//2] # 使用 fftfreq xrf = rfftfreq(N, T) # 使用 rfftfreq print("Frequencies (fftfreq):", xf[:10]) print("Frequencies (rfftfreq):", xrf[:10])
fftshift 和 ifftshift)fftshift(x, axes=None, norm=None) 函数将零频率分量移动到频谱中心。
ifftshift(x, axes=None, norm=None) 函数执行 fftshift 的逆操作。
代码示例:
import numpy as np from scipy.fft import fft, fftshift import matplotlib.pyplot as plt # 生成一个信号 N = 256 T = 1.0 / 800.0 x = np.linspace(0.0, N*T, N, endpoint=False) y = np.sin(2.0*np.pi*50.0*x) # 执行 FFT yf = fft(y) # 移动零频率分量 yf_shifted = fftshift(yf) # 生成频率轴 xf = np.linspace(-1.0/(2.0*T), 1.0/(2.0*T), N) # 绘制频谱 plt.figure(figsize=(12, 6)) plt.subplot(2, 1, 1) plt.plot(xf, np.abs(yf_shifted)) plt.title("FFT Spectrum (Shifted)") plt.xlabel("Frequency (Hz)") plt.ylabel("Amplitude") plt.tight_layout() plt.show()
norm)scipy.fft 模块中的 norm 参数控制 FFT 的规范化方式。有三种规范化模式:
"backward" (默认): DFT 的标准定义,没有额外的规范化因子。
"ortho": 使 DFT 成为酉变换,前向和逆向变换都乘以 1/sqrt(N)。这在信号处理中非常有用,因为它保持了能量。
"forward": 前向变换乘以 1/N,逆向变换没有额外的规范化因子。
选择哪种规范化模式取决于具体的应用场景。
对于大型数据集,FFT 的计算可能非常耗时。scipy.fft 模块提供了一些优化选项:
overwrite_x: 如果设置为 True,则允许修改输入数组 x,这可以减少内存占用和复制开销。
workers: 可以指定用于并行计算的线程数,从而利用多核 CPU 提高计算速度。
plan: 预先计算的 FFT 计划可以显著提高重复 FFT 操作的性能。
FFT 在许多领域都有广泛的应用,以下是一些例子:
信号处理: 频谱分析、滤波、信号重建。
图像处理: 图像增强、图像压缩、图像识别。
科学计算: 求解偏微分方程、计算卷积。
例如,可以使用 FFT 进行图像去噪:
import numpy as np from scipy.fft import fft2, ifft2, fftshift import matplotlib.pyplot as plt from skimage import io, img_as_float from skimage.util import random_noise # 加载图像 image = img_as_float(io.imread('image.jpg', as_gray=True)) # 添加噪声 noisy_image = random_noise(image, var=0.01) # 执行二维 FFT fourier_image = fft2(noisy_image) fourier_amplitudes = fftshift(fourier_image) # 理想低通滤波器 rows, cols = image.shape crow, ccol = rows//2 , cols//2 mask = np.zeros((rows, cols), np.uint8) r = 30 # 可调节半径 center = [crow, ccol] x, y = np.ogrid[:rows, :cols] mask_area = (x - center[0]) ** 2 + (y - center[1]) ** 2 <= r*r mask[mask_area] = 1 # 应用滤波器 fourier_amplitudes_filtered = fourier_amplitudes * mask # 逆移频 fourier_image_filtered = fftshift(fourier_amplitudes_filtered) # 执行二维逆 FFT filtered_image = ifft2(fourier_image_filtered).real # 显示结果 plt.figure(figsize=(15,5)) plt.subplot(131) plt.imshow(noisy_image, cmap='gray') plt.title('Noisy Image') plt.subplot(132) plt.imshow(np.log(np.abs(fourier_amplitudes)), cmap='gray') plt.title('Noisy Image Spectrum') plt.subplot(133) plt.imshow(filtered_image, cmap='gray') plt.title('Filtered Image') plt.tight_layout() plt.show()