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 の 2 つの正弦波で構成されています。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)|')

Swift コードの出力は、Matlab の出力と比較すると、まったく異なり、認識できません。スケーリング係数が適用されているかどうか、および実数から複素数への変換または複素数から複素数への変換が適用されているかどうかにかかわらずです。

https://dpaste.de/MUwB

これはなぜですか?

4

2 に答える 2

1

2 つの FFT の長さが異なるため、もちろん結果は一致しません。また、2 つの FFT に異なる量のデータを渡しています。

コードをデバッグするために、FFT 長と入力データ ベクトルを出力します。結果を比較する前に、入力が一致していることを確認してください。

また、Apple の Accelerate/vDSP FFT は、2 の累乗以外の長さを使用できます (係数 3 または 5 の長さも使用できます)。

また、C および Swift 関数でより一般的であるように、Matlab は配列を 0 ではなく 1 からインデックス付けすることに注意してください。

于 2017-01-07T20:48:20.047 に答える
0

実際、FFT 結果の不一致の問題は、入力サイズの不一致が原因でした。入力を 2 の累乗の特定の倍数に制限すると、Accelerate フレームワークでの FFT の使用が大幅に制限されます。1 つの提案は、適切な長さになるまで入力を 0 で埋めることでした。サイズが 2 の累乗の特定の倍数になるように 0 でパディングするか、入力を切り捨てるかに関係なく、Accelerate フレームワークからの結果は、MATLAB などのプログラムからの結果とは異なります。これに対する解決策は、Martin R によって指定されたリンクに記載されているように、chirp-z 変換を実行することです。chirp-z 変換自体は、FFT と同じ結果をもたらし、任意のサイズの入力に対して実行できます。

于 2017-01-08T20:00:12.673 に答える