在上一篇文章中,我们在Python中实施了离散的傅里叶变换(DFT)。
在本文中,让我们看一下逆过程:将频率值向量转换为时间值的向量。
从数学上讲,反离散的傅里叶变换(IDFT)由以下方式给出:
$$x[n]=\frac{1}{N}\sum_{k=0}^{N-1}X[k]\cdot e^{i2\pi\frac{k}{N}n}$$
其中:
- $N$是采样数量
- $n$是当前样本的序号
- $k$是当前频率
- $X[k]$是$n$处的DFT
- $x[n]$是$n$处的iDFT
由于离散傅里叶变换的矩阵是方形且可逆的,因此反向变换是可行的。理想情况下,我们应该能够收回我们的原始嘈杂信号。
前期准备:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| import numpy as np import matplotlib.pyplot as plt
rate = 100 interval = 1 / rate
t_start = 0 t_end = 1 t = np.arange(t_start, t_end, interval)
def getSineSignal(amps, freqs, t): x = np.zeros_like(t) for a, f in zip(amps, freqs): x += a * np.sin(2 * np.pi * f * t)
return x
amps = np.array([9, 10, 2.3]) freqs = np.array([2, 1, 10]) x = getSineSignal(amps, freqs, t)
def DFT(x): N = x.size n = np.arange(N) k = n.reshape((N, 1))
e = np.exp(-2j * np.pi * k * n / N) X_k = np.dot(e, x) return X_k
X_k = DFT(x) N = X_k.size n = np.arange(N) T = N / rate freq = n / T
plt.figure(figsize=(8,6)) plt.stem(freq, abs(X_k), 'b', markerfmt=' ', basefmt='-b') plt.xlabel(r'$\omega$ '+'(Hz)') plt.ylabel('DFT Amplitude '+r'$|X(\omega)|$') plt.grid(True)
|

DFT函数返回了一个复数的向量,包含每个频率下的幅度和相位。我们称该向量X_K。
现在,我们将使用X_K收回我们的原始信号。
1 2 3 4 5 6 7 8 9 10 11 12 13
| def iDFT(X_k): N = X_k.size n = np.arange(N) k = n.reshape((N,1))
e = np.exp(2j * np.pi * k * n / N) x = np.zeros_like(X_k) for row in range(N): for col in range(N): x[row] += e[row, col] * X_k[col] x /= N
return x.real
|
补充:取复数的实部和虚部
1 2 3
| z1 = 3+4j print(z1.real) print(z1.imag)
|
重建信号,并将其与原始信号进行比较。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| inv_x = iDFT(X_k)
plt.figure(figsize = (14, 5)) plt.subplot(121) plt.plot(t, x, 'b') plt.xlabel('t') plt.ylabel('x') plt.title('Original Signal') plt.grid(True) plt.subplot(122) plt.plot(t, inv_x, 'r') plt.xlabel('t') plt.ylabel('x') plt.title('Reconstructed Signal') plt.tight_layout() plt.grid(True)
|

当然,我们有一个干净的信号。这使重建过程变得更加容易
1 2 3 4 5 6 7 8 9 10
| plt.figure(figsize = (7, 5)) plt.plot(t, x, 'b', label='Original Signal') plt.plot(t, inv_x, 'r--', linewidth=2, label='Reconstructed Signal') plt.xlabel('t') plt.ylabel('x') plt.title('Original and Reconstructed Signals') plt.grid(True) plt.legend() plt.tight_layout() plt.show()
|

改进:
1 2 3 4 5 6 7 8 9 10
| def viDFT(X_k): N = X_k.size n = np.arange(N) k = n.reshape((N,1))
e = np.exp(2j * np.pi * k * n / N) x = np.dot(e, X_k) / N
return x.real
|
就像以前一样,矢量化函数的速度快了10倍。