在 Swift 中使用 Accelerate Framework 复数支持

Using Accelerate Framework complex number support in Swift

我需要在 Swift 中使用 Accelerate Multiply、Complex Conjugate 和 Exp 执行以下操作。我已经使用 Complex Swift code by dankogai 完成了此操作,但它对于我正在做的工作来说太慢了。我在使用 Accelerate 框架创建工作版本时遇到问题,我希望能加速我的理解。

Swift代码

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

delays 是一个包含大约 200k 个双精度数的数组,这些行将被调用数百次。我将它们转换为复数 a la Swift Complex 样式,然后对结果调用复数 exp() 和 conj() 方法。

双精度复向量标量乘法。

vDSP_zvzsmlD

共轭

复向量共轭;双精度。

vDSP_zvconjD

在 Accelerate 中是否有一个 exp() 等效项?您将如何重新组织此代码以执行等效的 Accelerate'd 操作版本?

将 Accelerate 与 Swift

结合使用的一般原则

我发现首先尝试将您的代码从使用 for-loops 的原始实现转换为映射很有帮助。如果您的代码结构适用于地图,那么切换到加速将变得非常容易,因为您已经解决了将算法结构化为矢量化操作的问题。

For-loop映射

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
})

在相同大小的数组版本上运行

如果你发现你想枚举两个或更多相同大小的数组那么上面可以结合map和enumerate

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

设置阵列以用于 Accelerate

使用 Accelerate 的方式并不总是显而易见的,特别是 UnsafePointerUnsafeMutablePointer 语法。这基本上是没有必要的。

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

因此 Swift 允许您创建一个自动内存管理对象,然后简单地将它与符号一起传递,从而避免了 malloc 和 free 的麻烦。我提到这一点是因为它避免了尝试在 UnsafeMutablePointer<Double>(alphaLowers).

中包装对象之类的事情

复数

我想做的大部分事情都依赖于涉及复数的运算。因此,要创建一个可以在 Accelerate 中使用的对象,您可以尝试以下操作。

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

复数 exp()

我没有找到 exp 的 Accelerate 等价物,但您可以分解这些值并使用 Complex Swift 库使用下面说明的 Euler 方法对实数和虚数执行必要的操作。

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))
}

我还没有找到避免这个问题的好方法,所以我实际上在没有使用 Accelerate 的情况下执行了这一步。只需将虚部取负即可计算出复共轭。