Пример #1
0
/*************************************************************************
1-dimensional Fast Hartley Transform.

Algorithm has O(N*logN) complexity for any N (composite or prime).

INPUT PARAMETERS
    A   -   array[0..N-1] - real function to be transformed
    N   -   problem size
    
OUTPUT PARAMETERS
    A   -   FHT of a input array, array[0..N-1],
            A_out[k] = sum(A_in[j]*(cos(2*pi*j*k/N)+sin(2*pi*j*k/N)), j=0..N-1)


  -- ALGLIB --
     Copyright 04.06.2009 by Bochkanov Sergey
*************************************************************************/
void fhtr1d(ap::real_1d_array& a, int n)
{
    ftplan plan;
    int i;
    ap::complex_1d_array fa;

    ap::ap_error::make_assertion(n>0, "FHTR1D: incorrect N!");
    
    //
    // Special case: N=1, FHT is just identity transform.
    // After this block we assume that N is strictly greater than 1.
    //
    if( n==1 )
    {
        return;
    }
    
    //
    // Reduce FHt to real FFT
    //
    fftr1d(a, n, fa);
    for(i = 0; i <= n-1; i++)
    {
        a(i) = fa(i).x-fa(i).y;
    }
}
/*************************************************************************
Test
*************************************************************************/
bool testfft(bool silent)
{
    bool result;
    int n;
    int i;
    int k;
    ap::complex_1d_array a1;
    ap::complex_1d_array a2;
    ap::complex_1d_array a3;
    ap::real_1d_array r1;
    ap::real_1d_array r2;
    ap::real_1d_array buf;
    ftplan plan;
    int maxn;
    double bidierr;
    double bidirerr;
    double referr;
    double refrerr;
    double reinterr;
    double errtol;
    bool referrors;
    bool bidierrors;
    bool refrerrors;
    bool bidirerrors;
    bool reinterrors;
    bool waserrors;

    maxn = 128;
    errtol = 100*pow(double(maxn), double(3)/double(2))*ap::machineepsilon;
    bidierrors = false;
    referrors = false;
    bidirerrors = false;
    refrerrors = false;
    reinterrors = false;
    waserrors = false;
    
    //
    // Test bi-directional error: norm(x-invFFT(FFT(x)))
    //
    bidierr = 0;
    bidirerr = 0;
    for(n = 1; n <= maxn; n++)
    {
        
        //
        // Complex FFT/invFFT
        //
        a1.setlength(n);
        a2.setlength(n);
        a3.setlength(n);
        for(i = 0; i <= n-1; i++)
        {
            a1(i).x = 2*ap::randomreal()-1;
            a1(i).y = 2*ap::randomreal()-1;
            a2(i) = a1(i);
            a3(i) = a1(i);
        }
        fftc1d(a2, n);
        fftc1dinv(a2, n);
        fftc1dinv(a3, n);
        fftc1d(a3, n);
        for(i = 0; i <= n-1; i++)
        {
            bidierr = ap::maxreal(bidierr, ap::abscomplex(a1(i)-a2(i)));
            bidierr = ap::maxreal(bidierr, ap::abscomplex(a1(i)-a3(i)));
        }
        
        //
        // Real
        //
        r1.setlength(n);
        r2.setlength(n);
        for(i = 0; i <= n-1; i++)
        {
            r1(i) = 2*ap::randomreal()-1;
            r2(i) = r1(i);
        }
        fftr1d(r2, n, a1);
        ap::vmul(&r2(0), ap::vlen(0,n-1), 0);
        fftr1dinv(a1, n, r2);
        for(i = 0; i <= n-1; i++)
        {
            bidirerr = ap::maxreal(bidirerr, ap::abscomplex(r1(i)-r2(i)));
        }
    }
    bidierrors = bidierrors||bidierr>errtol;
    bidirerrors = bidirerrors||bidirerr>errtol;
    
    //
    // Test against reference O(N^2) implementation
    //
    referr = 0;
    refrerr = 0;
    for(n = 1; n <= maxn; n++)
    {
        
        //
        // Complex FFT
        //
        a1.setlength(n);
        a2.setlength(n);
        for(i = 0; i <= n-1; i++)
        {
            a1(i).x = 2*ap::randomreal()-1;
            a1(i).y = 2*ap::randomreal()-1;
            a2(i) = a1(i);
        }
        fftc1d(a1, n);
        reffftc1d(a2, n);
        for(i = 0; i <= n-1; i++)
        {
            referr = ap::maxreal(referr, ap::abscomplex(a1(i)-a2(i)));
        }
        
        //
        // Complex inverse FFT
        //
        a1.setlength(n);
        a2.setlength(n);
        for(i = 0; i <= n-1; i++)
        {
            a1(i).x = 2*ap::randomreal()-1;
            a1(i).y = 2*ap::randomreal()-1;
            a2(i) = a1(i);
        }
        fftc1dinv(a1, n);
        reffftc1dinv(a2, n);
        for(i = 0; i <= n-1; i++)
        {
            referr = ap::maxreal(referr, ap::abscomplex(a1(i)-a2(i)));
        }
        
        //
        // Real forward/inverse FFT:
        // * calculate and check forward FFT
        // * use precalculated FFT to check backward FFT
        //   fill unused parts of frequencies array with random numbers
        //   to ensure that they are not really used
        //
        r1.setlength(n);
        r2.setlength(n);
        for(i = 0; i <= n-1; i++)
        {
            r1(i) = 2*ap::randomreal()-1;
            r2(i) = r1(i);
        }
        fftr1d(r1, n, a1);
        refinternalrfft(r2, n, a2);
        for(i = 0; i <= n-1; i++)
        {
            refrerr = ap::maxreal(refrerr, ap::abscomplex(a1(i)-a2(i)));
        }
        a3.setlength(ap::ifloor(double(n)/double(2))+1);
        for(i = 0; i <= ap::ifloor(double(n)/double(2)); i++)
        {
            a3(i) = a2(i);
        }
        a3(0).y = 2*ap::randomreal()-1;
        if( n%2==0 )
        {
            a3(ap::ifloor(double(n)/double(2))).y = 2*ap::randomreal()-1;
        }
        for(i = 0; i <= n-1; i++)
        {
            r1(i) = 0;
        }
        fftr1dinv(a3, n, r1);
        for(i = 0; i <= n-1; i++)
        {
            refrerr = ap::maxreal(refrerr, fabs(r2(i)-r1(i)));
        }
    }
    referrors = referrors||referr>errtol;
    refrerrors = refrerrors||refrerr>errtol;
    
    //
    // test internal real even FFT
    //
    reinterr = 0;
    for(k = 1; k <= maxn/2; k++)
    {
        n = 2*k;
        
        //
        // Real forward FFT
        //
        r1.setlength(n);
        r2.setlength(n);
        for(i = 0; i <= n-1; i++)
        {
            r1(i) = 2*ap::randomreal()-1;
            r2(i) = r1(i);
        }
        ftbasegeneratecomplexfftplan(n/2, plan);
        buf.setlength(n);
        fftr1dinternaleven(r1, n, buf, plan);
        refinternalrfft(r2, n, a2);
        reinterr = ap::maxreal(reinterr, fabs(r1(0)-a2(0).x));
        reinterr = ap::maxreal(reinterr, fabs(r1(1)-a2(n/2).x));
        for(i = 1; i <= n/2-1; i++)
        {
            reinterr = ap::maxreal(reinterr, fabs(r1(2*i+0)-a2(i).x));
            reinterr = ap::maxreal(reinterr, fabs(r1(2*i+1)-a2(i).y));
        }
        
        //
        // Real backward FFT
        //
        r1.setlength(n);
        for(i = 0; i <= n-1; i++)
        {
            r1(i) = 2*ap::randomreal()-1;
        }
        a2.setlength(ap::ifloor(double(n)/double(2))+1);
        a2(0) = r1(0);
        for(i = 1; i <= ap::ifloor(double(n)/double(2))-1; i++)
        {
            a2(i).x = r1(2*i+0);
            a2(i).y = r1(2*i+1);
        }
        a2(ap::ifloor(double(n)/double(2))) = r1(1);
        ftbasegeneratecomplexfftplan(n/2, plan);
        buf.setlength(n);
        fftr1dinvinternaleven(r1, n, buf, plan);
        fftr1dinv(a2, n, r2);
        for(i = 0; i <= n-1; i++)
        {
            reinterr = ap::maxreal(reinterr, fabs(r1(i)-r2(i)));
        }
    }
    reinterrors = reinterrors||reinterr>errtol;
    
    //
    // end
    //
    waserrors = bidierrors||bidirerrors||referrors||refrerrors||reinterrors;
    if( !silent )
    {
        printf("TESTING FFT\n");
        printf("FINAL RESULT:                             ");
        if( waserrors )
        {
            printf("FAILED\n");
        }
        else
        {
            printf("OK\n");
        }
        printf("* BI-DIRECTIONAL COMPLEX TEST:            ");
        if( bidierrors )
        {
            printf("FAILED\n");
        }
        else
        {
            printf("OK\n");
        }
        printf("* AGAINST REFERENCE COMPLEX FFT:          ");
        if( referrors )
        {
            printf("FAILED\n");
        }
        else
        {
            printf("OK\n");
        }
        printf("* BI-DIRECTIONAL REAL TEST:               ");
        if( bidirerrors )
        {
            printf("FAILED\n");
        }
        else
        {
            printf("OK\n");
        }
        printf("* AGAINST REFERENCE REAL FFT:             ");
        if( refrerrors )
        {
            printf("FAILED\n");
        }
        else
        {
            printf("OK\n");
        }
        printf("* INTERNAL EVEN FFT:                      ");
        if( reinterrors )
        {
            printf("FAILED\n");
        }
        else
        {
            printf("OK\n");
        }
        if( waserrors )
        {
            printf("TEST FAILED\n");
        }
        else
        {
            printf("TEST PASSED\n");
        }
    }
    result = !waserrors;
    return result;
}