Swift 通过线性调频Z变换(CZT)实现快速逆FFT(IFFT)

Swift 通过线性调频Z变换(CZT)实现快速逆FFT(IFFT),swift,fft,ifft,Swift,Fft,Ifft,对于任意大小的样本(样本不等于2^N),我已经能够使用iOS Accelerate的FFT函数(仅适用于等于2^N的样本),通过chirp Z变换(CZT)实现FFT 结果是好的,并且匹配任意长度序列(信号)的Matlab FFT输出。我将代码粘贴到下面 我的下一个挑战是使用iOS Accelerate的FFT函数(仅适用于等于2^N的样本)在任意样本大小(样本不等于2^N)上实现逆FFT 由于我的CZT现在可以完成任意长度的FFT(见下文),我希望反向CZT(ICZT)可以使用iOS Acce

对于任意大小的样本(样本不等于2^N),我已经能够使用iOS Accelerate的FFT函数(仅适用于等于2^N的样本),通过chirp Z变换(CZT)实现FFT

结果是好的,并且匹配任意长度序列(信号)的Matlab FFT输出。我将代码粘贴到下面

我的下一个挑战是使用iOS Accelerate的FFT函数(仅适用于等于2^N的样本)在任意样本大小(样本不等于2^N)上实现逆FFT

由于我的CZT现在可以完成任意长度的FFT(见下文),我希望反向CZT(ICZT)可以使用iOS Accelerate的FFT函数(仅适用于等于2^N的样本)完成任意长度的IFFT

有什么建议/指导吗

// FFT IOS ACCELERATE FRAMEWORK (works only for 2^N samples)
import Accelerate

public func fft(x: [Double], y: [Double], type: String) -> ([Double], [Double]) {

    var real = [Double](x)

    var imaginary = [Double](y)

    var splitComplex = DSPDoubleSplitComplex(realp: &real, imagp: &imaginary)

    let length = vDSP_Length(floor(log2(Float(real.count))))

    let radix = FFTRadix(kFFTRadix2)

    let weights = vDSP_create_fftsetupD(length, radix)

    switch type.lowercased() {

    case ("fft"): // CASE FFT
        vDSP_fft_zipD(weights!, &splitComplex, 1, length, FFTDirection(FFT_FORWARD))
        vDSP_destroy_fftsetup(weights)

    case ("ifft"): // CASE INVERSE FFT
        vDSP_fft_zipD(weights!, &splitComplex, 1, length, FFTDirection(FFT_INVERSE))
        vDSP_destroy_fftsetup(weights)
        real = real.map({ $0 / Double(x.count) }) // Normalize IFFT by sample count
        imaginary = imaginary.map({ $0 / Double(x.count) }) // Normalize IFFT by sample count

    default: // DEFAULT CASE (FFT)
        vDSP_fft_zipD(weights!, &splitComplex, 1, length, FFTDirection(FFT_FORWARD))
        vDSP_destroy_fftsetup(weights)
    }

    return (real, imaginary)
}

// END FFT IOS ACCELERATE FRAMEWORK (works only for 2^N samples)

// DEFINE COMPLEX NUMBERS
struct Complex<T: FloatingPoint> {
    let real: T
    let imaginary: T
    static func +(lhs: Complex<T>, rhs: Complex<T>) -> Complex<T> {
        return Complex(real: lhs.real + rhs.real, imaginary: lhs.imaginary + rhs.imaginary)
    }

    static func -(lhs: Complex<T>, rhs: Complex<T>) -> Complex<T> {
        return Complex(real: lhs.real - rhs.real, imaginary: lhs.imaginary - rhs.imaginary)
    }

    static func *(lhs: Complex<T>, rhs: Complex<T>) -> Complex<T> {
        return Complex(real: lhs.real * rhs.real - lhs.imaginary * rhs.imaginary,
                       imaginary: lhs.imaginary * rhs.real + lhs.real * rhs.imaginary)
    }
}

extension Complex: CustomStringConvertible {
    var description: String {
        switch (real, imaginary) {
        case (_, 0):
            return "\(real)"
        case (0, _):
            return "\(imaginary)i"
        case (_, let b) where b < 0:
            return "\(real) - \(abs(imaginary))i"
        default:
            return "\(real) + \(imaginary)i"
        }
    }
}

