| // 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() |