Swift vDSP_zrvmul不返回任何结果(或全部为零)
根据另一位用户的评论,我已经整理了我的代码,并对其进行了压缩以使其可读。我有一个complexFloatArray类,用来存储复数向量数组Swift vDSP_zrvmul不返回任何结果(或全部为零),swift,pointers,accelerate-framework,vdsp,Swift,Pointers,Accelerate Framework,Vdsp,根据另一位用户的评论,我已经整理了我的代码,并对其进行了压缩以使其可读。我有一个complexFloatArray类,用来存储复数向量数组 class complexFloatArray { var reals: [Float] var imaginaries: [Float] init(reals: [Float], imaginaries: [Float]){ self.reals = reals self.imaginaries = imagina
class complexFloatArray {
var reals: [Float]
var imaginaries: [Float]
init(reals: [Float], imaginaries: [Float]){
self.reals = reals
self.imaginaries = imaginaries
}
}
然后我在这个类的扩展中定义了一些函数。一个是:
func useAsDSPSplitComplex<R>(_ closure: (inout DSPSplitComplex) -> R) -> R {
return reals.withUnsafeMutableBufferPointer { realBufferPointer in
return imaginaries.withUnsafeMutableBufferPointer { imaginaryBufferPointer in
var dspSplitComplex = DSPSplitComplex(realp: realBufferPointer.baseAddress!, imagp: imaginaryBufferPointer.baseAddress!)
return closure(&dspSplitComplex)
}
}
}
我使用以下方法调用函数:
var kernel = sine.floatMultiply(with: gauss)
其中正弦是一个复数小波,高斯是一个浮点数组,两者长度相等,可以创建一个morlet小波。但是,结果是一个用零填充的complexFloatArray
调试时,我可以在floatMultiply函数的任意点上设置断点,并确认self和other(正弦和高斯)都用值填充。因此,vDSP调用中的某个地方没有返回正确的结果
为了完整性,complexFloatArray.stride=1(该值在complexFloatArray类中声明)
“零”是complexFloatArray中的一个函数,用于用特定长度的零填充数组。(数组(重复:0,计数:N)
有什么建议可以解释为什么我这次通话的结果为零
我现在已经包含了完整的代码,而不是提供不完整图片的片段。ComplexFloataRay类的完整代码如下:
class ComplexFloatArray {
var reals: [Float]
var imaginaries: [Float]
init(reals: [Float], imaginaries: [Float]){
self.reals = reals
self.imaginaries = imaginaries
}
}
extension ComplexFloatArray {
var count: Int {
assert(reals.count == imaginaries.count)
return reals.count
}
static let stride = 1
func append(real: Float, imaginary: Float) {
self.reals.append(real)
self.imaginaries.append(imaginary)
}
func removeAtIndex(index: Int) {
self.reals.remove(at: index)
self.imaginaries.remove(at: index)
}
func useAsDSPSplitComplex<R>(_ closure: (inout DSPSplitComplex) -> R) -> R {
return reals.withUnsafeMutableBufferPointer { realBufferPointer in
return imaginaries.withUnsafeMutableBufferPointer { imaginaryBufferPointer in
var dspSplitComplex = DSPSplitComplex(realp: realBufferPointer.baseAddress!, imagp: imaginaryBufferPointer.baseAddress!)
return closure(&dspSplitComplex)
}
}
}
}
extension ComplexFloatArray {
convenience init() {
self.init(reals:[], imaginaries:[])
}
static func zeros(count: Int) -> ComplexFloatArray {
return ComplexFloatArray(reals:Array(repeating: 0, count: count), imaginaries: Array(repeating:0, count:count))
}
}
extension ComplexFloatArray {
enum ComplexMultiplicationType: Int32 { case normal = 1, conjugate = -1}
func ComplexMultiply(
with other: ComplexFloatArray,
multiplicationType: ComplexMultiplicationType = .normal
) -> ComplexFloatArray {
assert(self.count == other.count, "Multiplied Vectors Must have the same size!")
var result = ComplexFloatArray.zeros(count: self.count)
self.useAsDSPSplitComplex { selfPointer in
other.useAsDSPSplitComplex { otherPointer in
result.useAsDSPSplitComplex { resultPointer in
vDSP_zvmul(
&selfPointer, ComplexFloatArray.stride,
&otherPointer, ComplexFloatArray.stride,
&resultPointer, ComplexFloatArray.stride,
vDSP_Length(result.count),
multiplicationType.rawValue)
}
}
}
return result
}
}
extension ComplexFloatArray {
func floatMultiply(
with other: [Float]
) -> ComplexFloatArray {
assert(self.count == other.count, "Multiplied Vectors Must have the same size!")
var result = ComplexFloatArray.zeros(count: other.count)
self.useAsDSPSplitComplex { selfPointer in
result.useAsDSPSplitComplex { resultPointer in
vDSP_zrvmul(
&selfPointer, ComplexFloatArray.stride,
other, ComplexFloatArray.stride,
&resultPointer, ComplexFloatArray.stride,
vDSP_Length(result.count))
}
}
return result
}
}
extension ComplexFloatArray {
enum FourierTransformDirection: Int32 { case forward = 1, inverse = -1 }
func outOfPlaceComplexFourierTransform(
setup: FFTSetup,
resultSize:Int,
logSize: UInt,
direction: FourierTransformDirection) -> ComplexFloatArray {
var result = ComplexFloatArray.zeros(count:resultSize)
self.useAsDSPSplitComplex { selfPointer in
result.useAsDSPSplitComplex { resultPointer in
vDSP_fft_zop(
setup,
&selfPointer,
ComplexFloatArray.stride,
&resultPointer,
ComplexFloatArray.stride,
logSize,
direction.rawValue)
}
}
return result
}
}
如果我调试这个并暂停makeMorlet函数,FloatMultiply的结果都是零,尽管在等式的左侧和右侧都有相同的长度值。不幸的是,您的代码没有在具有默认设置的Xcode 10.2上运行 线程1:同时访问0x600001170550,但修改需要独占访问 我不确定您是否将对内存的独占访问设置为关闭(仅限编译时强制),或使用某些旧版本的Xcode,但Swift编译器会在独占强制完全有效的情况下优化并生成代码。(因此,您永远不应将对内存的独占访问设置为关闭。) 请仔细阅读本文: 您在
ComplexFloatArray
中对count
的实现违反了此强制。在执行传递给reals的闭包时,使用unsafemtablebufferpointer
,您无法访问reals
,因为该数组被该方法独占
如果违反此规则,Swift运行时可能会显示任何类型的意外行为
尝试更改count
的实现,如下所示,然后查看发生的情况:
class ComplexFloatArray {
var reals: [Float]
var imaginaries: [Float]
init(reals: [Float], imaginaries: [Float]){
self.reals = reals
self.imaginaries = imaginaries
assert(reals.count == imaginaries.count)
self.count = reals.count
}
//Make `count` a stored property.
var count: Int
}
extension ComplexFloatArray {
//Remove this computed property.
// var count: Int {
// assert(reals.count == imaginaries.count)
// return reals.count
// }
static let stride = 1
func append(real: Float, imaginary: Float) {
self.reals.append(real)
self.imaginaries.append(imaginary)
count += 1
}
func removeAtIndex(index: Int) {
self.reals.remove(at: index)
self.imaginaries.remove(at: index)
count -= 1
}
//...
}
还有一点,您的代码会生成许多带有建议设置的警告,您最好不要忽略它们。我无法在显示的代码中重现相同的问题。
零的实现(计数:)
可能是错误的,或者您过于简化了代码,并且显示的代码丢失了实际代码中的一些重要内容。无论如何,请尝试创建一个项目,该项目可以复制相同的问题,并在不隐藏任何行的情况下显示整个代码。顺便说一句,通常使用大写字母作为类型名称,就像我最初导入时所做的那样lementedComplexFloatArray
。这样就可以很容易地将它们与包含该类型实例的变量区分开来。例如,让ComplexFloatArray=ComplexFloatArray()
@OOPer您知道other:[Float]的用法是否正确
作为类型为UnsafePointer
的参数的参数有效吗?我不太理解Swift在数组和指针类型之间的桥接。@Alexander:是的,它将指针传递到(连续的)元素存储。唯一需要记住的是,该指针只保证在函数调用期间有效。-这里也进行了讨论和澄清:。像往常一样,需要一个:)我刚刚阅读了这篇文章并进行了检查,您是正确的,对内存的独占访问被设置为关闭,尽管我不记得这样做过,即使我刚刚创建了一个新项目。我已经按照您的建议更正并实现了count,它工作正常。@samp17,排他性强制规则是新的,非常强大,默认设置可能会受到其他一些因素的影响。当我发现一些与排他性执行有关的问题时,我会考虑这种可能性。不管怎样,很高兴听到你成功了。
var nVoices = 96 //number of voices per octave
var kernelLength = 2048 //Length of N
var fs = globalSampleRate
class CWT{
var timeArray:[Float] = []
var sines: [ComplexFloatArray] = []
var gaussian:[[Float]] = []
var fftFilterBank:[ComplexFloatArray] = []
var filterBank:[ComplexFloatArray] = []
var convProduct:[ComplexFloatArray] = []
var centreFreqs:[Float]=[]
var phase:[Float] = []
var magnitude:[Float] = []
func synthesizeKernels(){
timeArray = makeArray(from: ((1.0/Float(fs))*((-0.5)*Float(kernelLength))), to: ((1.0/Float(fs))*((0.5)*Float(kernelLength))), increment: 1/fs)
centreFreqs = getCentreFreqs(N:timeArray.count)
for i in 0..<centreFreqs.count {
makeSine(freq: centreFreqs[i], N:timeArray.count, iteration: i)
makeGaus(freq: centreFreqs[i], N:timeArray.count, iteration: i)
makeMorlet(sine: sines[i], gauss: gaussian[i], count:timeArray.count, iteration: i)
fftKernel(kernel: filterBank[i], N:timeArray.count, iteration:i)
}
}
func convolveSignal(realSamples:[Float], imagSamples:[Float]) {
let logN = 11
let fft1Setup = vDSP_create_fftsetup(UInt(logN), FFTRadix(FFT_RADIX2))!
var product = ComplexFloatArray.zeros(count: filterBank.count)
var input = ComplexFloatArray(reals: realSamples, imaginaries: imagSamples)
var fftOfSamples = ComplexFloatArray.zeros(count: input.count)
fftOfSamples = input.outOfPlaceComplexFourierTransform(setup: fft1Setup, resultSize: input.count, logSize: UInt(logN), direction: ComplexFloatArray.FourierTransformDirection(rawValue: 1)!)
fftOfSamples.removeAtIndex(index: 0)
for i in 0..<self.filterBank.count {
var kernel = fftFilterBank[i]
var multiplyResult = kernel.ComplexMultiply(with: fftOfSamples)
convProduct.append(multiplyResult)
}
}
//HELPER FUNCTION FOR TIME ARRAY
func makeArray(from:Float, to:Float, increment:Float) ->[Float]{
var Array:[Float]=[]
for i in stride(from: from, to: to, by: increment) {
Array.append(i)
}
return Array
}
//MAKE COMPLEX SINE WAVE
func makeSine(freq:Float, N:Int, iteration:Int) {
var compSine = ComplexFloatArray.init()
for i in 0..<timeArray.count{
let x = 2 * Float.pi * freq * timeArray[i]
compSine.append(real: cos(x), imaginary: sin(x))
}
sines.append(compSine)
}
//MAKE GAUSSIAN WINDOW
func makeGaus(freq:Float, N:Int, iteration:Int) {
var gaus:[Float] = Array(repeating:0, count:N)
let s:Float = 7 / (2.0 * Float.pi * freq)
let interimCalc: Float = Float(2)*Float(pow(s,2))
for i in 0..<N{
var u = pow(timeArray[i],2)
u = (-u)
let v = u / interimCalc
gaus[i] = exp(v)
}
gaussian.append(gaus)
}
//CREATE CENTRE FREQUENCIES
func getCentreFreqs(N:Int) ->[Float]{
var CF:[Float] = []
var filteredCF:[Float] = []
var G:Float = pow(10,(3/10))
var x = makeArray(from: -1000, to: 1350, increment: 1)
for i in 0..<x.count {
var fraction:Float = (Float(2*Float(x[i]))-Float(59.0)) / Float(2*nVoices)
var fr:Float = Float(1000.0) * Float(powf(Float(G), Float(fraction)))
CF.append(fr)
}
for i in 0..<CF.count {
if (Float(20) < CF[i] && CF[i] < Float(20000)) {
filteredCF.append(CF[i])
}
}
return filteredCF
}
//MAKE COMPLEX MORLET WAVELET
func makeMorlet(sine:ComplexFloatArray, gauss:[Float], count:Int, iteration:Int) {
var kernel = sine.floatMultiply(with: gauss)
filterBank.append(kernel)
}
//PERFORM FFT ON KERNEL
func fftKernel(kernel: ComplexFloatArray, N:Int, iteration:Int) {
var size = kernel.count
var logSize = 11
var FFTSetup = vDSP_create_fftsetup(vDSP_Length(logSize), FFTRadix(FFT_RADIX2))
var output = kernel.outOfPlaceComplexFourierTransform(setup: FFTSetup!, resultSize: size, logSize: UInt(logSize), direction: ComplexFloatArray.FourierTransformDirection(rawValue: 1)!)
output.removeAtIndex(index:0)
fftFilterBank.append(output)
}
//Test Signal to Convolve - 1kHz Sine Wave
func testSine(){
var testTimeArray = makeArray(from: ((1.0/Float(fs))*((-0.5)*Float(kernelLength))), to: ((1.0/Float(fs))*((0.5)*Float(kernelLength))), increment: 1/fs)
var testSine = ComplexFloatArray.zeros(count: testTimeArray.count)
for i in 0..<testTimeArray.count{
var x = 2 * Float.pi * 1000 * testTimeArray[i]
testSine.reals[i] = cos(x)
testSine.imaginaries[i] = sin(x)
}
convolveSignal(realSamples: testSine.reals, imagSamples:testSine.imaginaries)
}
}
class ViewController: UIViewController {
var wavelet = CWT()
func viewDidLoad(){
wavelet.synthesizeKernels()
wavelet.testSine()
}
}
class ComplexFloatArray {
var reals: [Float]
var imaginaries: [Float]
init(reals: [Float], imaginaries: [Float]){
self.reals = reals
self.imaginaries = imaginaries
assert(reals.count == imaginaries.count)
self.count = reals.count
}
//Make `count` a stored property.
var count: Int
}
extension ComplexFloatArray {
//Remove this computed property.
// var count: Int {
// assert(reals.count == imaginaries.count)
// return reals.count
// }
static let stride = 1
func append(real: Float, imaginary: Float) {
self.reals.append(real)
self.imaginaries.append(imaginary)
count += 1
}
func removeAtIndex(index: Int) {
self.reals.remove(at: index)
self.imaginaries.remove(at: index)
count -= 1
}
//...
}