Python产生意外的FFT结果

时间:2018-07-19 18:42:01

标签: python numpy scipy fft dft

我正在分析实质上是一种呼吸波形,它以3种不同的形状构成(数据源自MRI,因此使用了多个回波时间;如果您需要一些快速的背景知识,请参见here)。在某些情况下,这是绘制的两个波形的几个片段:

enter image description here

对于每个波形,我都尝试执行DFT,以发现主要的呼吸频率。

我的问题是,当我绘制执行的DFT时,会得到两件事之一,这取决于我使用的FFT库。此外,它们都不代表我的期望。我知道数据并不总是按照我们想要的方式显示,但是我的数据中显然存在波形,因此我希望有一个离散的波形傅立叶变换在合理的地方产生一个频率峰值。作为参考,我希望大约80至130 Hz。

我的数据存储在pandas数据框中,每个回波时间的数据都在一个单独的序列中。我正在应用所选的FFT函数(请参见下面的代码),并对每个函数接收不同的结果。

SciPy(fftpack

import pandas as pd
import scipy.fftpack

# temporary copy to maintain data structure
lead_pts_fft_df = lead_pts_df.copy()

# apply a discrete fast Fourier transform to each data series in the data frame
lead_pts_fft_df.magnitude = lead_pts_df.magnitude.apply(scipy.fftpack.fft)
lead_pts_fft_df

NumPy:

import pandas as pd
import numpy as np 

# temporary copy to maintain data structure
lead_pts_fft_df = lead_pts_df.copy()

# apply a discrete fast Fourier transform to each data series in the data frame
lead_pts_fft_df.magnitude = lead_pts_df.magnitude.apply(np.fft.fft)
lead_pts_fft_df

其余相关代码:

ECHO_TIMES = [0.080, 0.200, 0.400] # milliseconds

f_s = 1 / (0.006) # 0.006 = time between samples
freq = np.linspace(0, 29556, 29556) * (f_s / 29556) # (29556 = length of data)

# generate subplots
fig, axes = plt.subplots(3, 1, figsize=(18, 16))

for idx in range(len(ECHO_TIMES)):
    axes[idx].plot(freq, lead_pts_fft_df.magnitude[idx].real, # real part
                   freq, lead_pts_fft_df.magnitude[idx].imag, # imaginary part

    axes[idx].legend() # apply legend to each set of axes

# show the plot
plt.show()

DFT后(SciPy fftpack):

enter image description here

DFT后(NumPy)

enter image description here

Here是用于创建这些绘图的数据集的链接(在Dropbox上),而here是Jupyter Notebook的链接。

编辑:

我使用发布的建议并获取了数据的大小(绝对值),并绘制了对数y轴。新结果发布在下面。似乎我的信号中有一些回绕。我没有使用正确的频率标度吗?更新的代码和图解如下。

# generate subplots
fig, axes = plt.subplots(3, 1, figsize=(18, 16))

for idx in range(len(ECHO_TIMES)):
    axes[idx].plot(freq[1::], np.log(np.abs(lead_pts_fft_df.magnitude[idx][1::])),
                   label=lead_pts_df.index[idx], # apply labels
                   color=plot_colors[idx]) # colors
    axes[idx].legend() # apply legend to each set of axes

# show the plot
plt.show()

enter image description here

1 个答案:

答案 0 :(得分:1)

我已经解决了问题。

Cris Luengothis link很有帮助,它帮助我确定了如何正确缩放频率范围并正确绘制DFT。

ADDITIONALLY:我忘记考虑信号中存在的偏移。它不仅会引起DFT中0 Hz处巨大峰值的问题,而且还导致转换后信号中的大部分噪声。我利用scipy.signal.detrend()消除了这一点,并获得了非常合适的DFT。

# import DFT and signal packages from SciPy
import scipy.fftpack
import scipy.signal

# temporary copy to maintain data structure; original data frame is NOT changed due to ".copy()"
lead_pts_fft_df = lead_pts_df.copy()

# apply a discrete fast Fourier transform to each data series in the data frame AND detrend the signal
lead_pts_fft_df.magnitude = lead_pts_fft_df.magnitude.apply(scipy.signal.detrend)
lead_pts_fft_df.magnitude = lead_pts_fft_df.magnitude.apply(np.fft.fft)
lead_pts_fft_df

相应安排频点:

num_projections = 29556
N = num_projections
T = (6 * 3) / 1000 # 6*3 b/c of the nature of my signal: 1 pt for each waveform collected every third acquisition
xf = np.linspace(0.0, 1.0 / (2.0 * T), num_projections / 2)

然后情节:

# generate subplots
fig, axes = plt.subplots(3, 1, figsize=(18, 16))

for idx in range(len(ECHO_TIMES)):
    axes[idx].plot(xf, 2.0/num_projections * np.abs(lead_pts_fft_df.magnitude[idx][:num_projections//2]),
                   label=lead_pts_df.index[idx], # apply labels
                   color=plot_colors[idx]) # colors
    axes[idx].legend() # apply legend to each set of axes

# show the plot
plt.show()

enter image description here