vDSP_zrvmul不返回任何结果(或全零)

时间:2019-04-12 15:27:33

标签: swift pointers accelerate-framework vdsp

根据其他用户的评论,我整理了代码并将其压缩以使其可读。我有一个complexFloatArray类,用于存储复杂向量的数组

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

这个想法是在complexFloatArray实例上调用时,它创建一个DSPSplitComplex指针以与Accelerate框架一起使用。

最后,我有一个加速函数,我想使用(vDSP_zrvmul)将我的复数向量乘以一个实数向量。

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
}

我使用以下函数调用函数:

var kernel = sine.floatMultiply(with: gauss)

其中正弦是complexFloatArray,高斯是FloatArray,两者的长度相等,以创建morlet小波。但是,结果是一个用零填充的complexFloatArray。

在调试时,我可以在floatMultiply函数的任意位置放置一个断点,并确认self和其他(正弦和高斯)都填充有值。因此,在vDSP调用中的某处未返回正确的结果。

对于完整性,complexFloatArray.stride = 1(此值在complexFloatArray类中声明)。

'zeros'是complexFloatArray中的一个函数,用于使用某个长度的零填充数组。 (数组(重复:0,计数:N)

有人建议为什么我的通话结果为零吗?

我现在包含了完整的代码,而不是包含不完整图片的摘录。
下面是ComplexFloatArray类的完整代码:

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
    }
}

我的CWT类的完整代码如下:

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)

    }
}

最后在ViewController类中,我有以下内容:

class ViewController: UIViewController {

    var wavelet = CWT()

    func viewDidLoad(){
        wavelet.synthesizeKernels()
        wavelet.testSine()
    }
}

如果我对此进行调试并在makeMorlet函数上暂停,则FloatMultiply的结果均为零,尽管等式的左侧和右侧的长度值相同。

1 个答案:

答案 0 :(得分:1)

不幸的是,您的代码无法在具有默认设置的Xcode 10.2上运行。

  

线程1:同时访问0x600001170550,但修改需要互斥权限

我不确定您是否将对内存的独占访问权限设置为关闭(仅编译时强制执行),或使用某些旧版本的Xcode,但是Swift编译器会假定专有排他性是完全有效。 (因此,永远不要关闭“对内存的独占访问”。)

请仔细阅读本文:

Swift 5 Exclusivity Enforcement

您在count中对ComplexFloatArray的实施违反了此强制措施。在执行传递给reals.withUnsafeMutableBufferPointer的闭包时,您无法访问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
    }

    //...    
}

再一次,您的代码会生成带有建议设置的许多警告,您最好不要忽略它们。