根据其他用户的评论,我整理了代码并将其压缩以使其可读。我有一个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的结果均为零,尽管等式的左侧和右侧的长度值相同。
答案 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
}
//...
}
再一次,您的代码会生成带有建议设置的许多警告,您最好不要忽略它们。