mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
740 lines
30 KiB
Swift
740 lines
30 KiB
Swift
// RUN: %target-run-simple-swift
|
|
// REQUIRES: executable_test
|
|
|
|
// REQUIRES: rdar50301438
|
|
// REQUIRES: objc_interop
|
|
// UNSUPPORTED: OS=watchos
|
|
|
|
import StdlibUnittest
|
|
import Accelerate
|
|
|
|
var Accelerate_vDSPFourierTransformTests = TestSuite("Accelerate_vDSPFourierTransform")
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// vDSP discrete Fourier transform tests; single-precision
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
if #available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *) {
|
|
|
|
let n = 2048
|
|
let tau: Float = .pi * 2
|
|
|
|
let frequencies: [Float] = [1, 5, 25, 30, 75, 100,
|
|
300, 500, 512, 1023]
|
|
|
|
let inputReal: [Float] = (0 ..< n).map { index in
|
|
frequencies.reduce(0) { accumulator, frequency in
|
|
let normalizedIndex = Float(index) / Float(n)
|
|
return accumulator + sin(normalizedIndex * frequency * tau)
|
|
}
|
|
}
|
|
|
|
let inputImag: [Float] = (0 ..< n).map { index in
|
|
frequencies.reduce(0) { accumulator, frequency in
|
|
let normalizedIndex = Float(index) / Float(n)
|
|
return accumulator + sin(normalizedIndex * 1/frequency * tau)
|
|
}
|
|
}
|
|
|
|
Accelerate_vDSPFourierTransformTests.test("vDSP/SinglePrecisionForwardComplexComplex") {
|
|
let fwdDFT = vDSP.DFT(count: n,
|
|
direction: .forward,
|
|
transformType: .complexComplex,
|
|
ofType: Float.self)!
|
|
|
|
var outputReal = [Float](repeating: 0, count: n)
|
|
var outputImag = [Float](repeating: 0, count: n)
|
|
|
|
fwdDFT.transform(inputReal: inputReal,
|
|
inputImaginary: inputImag,
|
|
outputReal: &outputReal,
|
|
outputImaginary: &outputImag)
|
|
|
|
// legacy...
|
|
|
|
let legacySetup = vDSP_DFT_zop_CreateSetup(nil,
|
|
vDSP_Length(n),
|
|
.FORWARD)!
|
|
|
|
var legacyOutputReal = [Float](repeating: -1, count: n)
|
|
var legacyOutputImag = [Float](repeating: -1, count: n)
|
|
|
|
vDSP_DFT_Execute(legacySetup,
|
|
inputReal,
|
|
inputImag,
|
|
&legacyOutputReal,
|
|
&legacyOutputImag)
|
|
|
|
expectTrue(outputReal.elementsEqual(legacyOutputReal))
|
|
expectTrue(outputImag.elementsEqual(legacyOutputImag))
|
|
|
|
let returnedResult = fwdDFT.transform(inputReal: inputReal,
|
|
inputImaginary: inputImag)
|
|
|
|
expectTrue(outputReal.elementsEqual(returnedResult.real))
|
|
expectTrue(outputImag.elementsEqual(returnedResult.imaginary))
|
|
}
|
|
|
|
Accelerate_vDSPFourierTransformTests.test("vDSP/SinglePrecisionInverseComplexComplex") {
|
|
let fwdDFT = vDSP.DFT(count: n,
|
|
direction: .inverse,
|
|
transformType: .complexComplex,
|
|
ofType: Float.self)!
|
|
|
|
var outputReal = [Float](repeating: 0, count: n)
|
|
var outputImag = [Float](repeating: 0, count: n)
|
|
|
|
fwdDFT.transform(inputReal: inputReal,
|
|
inputImaginary: inputImag,
|
|
outputReal: &outputReal,
|
|
outputImaginary: &outputImag)
|
|
|
|
// legacy...
|
|
|
|
let legacySetup = vDSP_DFT_zop_CreateSetup(nil,
|
|
vDSP_Length(n),
|
|
.INVERSE)!
|
|
|
|
var legacyOutputReal = [Float](repeating: -1, count: n)
|
|
var legacyOutputImag = [Float](repeating: -1, count: n)
|
|
|
|
vDSP_DFT_Execute(legacySetup,
|
|
inputReal,
|
|
inputImag,
|
|
&legacyOutputReal,
|
|
&legacyOutputImag)
|
|
|
|
expectTrue(outputReal.elementsEqual(legacyOutputReal))
|
|
expectTrue(outputImag.elementsEqual(legacyOutputImag))
|
|
|
|
let returnedResult = fwdDFT.transform(inputReal: inputReal,
|
|
inputImaginary: inputImag)
|
|
|
|
expectTrue(outputReal.elementsEqual(returnedResult.real))
|
|
expectTrue(outputImag.elementsEqual(returnedResult.imaginary))
|
|
}
|
|
|
|
Accelerate_vDSPFourierTransformTests.test("vDSP/SinglePrecisionForwardComplexReal") {
|
|
let fwdDFT = vDSP.DFT(count: n,
|
|
direction: .forward,
|
|
transformType: .complexReal,
|
|
ofType: Float.self)!
|
|
|
|
var outputReal = [Float](repeating: 0, count: n / 2)
|
|
var outputImag = [Float](repeating: 0, count: n / 2)
|
|
|
|
fwdDFT.transform(inputReal: inputReal,
|
|
inputImaginary: inputImag,
|
|
outputReal: &outputReal,
|
|
outputImaginary: &outputImag)
|
|
|
|
// legacy...
|
|
|
|
let legacySetup = vDSP_DFT_zrop_CreateSetup(nil,
|
|
vDSP_Length(n),
|
|
.FORWARD)!
|
|
|
|
var legacyOutputReal = [Float](repeating: -1, count: n / 2)
|
|
var legacyOutputImag = [Float](repeating: -1, count: n / 2)
|
|
|
|
vDSP_DFT_Execute(legacySetup,
|
|
inputReal,
|
|
inputImag,
|
|
&legacyOutputReal,
|
|
&legacyOutputImag)
|
|
|
|
expectTrue(outputReal.elementsEqual(legacyOutputReal))
|
|
expectTrue(outputImag.elementsEqual(legacyOutputImag))
|
|
|
|
let returnedResult = fwdDFT.transform(inputReal: inputReal,
|
|
inputImaginary: inputImag)
|
|
|
|
expectTrue(outputReal.elementsEqual(returnedResult.real))
|
|
expectTrue(outputImag.elementsEqual(returnedResult.imaginary))
|
|
}
|
|
|
|
Accelerate_vDSPFourierTransformTests.test("vDSP/SinglePrecisionInverseComplexReal") {
|
|
let fwdDFT = vDSP.DFT(count: n,
|
|
direction: .inverse,
|
|
transformType: .complexReal,
|
|
ofType: Float.self)!
|
|
|
|
var outputReal = [Float](repeating: 0, count: n / 2)
|
|
var outputImag = [Float](repeating: 0, count: n / 2)
|
|
|
|
fwdDFT.transform(inputReal: inputReal,
|
|
inputImaginary: inputImag,
|
|
outputReal: &outputReal,
|
|
outputImaginary: &outputImag)
|
|
|
|
// legacy...
|
|
|
|
let legacySetup = vDSP_DFT_zrop_CreateSetup(nil,
|
|
vDSP_Length(n),
|
|
.INVERSE)!
|
|
|
|
var legacyOutputReal = [Float](repeating: -1, count: n / 2)
|
|
var legacyOutputImag = [Float](repeating: -1, count: n / 2)
|
|
|
|
vDSP_DFT_Execute(legacySetup,
|
|
inputReal,
|
|
inputImag,
|
|
&legacyOutputReal,
|
|
&legacyOutputImag)
|
|
|
|
expectTrue(outputReal.elementsEqual(legacyOutputReal))
|
|
expectTrue(outputImag.elementsEqual(legacyOutputImag))
|
|
|
|
let returnedResult = fwdDFT.transform(inputReal: inputReal,
|
|
inputImaginary: inputImag)
|
|
|
|
expectTrue(outputReal.elementsEqual(returnedResult.real))
|
|
expectTrue(outputImag.elementsEqual(returnedResult.imaginary))
|
|
}
|
|
}
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// vDSP discrete Fourier transform tests; double-precision
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
if #available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *) {
|
|
|
|
let n = 2048
|
|
let tau: Double = .pi * 2
|
|
|
|
let frequencies: [Double] = [1, 5, 25, 30, 75, 100,
|
|
300, 500, 512, 1023]
|
|
|
|
let inputReal: [Double] = (0 ..< n).map { index in
|
|
frequencies.reduce(0) { accumulator, frequency in
|
|
let normalizedIndex = Double(index) / Double(n)
|
|
return accumulator + sin(normalizedIndex * frequency * tau)
|
|
}
|
|
}
|
|
|
|
let inputImag: [Double] = (0 ..< n).map { index in
|
|
frequencies.reduce(0) { accumulator, frequency in
|
|
let normalizedIndex = Double(index) / Double(n)
|
|
return accumulator + sin(normalizedIndex * 1/frequency * tau)
|
|
}
|
|
}
|
|
|
|
Accelerate_vDSPFourierTransformTests.test("vDSP/DoublePrecisionForwardComplexComplex") {
|
|
let fwdDFT = vDSP.DFT(count: n,
|
|
direction: .forward,
|
|
transformType: .complexComplex,
|
|
ofType: Double.self)!
|
|
|
|
var outputReal = [Double](repeating: 0, count: n)
|
|
var outputImag = [Double](repeating: 0, count: n)
|
|
|
|
fwdDFT.transform(inputReal: inputReal,
|
|
inputImaginary: inputImag,
|
|
outputReal: &outputReal,
|
|
outputImaginary: &outputImag)
|
|
|
|
// legacy...
|
|
|
|
let legacySetup = vDSP_DFT_zop_CreateSetupD(nil,
|
|
vDSP_Length(n),
|
|
.FORWARD)!
|
|
|
|
var legacyOutputReal = [Double](repeating: -1, count: n)
|
|
var legacyOutputImag = [Double](repeating: -1, count: n)
|
|
|
|
vDSP_DFT_ExecuteD(legacySetup,
|
|
inputReal,
|
|
inputImag,
|
|
&legacyOutputReal,
|
|
&legacyOutputImag)
|
|
|
|
expectTrue(outputReal.elementsEqual(legacyOutputReal))
|
|
expectTrue(outputImag.elementsEqual(legacyOutputImag))
|
|
|
|
let returnedResult = fwdDFT.transform(inputReal: inputReal,
|
|
inputImaginary: inputImag)
|
|
|
|
expectTrue(outputReal.elementsEqual(returnedResult.real))
|
|
expectTrue(outputImag.elementsEqual(returnedResult.imaginary))
|
|
}
|
|
|
|
Accelerate_vDSPFourierTransformTests.test("vDSP/DoublePrecisionInverseComplexComplex") {
|
|
let fwdDFT = vDSP.DFT(count: n,
|
|
direction: .inverse,
|
|
transformType: .complexComplex,
|
|
ofType: Double.self)!
|
|
|
|
var outputReal = [Double](repeating: 0, count: n)
|
|
var outputImag = [Double](repeating: 0, count: n)
|
|
|
|
fwdDFT.transform(inputReal: inputReal,
|
|
inputImaginary: inputImag,
|
|
outputReal: &outputReal,
|
|
outputImaginary: &outputImag)
|
|
|
|
// legacy...
|
|
|
|
let legacySetup = vDSP_DFT_zop_CreateSetupD(nil,
|
|
vDSP_Length(n),
|
|
.INVERSE)!
|
|
|
|
var legacyOutputReal = [Double](repeating: -1, count: n)
|
|
var legacyOutputImag = [Double](repeating: -1, count: n)
|
|
|
|
vDSP_DFT_ExecuteD(legacySetup,
|
|
inputReal,
|
|
inputImag,
|
|
&legacyOutputReal,
|
|
&legacyOutputImag)
|
|
|
|
expectTrue(outputReal.elementsEqual(legacyOutputReal))
|
|
expectTrue(outputImag.elementsEqual(legacyOutputImag))
|
|
|
|
let returnedResult = fwdDFT.transform(inputReal: inputReal,
|
|
inputImaginary: inputImag)
|
|
|
|
expectTrue(outputReal.elementsEqual(returnedResult.real))
|
|
expectTrue(outputImag.elementsEqual(returnedResult.imaginary))
|
|
}
|
|
|
|
Accelerate_vDSPFourierTransformTests.test("vDSP/DoublePrecisionForwardComplexReal") {
|
|
let fwdDFT = vDSP.DFT(count: n,
|
|
direction: .forward,
|
|
transformType: .complexReal,
|
|
ofType: Double.self)!
|
|
|
|
var outputReal = [Double](repeating: 0, count: n / 2)
|
|
var outputImag = [Double](repeating: 0, count: n / 2)
|
|
|
|
fwdDFT.transform(inputReal: inputReal,
|
|
inputImaginary: inputImag,
|
|
outputReal: &outputReal,
|
|
outputImaginary: &outputImag)
|
|
|
|
// legacy...
|
|
|
|
let legacySetup = vDSP_DFT_zrop_CreateSetupD(nil,
|
|
vDSP_Length(n),
|
|
.FORWARD)!
|
|
|
|
var legacyOutputReal = [Double](repeating: -1, count: n / 2)
|
|
var legacyOutputImag = [Double](repeating: -1, count: n / 2)
|
|
|
|
vDSP_DFT_ExecuteD(legacySetup,
|
|
inputReal,
|
|
inputImag,
|
|
&legacyOutputReal,
|
|
&legacyOutputImag)
|
|
|
|
expectTrue(outputReal.elementsEqual(legacyOutputReal))
|
|
expectTrue(outputImag.elementsEqual(legacyOutputImag))
|
|
|
|
let returnedResult = fwdDFT.transform(inputReal: inputReal,
|
|
inputImaginary: inputImag)
|
|
|
|
expectTrue(outputReal.elementsEqual(returnedResult.real))
|
|
expectTrue(outputImag.elementsEqual(returnedResult.imaginary))
|
|
}
|
|
|
|
Accelerate_vDSPFourierTransformTests.test("vDSP/DoublePrecisionInverseComplexReal") {
|
|
let fwdDFT = vDSP.DFT(count: n,
|
|
direction: .inverse,
|
|
transformType: .complexReal,
|
|
ofType: Double.self)!
|
|
|
|
var outputReal = [Double](repeating: 0, count: n / 2)
|
|
var outputImag = [Double](repeating: 0, count: n / 2)
|
|
|
|
fwdDFT.transform(inputReal: inputReal,
|
|
inputImaginary: inputImag,
|
|
outputReal: &outputReal,
|
|
outputImaginary: &outputImag)
|
|
|
|
// legacy...
|
|
|
|
let legacySetup = vDSP_DFT_zrop_CreateSetupD(nil,
|
|
vDSP_Length(n),
|
|
.INVERSE)!
|
|
|
|
var legacyOutputReal = [Double](repeating: -1, count: n / 2)
|
|
var legacyOutputImag = [Double](repeating: -1, count: n / 2)
|
|
|
|
vDSP_DFT_ExecuteD(legacySetup,
|
|
inputReal,
|
|
inputImag,
|
|
&legacyOutputReal,
|
|
&legacyOutputImag)
|
|
|
|
expectTrue(outputReal.elementsEqual(legacyOutputReal))
|
|
expectTrue(outputImag.elementsEqual(legacyOutputImag))
|
|
|
|
let returnedResult = fwdDFT.transform(inputReal: inputReal,
|
|
inputImaginary: inputImag)
|
|
|
|
expectTrue(outputReal.elementsEqual(returnedResult.real))
|
|
expectTrue(outputImag.elementsEqual(returnedResult.imaginary))
|
|
}
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// vDSP Fast Fourier Transform Tests
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
if #available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *) {
|
|
|
|
Accelerate_vDSPFourierTransformTests.test("vDSP/SinglePrecisionComplexConversions") {
|
|
func convert(splitComplexVector: DSPSplitComplex,
|
|
toInterleavedComplexVector interleavedComplexVector: inout [DSPComplex]) {
|
|
|
|
withUnsafePointer(to: splitComplexVector) {
|
|
vDSP_ztoc($0, 1,
|
|
&interleavedComplexVector, 2,
|
|
vDSP_Length(interleavedComplexVector.count))
|
|
}
|
|
}
|
|
|
|
func convert(interleavedComplexVector: [DSPComplex],
|
|
toSplitComplexVector splitComplexVector: inout DSPSplitComplex) {
|
|
|
|
vDSP_ctoz(interleavedComplexVector, 2,
|
|
&splitComplexVector, 1,
|
|
vDSP_Length(interleavedComplexVector.count))
|
|
}
|
|
|
|
var realSrc: [Float] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
|
var imagSrc: [Float] = realSrc.reversed()
|
|
|
|
let splitSrc = DSPSplitComplex(realp: &realSrc,
|
|
imagp: &imagSrc)
|
|
|
|
var interleavedDest = [DSPComplex](repeating: DSPComplex(),
|
|
count: realSrc.count)
|
|
|
|
convert(splitComplexVector: splitSrc,
|
|
toInterleavedComplexVector: &interleavedDest)
|
|
|
|
var realDest = [Float](repeating: .nan, count: realSrc.count)
|
|
var imagDest = [Float](repeating: .nan, count: realSrc.count)
|
|
|
|
var splitDest = DSPSplitComplex(realp: &realDest,
|
|
imagp: &imagDest)
|
|
|
|
convert(interleavedComplexVector: interleavedDest,
|
|
toSplitComplexVector: &splitDest)
|
|
|
|
expectTrue(realSrc.elementsEqual(realDest))
|
|
expectTrue(imagSrc.elementsEqual(imagDest))
|
|
}
|
|
|
|
Accelerate_vDSPFourierTransformTests.test("vDSP/DoublePrecisionComplexConversions") {
|
|
func convert(splitComplexVector: DSPDoubleSplitComplex,
|
|
toInterleavedComplexVector interleavedComplexVector: inout [DSPDoubleComplex]) {
|
|
|
|
withUnsafePointer(to: splitComplexVector) {
|
|
vDSP_ztocD($0, 1,
|
|
&interleavedComplexVector, 2,
|
|
vDSP_Length(interleavedComplexVector.count))
|
|
}
|
|
}
|
|
|
|
func convert(interleavedComplexVector: [DSPDoubleComplex],
|
|
toSplitComplexVector splitComplexVector: inout DSPDoubleSplitComplex) {
|
|
|
|
vDSP_ctozD(interleavedComplexVector, 2,
|
|
&splitComplexVector, 1,
|
|
vDSP_Length(interleavedComplexVector.count))
|
|
}
|
|
|
|
var realSrc: [Double] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
|
var imagSrc: [Double] = realSrc.reversed()
|
|
|
|
let splitSrc = DSPDoubleSplitComplex(realp: &realSrc,
|
|
imagp: &imagSrc)
|
|
|
|
var interleavedDest = [DSPDoubleComplex](repeating: DSPDoubleComplex(),
|
|
count: realSrc.count)
|
|
|
|
convert(splitComplexVector: splitSrc,
|
|
toInterleavedComplexVector: &interleavedDest)
|
|
|
|
var realDest = [Double](repeating: .nan, count: realSrc.count)
|
|
var imagDest = [Double](repeating: .nan, count: realSrc.count)
|
|
|
|
var splitDest = DSPDoubleSplitComplex(realp: &realDest,
|
|
imagp: &imagDest)
|
|
|
|
convert(interleavedComplexVector: interleavedDest,
|
|
toSplitComplexVector: &splitDest)
|
|
|
|
expectTrue(realSrc.elementsEqual(realDest))
|
|
expectTrue(imagSrc.elementsEqual(imagDest))
|
|
}
|
|
|
|
Accelerate_vDSPFourierTransformTests.test("vDSP/2DSinglePrecision") {
|
|
let width = 256
|
|
let height = 256
|
|
let pixelCount = width * height
|
|
let n = pixelCount / 2
|
|
|
|
let pixels: [Float] = (0 ..< pixelCount).map { i in
|
|
return abs(sin(Float(i) * 0.001 * 2))
|
|
}
|
|
|
|
var sourceImageReal = [Float](repeating: 0, count: n)
|
|
var sourceImageImaginary = [Float](repeating: 0, count: n)
|
|
|
|
var sourceImage = DSPSplitComplex(fromInputArray: pixels,
|
|
realParts: &sourceImageReal,
|
|
imaginaryParts: &sourceImageImaginary)
|
|
|
|
let pixelsRecreated = [Float](fromSplitComplex: sourceImage,
|
|
scale: 1, count: pixelCount)
|
|
|
|
expectTrue(pixelsRecreated.elementsEqual(pixels))
|
|
|
|
// Create FFT2D object
|
|
let fft2D = vDSP.FFT2D(width: 256,
|
|
height: 256,
|
|
ofType: DSPSplitComplex.self)!
|
|
|
|
// New style transform
|
|
var transformedImageReal = [Float](repeating: 0,
|
|
count: n)
|
|
var transformedImageImaginary = [Float](repeating: 0,
|
|
count: n)
|
|
var transformedImage = DSPSplitComplex(
|
|
realp: &transformedImageReal,
|
|
imagp: &transformedImageImaginary)
|
|
|
|
fft2D.transform(input: sourceImage,
|
|
output: &transformedImage,
|
|
direction: .forward)
|
|
|
|
// Legacy 2D FFT
|
|
|
|
let log2n = vDSP_Length(log2(Float(width * height)))
|
|
let legacySetup = vDSP_create_fftsetup(
|
|
log2n,
|
|
FFTRadix(kFFTRadix2))!
|
|
|
|
var legacyTransformedImageReal = [Float](repeating: -1,
|
|
count: n)
|
|
var legacyTransformedImageImaginary = [Float](repeating: -1,
|
|
count: n)
|
|
var legacyTransformedImage = DSPSplitComplex(
|
|
realp: &legacyTransformedImageReal,
|
|
imagp: &legacyTransformedImageImaginary)
|
|
|
|
vDSP_fft2d_zrop(legacySetup,
|
|
&sourceImage, 1, 0,
|
|
&legacyTransformedImage, 1, 0,
|
|
vDSP_Length(log2(Float(width))),
|
|
vDSP_Length(log2(Float(height))),
|
|
FFTDirection(kFFTDirection_Forward))
|
|
|
|
expectTrue(transformedImageReal.elementsEqual(legacyTransformedImageReal))
|
|
expectTrue(transformedImageImaginary.elementsEqual(legacyTransformedImageImaginary))
|
|
}
|
|
|
|
Accelerate_vDSPFourierTransformTests.test("vDSP/2DDoublePrecision") {
|
|
let width = 256
|
|
let height = 256
|
|
let pixelCount = width * height
|
|
let n = pixelCount / 2
|
|
|
|
let pixels: [Double] = (0 ..< pixelCount).map { i in
|
|
return abs(sin(Double(i) * 0.001 * 2))
|
|
}
|
|
|
|
var sourceImageReal = [Double](repeating: 0, count: n)
|
|
var sourceImageImaginary = [Double](repeating: 0, count: n)
|
|
|
|
var sourceImage = DSPDoubleSplitComplex(fromInputArray: pixels,
|
|
realParts: &sourceImageReal,
|
|
imaginaryParts: &sourceImageImaginary)
|
|
|
|
let pixelsRecreated = [Double](fromSplitComplex: sourceImage,
|
|
scale: 1, count: pixelCount)
|
|
expectTrue(pixelsRecreated.elementsEqual(pixels))
|
|
|
|
// Create FFT2D object
|
|
let fft2D = vDSP.FFT2D(width: width,
|
|
height: height,
|
|
ofType: DSPDoubleSplitComplex.self)!
|
|
|
|
// New style transform
|
|
var transformedImageReal = [Double](repeating: 0,
|
|
count: n)
|
|
var transformedImageImaginary = [Double](repeating: 0,
|
|
count: n)
|
|
var transformedImage = DSPDoubleSplitComplex(
|
|
realp: &transformedImageReal,
|
|
imagp: &transformedImageImaginary)
|
|
|
|
fft2D.transform(input: sourceImage,
|
|
output: &transformedImage,
|
|
direction: .forward)
|
|
|
|
// Legacy 2D FFT
|
|
|
|
let log2n = vDSP_Length(log2(Float(width * height)))
|
|
let legacySetup = vDSP_create_fftsetupD(
|
|
log2n,
|
|
FFTRadix(kFFTRadix2))!
|
|
|
|
var legacyTransformedImageReal = [Double](repeating: -1,
|
|
count: n)
|
|
var legacyTransformedImageImaginary = [Double](repeating: -1,
|
|
count: n)
|
|
var legacyTransformedImage = DSPDoubleSplitComplex(
|
|
realp: &legacyTransformedImageReal,
|
|
imagp: &legacyTransformedImageImaginary)
|
|
|
|
vDSP_fft2d_zropD(legacySetup,
|
|
&sourceImage, 1, 0,
|
|
&legacyTransformedImage, 1, 0,
|
|
vDSP_Length(log2(Float(width))),
|
|
vDSP_Length(log2(Float(height))),
|
|
FFTDirection(kFFTDirection_Forward))
|
|
|
|
expectTrue(transformedImageReal.elementsEqual(legacyTransformedImageReal))
|
|
expectTrue(transformedImageImaginary.elementsEqual(legacyTransformedImageImaginary))
|
|
}
|
|
|
|
Accelerate_vDSPFourierTransformTests.test("vDSP/1DSinglePrecision") {
|
|
let n = vDSP_Length(2048)
|
|
|
|
let frequencies: [Float] = [1, 5, 25, 30, 75, 100,
|
|
300, 500, 512, 1023]
|
|
|
|
let tau: Float = .pi * 2
|
|
let signal: [Float] = (0 ... n).map { index in
|
|
frequencies.reduce(0) { accumulator, frequency in
|
|
let normalizedIndex = Float(index) / Float(n)
|
|
return accumulator + sin(normalizedIndex * frequency * tau)
|
|
}
|
|
}
|
|
|
|
let halfN = Int(n / 2)
|
|
|
|
var forwardInputReal = [Float](repeating: 0, count: halfN)
|
|
var forwardInputImag = [Float](repeating: 0, count: halfN)
|
|
|
|
var forwardInput = DSPSplitComplex(fromInputArray: signal,
|
|
realParts: &forwardInputReal,
|
|
imaginaryParts: &forwardInputImag)
|
|
|
|
let log2n = vDSP_Length(log2(Float(n)))
|
|
|
|
// New API
|
|
|
|
guard let fft = vDSP.FFT(log2n: log2n,
|
|
radix: .radix2,
|
|
ofType: DSPSplitComplex.self) else {
|
|
fatalError("Can't create FFT.")
|
|
}
|
|
|
|
var outputReal = [Float](repeating: 0, count: halfN)
|
|
var outputImag = [Float](repeating: 0, count: halfN)
|
|
var forwardOutput = DSPSplitComplex(realp: &outputReal,
|
|
imagp: &outputImag)
|
|
|
|
fft.transform(input: forwardInput,
|
|
output: &forwardOutput,
|
|
direction: .forward)
|
|
|
|
// Legacy Style
|
|
|
|
let legacySetup = vDSP_create_fftsetup(log2n,
|
|
FFTRadix(kFFTRadix2))!
|
|
|
|
var legacyoutputReal = [Float](repeating: -1, count: halfN)
|
|
var legacyoutputImag = [Float](repeating: -1, count: halfN)
|
|
var legacyForwardOutput = DSPSplitComplex(realp: &legacyoutputReal,
|
|
imagp: &legacyoutputImag)
|
|
|
|
|
|
vDSP_fft_zrop(legacySetup,
|
|
&forwardInput, 1,
|
|
&legacyForwardOutput, 1,
|
|
log2n,
|
|
FFTDirection(kFFTDirection_Forward))
|
|
|
|
expectTrue(outputReal.elementsEqual(legacyoutputReal))
|
|
expectTrue(outputImag.elementsEqual(legacyoutputImag))
|
|
}
|
|
|
|
Accelerate_vDSPFourierTransformTests.test("vDSP/1DDoublePrecision") {
|
|
let n = vDSP_Length(2048)
|
|
|
|
let frequencies: [Double] = [1, 5, 25, 30, 75, 100,
|
|
300, 500, 512, 1023]
|
|
|
|
let tau: Double = .pi * 2
|
|
let signal: [Double] = (0 ... n).map { index in
|
|
frequencies.reduce(0) { accumulator, frequency in
|
|
let normalizedIndex = Double(index) / Double(n)
|
|
return accumulator + sin(normalizedIndex * frequency * tau)
|
|
}
|
|
}
|
|
|
|
let halfN = Int(n / 2)
|
|
|
|
var forwardInputReal = [Double](repeating: 0, count: halfN)
|
|
var forwardInputImag = [Double](repeating: 0, count: halfN)
|
|
|
|
var forwardInput = DSPDoubleSplitComplex(fromInputArray: signal,
|
|
realParts: &forwardInputReal,
|
|
imaginaryParts: &forwardInputImag)
|
|
|
|
let log2n = vDSP_Length(log2(Double(n)))
|
|
|
|
// New API
|
|
|
|
guard let fft = vDSP.FFT(log2n: log2n,
|
|
radix: .radix2,
|
|
ofType: DSPDoubleSplitComplex.self) else {
|
|
fatalError("Can't create FFT.")
|
|
}
|
|
|
|
var outputReal = [Double](repeating: 0, count: halfN)
|
|
var outputImag = [Double](repeating: 0, count: halfN)
|
|
var forwardOutput = DSPDoubleSplitComplex(realp: &outputReal,
|
|
imagp: &outputImag)
|
|
|
|
fft.transform(input: forwardInput,
|
|
output: &forwardOutput,
|
|
direction: .forward)
|
|
|
|
// Legacy Style
|
|
|
|
let legacySetup = vDSP_create_fftsetupD(log2n,
|
|
FFTRadix(kFFTRadix2))!
|
|
|
|
var legacyoutputReal = [Double](repeating: 0, count: halfN)
|
|
var legacyoutputImag = [Double](repeating: 0, count: halfN)
|
|
var legacyForwardOutput = DSPDoubleSplitComplex(realp: &legacyoutputReal,
|
|
imagp: &legacyoutputImag)
|
|
|
|
|
|
vDSP_fft_zropD(legacySetup,
|
|
&forwardInput, 1,
|
|
&legacyForwardOutput, 1,
|
|
log2n,
|
|
FFTDirection(kFFTDirection_Forward))
|
|
|
|
expectTrue(outputReal.elementsEqual(legacyoutputReal))
|
|
expectTrue(outputImag.elementsEqual(legacyoutputImag))
|
|
}
|
|
}
|
|
|
|
runAllTests()
|