【发布时间】:2013-08-06 08:52:14
【问题描述】:
我正在尝试将最初用 numpy 编写的算法转换为 JavaScript,但我无法从反向 FFT 重现结果。
原算法使用numpy.fft.rfft和numpy.fft.irfft:
# Get the amplitude
amplitudes = abs(np.fft.rfft(buf, axis=0))
# Randomize phases
ph = np.random.uniform(0, 2*np.pi, (amplitudes.shape[0], 1)) * 1j
amplitudes = amplitudes * np.exp(ph)
# do the inverse FFT
buf = np.fft.irfft(amplitudes, axis=0)
我发现 a JavaScript library 似乎可以完成 FFT 的工作,我正在使用 mathjs 进行矩阵/向量工作。
我做了很多尝试,问题是我不知道我应该做什么来模仿numpy.fft.irfft。
两个 FFT 之间的差异:
JavaScript FFT 函数返回一个具有负频率的复数输出,因此它包含的点数是使用
numpy.fft.rfft获得的结果的 2 倍。虽然正频率[0, WIN/2]的幅度似乎匹配。JavaScript iFFT 返回一个复数输出,而
numpy.fft.rfft返回一个实数输出。
回答
感谢@hotpaw2,我设法解决了我的问题。
真实信号的频谱是对称的,numpy.fft.rfft 仅返回该频谱的唯一分量。因此,对于 128 个样本的块,numpy.fft.rfft 返回一个包含128/2 + 1 值的频谱,即65 值。
因此,如果我想这样做,我需要从我的振幅中丢弃所有对称值,然后应用相位变化。
对于反向 FFT:“要从全长 IFFT 获得仅实数输出,输入必须是复共轭对称的”。所以我需要通过使实部对称和虚部镜像对称来重建光谱。
这是算法:
fft(1, re, im)
amplitudes = math.select(re)
.subset([math.range(0, frameCount / 2)]) // get only the unique part
.abs().done() // input signal is real, so abs value of `re` is the amplitude
// Apply the new phases
re = math.emultiply(math.cos(phases), amplitudes)
im = math.emultiply(math.sin(phases), amplitudes)
// Rebuild `re` and `im` by adding the symetric part
re = math.concat(re, math.subset(re, [symRange]).reverse())
im = math.concat(im, math.select(im).subset([symRange]).emultiply(-1).done().reverse())
// do the inverse FFT
fft(-1, re, im)
【问题讨论】:
-
我会尝试规范化,看看是否能得到更好的结果。查看库,这不是一个简单的DFT(虽然它叫ndfft,意思是n维fft)
-
在应用反向 fft 时得到一个复杂的结果仍然很奇怪。 numpy.fft.irfft 是否以任何方式组合信号?
-
糟糕...完全忽略我的评论:我误读了您的代码,并认为您在做其他事情。抱歉打扰了。
-
我正在尝试使用您的 JS,但我无法让 math.subset([math.range(0, frameCount / 2)] 正常工作。它不断给我一个索引错误。跨度>
-
@mauritslamers 您可能需要查看 mathjs 的文档。自从我上次使用它以来,它发生了很大变化!
标签: javascript python numpy fft ifft