我正在努力将我的代码从python转换为objective c。 在matplotlib.mlab.specgram函数内部,我在fft之前看到了3个重要的函数:
result = stride_windows(x, NFFT, noverlap, axis=0)
result = detrend(result, detrend_func, axis=0)
result, windowVals = apply_window(result, window, axis=0,
return_window=True)
result = np.fft.fft(result, n=pad_to, axis=0)[:numFreqs, :]
我尝试调试以了解每个目的。例如,我有输入数组:
x = [1,2,3,4,5,6,7,8,9,10,11,12]
在第一个函数stride_windows(这个以防止泄漏?)之后,如果NFFT = 4,则noverlap = 2然后:
x = [ [1,3,5,7,9],
[2,4,6,8,10],
[3,5,7,9,11],
[4,6,8,10,12]
]
在趋势后没有任何变化(我理解fft之前的趋势)
在apply_window里面(我不明白这一步):
xshape = list(x.shape)
xshapetarg = xshape.pop(axis) // =4
windowVals = window(np.ones(xshapetarg, dtype=x.dtype))
//result of 4 elements [0.0, 0.75, 0.75, 0.0]
xshapeother = xshape.pop() // =5
otheraxis = (axis+1) % 2 // =1
windowValsRep = stride_repeat(windowVals, xshapeother, axis=otheraxis)
// result windowValsRep = [
[ 0. ,0. ,0. ,0. ,0. ,],
[0.75, 0.75, 0.75, 0.75,
[0.75, 0.75, 0.75, 0.75,
[ 0. ,0. ,0. ,0. ,0. ,]
]
然后将其与x
相乘windowValsRep * x
现在
x = [
[ 0. , 0. , 0. , 0. , 0. ],
[ 1.5 , 3 , 4.5 , 6. , 7.5 ],
[ 2.25, 3.75 , 5.25 , 6.75 , 8.25 ],
[ 0. , 0. , 0. , 0. , 0. ]
]
然后最后是fft,因为我知道fft只需要一个数组但在这里处理2维数组。为什么?
result = np.fft.fft(x, n=pad_to, axis=0)[:numFreqs, :]
有人可以一步一步地向我解释为什么数据需要在fft之前像这样处理吗?
谢谢,
答案 0 :(得分:4)
频谱图和FFT不是一回事。 spectogram的目的是采用小的,相等大小的时间块的FFT。这产生2D傅里叶变换,其中X轴是时间块的开始时间,Y轴是该时间块中每个频率的能量(或功率等)。这使您可以查看频率成分如何随时间变化。
specgram函数的文档中对此进行了解释:
将数据分成NFFT长度段,并计算每个部分的频谱。窗口函数窗口应用于每个段,并且使用noverlap指定每个段的重叠量。
至于各个功能,你要问的很多东西都在触及功能的文档中有描述,但我会尝试更详细地解释一下。
如documentation中所述,stride_windows
的目的是将一维数据转换为连续时间块的二维数组。这些是在最终频谱图中计算FFT的时间块。在您的情况下,它们是长度为4(NFFT=4
)的时间块(注意每列4个元素)。因为您设置了noverlap=2
,所以每列的最后2个元素与下一列的前2个元素相同(这就是重叠的含义)。它被称为" stride"因为它使用了关于numpy数组的内部存储的技巧,允许它创建一个具有重叠窗口的数组而不需要任何额外的内存。
正如其名称所暗示的,并且如其documentation中所描述的那样,去趋势函数从信号中移除趋势。默认情况下,它使用均值,如detrend_mean
documentation所述,删除信号的mean
(DC offset)。
apply_window
函数正如其名称所暗示的那样,以及documentation所说的内容:它为每个时间块应用window function。这是必要的,因为在时间块开始和结束时突然切断信号会导致称为transients的大量突发宽带能量,这将扰乱频谱图。窗口化信号可以减少这些瞬变。默认情况下,频谱图功能使用hanning window。这会减弱每个时间块的开始和结束。
FFT实际上并不是2D。 numpy FFT function允许您指定要进行FFT的轴。所以在这种情况下,我们有一个2D数组,我们采用该数组每列的FFT。只需一步即可完成此操作,而不是手动循环每列,这样做更清洁,速度更快。