使用python实现快速傅里叶变换(FFT)

说明:本文适合信号处理方面有一定的基础的人阅读,能够理解什么时候傅里叶级数和傅里叶变换,能够理解他们的核心思想以及基本原理,能够理解到底什么是“频率域”,能够从频率的角度分析信号。

一、一些关键概念的引入

1、离散傅里叶变换(DFT)

离散傅里叶变换(discrete Fourier transform) 傅里叶分析方法是信号分析的最基本方法,傅里叶变换是傅里叶分析的核心,通过它把信号从时间域变换到频率域,进而研究信号的频谱结构和变化规律。但是它的致命缺点是:计算量太大,时间复杂度太高,当采样点数太高的时候,计算缓慢,由此出现了DFT的快速实现,即下面的快速傅里叶变换FFT。

2、快速傅里叶变换(FFT)

计算量更小的离散傅里叶的一种实现方法。详细细节这里不做描述。

3、采样频率以及采样定理

采样频率:采样频率,也称为采样速度或者采样率,定义了每秒从连续信号中提取并组成离散信号的采样个数,它用赫兹(Hz)来表示。采样频率的倒数是采样周期或者叫作采样时间,它是采样之间的时间间隔。通俗的讲采样频率是指计算机每秒钟采集多少个信号样本。

采样定理:所谓采样定理 ,又称香农采样定理,奈奎斯特采样定理,是信息论,特别是通讯与信号处理学科中的一个重要基本结论。采样定理指出,如果信号是带限的,并且采样频率高于信号带宽的两倍,那么,原来的连续信号可以从采样样本中完全重建出来。

定理的具体表述为:在进行模拟/数字信号的转换过程中,当采样频率fs大于信号中最高频率fmax的2倍时,即

fs>2*fmax

采样之后的数字信号完整地保留了原始信号中的信息,一般实际应用中保证采样频率为信号最高频率的2.56~4倍;采样定理又称奈奎斯特定理

4、如何理解采样定理?

在对连续信号进行离散化的过程中,难免会损失很多信息,就拿一个简单地正弦波而言,如果我1秒内就选择一个点,很显然,损失的信号太多了,光着一个点我根本不知道这个正弦信号到底是什么样子的,自然也没有办法根据这一个采样点进行正弦波的还原,很明显,我采样的点越密集,那越接近原来的正弦波原始的样子,自然损失的信息越少,越方便还原正弦波。故而

采样定理说明采样频率与信号频率之间的关系,是连续信号离散化的基本依据。 它为采样率建立了一个足够的条件,该采样率允许离散采样序列从有限带宽的连续时间信号中捕获所有信息。

二、使用scipy包实现快速傅里叶变换

本节不会说明FFT的底层实现,只介绍scipy中fft的函数接口以及使用的一些细节。

1、产生原始信号——原始信号是三个正弦波的叠加

import numpy as np
from scipy.fftpack import fft,ifft
import matplotlib.pyplot as plt
from matplotlib.pylab import mpl 
mpl.rcParams['font.sans-serif'] = ['SimHei']   #显示中文mpl.rcParams['axes.unicode_minus']=False       #显示负号  
#采样点选择1400个,因为设置的信号频率分量最高为600赫兹,根据采样定理知采样频率要大于信号频率2倍,所以这里设置采样频率为1400赫兹(即一秒内有1400个采样点,一样意思的)
x=np.linspace(0,1,1400)       
#设置需要采样的信号,频率分量有200,400和600
y=7*np.sin(2*np.pi*200*x) + 5*np.sin(2*np.pi*400*x)+3*np.sin(2*np.pi*600*x)

这里原始信号的三个正弦波的频率分别为,200Hz、400Hz、600Hz,最大频率为600赫兹。根据采样定理,fs至少是600赫兹的2倍,这里选择1400赫兹,即在一秒内选择1400个点。

原始的函数图像如下:

plt.figure()
plt.plot(x,y)   
plt.title('原始波形') 
plt.figure()
plt.plot(x[0:50],y[0:50])   
plt.title('原始部分波形(前50组样本)')
plt.show()

由图可见,由于采样点太过密集,看起来不好看,我们只显示前面的50组数据,如下:

2、快速傅里叶变换

其实scipy和numpy一样,实现FFT非常简单,仅仅是一句话而已,函数接口如下:

from scipy.fftpack import fft,ifft

from numpy import fft,ifft

其中fft表示快速傅里叶变换,ifft表示其逆变换。具体实现如下:

fft_y=fft(y)                          #快速傅里叶变换
print(len(fft_y))
print(fft_y[0:5])
'''
运行结果如下:
1400
[-4.18864943e-12+0.j   9.66210986e-05-0.04305756j   
3.86508070e-04-0.08611996j    8.69732036e-04-0.12919206j    
1.54641157e-03-0.17227871j]
'''

我们发现以下几个特点:

(1)变换之后的结果数据长度和原始采样信号是一样的

(2)每一个变换之后的值是一个复数,为a+bj的形式,那这个复数是什么意思呢?

我们知道,复数a+bj在坐标系中表示为(a,b),故而复数具有模和角度,我们都知道快速傅里叶变换具有

“振幅谱”“相位谱”,它其实就是通过对快速傅里叶变换得到的复数结果进一步求出来的,

那这个直接变换后的结果是不是就是我需要的,当然是需要的,在FFT中,得到的结果是复数,

(3)FFT得到的复数的模(即绝对值)就是对应的“振幅谱”,复数所对应的角度,就是所对应的“相位谱”,现在可以画图了。

3、FFT的原始频谱

