Swift vDSP_conv()的结果不正确

Swift vDSP_conv()的结果不正确,swift,accelerate-framework,vdsp,Swift,Accelerate Framework,Vdsp,与MATLAB实现相比,在尝试使用Accelerate的vDSP_conv()进行卷积时,我得到了不一致的结果。在使用这个函数计算卷积时,有几篇StackOverflow文章提到了一些奇怪的结果,但是据我所知,我正确地使用了这个框架,并采纳了其他Stack Overflow文章的建议。这是我的密码: public func conv(x: [Float], k: [Float]) -> [Float] { let resultSize = x.count + k.count -

与MATLAB实现相比,在尝试使用Accelerate的vDSP_conv()进行卷积时,我得到了不一致的结果。在使用这个函数计算卷积时,有几篇StackOverflow文章提到了一些奇怪的结果,但是据我所知,我正确地使用了这个框架,并采纳了其他Stack Overflow文章的建议。这是我的密码:

public func conv(x: [Float], k: [Float]) -> [Float] {  
    let resultSize = x.count + k.count - 1
    var result = [Float](count: resultSize, repeatedValue: 0)
    let kEnd = UnsafePointer<Float>(k).advancedBy(k.count - 1)
    let xPad: [Float] = [Float](count: (2*k.count)+1, repeatedValue: 0.0)
    let xPadded = x + xPad
    vDSP_conv(xPadded, 1, kEnd, -1, &result, 1, vDSP_Length(resultSize), vDSP_Length(k.count))
}
使用此代码,
conv(A,B)
仍然返回[1,0,0,0,0,0]

我正在调用如下所示的函数:

let A: [Float] = [0, 0, 1, 0, 0]
let B: [Float] = [1, 0, 0]
let C: [Float] = conv(A, k: B)

对于长度为
m
n
的两个数组
A
B
, 加速框架中的函数计算一个新的长度数组
m-n+1

这与具有形状的MATLAB函数的结果相对应 参数设置为“有效”:

仅计算卷积中没有零填充边的部分

从MATLAB中获得与“完全”卷积相同的结果 您必须在
A
数组的开始和结束处使用
n-1
元素对其进行零填充,这将产生长度
m+n-1
的结果数组

适用于您的功能:

let xPad = Repeat(count: k.count - 1, repeatedValue: Float(0.0))
let xPadded = xPad + x + xPad 
使用
Repeat()
创建序列而不是数组。但最终,一个新的阵列
必须创建为
vDSP_conv()
函数的参数,
因此没有太多的改进空间。

@MartinR我找到了我的代码不能处理数组的原因。我在一个项目中编写了这段代码,该项目使用了喘振作为链接框架。喘振会使[Float]和[Double]数组的
+
运算符过载,从而使其成为数组元素的按元素添加。因此,当我执行
x+xPad
时,它没有像预期的那样扩展数组的大小,它只是返回
x
,因为
xPad
只包含零。但是,喘振并没有使序列的
+
操作符过载,因此使用
Repeat()
成功地扩展了数组。谢谢你的帮助-从来没有想过尝试序列

为下一个跌入这一困境的可怜人澄清一下: 苹果公司提供了关于如何使用vDSP_conv的信息,但这是毫无用处的。事实上,这让我很困惑,因为代码中的一条注释说需要填充输入缓冲区,而没有指定实际输入样本应该放在哪里:

下面定义的SignalLength用于分配空间,它是过滤器长度,四舍五入为四个元素的倍数,并添加到结果长度

SignalLength=(滤波器长度+3&-4u)+ResultLength

因此,上面的公式给出的长度(大于)不同于
xPad+x+xPad
,其中xPad是k.count-1

重要的是在填充的缓冲区中复制输入(信号)样本的位置:它必须位于
k.count-1

因此,上述公认的解决方案是有效的。但是如果你相信苹果的例子中的评论(顺便说一句,官方文档中没有显示),那么你可以做一个折衷:使用他们的公式(上面的信号长度)来计算和分配填充缓冲区(它会大一点),并使用
k.count-1
(即过滤器长度-1)作为信号的起始偏移量(本例中为x)。我这样做了,结果现在与ippsConvolve_32f和Matlab匹配


(对不起,这应该是一个评论,但我没有足够的声誉).

不幸的是,这没有帮助。当我在数组的开头和结尾用
k.count-1
0相等地填充数组时,我得到的卷积值完全不正确。我也尝试过在开头和结尾使用不同的填充组合。不过谢谢你的建议!@RemyPrechelt:对于输入数组A,B I在您的问题中,它会产生输出
[0.0,0.0,1.0,0.0,0.0,0.0,0.0]
,这似乎是您所期望的。您能否给出一个不起作用的示例?(输入、输出和预期输出)我在上面添加了编辑过的代码,还添加了调用代码。函数仍然返回一个与MATLAB/Octave和Numpy不一致的结果。@RemyPrechelt:我已将更新后的函数和测试代码复制/粘贴到我的Xcode项目中,结果是
C=[0.0,0.0,1.0,0.0,0.0]
。好的。这很奇怪。我清理了项目,并使用上面的代码运行了
conv()
。我得到了不正确的值
[1.0,4.59093e-41,0.0,0.0,0.0,0.0,0.0,3.21425e-39]
。但是,如果我将
xPad
的定义更改为使用
重复
,我会得到
[0.0,0.0,1.0,0,0,0.0,0,0.0]的正确答案
。我已经用其他数组对此进行了5次测试。每当我将
xPad
声明为数组时,我的卷积总是移到2个单位以上,并且当
xPad
是一个序列时,卷积总是正确的。你对这种行为有什么见解吗?它在你这边可以重复吗?
let xPad = Repeat(count: k.count - 1, repeatedValue: Float(0.0))
let xPadded = xPad + x + xPad