IDFT的python实现

本文深入探讨了IDFT(逆离散傅里叶变换)的基本原理,包括其数学公式及矩阵表示,并通过代码实例展示了如何使用scipy库进行IDFT运算,同时也提供了手动实现IDFT的Python代码。
该文章已生成可运行项目,

IDFT

IDFT(Inverse Discrete Fourier Transform), 傅里叶逆变换,可以将频域信号转换到时域中, 它的公式非常简单:
x[n]=1N∑k=0N−1X[k]ej2πkn/N x[n] = \frac{1}{N} \sum_{k=0}^{N-1} X[k] e^{j2\pi kn/N} x[n]=N1k=0N1X[k]ej2πkn/N

X[k]X[k]X[k]:离散频率下标为k时的频率大小

x[n]x[n]x[n]: 离散时域信号序列

NNN: 信号序列的长度,也就是采样的个数

对比我们之前讲过的DFT,两者公式类似,但是注意在DFT中指数带负号,而IDFT中不带

从矩阵的角度看IDFT

DFT的矩阵表示

讲IDFT之前,我们先复习DFT的矩阵表示形式:
[s00s01⋯s0N−1⋮⋮⋮⋮sk0sk1⋯skN−1⋮⋮⋱⋮sN−10sN−11⋯sN−1N−1][x[0]x[1]⋮x[n]⋮x[N−1]]=[X[0]X[1]⋮X[k]⋮X[N−1]] \begin{bmatrix} s_0^0 & s_0^1 & \cdots & s_0^{N-1} \\ \vdots & \vdots & \vdots & \vdots\\ s_k^0 & s_k^1 & \cdots & s_k^{N-1} \\ \vdots & \vdots & \ddots & \vdots\\ s_{N-1}^0 & s_{N-1}^1 & \cdots & s_{N-1}^{N-1} \\ \end{bmatrix} \begin{bmatrix} x[0] \\ x[1] \\ \vdots\\ x[n] \\ \vdots \\ x[N-1] \end{bmatrix} = \begin{bmatrix} X[0] \\ X[1] \\ \vdots\\ X[k] \\ \vdots \\ X[N-1] \end{bmatrix} s00sk0sN10s01sk1sN11s0N1skN1sN1N1x[0]x[1]x[n]x[N1]=X[0]X[1]X[k]X[N1]
SSS矩阵中的每一行都是一个SkS_kSk向量,Sk=e−j2πkn/N,n=0,1,⋯ ,N−1S_k = e^{-j2\pi kn/N}, n=0,1,\cdots,N-1Sk=ej2πkn/N,n=0,1,,N1,进一步简化上面的表示,得到:
[⋯S0⋯⋮⋯Sk⋯⋮⋯SN−1⋯][x[0]x[1]⋮x[n]⋮x[N−1]]=[X[0]X[1]⋮X[k]⋮X[N−1]] \begin{bmatrix} \cdots & S_0 & \cdots \\ & \vdots & \\ \cdots & S_k & \cdots \\ & \vdots & \\ \cdots & S_{N-1} & \cdots \\ \end{bmatrix} \begin{bmatrix} x[0] \\ x[1] \\ \vdots\\ x[n] \\ \vdots \\ x[N-1] \end{bmatrix} = \begin{bmatrix} X[0] \\ X[1] \\ \vdots\\ X[k] \\ \vdots \\ X[N-1] \end{bmatrix} S0SkSN1x[0]x[1]x[n]x[N1]=X[0]X[1]X[k]X[N1]

IDFT的矩阵表示

从IDFT的公式,可以看出,其实IDFT和DFT表示是一样的,只是对象发生了变化。具体来说,有两个变化:

  • 由于指数部分不再有符号,SkS_kSk进行了共轭操作,得到Sk∗S_k^*Sk
  • 输入是频率信息X[k]

因此,矩阵表示变成了下面这样:
[⋯S0∗⋯⋮⋯Sk∗⋯⋮⋯SN−1∗⋯][X[0]X[1]⋮X[n]⋮X[N−1]]=[x[0]x[1]⋮x[k]⋮x[N−1]] \begin{bmatrix} \cdots & S_0^* & \cdots \\ & \vdots & \\ \cdots & S_k^* & \cdots \\ & \vdots & \\ \cdots & S_{N-1}^* & \cdots \\ \end{bmatrix} \begin{bmatrix} X[0] \\ X[1] \\ \vdots\\ X[n] \\ \vdots \\ X[N-1] \end{bmatrix} = \begin{bmatrix} x[0] \\ x[1] \\ \vdots\\ x[k] \\ \vdots \\ x[N-1] \end{bmatrix} S0SkSN1X[0]X[1]X[n]X[N1]=x[0]x[1]x[k]x[N1]

Talk is cheap, show me the code

接下来就简单多了,我们将先介绍如何使用scipy中ifft,然后自己动手实现一份ifft

导入必要的包

import numpy as np
from scipy.fftpack import fft, ifft

import matplotlib.pyplot as plt

%matplotlib notebook

生成信号用于测试

def generate_sine(N, A, fs, f0, phi):
    '''
    N : number of samples
    A : amplitude
    fs: sample rate
    f0: frequency
    phi: initial phase
    '''
    
    T = 1/fs
    n = np.arange(N)
    x = A*np.cos( 2*np.pi*f0*n*T + phi )
    
    return x

# generate signal
N = 501
A = 0.8
fs = 44100
f0 = 1000
phi = 0.0

x = generate_sine(N, A, fs, f0, phi)

plt.figure()
plt.plot(x)
plt.show()

png

使用scipy中的ifft

# fft the signal
N = 512                       # fft size
X = fft(x, N)
mX = np.abs(X)
pX = np.angle(X)

freq_axis = np.arange(N)/N * fs
plt.figure(figsize=(10, 12))
ax = plt.subplot(3,1,1)
plt.plot(freq_axis, mX)
ax.set_title('Magnitude')

ax = plt.subplot(3,1,2)
plt.plot(freq_axis, pX)
ax.set_title('Phase')


# ifft it
ifft_x = ifft(X)
ax = plt.subplot(3,1,3)
plt.plot(ifft_x)
ax.set_title('Synthesise')

plt.show()

png

自己动手写ifft

只有两个地方要注意:

  • 不要忘记乘上 1/N
  • Sk∗S_k^*SkSkS_kSk向量的共轭后的结果。反映在代码中,就是Sk∗S_k^*Sk不要共轭操作之间返回
def generate_complex_sinusoid(n, N):
    '''
    n : time index (or frequency index)
    N : number of sample
    '''
    
    k = np.arange(N)
    
    c_sin = np.exp(1j*2*np.pi*k*n/N)
    
    return c_sin

# ifft loop
ifft_x = np.array([])

for i in range(N):
    s = generate_complex_sinusoid(i, N)
    ifft_x = np.append(ifft_x, 1/N * np.sum(X*s))

plt.figure()
plt.plot(ifft_x)
plt.show()

png

总结

通过自己动手,我们发现IDFT的原来和实现很简单,几乎与DFT一模一样,唯一需要注意的点就是Sk∗S_k^*Sk

本文章已经生成可运行项目
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值