根据其他用户的评论,我整理了我的代码并将其压缩成可读的。我有一个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是一个复数的loatarray,gauss是一个FloatArray,两者的长度都相等以创建morlet小波。然而,结果是一个充满零的complexFloatArray。
调试时,我可以在floatMultiply函数的任意点设置断点,并确认self和other(sine和gauss)都填充了vales。所以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的结果都是零,尽管在等式的左侧和右侧都有相同的长度值。
最佳答案
不幸的是,您的代码不能在默认设置的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
}
//...
}
另外,您的代码使用建议的设置生成许多警告,您最好不要忽略它们。