N=1400x = np.arange(N)           # 频率个数 
abs_y=np.abs(fft_y)                # 取复数的绝对值,即复数的模(双边频谱)
angle_y=np.angle(fft_y)              #取复数的角度 
plt.figure()
plt.plot(x,abs_y)   
plt.title('双边振幅谱(未归一化)') 
plt.figure()
plt.plot(x,angle_y)   
plt.title('双边相位谱(未归一化)')
plt.show()

显示结果如下:

双边振幅谱(未归一化)
双边相位谱(未归一化)

注意:我们在此处仅仅考虑“振幅谱”,不再考虑相位谱。

我们发现,振幅谱的纵坐标很大,而且具有对称性,这是怎么一回事呢?

关键:关于振幅值很大的解释以及解决办法——归一化取一半处理

比如有一个信号如下:

Y=A1+A2cos(2πω2+φ2)+A3cos(2πω3+φ3)+A4*cos(2πω4+φ4)

经过FFT之后,得到的“振幅图”中,

第一个峰值(频率位置)的模是A1的N倍,N为采样点,本例中为N=1400,此例中没有,因为信号没有常数项A1

第二个峰值(频率位置)的模是A2的N/2倍,N为采样点,

第三个峰值(频率位置)的模是A3的N/2倍,N为采样点,

第四个峰值(频率位置)的模是A4的N/2倍,N为采样点,

依次下去......

考虑到数量级较大,一般进行归一化处理,既然第一个峰值是A1的N倍,那么将每一个振幅值都除以N即可

FFT具有对称性,一般只需要用N的一半,前半部分即可。

4、将振幅谱进行归一化和取半处理

先进行归一化

normalization_y=abs_y/N            #归一化处理(双边频谱)plt.figure()
plt.plot(x,normalization_y,'g')
plt.title('双边频谱(归一化)',fontsize=9,color='green')
plt.show()

结果为:

双边频谱(归一化)

现在我们发现,振幅谱的数量级不大了,变得合理了,

接下来进行取半处理:

half_x = x[range(int(N/2))]                                  #取一半区间
normalization_half_y = normalization_y[range(int(N/2))]      #由于对称性,只取一半区间(单边频谱)
plt.figure()
plt.plot(half_x,normalization_half_y,'b')
plt.title('单边频谱(归一化)',fontsize=9,color='blue')
plt.show()
单边频谱(归一化)'

这就是我们最终的结果,需要的“振幅谱”

PS:还需要注意fft的第0个数据,是表示直流分量,本例中没有,大部分情况不考虑第0个数据

三、完整代码

import numpy as npfrom scipy.fftpack import fft,ifftimport matplotlib.pyplot as pltfrom matplotlib.pylab import mpl mpl.rcParams['font.sans-serif'] = ['SimHei']   #显示中文mpl.rcParams['axes.unicode_minus']=False       #显示负号 #采样点选择1400个,因为设置的信号频率分量最高为600赫兹,根据采样定理知采样频率要大于信号频率2倍,所以这里设置采样频率为1400赫兹(即一秒内有1400个采样点,一样意思的)x=np.linspace(0,1,1400)       #设置需要采样的信号,频率分量有200,400和600y=7*np.sin(2*np.pi*200*x) + 5*np.sin(2*np.pi*400*x)+3*np.sin(2*np.pi*600*x) fft_y=fft(y)                          #快速傅里叶变换 N=1400x = np.arange(N)             # 频率个数half_x = x[range(int(N/2))]  #取一半区间 abs_y=np.abs(fft_y)                # 取复数的绝对值,即复数的模(双边频谱)angle_y=np.angle(fft_y)            #取复数的角度normalization_y=abs_y/N            #归一化处理(双边频谱)                              normalization_half_y = normalization_y[range(int(N/2))]      #由于对称性,只取一半区间(单边频谱) plt.subplot(231)plt.plot(x,y)   plt.title('原始波形') plt.subplot(232)plt.plot(x,fft_y,'black')plt.title('双边振幅谱(未求振幅绝对值)',fontsize=9,color='black')  plt.subplot(233)plt.plot(x,abs_y,'r')plt.title('双边振幅谱(未归一化)',fontsize=9,color='red')  plt.subplot(234)plt.plot(x,angle_y,'violet')plt.title('双边相位谱(未归一化)',fontsize=9,color='violet') plt.subplot(235)plt.plot(x,normalization_y,'g')plt.title('双边振幅谱(归一化)',fontsize=9,color='green') plt.subplot(236)plt.plot(half_x,normalization_half_y,'blue')plt.title('单边振幅谱(归一化)',fontsize=9,color='blue') plt.show() 
汇总
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容

  • 快速傅里叶变换(FFT) 离散傅里叶变换(DFT) 基础理论是傅里叶变换的分离形式,和采样定理(香菜定理) 采样定...
    DUTZCS阅读 2,746评论 0 1
  • 采样定理:所谓采样定理 ,又称香农采样定理,奈奎斯特采样定理,是信息论,特别是通讯与信号处理学科中的一个重要基本结...
    dingtom阅读 1,752评论 0 0
  • 对于通信和信号领域的同学来说,傅里叶变换、信号采样定理一定不陌生。本文主要对傅里叶变换中涉及的时频关系对应进行说明...
    in469阅读 4,209评论 0 0
  • 傅里叶变换 傅里叶变换(Fourier Transform,简称FT)常用于数字信号处理,它的目的是将时间域上的信...
    lk311阅读 1,827评论 0 2
  • 一、傅立叶变换的由来 关于傅立叶变换,无论是书本还是在网上可以很容易找到关于傅立叶变换的描述,但是大都是些故弄玄虚...
    constant007阅读 4,398评论 1 10