vDSP_conv偶尔会返回NAN

时间:2016-05-12 01:05:13

标签: swift swift2 signal-processing

我使用vDSP_conv执行自相关。大多数情况下它的工作正常,但每隔一段时间它就会用NaN填充输出数组。

代码:

func corr_test() {
  var pass = 0

  var x = [Float]()
  for i in 0..<2000 {
    x.append(Float(i))
  }

  while true {
    print("pass \(pass)")

    let corr = autocorr(x)
    if corr[1].isNaN {
        print("!!!")
    }
    pass += 1
  }
}

func autocorr(a: [Float]) -> [Float] {
    let resultLen = a.count * 2 + 1
    let padding = [Float].init(count: a.count, repeatedValue: 0.0)
    let a_pad = padding + a + padding
    var result = [Float].init(count: resultLen, repeatedValue: 0.0)

    vDSP_conv(a_pad, 1, a_pad, 1, &result, 1, UInt(resultLen), UInt(a_pad.count))

    return result
}

输出:

pass ...
pass 169
pass 170
pass 171
(lldb) p corr
([Float]) $R0 = 4001 values {
  [0] = 2.66466637E+9
  [1] = NaN
  [2] = NaN
  [3] = NaN
  [4] = NaN
...

我不确定这里发生了什么。我认为我正确处理了0填充,因为如果我不认为我在99%的时间内都能得到正确的结果。

想法?格拉西亚斯。

1 个答案:

答案 0 :(得分:0)

想出来。关键是来自https://developer.apple.com/library/mac/samplecode/vDSPExamples/Listings/DemonstrateConvolution_c.html的评论:

// “The signal length is padded a bit. This length is not actually passed to the vDSP_conv routine; it is the number of elements
// that the signal array must contain. The SignalLength defined below is used to allocate space, and it is the filter length
// rounded up to a multiple of four elements and added to the result length. The extra elements give the vDSP_conv routine
// leeway to perform vector-load instructions, which load multiple elements even if they are not all used. If the caller did not
// guarantee that memory beyond the values used in the signal array were accessible, a memory access violation might result.”

“填补了一点。”谢谢你这么具体。无论如何,这是最终的工作产品:

func autocorr(a: [Float]) -> [Float] {
let filterLen = a.count
let resultLen = filterLen * 2 - 1
let signalLen = ((filterLen + 3) & 0xFFFFFFFC) + resultLen

let padding1 = [Float].init(count: a.count - 1, repeatedValue: 0.0)
let padding2 = [Float].init(count: (signalLen - padding1.count - a.count), repeatedValue: 0.0)
let signal = padding1 + a + padding2

var result = [Float].init(count: resultLen, repeatedValue: 0.0)

vDSP_conv(signal, 1, a, 1, &result, 1, UInt(resultLen), UInt(filterLen))

// Remove the first n-1 values which are just mirrored from the end so that [0] always has the autocorrelation.
result.removeFirst(filterLen - 1)

return result
}

请注意,此处的结果未标准化。