3
import Cocoa
import Accelerate

let filePath = Bundle.main.path(forResource: "sinusoid", ofType: "txt")
let contentData = FileManager.default.contents(atPath: filePath!)
var content = NSString(data: contentData!, encoding: String.Encoding.utf8.rawValue) as? String

var idx = content?.characters.index(of: "\n")
idx = content?.index(after: idx!)

repeat {
    //let fromIndex = index(from: )
    content = content?.substring(from: idx!)
    idx = content?.characters.index(of: "\n")
    idx = content?.index(after: idx!)
} while content!.characters.contains("%")

let regex = try? NSRegularExpression(pattern: "[ ]+", options:[])

let delimiter = ","
var modifiedString = regex?.stringByReplacingMatches(in: content!, options: [], range: NSRange(location: 0, length: (content! as NSString).length), withTemplate: delimiter)

let lines = modifiedString?.components(separatedBy: "\n")

var s = [Double]()

for var line in lines! {
    if !line.isEmpty {
        let data = line.components(separatedBy: ",")
        s.append(Double(data[1])!)
    }
}

let length = vDSP_Length(pow(2, floor(log2(Float(s.count)))))
let L = Int(length)

// zrop or zop? 
// zrop covers real to complex, and zop covers complex
// length must be a power of 2 or specific multiples of powers of 2 if size is at least 4
let setup = vDSP_DFT_zrop_CreateSetupD(nil, length, vDSP_DFT_Direction.FORWARD)

var inputReal = UnsafeMutablePointer<Double>.allocate(capacity: L)
var inputImaginary = UnsafeMutablePointer<Double>.allocate(capacity: L)
var outputReal = UnsafeMutablePointer<Double>.allocate(capacity: L)
var outputImaginary = UnsafeMutablePointer<Double>.allocate(capacity: L)

for i in 0..<L {
    inputReal[i] = s[i]
    inputImaginary[i] = 0.0
}

vDSP_DFT_ExecuteD(setup!, inputReal, inputImaginary, outputReal, outputImaginary)

for i in 0..<L {
    print("\(outputReal[i]) + \(outputImaginary[i])i")
}

输入文件“sinusoid.txt”位于以下链接 https://dpaste.de/M1VD

输入文件数据由频率为 50 和 120 的两个正弦波组成。Matlab 代码生成以下链接中给出的正确输出:

https://dpaste.de/2mdK

当Matlab的结果被缩放并取大小时,它正确地表明频率为50的幅度为0.7,频率为120的幅度为1。

clear all; close all; clc;
data = load('sinusoid.txt');
S = data(:,2);
Fs = 1000;
Y = fft(S);
L = length(S);
P2 = abs(Y/L);
P1 = P2(1:L/2+1);
P1(2:end-1) = 2*P1(2:end-1);
f = Fs*(0:(L/2))/L;
plot(f,P1)
title('Single-Sided Amplitude Spectrum of X(t)')
xlabel('f (Hz)')
ylabel('|P1(f)|')

与 Matlab 输出相比,Swift 代码输出完全不同且无法识别,无论应用了何种比例因子以及是否应用了实数到复数或复数到复数的转换:

https://dpaste.de/MUwB

任何想法为什么会这样?

4

2 回答 2

1

您的 2 FFT 的长度不同,因此结果当然不匹配。您还将不同数量的数据传递给您的 2 个 FFT。

打印出 FFT 长度和输入数据向量以调试您的代码。在比较结果之前确保输入匹配。

此外,Apple 的 Accelerate/vDSP FFT 可以使用除 2 的幂以外的长度(也允许使用因子为 3 或 5 的长度)。

另外,请注意,Matlab 索引数组从 1 开始,而不是 0,这在 C 和 Swift 函数中更为典型。

于 2017-01-07T20:48:20.047 回答
0

事实上,FFT 结果不匹配的问题是由于输入大小不匹配造成的。将输入限制为 2 的特定幂的倍数极大地限制了 Accelerate 框架中的 FFT 使用。一个建议是用 0 填充输入,直到它具有适当的长度。无论您使用 0 填充还是截断输入以使其大小为 2 的幂的特定倍数,Accelerate 框架的结果都将不同于 MATLAB 等程序的结果。对此的解决方案是执行 Martin R 指定的链接中提到的 chirp-z 变换。chirp-z 变换本身产生与 FFT 相同的结果,并且可以对任意大小的输入执行。

于 2017-01-08T20:00:12.673 回答