【问题标题】:Accelerate and NumPy produce different results for FFTAccelerate 和 NumPy 对 FFT 产生不同的结果
【发布时间】:2019-08-02 08:39:55
【问题描述】:

我正在为 CoreML 开发特征工程管道,我需要对我的数据执行 FFT。问题是Accelerate框架的结果和NumPy FFT的结果不一样。

斯威夫特:

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)

我对每种方法都使用相同的 100 个值。

我猜这与规范化部分有关,但我什至不确定两个数组是否包含相同的内容,例如:

  • 索引 0:零频率项
  • 索引 1-50:正幅度
  • 索引 50-99:负震级

我只对正数感兴趣。

编辑:

这是 NumPy 图:

这是加速情节:

希望有人可以帮忙:)

【问题讨论】:

    标签: python swift numpy fft coreml


    【解决方案1】:

    有两个问题:

    • 正如E.Coms 所指出的,使用 Accelerate 框架的 FFT 的实现包括一个标准化步骤,该步骤取幅度的平方根并乘以标量 2/N。使用 NumPy 的实现不会。

    • NumPy 的 FFT 支持任意长度的输入,并且生成的频率区间与您预期的一样(索引 0 处的零频率,索引 1-50 处的正频率和索引 51-99 处的负频率)。另一方面,Accelerate 框架中的 FFT 需要具有 2 的幂的长度。相应地,该代码示例计算前 64 个输入值的 FFT。这将零频率置于索引 0,正频率置于索引 1-32,负频率置于索引 33-63。剩余的索引 (64-99) 只是剩余的未触及输入。

    【讨论】:

      【解决方案2】:

      如果加速返回量级的sqrt,结果与python相同。

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

      您可能会弄清楚哪个不是现在。如果你想使用加速, 可以使用以下内容:

          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}
      

      【讨论】:

      • 但是你如何解释加速图中 60 处的峰值?不能是 sqrt...而且我似乎是某种线性缩放,因为比例约为 2。
      • 那你还是错过了numpy中的线性缩放步骤
      猜你喜欢
      • 1970-01-01
      • 2022-01-07
      • 1970-01-01
      • 2017-09-28
      • 2012-01-30
      • 1970-01-01
      • 2015-11-16
      • 1970-01-01
      • 2016-06-09
      相关资源
      最近更新 更多