FFT Calculating incorrectly - Swift

 ̄綄美尐妖づ 提交于 2021-02-07 08:39:47

问题


I am trying to take the fast Fast Fourier Transform. I am basing my calculation off of the Surge. I am having trouble getting correct results. When I take the fft of a 1000 hz sound I get something that looks like this. . When i take the same tone and use python I get something that looks way more correct. The python code looks like:

import numpy as np
import scipy.io.wavfile
import numpy.fft
import matplotlib.pyplot as plt

FILENAME = 'beep.wav'

fs, data = scipy.io.wavfile.read(FILENAME)
data = data[:801]
spacing = 1 / float(fs)
freq = numpy.fft.rfft(data)
freq_power = np.abs(freq)
a = 1 / (2 * spacing)
b = (len(data) + 1) // 2
freq_axis = np.linspace(0, a, b)
plt.plot(freq_axis, freq_power)
plt.show()

The swift code looks like

import Accelerate
public func sqrt(x: [Float]) -> [Float] {
var results = [Float](count: x.count, repeatedValue: 0.0)
vvsqrtf(&results, x, [Int32(x.count)])

return results
}

public func fft(input: [Float]) -> [Float] {
var real = [Float](input)
var imaginary = [Float](count: input.count, repeatedValue: 0.0)
var splitComplex = DSPSplitComplex(realp: &real, imagp: &imaginary)

let length = vDSP_Length(floor(log2(Float(input.count))))
let radix = FFTRadix(kFFTRadix2)
let weights = vDSP_create_fftsetup(length, radix)
println(weights)
vDSP_fft_zip(weights, &splitComplex, 1, 8, FFTDirection(FFT_FORWARD))

var magnitudes = [Float](count: input.count, repeatedValue: 0.0)
vDSP_zvmags(&splitComplex, 1, &magnitudes, 1, vDSP_Length(input.count))

var normalizedMagnitudes = [Float](count: input.count, repeatedValue: 0.0)
vDSP_vsmul(sqrt(magnitudes), 1, [2.0 / Float(input.count)], &normalizedMagnitudes, 1, vDSP_Length(input.count))
vDSP_destroy_fftsetup(weights)

return normalizedMagnitudes
}

To reiterate. The swift code is the code giving unexpected results. What am I doing wrong?


回答1:


It looks like you are using Swift Float arrays with the Accelerate framework, but you might instead need to allocate your vectors using UnsafeMutablePointer<Float> types since the Accelerate framework is an Objective C framework. Here is an example how to do this.

public func sqrt(x: [Float]) -> [Float] {
    // convert swift array to C vector
    var temp = UnsafeMutablePointer<Float>.alloc(x.count)
    for (var i=0;i<x.count;i++) {
        temp[i] = x[i];
    }
    var count = UnsafeMutablePointer<Int32>.alloc(1)
    count[0] = Int32(x.count)
    vvsqrtf(temp, temp, count)
    // convert C vector to swift array
    var results = [Float](count: x.count, repeatedValue: 0.0)
    for (var i=0;i<x.count;i++) {
        results[i] = temp[i];
    }
    // Free memory
    count.dealloc(1)
    temp.dealloc(x.count)
    return results
}

It will work out better for performance to use the UnsafeMutablePointer<Float> types throughout your code for your vectors of data rather than converting back and forth in function calls as I did for this example. Also you should save your FFT setup and reuse that as well for better performance.

Since you're using the vDSP FFT you might also like the vDSP_zvabs API which calculates magnitude in dB from the FFT results.

Finally be sure to read this link on data packing and scaling for the Accelerate framework FFT APIs. https://developer.apple.com/library/mac/documentation/Performance/Conceptual/vDSP_Programming_Guide/UsingFourierTransforms/UsingFourierTransforms.html

To improve performance, the vDSP APIs do not output the most obvious scale values (since you will undoubtedly be scaling the data anyway somewhere else) and they pack in some extra data into a few of the FFT points.



来源:https://stackoverflow.com/questions/31999725/fft-calculating-incorrectly-swift

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!