I am working on a feature engineering pipeline for CoreML and I need to perform the FFT on my data. The problem is that the results of the Accelerate framework and the results of the NumPy FFT are different.
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.
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:
I'm only interested in the positive magnitudes.
Edit:
Here is the NumPy plot:
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
. The implementation using NumPy doesn't.
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). 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. This puts the zero frequency at index 0, positive frequencies at index 1-32 and negative frequencies at index 33-63. The remaining index (64-99) are just leftover untouched inputs.