ASDFQWERTY
ASDFQWERTY

Reputation: 424

Segmentation fault using Swift Accelerate vDSP_ctoz

I'm trying to convert an interleaved DSPComplex vector to a DSPSplitComplex vector, using vDSP_ctoz from the Swift Accelerate library. The last line of the code below produces the error Segmentation fault: 11

I don't understand why vDSP_ctoz would try to access out-of-bound memory when I've allocated large vectors and am only trying to process a small number of elements. The vectors are size 2048 and the argument for N (number of elements to process) in vDSP_ctoz is 1.

I've also tried using different stride and N values when calling vDSP_ctoz, to no avail.

// set stride values
let dspComplexStride = MemoryLayout<DSPComplex>.stride
let dspSplitComplexStride = MemoryLayout<DSPSplitComplex>.stride

// make interleaved vector
var interleaved = UnsafeMutablePointer<DSPComplex>.allocate(capacity: 2048)
for index in 0..<16 {
    interleaved[index] = DSPComplex(real: Float(2*index), imag: Float(2*index+1))
}

// make split vector
var splitComplex = UnsafeMutablePointer<DSPSplitComplex>.allocate(capacity: 2048)
vDSP_ctoz(
    interleaved, dspComplexStride, splitComplex, dspSplitComplexStride, 1
)

Upvotes: 1

Views: 426

Answers (1)

Martin R
Martin R

Reputation: 539975

DSPSplitComplex is a structure containing pointers arrays, so you need a single DSPSplitComplex element and must allocate storage for its realp and imagp properties.

The "stride" arguments are not measured in bytes but in "element" units. So you pass __IZ == 1 because you want to fill contiguous elements in the destination arrays.

It may not be obvious that you have to pass __IC == 2 for the source array, i.e. the stride of the source array is given in Float units and not in DSPComplex units. This can be deduced from the vDSP_ctoz documentation which mentions that the function effectively does

for (n = 0; n < N; ++n)
{
  Z->realp[n*IZ] = C[n*IC/2].real;
  Z->imagp[n*IZ] = C[n*IC/2].imag;
}

Finally, the last argument of vDSP_ctoz is the number of elements to process.

Putting it all together, this is how it should work:

import Accelerate

let N = 16

var interleaved = UnsafeMutablePointer<DSPComplex>.allocate(capacity: N)
for index in 0..<N {
    interleaved[index] = DSPComplex(real: Float(2*index), imag: Float(2*index+1))
}

let realp = UnsafeMutablePointer<Float>.allocate(capacity: N)
let imagp = UnsafeMutablePointer<Float>.allocate(capacity: N)
var splitComplex = DSPSplitComplex(realp: realp, imagp: imagp)

vDSP_ctoz(interleaved, 2, &splitComplex, 1, vDSP_Length(N))

for index in 0..<N {
    print(splitComplex.realp[index], splitComplex.imagp[index])
}

and of course you have to release the memory eventually.

Upvotes: 2

Related Questions