在 Swift 中使用 Accelerate Framework 复数支持
Posted
技术标签:
【中文标题】在 Swift 中使用 Accelerate Framework 复数支持【英文标题】:Using Accelerate Framework complex number support in Swift 【发布时间】:2016-01-20 10:56:09 【问题描述】:我需要在 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 双精度的数组,这些行将被调用几百次。我将它们转换为 Swift Complex 风格的复数,然后在结果上调用复数 exp() 和 conj() 方法。
相乘
双精度复数向量标量乘法。
vDSP_zvzsmlD
共轭
复向量共轭;双精度。
vDSP_zvconjD
Accelerate 中是否有 exp()
等效项?您将如何重新组织此代码以执行等效的 Accelerate 版本的操作?
【问题讨论】:
【参考方案1】:在 Swift 中使用 Accelerate 的一般原则
我发现首先尝试将您的代码从使用 for 循环的幼稚实现转换为映射很有帮助。如果您的代码被构造为使用地图,那么切换到加速变得非常容易,因为您已经解决了将算法结构化为矢量化操作的问题。
for 循环映射
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 的方式并不总是很明显,特别是 UnsafePointer
和 UnsafeMutablePointer
语法。这基本上是不必要的。
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 库。
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 的情况下执行此步骤。只需将虚部取反即可计算复共轭。
【讨论】:
哇,Swift 中 malloc/free 的消除值得了解,我很高兴我加入了这个线程!以上是关于在 Swift 中使用 Accelerate Framework 复数支持的主要内容,如果未能解决你的问题,请参考以下文章
使用 Swift 中的 Accelerate 框架来自 AVAudioPCMBuffer 的频谱图
Swift SIMD 或 Accelerate Sum UInt32
如何使用 vDSP / Accelerate in swift for iOS 计算向量元素的平方根