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
)
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.