如何使用 vDSP 集成到 Swift

Posted

技术标签:

【中文标题】如何使用 vDSP 集成到 Swift【英文标题】:How to integrate in Swift using vDSP 【发布时间】:2021-11-14 15:23:53 【问题描述】:

我尝试在 Swift 中寻找 SciPy's cumtrapz function 函数的替代品。我找到了一个名为vDSP_vtrapzD 的东西,但我不知道如何使用它。这是我到目前为止所做的:

import Accelerate
var f1: [Double] = [<some data>]
var tdata: [Double] = [<time vector>]
var output = [Double](unsafeUninitializedCapacity:Int(f1.count), initializingWith: _, _ in)

vDSP_vtrapzD(&f1, 1, &tdata, &output, 1, vDSP_Length(f1.count))

【问题讨论】:

不相关,但我要补充一点:如果您将变量命名为比 f1tdata 更有用的名称,则无需编写像 some datatime vector 这样的 cmets。您可以将变量命名为 :p 对不起。它在我的计算中更有意义,但我在发布问题时忘记更改它。 【参考方案1】:

您很接近,但您错误地使用了Array.init(unsafeUninitializedCapacity:initializingWith:)。来自its documentation:

讨论

在闭包内部,将initializedCount 参数设置为闭包初始化的元素数量。 buffer[0..&lt;initializedCount] 范围内的内存必须在闭包执行结束时初始化,buffer[initializedCount...] 范围内的内存必须未初始化。即使initializer 闭包抛出错误,这个后置条件也必须成立。

这个 API 比 Array.init(repeating:count:) 更不安全(但性能更好),它分配一个固定大小的数组,并花时间初始化它的所有内容)。这有两个潜在的缺点:

如果数组的目的是提供一个缓冲区来写入结果,那么在此之前对其进行初始化是多余和浪费的

如果您放入该缓冲区的结果最终大于您的 数组,您需要记住手动“修剪”多余的部分 将其复制到一个新数组中。

Array.init(unsafeUninitializedCapacity:initializingWith:) 对此进行了改进:

询问您可能需要的最大容量 为您提供具有容量的临时缓冲区 重要的是,它未初始化。这使它更快,但如果使用不当也会更危险(buffer underflow errors 的风险)。 然后你告诉它你实际使用了多少临时缓冲区 它会自动将大部分缓冲区复制到最终数组中,并将其作为结果返回。

您正在使用Array.init(unsafeUninitializedCapacity:initializingWith:),就好像它是Array.init(repeating:count:)。要正确使用它,您可以将初始化逻辑放入 initializer 参数中,如下所示:

let result = Array<Double>(unsafeUninitializedCapacity: f1.count, initializingWith:  resultBuffer, count in
    assert(f1.count == tdata.count)
    
    vDSP_vtrapzD(
        &f1,                       // Double-precision real input vector.
        1,                         // Address stride for A.
        &tdata,                    // Pointer to double-precision real input scalar: step size.
        resultBuffer.baseAddress!, // Double-precision real output vector.
        1,                         // Address stride for C.
        vDSP_Length(f1.count)      // The number of elements to process.,
    )
    
    count = f1.count // This tells Swift how many elements of the buffer to copy into the resultant Array
)

【讨论】:

【参考方案2】:

仅供参考,vDSP_vtrapzD 有一个不错的 Swift 版本,您可以在这里看到:https://developer.apple.com/documentation/accelerate/vdsp/integration_functions。返回结果的变体使用unsafeUninitializedCapacity 初始化器。

在相关说明中,Quadrature 还有一个不错的 Swift API:https://developer.apple.com/documentation/accelerate/quadrature-smu

西蒙

【讨论】:

以上是关于如何使用 vDSP 集成到 Swift的主要内容,如果未能解决你的问题,请参考以下文章

转换参数以使 Swift 使用 vDSP API 进行编译

如何在 iOS 中使用 vDSP 将声音文件转换为 FFT

将 vDSP.convertElements 与 vDSP.RoundingMode 一起使用

Swift - 如何将 SwiftValidator 集成到我的项目中

使用 vDSP 的 FFT 频率范围

Apple 的 Accelerate vDSP:如何从 FFT 中获取复数向量的参数