static void obackward(int length, void * setup, float * H, float * scratch) {pffft_transform_ordered(setup, H, H, scratch, PFFFT_BACKWARD);(void)length;}
static void oforward (int length, void * setup, float * h, float * scratch) {pffft_transform_ordered(setup, h, h, scratch, PFFFT_FORWARD); (void)length;}
void TimeOnePfRFFT(int count, int fft_log_size, float signal_value, int signal_type) { struct AlignedPtr* x_aligned; struct AlignedPtr* y_aligned; struct AlignedPtr* z_aligned; struct AlignedPtr* y_tmp_aligned; float* x; struct ComplexFloat* y; OMX_F32* z; float* y_true; float* y_tmp; int n; int fft_size; struct timeval start_time; struct timeval end_time; double elapsed_time; PFFFT_Setup *s; struct SnrResult snr_forward; struct SnrResult snr_inverse; fft_size = 1 << fft_log_size; x_aligned = AllocAlignedPointer(32, sizeof(*x) * fft_size); y_aligned = AllocAlignedPointer(32, sizeof(*y) * (fft_size + 2)); z_aligned = AllocAlignedPointer(32, sizeof(*z) * fft_size); y_tmp_aligned = AllocAlignedPointer(32, sizeof(*y_tmp) * (fft_size + 2)); y_true = (float*) malloc(sizeof(*y_true) * 2 * fft_size); x = x_aligned->aligned_pointer_; y = y_aligned->aligned_pointer_; z = z_aligned->aligned_pointer_; y_tmp = y_tmp_aligned->aligned_pointer_; s = pffft_new_setup(fft_size, PFFFT_REAL); if (!s) { fprintf(stderr, "TimeOnePfRFFT: Could not initialize structure for order %d\n", fft_log_size); } GenerateRealFloatSignal(x, (struct ComplexFloat*) y_true, fft_size, signal_type, signal_value); if (do_forward_test) { GetUserTime(&start_time); for (n = 0; n < count; ++n) { pffft_transform_ordered(s, (float*)x, (float*)y, NULL, PFFFT_FORWARD); } GetUserTime(&end_time); elapsed_time = TimeDifference(&start_time, &end_time); /* * Arrange the output of the FFT to match the expected output. */ y[fft_size / 2].Re = y[0].Im; y[fft_size / 2].Im = 0; y[0].Im = 0; CompareComplexFloat(&snr_forward, (OMX_FC32*) y, (OMX_FC32*) y_true, fft_size / 2 + 1); PrintResult("Forward PFFFT RFFT", fft_log_size, elapsed_time, count, snr_forward.complex_snr_); if (verbose >= 255) { printf("FFT Actual:\n"); DumpArrayComplexFloat("y", fft_size / 2 + 1, (OMX_FC32*) y); printf("FFT Expected:\n"); DumpArrayComplexFloat("true", fft_size / 2 + 1, (OMX_FC32*) y_true); } } if (do_inverse_test) { float scale = 1.0 / fft_size; /* Copy y_true to true, but arrange the values according to what rdft wants. */ memcpy(y_tmp, y_true, sizeof(y_tmp[0]) * fft_size); y_tmp[1] = y_true[fft_size / 2]; GetUserTime(&start_time); for (n = 0; n < count; ++n) { int m; pffft_transform_ordered(s, (float*)y_tmp, (float*)z, NULL, PFFFT_BACKWARD); /* * Need to include cost of scaling the inverse */ ScaleVector(z, fft_size, fft_size); } GetUserTime(&end_time); elapsed_time = TimeDifference(&start_time, &end_time); CompareFloat(&snr_inverse, (OMX_F32*) z, (OMX_F32*) x, fft_size); PrintResult("Inverse PFFFT RFFT", fft_log_size, elapsed_time, count, snr_inverse.complex_snr_); if (verbose >= 255) { printf("IFFT Actual:\n"); DumpArrayFloat("z", fft_size, z); printf("IFFT Expected:\n"); DumpArrayFloat("x", fft_size, x); } } FreeAlignedPointer(x_aligned); FreeAlignedPointer(y_aligned); FreeAlignedPointer(z_aligned); FreeAlignedPointer(y_tmp_aligned); pffft_destroy_setup(s); free(y_true); }
void TimeOnePfFFT(int count, int fft_log_size, float signal_value, int signal_type) { struct AlignedPtr* x_aligned; struct AlignedPtr* y_aligned; struct AlignedPtr* z_aligned; struct AlignedPtr* y_true_aligned; struct ComplexFloat* x; struct ComplexFloat* y; OMX_FC32* z; struct ComplexFloat* y_true; int n; int fft_size; struct timeval start_time; struct timeval end_time; double elapsed_time; PFFFT_Setup *s; struct SnrResult snr_forward; struct SnrResult snr_inverse; fft_size = 1 << fft_log_size; x_aligned = AllocAlignedPointer(32, sizeof(*x) * fft_size); y_aligned = AllocAlignedPointer(32, sizeof(*y) * (fft_size + 2)); z_aligned = AllocAlignedPointer(32, sizeof(*z) * fft_size); y_true_aligned = AllocAlignedPointer(32, sizeof(*y_true) * fft_size); x = x_aligned->aligned_pointer_; y = y_aligned->aligned_pointer_; z = z_aligned->aligned_pointer_; y_true = y_true_aligned->aligned_pointer_; s = pffft_new_setup(fft_size, PFFFT_COMPLEX); if (!s) { fprintf(stderr, "TimeOnePfFFT: Could not initialize structure for order %d\n", fft_log_size); } GenerateTestSignalAndFFT(x, y_true, fft_size, signal_type, signal_value, 0); if (do_forward_test) { GetUserTime(&start_time); for (n = 0; n < count; ++n) { pffft_transform_ordered(s, (float*)x, (float*)y, NULL, PFFFT_FORWARD); } GetUserTime(&end_time); elapsed_time = TimeDifference(&start_time, &end_time); CompareComplexFloat(&snr_forward, (OMX_FC32*) y, (OMX_FC32*) y_true, fft_size); PrintResult("Forward PFFFT FFT", fft_log_size, elapsed_time, count, snr_forward.complex_snr_); if (verbose >= 255) { printf("FFT Actual:\n"); DumpArrayComplexFloat("y", fft_size, (OMX_FC32*) y); printf("FFT Expected:\n"); DumpArrayComplexFloat("true", fft_size, (OMX_FC32*) y_true); } } if (do_inverse_test) { float scale = 1.0 / fft_size; memcpy(y, y_true, sizeof(*y) * (fft_size + 2)); GetUserTime(&start_time); for (n = 0; n < count; ++n) { int m; pffft_transform_ordered(s, (float*)y_true, (float*)z, NULL, PFFFT_BACKWARD); /* * Need to include cost of scaling the inverse */ ScaleVector((OMX_F32*) z, 2 * fft_size, fft_size); } GetUserTime(&end_time); elapsed_time = TimeDifference(&start_time, &end_time); CompareComplexFloat(&snr_inverse, (OMX_FC32*) z, (OMX_FC32*) x, fft_size); PrintResult("Inverse PFFFT FFT", fft_log_size, elapsed_time, count, snr_inverse.complex_snr_); if (verbose >= 255) { printf("IFFT Actual:\n"); DumpArrayComplexFloat("z", fft_size, z); printf("IFFT Expected:\n"); DumpArrayComplexFloat("x", fft_size, (OMX_FC32*) x); } } FreeAlignedPointer(x_aligned); FreeAlignedPointer(y_aligned); FreeAlignedPointer(z_aligned); FreeAlignedPointer(y_true_aligned); pffft_destroy_setup(s); }
/* compare results with the regular fftpack */ void pffft_validate_N(int N, int cplx) { int Nfloat = N*(cplx?2:1); int Nbytes = Nfloat * sizeof(float); float *ref, *in, *out, *tmp, *tmp2; PFFFT_Setup *s = pffft_new_setup(N, cplx ? PFFFT_COMPLEX : PFFFT_REAL); int pass; if (!s) { printf("Skipping N=%d, not supported\n", N); return; } ref = pffft_aligned_malloc(Nbytes); in = pffft_aligned_malloc(Nbytes); out = pffft_aligned_malloc(Nbytes); tmp = pffft_aligned_malloc(Nbytes); tmp2 = pffft_aligned_malloc(Nbytes); for (pass=0; pass < 2; ++pass) { float ref_max = 0; int k; //printf("N=%d pass=%d cplx=%d\n", N, pass, cplx); // compute reference solution with FFTPACK if (pass == 0) { float *wrk = malloc(2*Nbytes+15*sizeof(float)); for (k=0; k < Nfloat; ++k) { ref[k] = in[k] = frand()*2-1; out[k] = 1e30; } if (!cplx) { rffti(N, wrk); rfftf(N, ref, wrk); // use our ordering for real ffts instead of the one of fftpack { float refN=ref[N-1]; for (k=N-2; k >= 1; --k) ref[k+1] = ref[k]; ref[1] = refN; } } else { cffti(N, wrk); cfftf(N, ref, wrk); } free(wrk); } for (k = 0; k < Nfloat; ++k) ref_max = MAX(ref_max, fabs(ref[k])); // pass 0 : non canonical ordering of transform coefficients if (pass == 0) { // test forward transform, with different input / output pffft_transform(s, in, tmp, 0, PFFFT_FORWARD); memcpy(tmp2, tmp, Nbytes); memcpy(tmp, in, Nbytes); pffft_transform(s, tmp, tmp, 0, PFFFT_FORWARD); for (k = 0; k < Nfloat; ++k) { assert(tmp2[k] == tmp[k]); } // test reordering pffft_zreorder(s, tmp, out, PFFFT_FORWARD); pffft_zreorder(s, out, tmp, PFFFT_BACKWARD); for (k = 0; k < Nfloat; ++k) { assert(tmp2[k] == tmp[k]); } pffft_zreorder(s, tmp, out, PFFFT_FORWARD); } else { // pass 1 : canonical ordering of transform coeffs. pffft_transform_ordered(s, in, tmp, 0, PFFFT_FORWARD); memcpy(tmp2, tmp, Nbytes); memcpy(tmp, in, Nbytes); pffft_transform_ordered(s, tmp, tmp, 0, PFFFT_FORWARD); for (k = 0; k < Nfloat; ++k) { assert(tmp2[k] == tmp[k]); } memcpy(out, tmp, Nbytes); } { for (k=0; k < Nfloat; ++k) { if (!(fabs(ref[k] - out[k]) < 1e-3*ref_max)) { printf("%s forward PFFFT mismatch found for N=%d\n", (cplx?"CPLX":"REAL"), N); exit(1); } } if (pass == 0) pffft_transform(s, tmp, out, 0, PFFFT_BACKWARD); else pffft_transform_ordered(s, tmp, out, 0, PFFFT_BACKWARD); memcpy(tmp2, out, Nbytes); memcpy(out, tmp, Nbytes); if (pass == 0) pffft_transform(s, out, out, 0, PFFFT_BACKWARD); else pffft_transform_ordered(s, out, out, 0, PFFFT_BACKWARD); for (k = 0; k < Nfloat; ++k) { assert(tmp2[k] == out[k]); out[k] *= 1.f/N; } for (k = 0; k < Nfloat; ++k) { if (fabs(in[k] - out[k]) > 1e-3 * ref_max) { printf("pass=%d, %s IFFFT does not match for N=%d\n", pass, (cplx?"CPLX":"REAL"), N); break; exit(1); } } } // quick test of the circular convolution in fft domain { float conv_err = 0, conv_max = 0; pffft_zreorder(s, ref, tmp, PFFFT_FORWARD); memset(out, 0, Nbytes); pffft_zconvolve_accumulate(s, ref, ref, out, 1.0); pffft_zreorder(s, out, tmp2, PFFFT_FORWARD); for (k=0; k < Nfloat; k += 2) { float ar = tmp[k], ai=tmp[k+1]; if (cplx || k > 0) { tmp[k] = ar*ar - ai*ai; tmp[k+1] = 2*ar*ai; } else { tmp[0] = ar*ar; tmp[1] = ai*ai; } } for (k=0; k < Nfloat; ++k) { float d = fabs(tmp[k] - tmp2[k]), e = fabs(tmp[k]); if (d > conv_err) conv_err = d; if (e > conv_max) conv_max = e; } if (conv_err > 1e-5*conv_max) { printf("zconvolve error ? %g %g\n", conv_err, conv_max); exit(1); } } } printf("%s PFFFT is OK for N=%d\n", (cplx?"CPLX":"REAL"), N); fflush(stdout); pffft_destroy_setup(s); pffft_aligned_free(ref); pffft_aligned_free(in); pffft_aligned_free(out); pffft_aligned_free(tmp); pffft_aligned_free(tmp2); }