将 Matlab 的 FFT 移植到本机 Java

发布于 2024-11-30 02:28:25 字数 2113 浏览 3 评论 0原文

我想将 Matlab 的快速傅里叶变换函数 fft() 移植到本机 Java 代码。

作为起点,我使用 JMathLib 的代码,其中 FFT 的实现如下:

    // given double[] x as the input signal

    n = x.length;  // assume n is a power of 2
    nu = (int)(Math.log(n)/Math.log(2));
    int n2 = n/2;
    int nu1 = nu - 1;
    double[] xre = new double[n];
    double[] xim = new double[n];
    double[] mag = new double[n2];
    double tr, ti, p, arg, c, s;
    for (int i = 0; i < n; i++) {
        xre[i] = x[i];
        xim[i] = 0.0;
    }
    int k = 0;

    for (int l = 1; l <= nu; l++) {
        while (k < n) {
            for (int i = 1; i <= n2; i++) {
                p = bitrev (k >> nu1);
                arg = 2 * (double) Math.PI * p / n;
                c = (double) Math.cos (arg);
                s = (double) Math.sin (arg);
                tr = xre[k+n2]*c + xim[k+n2]*s;
                ti = xim[k+n2]*c - xre[k+n2]*s;
                xre[k+n2] = xre[k] - tr;
                xim[k+n2] = xim[k] - ti;
                xre[k] += tr;
                xim[k] += ti;
                k++;
            }
            k += n2;
        }
        k = 0;
        nu1--;
        n2 = n2/2;
    }
    k = 0;
    int r;
    while (k < n) {
        r = bitrev (k);
        if (r > k) {
            tr = xre[k];
            ti = xim[k];
            xre[k] = xre[r];
            xim[k] = xim[r];
            xre[r] = tr;
            xim[r] = ti;
        }
        k++;
    }
    // The result 
    // -> real part stored in xre
    // -> imaginary part stored in xim

不幸的是,它没有当我对它进行单元测试时,给我正确的结果,例如使用数组

双[] x = { 1.0d, 5.0d, 9.0d, 13.0d };

Matlab中的结果:

28.0
-8.0 - 8.0i
-8.0
-8.0 + 8.0i

我的实现结果:

28.0
-8.0 + 8.0i
-8.0
-8.0 - 8.0i

请注意复杂部分中的符号是如何错误的。

当我使用更长、更复杂的信号时,实现之间的差异也会影响数字。因此,实现差异不仅仅与某些符号“错误”有关。

我的问题:我怎样才能调整我的实现,使其“等于”Matlab 的实现? 或者:是否已经有一个库可以做到这一点?

I want to port Matlab's Fast Fourier transform function fft() to native Java code.

As a starting point I am using the code of JMathLib where the FFT is implemented as follows:

    // given double[] x as the input signal

    n = x.length;  // assume n is a power of 2
    nu = (int)(Math.log(n)/Math.log(2));
    int n2 = n/2;
    int nu1 = nu - 1;
    double[] xre = new double[n];
    double[] xim = new double[n];
    double[] mag = new double[n2];
    double tr, ti, p, arg, c, s;
    for (int i = 0; i < n; i++) {
        xre[i] = x[i];
        xim[i] = 0.0;
    }
    int k = 0;

    for (int l = 1; l <= nu; l++) {
        while (k < n) {
            for (int i = 1; i <= n2; i++) {
                p = bitrev (k >> nu1);
                arg = 2 * (double) Math.PI * p / n;
                c = (double) Math.cos (arg);
                s = (double) Math.sin (arg);
                tr = xre[k+n2]*c + xim[k+n2]*s;
                ti = xim[k+n2]*c - xre[k+n2]*s;
                xre[k+n2] = xre[k] - tr;
                xim[k+n2] = xim[k] - ti;
                xre[k] += tr;
                xim[k] += ti;
                k++;
            }
            k += n2;
        }
        k = 0;
        nu1--;
        n2 = n2/2;
    }
    k = 0;
    int r;
    while (k < n) {
        r = bitrev (k);
        if (r > k) {
            tr = xre[k];
            ti = xim[k];
            xre[k] = xre[r];
            xim[k] = xim[r];
            xre[r] = tr;
            xim[r] = ti;
        }
        k++;
    }
    // The result 
    // -> real part stored in xre
    // -> imaginary part stored in xim

Unfortunately it doesn't give me the right results when I unit test it, for example with the array

double[] x = { 1.0d, 5.0d, 9.0d, 13.0d };

the result in Matlab:

28.0
-8.0 - 8.0i
-8.0
-8.0 + 8.0i

the result in my implementation:

28.0
-8.0 + 8.0i
-8.0
-8.0 - 8.0i

Note how the signs are wrong in the complex part.

When I use longer, more complex signals the differences between the implementations affects also the numbers. So the implementation differences does not only relate to some sign-"error".

My question: how can I adapt my implemenation to make it "equal" to the Matlab one?
Or: is there already a library that does exactly this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

演出会有结束 2024-12-07 02:28:25

为了在矩阵上使用 Jtransforms 进行 FFT,您需要逐列进行 fft col,然后将它们连接到矩阵中。这是我的代码,我将其与 Matlab fft 进行比较,

double [][] newRes = new double[samplesPerWindow*2][Matrixres.numberOfSegments];
double [] colForFFT = new double [samplesPerWindow*2];
DoubleFFT_1D fft = new DoubleFFT_1D(samplesPerWindow);

for(int y = 0; y < Matrixres.numberOfSegments; y++)
{
    //copy the original col into a col and and a col of zeros before FFT
    for(int x = 0; x < samplesPerWindow; x++)
    {
        colForFFT[x] = Matrixres.res[x][y];        
    }

    //fft on each col of the matrix
    fft.realForwardFull(colForFFT);                                                     //Y=fft(y,nfft);

    //copy the output of col*2 size into a new matrix 
    for(int x = 0; x < samplesPerWindow*2; x++)
    {
        newRes[x][y] = colForFFT[x];    
    }

}

希望这是您正在寻找的。请注意,Jtransforms 将复数表示为

array[2*k] = Re[k], array[2*k+1] = Im[k]

in order to use Jtransforms for FFT on matrix you need to do fft col by col and then join them into a matrix. here is my code which i compared with Matlab fft

double [][] newRes = new double[samplesPerWindow*2][Matrixres.numberOfSegments];
double [] colForFFT = new double [samplesPerWindow*2];
DoubleFFT_1D fft = new DoubleFFT_1D(samplesPerWindow);

for(int y = 0; y < Matrixres.numberOfSegments; y++)
{
    //copy the original col into a col and and a col of zeros before FFT
    for(int x = 0; x < samplesPerWindow; x++)
    {
        colForFFT[x] = Matrixres.res[x][y];        
    }

    //fft on each col of the matrix
    fft.realForwardFull(colForFFT);                                                     //Y=fft(y,nfft);

    //copy the output of col*2 size into a new matrix 
    for(int x = 0; x < samplesPerWindow*2; x++)
    {
        newRes[x][y] = colForFFT[x];    
    }

}

hope this what you are looking for. note that Jtransforms represent Complex numbers as

array[2*k] = Re[k], array[2*k+1] = Im[k]
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文