简体   繁体   English

Accelerate和NumPy产生不同的FFT结果

[英]Accelerate and NumPy produce different results for FFT

I am working on a feature engineering pipeline for CoreML and I need to perform the FFT on my data. 我正在为CoreML构建功能工程流水线,并且需要对数据执行FFT。 The problem is that the results of the Accelerate framework and the results of the NumPy FFT are different. 问题在于,加速框架的结果和NumPy FFT的结果是不同的。

Swift: 迅速:

public func fft(_ input: [Double]) -> [Double] {
    var real = [Double](input)
    var imaginary = [Double](repeating: 0.0, count: input.count)
    var splitComplex = DSPDoubleSplitComplex(realp: &real, imagp: &imaginary)

    let length = vDSP_Length(floor(log2(Float(input.count))))
    let radix = FFTRadix(kFFTRadix2)
    let weights = vDSP_create_fftsetupD(length, radix)
    vDSP_fft_zipD(weights!, &splitComplex, 1, length, FFTDirection(FFT_FORWARD))

    var magnitudes = [Double](repeating: 0.0, count: input.count)
    vDSP_zvmagsD(&splitComplex, 1, &magnitudes, 1, vDSP_Length(input.count))

    var normalizedMagnitudes = [Double](repeating: 0.0, count: input.count)
    vDSP_vsmulD(sqrt(magnitudes), 1, [2.0 / Double(input.count)], &normalizedMagnitudes, 1, vDSP_Length(input.count))

    vDSP_destroy_fftsetupD(weights)

    return normalizedMagnitudes
}

Python: 蟒蛇:

def fft(series: pd.Series):
    f = np.fft.fft(series)
    fa = np.abs(f)
    return pd.Series(fa)

I use the same 100 values for every method. 我对每种方法都使用相同的100个值。

I guess it has something to do with the normalizing part, but i'm not even sure if both arrays contain the same things like: 我想这与规范化部分有关,但我什至不确定两个数组是否包含相同的内容,例如:

  • index 0: zero frequency term 索引0:零频率项
  • index 1-50: positive magnitudes 指数1-50:正值
  • index 50-99: negative magnitudes 指数50-99:负幅值

I'm only interested in the positive magnitudes. 我只对积极的幅度感兴趣。

Edit: 编辑:

Here is the NumPy plot: 这是NumPy图:

NumPy的

And here is the Accelerate plot: 这是加速图:

加速

I hope someone can help :) 我希望有人能帮帮忙 :)

There are two issues: 有两个问题:

  • As pointed out by E.Coms , the implementation using Accelerate framework's FFT includes a normalization step which takes the square root of the magnitude and multiplies by the scalar 2/N . 正如E.Coms所指出的那样 ,使用Accelerate框架的FFT的实现包括归一化步骤,该步骤采用幅度的平方根并乘以标量2/N The implementation using NumPy doesn't. 使用NumPy的实现则没有。

  • NumPy's FFT supports arbitrary length inputs, and the resulting frequency bins are as you are expecting (zero frequency at index 0, positive frequencies at index 1-50 and negative frequencies at index 51-99). NumPy的FFT支持任意长度的输入,并且得到的频率仓符合您的期望(索引0处的零频率,索引1-50处的正频率和索引51-99处的负频率)。 On the other hand, the FFT in Accelerate framework needs to have a length that is a power of 2. Correspondingly, that code sample computes the FFT of your first 64 input values. 另一方面,加速框架中的FFT的长度必须是2的幂。相应地,该代码示例将计算您的前64个输入值的FFT。 This puts the zero frequency at index 0, positive frequencies at index 1-32 and negative frequencies at index 33-63. 这会将零频率设为索引0,将正频率设为索引1-32,将负频率设为索引33-63。 The remaining index (64-99) are just leftover untouched inputs. 其余的索引(64-99)只是剩下的未修改的输入。

If accelerate return the sqrt of magnitude, the result is same as python . 如果加速返回幅度的平方,结果与python相同。

  public func fft(_ input: [Double]) -> [Double] {
   ....
   return  magnitudes.map{sqrt($0)}
   }

You may figure out which one is not right now. 您可能会发现哪个不是当前。 If you want to use accelerate, can use the following: 如果要使用加速,可以使用以下方法:

    public func fft(_ input: [Double]) -> [Double] {
   ....

    var normalizedMagnitudes = [Double](repeating: 0.0, count: input.count)
    var count : Int32 = Int32(input.count)
    vvsqrt(   &normalizedMagnitudes, &magnitudes, &count )



     vDSP_destroy_fftsetupD(weights)

     return normalizedMagnitudes}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM