首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在SWIFT中使用C++ FFT码

在SWIFT中使用C++ FFT码
EN

Stack Overflow用户
提问于 2017-10-24 07:45:35
回答 1查看 849关注 0票数 0

我有C++ FFT代码(粘贴在下面)。

在C++中,当我输入main(),RL_Input = {1,2,-3,4},IM_Input = { -4,3,2,1}时,得到的答案是RL_Output = {4,6,-8,2},IM_Output = {2,-4,-6,-8}。

我想从SWIFT调用这个C++代码。所以,在SWIFT中,我想做一些如下的事情:

代码语言:javascript
复制
   let (RL_Output, IM_Output) = Some_Swift_Function([1,2,-3,4], [-4,3,2,1]) // INPUT RL & IM
   print(RL_Output)
   print(IM_Output)

   // RL_Output = [4, 6, -8, 2]  //Answer (REAL)
   // IM_Output = [2, -4, -6, -8] //Answer (IMAG)

如何使用我所拥有的C++代码(下面给出)来完成上面的工作?

代码语言:javascript
复制
    //FftRealPairTest.cpp
    #include <algorithm>
    #include <cmath>
    #include <cstdlib>
    #include <iomanip>
    #include <iostream>
    #include <random>
    #include <vector>
    #include "FftRealPair.hpp"

    using std::cout;
    using std::endl;
    using std::vector;

    int main() {
        vector<double> inputreal({1,2,-3,4});

        vector<double> inputimag({-4,3,2,1});

        vector<double> actualoutreal(inputreal);

        vector<double> actualoutimag(inputimag);

        Fft::transform(actualoutreal, actualoutimag);

        std::cout << "REAL:" << std::endl;
        for (int i = 0; i < inputimag.size(); ++i)
        {
            std::cout << actualoutreal[i] << std::endl;
        }


        std::cout << "IMAG" << std::endl;
        for (int i = 0; i < inputimag.size(); ++i)
        {
            std::cout << actualoutimag[i] << std::endl;
        }
        
    }


    /////////////////////////////////////////////////

    //FftRealPair.cpp
    /*
     * Free FFT and convolution (C++)
     *
     * Copyright (c) 2017 Project Nayuki. (MIT License)
     * https://www.nayuki.io/page/free-small-fft-in-multiple-languages
     *
     * Permission is hereby granted, free of charge, to any person obtaining a copy of
     * this software and associated documentation files (the "Software"), to deal in
     * the Software without restriction, including without limitation the rights to
     * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
     * the Software, and to permit persons to whom the Software is furnished to do so,
     * subject to the following conditions:
     * - The above copyright notice and this permission notice shall be included in
     *   all copies or substantial portions of the Software.
     * - The Software is provided "as is", without warranty of any kind, express or
     *   implied, including but not limited to the warranties of merchantability,
     *   fitness for a particular purpose and noninfringement. In no event shall the
     *   authors or copyright holders be liable for any claim, damages or other
     *   liability, whether in an action of contract, tort or otherwise, arising from,
     *   out of or in connection with the Software or the use or other dealings in the
     *   Software.
     */

    #include <algorithm>
    #include <cmath>
    #include <cstddef>
    #include <cstdint>
    #include "FftRealPair.hpp"

    using std::size_t;
    using std::vector;


    // Private function prototypes
    static size_t reverseBits(size_t x, int n);


    void Fft::transform(vector<double> &real, vector<double> &imag) {
        size_t n = real.size();
        if (n != imag.size())
            throw "Mismatched lengths";
        if (n == 0)
            return;
        else if ((n & (n - 1)) == 0)  // Is power of 2
            transformRadix2(real, imag);
        else  // More complicated algorithm for arbitrary sizes
            transformBluestein(real, imag);
    }


    void Fft::inverseTransform(vector<double> &real, vector<double> &imag) {
        transform(imag, real);
    }


    void Fft::transformRadix2(vector<double> &real, vector<double> &imag) {
        // Length variables
        size_t n = real.size();
        if (n != imag.size())
            throw "Mismatched lengths";
        int levels = 0;  // Compute levels = floor(log2(n))
        for (size_t temp = n; temp > 1U; temp >>= 1)
            levels++;
        if (static_cast<size_t>(1U) << levels != n)
            throw "Length is not a power of 2";

        // Trignometric tables
        vector<double> cosTable(n / 2);
        vector<double> sinTable(n / 2);
        for (size_t i = 0; i < n / 2; i++) {
            cosTable[i] = std::cos(2 * M_PI * i / n);
            sinTable[i] = std::sin(2 * M_PI * i / n);
        }

        // Bit-reversed addressing permutation
        for (size_t i = 0; i < n; i++) {
            size_t j = reverseBits(i, levels);
            if (j > i) {
                std::swap(real[i], real[j]);
                std::swap(imag[i], imag[j]);
            }
        }

        // Cooley-Tukey decimation-in-time radix-2 FFT
        for (size_t size = 2; size <= n; size *= 2) {
            size_t halfsize = size / 2;
            size_t tablestep = n / size;
            for (size_t i = 0; i < n; i += size) {
                for (size_t j = i, k = 0; j < i + halfsize; j++, k += tablestep) {
                    size_t l = j + halfsize;
                    double tpre =  real[l] * cosTable[k] + imag[l] * sinTable[k];
                    double tpim = -real[l] * sinTable[k] + imag[l] * cosTable[k];
                    real[l] = real[j] - tpre;
                    imag[l] = imag[j] - tpim;
                    real[j] += tpre;
                    imag[j] += tpim;
                }
            }
            if (size == n)  // Prevent overflow in 'size *= 2'
                break;
        }
    }


    void Fft::transformBluestein(vector<double> &real, vector<double> &imag) {
        // Find a power-of-2 convolution length m such that m >= n * 2 + 1
        size_t n = real.size();
        if (n != imag.size())
            throw "Mismatched lengths";
        size_t m = 1;
        while (m / 2 <= n) {
            if (m > SIZE_MAX / 2)
                throw "Vector too large";
            m *= 2;
        }

        // Trignometric tables
        vector<double> cosTable(n), sinTable(n);
        for (size_t i = 0; i < n; i++) {
            unsigned long long temp = static_cast<unsigned long long>(i) * i;
            temp %= static_cast<unsigned long long>(n) * 2;
            double angle = M_PI * temp / n;
            // Less accurate alternative if long long is unavailable: double angle = M_PI * i * i / n;
            cosTable[i] = std::cos(angle);
            sinTable[i] = std::sin(angle);
        }

        // Temporary vectors and preprocessing
        vector<double> areal(m), aimag(m);
        for (size_t i = 0; i < n; i++) {
            areal[i] =  real[i] * cosTable[i] + imag[i] * sinTable[i];
            aimag[i] = -real[i] * sinTable[i] + imag[i] * cosTable[i];
        }
        vector<double> breal(m), bimag(m);
        breal[0] = cosTable[0];
        bimag[0] = sinTable[0];
        for (size_t i = 1; i < n; i++) {
            breal[i] = breal[m - i] = cosTable[i];
            bimag[i] = bimag[m - i] = sinTable[i];
        }

        // Convolution
        vector<double> creal(m), cimag(m);
        convolve(areal, aimag, breal, bimag, creal, cimag);

        // Postprocessing
        for (size_t i = 0; i < n; i++) {
            real[i] =  creal[i] * cosTable[i] + cimag[i] * sinTable[i];
            imag[i] = -creal[i] * sinTable[i] + cimag[i] * cosTable[i];
        }
    }


    void Fft::convolve(const vector<double> &x, const vector<double> &y, vector<double> &out) {
        size_t n = x.size();
        if (n != y.size() || n != out.size())
            throw "Mismatched lengths";
        vector<double> outimag(n);
        convolve(x, vector<double>(n), y, vector<double>(n), out, outimag);
    }


    void Fft::convolve(
                       const vector<double> &xreal, const vector<double> &ximag,
                       const vector<double> &yreal, const vector<double> &yimag,
                       vector<double> &outreal, vector<double> &outimag) {

        size_t n = xreal.size();
        if (n != ximag.size() || n != yreal.size() || n != yimag.size()
            || n != outreal.size() || n != outimag.size())
            throw "Mismatched lengths";

        vector<double> xr(xreal);
        vector<double> xi(ximag);
        vector<double> yr(yreal);
        vector<double> yi(yimag);
        transform(xr, xi);
        transform(yr, yi);
        
        for (size_t i = 0; i < n; i++) {
            double temp = xr[i] * yr[i] - xi[i] * yi[i];
            xi[i] = xi[i] * yr[i] + xr[i] * yi[i];
            xr[i] = temp;
        }
        inverseTransform(xr, xi);
        
        for (size_t i = 0; i < n; i++) {  // Scaling (because this FFT implementation omits it)
            outreal[i] = xr[i] / n;
            outimag[i] = xi[i] / n;
        }
    }


    static size_t reverseBits(size_t x, int n) {
        size_t result = 0;
        for (int i = 0; i < n; i++, x >>= 1)
            result = (result << 1) | (x & 1U);
        return result;
    }



    ////////////////////////////////////////////////////


    //FftRealPair.hpp

    /*
     * Free FFT and convolution (C++)
     *
     * Copyright (c) 2017 Project Nayuki. (MIT License)
     * https://www.nayuki.io/page/free-small-fft-in-multiple-languages
     *
     * Permission is hereby granted, free of charge, to any person obtaining a copy of
     * this software and associated documentation files (the "Software"), to deal in
     * the Software without restriction, including without limitation the rights to
     * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
     * the Software, and to permit persons to whom the Software is furnished to do so,
     * subject to the following conditions:
     * - The above copyright notice and this permission notice shall be included in
     *   all copies or substantial portions of the Software.
     * - The Software is provided "as is", without warranty of any kind, express or
     *   implied, including but not limited to the warranties of merchantability,
     *   fitness for a particular purpose and noninfringement. In no event shall the
     *   authors or copyright holders be liable for any claim, damages or other
     *   liability, whether in an action of contract, tort or otherwise, arising from,
     *   out of or in connection with the Software or the use or other dealings in the
     *   Software.
     */

    #pragma once

    #include <vector>


    namespace Fft {

        /*
         * Computes the discrete Fourier transform (DFT) of the given complex vector, storing the result back into the vector.
         * The vector can have any length. This is a wrapper function.
         */
        void transform(std::vector<double> &real, std::vector<double> &imag);


        /*
         * Computes the inverse discrete Fourier transform (IDFT) of the given complex vector, storing the result back into the vector.
         * The vector can have any length. This is a wrapper function. This transform does not perform scaling, so the inverse is not a true inverse.
         */
        void inverseTransform(std::vector<double> &real, std::vector<double> &imag);





        /*
         * Computes the discrete Fourier transform (DFT) of the given complex vector, storing the result back into the vector.
         * The vector's length must be a power of 2. Uses the Cooley-Tukey decimation-in-time radix-2 algorithm.
         */
        void transformRadix2(std::vector<double> &real, std::vector<double> &imag);


        /*
         * Computes the discrete Fourier transform (DFT) of the given complex vector, storing the result back into the vector.
         * The vector can have any length. This requires the convolution function, which in turn requires the radix-2 FFT function.
         * Uses Bluestein's chirp z-transform algorithm.
         */
        void transformBluestein(std::vector<double> &real, std::vector<double> &imag);


        /*
         * Computes the circular convolution of the given real vectors. Each vector's length must be the same.
         */
        void convolve(const std::vector<double> &x, const std::vector<double> &y, std::vector<double> &out);


        /*
         * Computes the circular convolution of the given complex vectors. Each vector's length must be the same.
         */
        void convolve(
                      const std::vector<double> &xreal, const std::vector<double> &ximag,
                      const std::vector<double> &yreal, const std::vector<double> &yimag,
                      std::vector<double> &outreal, std::vector<double> &outimag);
        
    }
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-10-25 00:24:00