// DEFINE COMPLEX NUMBERS

// DFT BASED ON CHIRP Z TRANSFORM (CZT)
public func dft(x: [Double]) -> ([Double], [Double]) {

    let m = x.count // number of samples

    var N: [Double] = Array(stride(from: Double(0), through: Double(m - 1), by: 1.0))

    N = N.map({ $0 + Double(m) })

    var NM: [Double] = Array(stride(from: Double(-(m - 1)), through: Double(m - 1), by: 1.0))

    NM = NM.map({ $0 + Double(m) })

    var M: [Double] = Array(stride(from: Double(0), through: Double(m - 1), by: 1.0))

    M = M.map({ $0 + Double(m) })

    let nfft = Int(pow(2, ceil(log2(Double(m + m - 1))))) // fft pad

    var p1: [Double] = Array(stride(from: Double(-(m - 1)), through: Double(m - 1), by: 1.0))

    p1 = (zip(p1, p1).map(*)).map({ $0 / Double(2) }) // W = WR + j*WI has to be raised to power p1

    var WR = [Double]()
    var WI = [Double]()

    for i in 0 ..< p1.count { // Use De Moivre's formula to raise to power p1
        WR.append(cos(p1[i] * 2.0 * M_PI / Double(m)))
        WI.append(sin(-p1[i] * 2.0 * M_PI / Double(m)))
    }

    var aaR = [Double]()
    var aaI = [Double]()

    for j in 0 ..< N.count {
        aaR.append(WR[Int(N[j] - 1)] * x[j])
        aaI.append(WI[Int(N[j] - 1)] * x[j])
    }

    let la = nfft - aaR.count

    let pad: [Double] = Array(repeating: 0, count: la) // 1st zero padding

    aaR += pad

    aaI += pad

    let (fgr, fgi) = fft(x: aaR, y: aaI, type: "fft") // 1st FFT

    var bbR = [Double]()
    var bbI = [Double]()

    for k in 0 ..< NM.count {
        bbR.append((WR[Int(NM[k] - 1)]) / (((WR[Int(NM[k] - 1)])) * ((WR[Int(NM[k] - 1)])) + ((WI[Int(NM[k] - 1)])) * ((WI[Int(NM[k] - 1)])))) // take reciprocal
        bbI.append(-(WI[Int(NM[k] - 1)]) / (((WR[Int(NM[k] - 1)])) * ((WR[Int(NM[k] - 1)])) + ((WI[Int(NM[k] - 1)])) * ((WI[Int(NM[k] - 1)])))) // take reciprocal
    }

    let lb = nfft - bbR.count

    let pad2: [Double] = Array(repeating: 0, count: lb) // 2nd zero padding

    bbR += pad2

    bbI += pad2

    let (fwr, fwi) = fft(x: bbR, y: bbI, type: "fft") // 2nd FFT

    let fg = zip(fgr, fgi).map { Complex<Double>(real: $0, imaginary: $1) } // complexN 1

    let fw = zip(fwr, fwi).map { Complex<Double>(real: $0, imaginary: $1) } // complexN 2

    let cc = zip(fg, fw).map { $0 * $1 } // multiply above 2 complex numbers fg * fw

    var ccR = cc.map { $0.real } // real part (vector) of complex multiply

    var ccI = cc.map { $0.imaginary } // imag part (vector) of complex multiply

    let lc = nfft - ccR.count

    let pad3: [Double] = Array(repeating: 0, count: lc) // 3rd zero padding

    ccR += pad3

    ccI += pad3

    let (ggr, ggi) = fft(x: ccR, y: ccI, type: "ifft") // 3rd FFT (IFFT)

    var GGr = [Double]()
    var GGi = [Double]()
    var W2r = [Double]()
    var W2i = [Double]()

    for v in 0 ..< M.count {
        GGr.append(ggr[Int(M[v] - 1)])
        GGi.append(ggi[Int(M[v] - 1)])
        W2r.append(WR[Int(M[v] - 1)])
        W2i.append(WI[Int(M[v] - 1)])
    }

    let ggg = zip(GGr, GGi).map { Complex<Double>(real: $0, imaginary: $1) }

    let www = zip(W2r, W2i).map { Complex<Double>(real: $0, imaginary: $1) }

    let y = zip(ggg, www).map { $0 * $1 }

    let yR = y.map { $0.real } // FFT real part (output vector)

    let yI = y.map { $0.imaginary } // FFT imag part (output vector)

    return (yR, yI)
}

