傅里叶Fourier变换fft-python-scipy-幅值-辐角-相位(一)

基础回顾

Fourier变换就是将周期信号沿正交基分解,而一组良好的正交基就是正弦/余弦函数,完备的正交基为 e j 2 π n t T 或 e j 2 π n f 0 t \displaystyle e^{j\frac {2 \pi n t}{T}} 或 e^{j2 \pi n f_0t} ejT2πntej2πnf0t , 正交容易证明,完备性证明复杂。

基于此,连续域上的Fourier变换可以写为

F ( ω ) = ∫ − ∞ + ∞ f ( t ) e − j ω t d t \displaystyle F(\omega) = \int_{-\infin}^{+\infin} f(t) e^{-j\omega t} {\rm d}t F(ω)=+f(t)ejωtdt

其逆变换为

f ( t ) = 1 2 π ∫ − ∞ + ∞ F ( ω ) e − j ω t d w \displaystyle f(t) = \frac 1 {2\pi} \int_{-\infin}^{+\infin} F(\omega) e^{-j\omega t}{\rm d}w f(t)=2π1+F(ω)ejωtdw

在上述工作基础之上发展了离散Fourier变换(DFT),将其变换对写为

F ( k ) = ∑ n = 0 N − 1 f ( n ) e − j 2 π N k n F(k) = \sum_{n=0}^{N-1} f(n) e^{-j \frac{2\pi }{N} k n} F(k)=n=0N1f(n)ejN2πkn

f ( n ) = 1 N ∑ n = 0 N − 1 F ( k ) e j 2 π N k n \displaystyle f(n) = \frac 1 {N} \sum_{n=0}^{N-1} F(k)e^{j \frac{2\pi }{N} k n} f(n)=N1n=0N1F(k)ejN2πkn

scipy-fft

假设 采样频率Fs,信号频率F,信号长度L,采样点数N。那么FFT之后结果就是N个点的复数。每一个点就对应着一个频率点。这个点的模值,就是该频率值下的幅度特性。

采样频率Fs,被N-1个点平均分成N等份,每个点的频率依次增加。为了方便进行FFT运算,通常N取大于信号长度L的2的整数次方。用matlab 的 nextpower2 函数实现。
例如某点n所表示的频率为:Fn=(n-1)*Fs/N。由上面的公式可以看出,Fn所能分辨的最小频率为Fs/N。如果采样频率Fs为1024Hz,采样点数为1024点,则可以分辨到1Hz。 1024Hz的采样率采样1024点,刚好是1秒,也就是说,采样1秒时间的信号并做FFT,则结果可以分析到1Hz。如果采样2秒时间的信号,则N为2048,并做FFT,则结果可以分析到0.5Hz。 如果要提高频率分辨力,则必须增加采样点数,也即采样时间。频率分辨率和采样时间是倒数关系。
引用自cnblogs
假设FFT之后某点n用复数a+bi表示,该复数的模就是 A n = a 2 + b 2 A_n=\sqrt{a^2+b^2} An=a2+b2 ,相位就是 P n = a r c t a n b a P_n=arctan \displaystyle\frac{b}{a} Pn=arctanab 。根据以上的结果,就可以计算出n点(n≠1,且n<=N/2)对应的信号的表达式为:

A n N / 2 c o s ( 2 π F n t + P n ) \displaystyle \frac{A_n}{N/2}cos(2\pi F_nt+P_n) N/2Ancos(2πFnt+Pn), 即 2 A n N c o s ( 2 π F n t + P n ) \displaystyle \frac{2A_n}{N}cos(2\pi F_nt+P_n) N2Ancos(2πFnt+Pn)

示例计算 频率、幅值、相位

原始波形

# 基频是 1/(2pi)Hz, 最大是 3/(2pi) Hz, ω分别是1,2,3
t = np.linspace(0,2*np.pi,240)
y = 1+ 1*np.sin(t ) + 2*np.sin(2*t)+3*np.sin(3*t)
plt.figure()
plt.plot(t,y)   
plt.title('原始波形')

输出为:
原始波形

FFT处理