如果您想从Swift调用该C++代码,则需要通过Objective++进行桥接。在这里简单的搜索就会发现很多关于如何做到这一点的帖子。

在这种情况下,我们希望尽量减少数据的复制,因为我们将C++/Objective++/Swift粘合在一起,以减少对性能的负面影响。Swift中的Array of Doubles将其数据存储在连续存储中,因为Double不是一个类。withUnsafeMutableBufferPointer方法Array似乎是解决方案的一个很有前途的选择。不过,我会非常小心,首先在一个简单的测试程序上测试这种方法。如果时间允许的话,我会在几天内想出办法的。

请参阅Arrayhttps://developer.apple.com/documentation/swift/array上的文档。另一个非常有用的资源是ref/doc/uid/TP40014216-CH2-ID0,您可能已经看到它搜索过这个主题。

通常需要注意的一点是,如果调整向量大小,C++中的C++存储可以重新定位到内存中,例如,在这种情况下,当从Swift连接到C++时,我们必须额外复制数据。然而,这段C++代码似乎没有做任何会移动底层存储的事情。

更新10/25/2017:使用withUnsafeMutableBufferPointer将需要在内存中复制数组,因为创建一个直接使用给定缓冲区的vector是有问题的。见How to cheaply assign C-style array to std::vector?

但是,由于有一个C版本的库,这就成了小菜一碟:

  • fft.hfft.c添加到Xcode项目中。
  • 在桥接头中导入fft.h

然后您可以在Swift中使用C代码,如下所示:

代码语言:javascript
复制
var dReal : [Double] = [1,2,-3,4]
var dImg : [Double] = [-4,3,2,1]

dReal.withUnsafeMutableBufferPointer { (real : inout UnsafeMutableBufferPointer<Double> ) in
    dImg.withUnsafeMutableBufferPointer { (img : inout UnsafeMutableBufferPointer<Double>) in
        if (real.count == img.count) {
            Fft_transform(real.baseAddress, img.baseAddress, real.count)
        }
    }
}

当然,这只是一个简单的例子。您可以使它更时尚,添加错误处理等。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/46904905

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档