// END DFT BASED ON CHIRP Z TRANSFORM (CZT)

// CHIRP DFT (CZT) TEST
let x: [Double] = [1, 2, 3, 4, 5] // arbitrary sample size
let (fftR, fftI) = dft(x: x)
print("DFT Real Part:", fftR)
print(" ")
print("DFT Imag Part:", fftI)

// Matches Matlab FFT Output
// DFT Real Part: [15.0, -2.5000000000000018, -2.5000000000000013, -2.4999999999999991, -2.499999999999996]
// DFT Imag Part: [-1.1102230246251565e-16, 3.4409548011779334, 0.81229924058226477, -0.81229924058226599, -3.4409548011779356]

// END CHIRP DFT (CZT) TEST
//FFT IOS加速框架(仅适用于2^N个样本)
进口加速
公共函数fft(x:[Double],y:[Double],类型:String)->([Double],[Double]){
var real=[双精度](x)
虚变量=[双精度](y)
var splitComplex=DSPDoubleSplitComplex(realp:&real,imagp:&virtual)
let length=vDSP_length(floor(Float(real.count)))
设基数=FFTRadix(kFFTRadix2)
让权重=vDSP_create_fft设置(长度,基数)
开关类型。小写(){
case(“fft”)://case fft
vDSP_fft_zipD(权重!,&分割复数,1,长度,fft方向(fft_前向))
vDSP_销毁_FFT安装(重量)
case(“ifft”)://case INVERSE FFT
vDSP_fft_zipD(权重!,&拆分复数,1,长度,fft方向(fft_逆))
vDSP_销毁_FFT安装(重量)
real=real.map({$0/Double(x.count)})//通过样本计数规范化IFFT
Imaginate=Imaginate.map({$0/Double(x.count)})//通过样本计数规范化IFFT
默认值://默认情况(FFT)
vDSP_fft_zipD(权重!,&分割复数,1,长度,fft方向(fft_前向))
vDSP_销毁_FFT安装(重量)
}
返回(真实的、想象的)
}
//结束FFT IOS加速框架(仅适用于2^N个样本)
//定义复数
结构复合体{
让现实:T
让我们想象一下:T
静态函数+(左:复杂,右:复杂)->复杂{
返回复数(实:左S.实+右S.实,虚:左S.虚+右S.虚)
}
静态函数-(左:复杂,右:复杂)->复杂{
返回复数(实:lhs.real-rhs.real,虚:lhs.virtual-rhs.virtual)
}
静态函数*(左:复杂,右:复杂)->复杂{
返回复数(实:lhs.real*rhs.real-lhs.virginal*rhs.virginal,
想象的:左。想象的*右。真实的+左。真实的*右。想象的)
}
}
扩展复合体:CustomStringConvertible{
变量说明:字符串{
开关(实、虚){
案例(0):
返回“\(真实)”
案例(0,u):
返回“\(想象的)i”
情形(u,设b),其中b<0:
返回“\(实)-(abs(虚))i”
违约:
返回“\(实)+\(虚)i”
}
}
}
//定义复数
//基于线性调频Z变换(CZT)的DFT
公共函数dft(x:[Double])->([Double],[Double]){
设m=x.count//样本数
var N:[Double]=数组(步长(从:Double(0),到:Double(m-1),由:1.0))
N=N.map({$0+Double(m)})
var NM:[Double]=数组(步长(从:Double(-(m-1)),到:Double(m-1),由:1.0)
NM=NM.map({$0+Double(m)})
var M:[Double]=数组(步长(从:Double(0),到:Double(M-1),by:1.0))
M=M.map({$0+Double(M)})
设nfft=Int(pow(2,ceil)(log2(Double(m+m-1 '))//fft-pad
变量p1:[Double]=数组(步长(从:Double(-(m-1)),到:Double(m-1),由:1.0)
p1=(zip(p1,p1).map(*).map({$0/Double(2)})//W=WR+j*WI必须提升到p1的幂
var WR=[Double]()
变量WI=[Double]()
对于0..