# 采样点数
N = len(t)
# 采样频率
fs = N/(2*np.pi)
N,fs
# FFT得到的复数的模(即绝对值)就是对应的“振幅谱”,复数所对应的角度,就是所对应的“相位谱”
fft_y=fft(y)                          #快速傅里叶变换
## 构造一个dataFrame
df_fft=pd.DataFrame(data=fft_y)
df_fft.columns=['变换值']
df_fft['幅值']=df_fft['变换值'].abs()
df_fft['幅值归一化']=df_fft['幅值']/N*2
df_fft.loc[0,'幅值归一化']=df_fft['幅值归一化'][0]/2
df_fft['辐角']=angle_y=np.angle(fft_y)
# 开始遗漏了这一关键项
df_fft['频率']=np.arange(N)/(2*np.pi)
pd.options.display.float_format = '{:.2f}'.format
df_fft.head()

输出为

	变换值			幅值   幅值归一化 辐角	频率
0	240.00-0.00j	240.00	 1.00	-0.00	0.00
1	1.60-122.18j	122.19	 1.02	-1.56	0.16
2	6.34-242.28j	242.36	 2.02	-1.54	0.32
3	13.99-356.08j	356.35	 2.97	-1.53	0.48
4	-0.36+6.82j		6.83	 0.06	1.62	0.64

做幅值图、归一化幅值图与相位图

fig,axs = plt.subplots(1,3,figsize=(8,2),dpi=100)
x=np.arange(N)

axs[0].plot(x,df_fft['幅值'])
axs[0].set_title('幅值-双边')
axs[1].plot(x,df_fft['辐角'])   
axs[1].set_title('双边相位谱')
axs[2].plot(x,df_fft['幅值归一化'])
axs[2].set_title('双边幅值归一化')
plt.show()

幅值-相位-归一化幅值

归一化,取半处理,

# 取半处理
df_fft_harlf = df_fft.loc[np.arange(int(N/2)),:]

# half_x = x[range(int(N/2))]                                  #取一半区间
# normalization_half_y = df_fft['幅值归一化'][np.arange(int(N/2))]     #由于对称性,只取一半区间(单边频谱)
fig,axs = plt.subplots(1,2,figsize=(8,2),dpi=150)

axs[0].stem(df_fft_harlf.index,df_fft_harlf['幅值归一化'],'b')
axs[0].set_xlim(0,9)
axs[0].set_title('单边频谱(归一化)',fontsize=9,color='blue')
plt.gca().set_xlim(0,10)

axs[1].stem(df_fft_harlf.index,df_fft_harlf['辐角'],'b')
axs[1].set_xlim(0,10)
axs[1].set_title('相位',fontsize=9,color='blue')
plt.show()

取一半作图

查看较大的幅值

df_fft_harlf[df_fft_harlf['幅值归一化']>0.5]

输出为

	变换值			幅值	幅值归一化	辐角	频率
0	240.00-0.00j	240.00		1.00	-0.00	0.00
1	1.60-122.18j	122.19		1.02	-1.56	0.16
2	6.34-242.28j	242.36		2.02	-1.54	0.32
3	13.99-356.08j	356.35		2.97	-1.53	0.48

把辐角换算为角度看一看。

df_fft_harlf[df_fft_harlf['幅值归一化']>0.5]['辐角']/np.pi*180
0    -0.00
1   -89.25
2   -88.50
3   -87.75
Name: 辐角, dtype: float64

重新拟合

重新加和,看是否与原函数相符

yy =1+ 1.018237*np.cos(t-1.557706)+ 2.019664* np.cos(2*t-1.544616)+ 2.969593*np.cos(3*t-1.531526)
plt.plot(t,y,'r',t,yy,'b')

可见基本与原函数相同,同时scipy默认的fft是分解为余弦波。
加和

ifft逆变换

可见逆变换需要用处理前变换的数据。

plt.plot(t,y,'r',label='原始')
plt.plot(t,np.real(ifft(fft_y)),'b',label='逆变换')
plt.legend();

逆变换

  • 9
    点赞
  • 63
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值