vDSP_zrvmul не возвращает никаких результатов (или все нули) - PullRequest
1 голос
/ 12 апреля 2019

Я убрал свой код и сжал его, чтобы сделать его читабельным, согласно комментариям других пользователей. У меня есть класс 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)

где sine - комплексный массив чисел, а гаусс - массив чисел Float, оба одинаковой длины для создания вейвлета морлета. Однако результатом является сложный FloatArray, заполненный нулями.

При отладке я могу поставить точку останова в любой точке функции floatMultiply и подтвердить, что и self, и другие (sine и gauss) заполнены значениями. Так что это где-то в вызове vDSP, который не возвращает правильные результаты.

Для полноты complexFloatArray.stride = 1 (это значение объявлено в классе complexFloatArray).

И «нули» - это функция в 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 Ответ

1 голос
/ 13 апреля 2019

К сожалению, ваш код не запускается на Xcode 10.2 с настройками по умолчанию.

Поток 1: одновременный доступ к 0x600001170550, но для модификации требуется эксклюзивный доступ

Я не уверен, что вы отключаете Эксклюзивный доступ к памяти (только для времени компиляции) или используете более старую версию XCode, но компилятор Swift оптимизирует и генерирует код, предполагая, что принудительное применение эксклюзивности полностью действительный. (Таким образом, вы никогда не должны отключать эксклюзивный доступ к памяти.)

Пожалуйста, внимательно прочитайте эту статью:

Swift 5 Система обеспечения эксклюзивности

Ваша реализация 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
    }

    //...    
}

Еще один, ваш код генерирует много предупреждений с рекомендуемыми настройками, вам лучше не игнорировать их.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...