2017-01-07 12 views
2
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/M1VDDFT 결과 MATLAB

입력 파일 데이터 (50) 및 (120)의 주파수에 두 개의 사인 곡선으로 구성되어 .

https://dpaste.de/2mdK

matlab에의 결과를 확장하고, 크기가 촬영 될 때, 정확하게 amplitu 것을 보여준다 다음 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)|') 

스위프트 코드 출력 스케일링 인자를 적용 하든지 관계없이 완전히 상이하고 인식 할이며 진정한 - 투 - 복잡하거나 복잡한에 복잡한 변환이 적용 여부 :

https://dpaste.de/MUwB

이 왜 어떤 아이디어?

+1

입력 데이터의 수가 1000이지만 숫자 중 512 개만 DSP 함수로 전달되고 나머지 488 값은 무시됩니다. 어떻게 그 일을 할 수 있니? –

+0

그게 어떻게 효과가 있니? 스위프트의 FFT 함수는 2의 거듭 제곱을 필요로하므로 512가되어야합니다. – SwiftMatt

+0

1024로 시도해보십시오. – SwiftMatt

답변

1

2 FFT의 길이가 다르므로 결과가 일치하지 않습니다. 또한 서로 다른 양의 데이터를 2 개의 FFT에 전달합니다.

코드를 디버깅하려면 FFT 길이와 입력 데이터 벡터를 인쇄하십시오. 결과를 비교하기 전에 입력이 일치하는지 확인하십시오.

또한 Apple Accelerate/vDSP FFT는 2의 제곱 이외의 길이 (3 또는 5의 길이를 갖는 길이도 허용됨)를 사용할 수 있습니다.

또한 Matlab은 C 및 Swift 함수에서보다 일반적이므로 0이 아닌 1부터 배열을 인덱싱합니다.

0

사실, FFT 결과 불일치 문제는 입력 크기 불일치로 인한 것입니다. 입력을 2의 거듭 제곱의 특정 배수로 제한하면 Accelerate 프레임 워크에서 FFT 사용이 크게 제한됩니다. 한 가지 제안은 입력이 적절한 길이가 될 때까지 0으로 채 웁니다. 0을 채우든지 입력이 2의 거듭 제곱의 특정 배수가되도록 입력을 절단해도 Accelerate 프레임 워크의 결과는 MATLAB과 같은 프로그램의 결과와 다릅니다. 이 문제에 대한 해결책은 Martin R이 지정한 링크에서 언급 한대로 처프 -z 변환을 수행하는 것입니다. 처프 -z 변환 자체는 FFT와 동일한 결과를 산출하며 임의의 크기의 입력에 대해 수행 될 수 있습니다.