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