简体   繁体   中英

Using Accelerate Framework complex number support in Swift

I need to perform the following operations in Swift with Accelerate Multiply, Complex Conjugate, and Exp. I've done this already using the Complex Swift code by dankogai , but it is just too slow for the work I'm doing. I'm having trouble creating a working version using the Accelerate framework and I'm hoping to accelerate my understanding.

Swift code

let frequencyShift = (2 * M_PI * Double(self.centralFrequency) * delays).i / Double(self.samplingFrequencyHertz)
let result = conj(exp(frequencyShift))

delays is an array of about 200k doubles and these lines will be called a couple of hundred times. I convert them to Complex numbers a la Swift Complex style and then call the complex exp() and conj() methods on the result.

Multiply

Double-precision complex vector-scalar multiply.

vDSP_zvzsmlD

Conjugate

Complex vector conjugate; double precision.

vDSP_zvconjD

Is there an exp() equivalent in Accelerate and how would you reorganize this code to perform an equivalent Accelerate'd version of the operations?

General principles of using Accelerate with Swift

I find it helpful to first attempt to convert your code from a naive implementation using for-loops to maps. If your code is structured to work with maps then it becomes pretty easy to switch to accelerate since you have already tackled structuring your algorithm into vectorized operations.

For-loop to map

let array: [Int] = [1, 2, 3, 4]
let array2 = [Int]()
for value in array {
    array2 = value * 2
}

let array: [Int] = [1, 2, 3, 4]
array.map({ (value: Int) -> Int in
    return value * 2
})

Operating on equal sized arrays version

If you find that you want to enumerate two or more arrays of the same size then the above can combine map with enumerate

let alphas: [Double] = betas.enumerate().map({ (index: Int, beta: Double) -> Double in
    return beta * phis[index]
})

Setting up the arrays for use with Accelerate

The way to use Accelerate is not always obvious and specifically the UnsafePointer and UnsafeMutablePointer syntax. This is basically unnecessary.

var alphaLowers = [Double](count: elementDelays.count, repeatedValue: 0)
vDSP_vmulD(&alphas, 1, &x_ns, 1, &alphaLowers, 1, UInt(elementDelays.count))

So Swift avoids the hassles of malloc and free by allowing you to create an automatic memory managed object and then simply passing it along with the ampersand. I mention this because it avoids trying things like wrapping the object in this UnsafeMutablePointer<Double>(alphaLowers) .

Complex numbers

Most of what I wanted to do relied on operations involving complex numbers. So to create an object you can use in Accelerate you might try the following.

var reals = [Double](count: 100, repeatedValue: 0)
var imaginaries = [Double](count: 100, repeatedValue: 0)
var complexNumbers = DSPDoubleSplitComplex(realp: &reals, imagp: &imaginaries)

Complex exp()

I didn't find an Accelerate equivalent of exp, but you can break up the values and perform the necessary operation on the reals and imaginaries using Euler's method illustrated below using the Complex Swift library.

public func exp<T:RealType>(z:Complex<T>) -> Complex<T> {
    let r = T.exp(z.re)
    let a = z.im
    return Complex(r * T.cos(a), r * T.sin(a))
}

I haven't found a good way of avoiding this problem so I actually do this step without using Accelerate. The complex conjugate is calculated simply by negating the imaginary portion.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM