// create FFT plan for regular DFT // _nfft : FFT size // _x : input array [size: _nfft x 1] // _y : output array [size: _nfft x 1] // _dir : fft direction: {LIQUID_FFT_FORWARD, LIQUID_FFT_BACKWARD} // _method : fft method FFT(plan) FFT(_create_plan_rader)(unsigned int _nfft, TC * _x, TC * _y, int _dir, int _flags) { // allocate plan and initialize all internal arrays to NULL FFT(plan) q = (FFT(plan)) malloc(sizeof(struct FFT(plan_s))); q->nfft = _nfft; q->x = _x; q->y = _y; q->flags = _flags; q->type = (_dir == LIQUID_FFT_FORWARD) ? LIQUID_FFT_FORWARD : LIQUID_FFT_BACKWARD; q->direction = (_dir == LIQUID_FFT_FORWARD) ? LIQUID_FFT_FORWARD : LIQUID_FFT_BACKWARD; q->method = LIQUID_FFT_METHOD_RADER; q->execute = FFT(_execute_rader); // allocate memory for sub-transforms q->data.rader.x_prime = (TC*)malloc((q->nfft-1)*sizeof(TC)); q->data.rader.X_prime = (TC*)malloc((q->nfft-1)*sizeof(TC)); // create sub-FFT of size nfft-1 q->data.rader.fft = FFT(_create_plan)(q->nfft-1, q->data.rader.x_prime, q->data.rader.X_prime, LIQUID_FFT_FORWARD, q->flags); // create sub-IFFT of size nfft-1 q->data.rader.ifft = FFT(_create_plan)(q->nfft-1, q->data.rader.X_prime, q->data.rader.x_prime, LIQUID_FFT_BACKWARD, q->flags); // compute primitive root of nfft unsigned int g = liquid_primitive_root_prime(q->nfft); // create and initialize sequence q->data.rader.seq = (unsigned int *)malloc((q->nfft-1)*sizeof(unsigned int)); unsigned int i; for (i=0; i<q->nfft-1; i++) q->data.rader.seq[i] = liquid_modpow(g, i+1, q->nfft); // compute DFT of sequence { exp(-j*2*pi*g^i/nfft }, size: nfft-1 // NOTE: R[0] = -1, |R[k]| = sqrt(nfft) for k != 0 // (use newly-created FFT plan of length nfft-1) T d = (q->direction == LIQUID_FFT_FORWARD) ? -1.0 : 1.0; for (i=0; i<q->nfft-1; i++) q->data.rader.x_prime[i] = cexpf(_Complex_I*d*2*M_PI*q->data.rader.seq[i]/(T)(q->nfft)); FFT(_execute)(q->data.rader.fft); // copy result to R q->data.rader.R = (TC*)malloc((q->nfft-1)*sizeof(TC)); memmove(q->data.rader.R, q->data.rader.X_prime, (q->nfft-1)*sizeof(TC)); // return main object return q; }
// create FFT plan // _nfft : FFT size // _x : input array [size: _nfft x 1] // _y : output array [size: _nfft x 1] // _dir : fft direction: {LIQUID_FFT_FORWARD, LIQUID_FFT_BACKWARD} // _method : fft method FFT(plan) FFT(_create_plan_rader2)(unsigned int _nfft, TC * _x, TC * _y, int _dir, int _flags) { // allocate plan and initialize all internal arrays to NULL FFT(plan) q = (FFT(plan)) malloc(sizeof(struct FFT(plan_s))); q->nfft = _nfft; q->x = _x; q->y = _y; q->flags = _flags; q->type = (_dir == LIQUID_FFT_FORWARD) ? LIQUID_FFT_FORWARD : LIQUID_FFT_BACKWARD; q->direction = (_dir == LIQUID_FFT_FORWARD) ? LIQUID_FFT_FORWARD : LIQUID_FFT_BACKWARD; q->method = LIQUID_FFT_METHOD_RADER2; q->execute = FFT(_execute_rader2); unsigned int i; // compute primitive root of nfft unsigned int g = liquid_primitive_root_prime(q->nfft); // create and initialize sequence q->data.rader2.seq = (unsigned int *)malloc((q->nfft-1)*sizeof(unsigned int)); for (i=0; i<q->nfft-1; i++) q->data.rader2.seq[i] = liquid_modpow(g, i+1, q->nfft); #if 0 // compute larger FFT length greater than 2*nfft-4 // NOTE: while any length greater than 2*nfft-4 will work, use // nfft_prime as smallest 'simple' FFT (mostly small factors) // // TODO: devise better score (fewer factors is better) // score(n) = n / sum(factors(n).^2) float gamma_max = 0.0f; // score unsigned int nfft_prime_opt = 0; unsigned int num_steps = 10;// + q->nfft; for (i=1; i<=num_steps; i++) { unsigned int n_hat = 2*q->nfft - 4 + i; // compute factors unsigned int k; unsigned int num_factors = 0; unsigned int m = n_hat; float gamma = 0.0f; do { for (k=2; k<=m; k++) { if ( (m % k) == 0) { m /= k; num_factors++; gamma += k*k; break; } } } while (m > 1); // compute score: //float gamma = (float)n_hat / (float)num_factors; //float gamma = 1e3f * (float)num_factors / (float)n_hat; gamma = (float)n_hat / gamma; if (gamma > gamma_max) { gamma_max = gamma; nfft_prime_opt = n_hat; } } q->data.rader2.nfft_prime = nfft_prime_opt; #else // compute larger FFT length greater than 2*nfft-4 // NOTE: while any length greater than 2*nfft-4 will work, use // nfft_prime = 2 ^ nextpow2( 2*nfft - 4 ) to enable // radix-2 transform unsigned int m=0; q->data.rader2.nfft_prime = (2*q->nfft-4)-1; while (q->data.rader2.nfft_prime > 0) { q->data.rader2.nfft_prime >>= 1; m++; } q->data.rader2.nfft_prime = 1 << m; #endif //printf("nfft_prime = %u\n", q->data.rader2.nfft_prime); // assert(nfft_prime > 2*nfft-4) // allocate memory for sub-transforms q->data.rader2.x_prime = (TC*)malloc((q->data.rader2.nfft_prime)*sizeof(TC)); q->data.rader2.X_prime = (TC*)malloc((q->data.rader2.nfft_prime)*sizeof(TC)); // create sub-FFT of size nfft-1 q->data.rader2.fft = FFT(_create_plan)(q->data.rader2.nfft_prime, q->data.rader2.x_prime, q->data.rader2.X_prime, LIQUID_FFT_FORWARD, q->flags); // create sub-IFFT of size nfft-1 q->data.rader2.ifft = FFT(_create_plan)(q->data.rader2.nfft_prime, q->data.rader2.X_prime, q->data.rader2.x_prime, LIQUID_FFT_BACKWARD, q->flags); // compute DFT of sequence { exp(-j*2*pi*g^i/nfft }, size: nfft_prime // NOTE: R[0] = -1, |R[k]| = sqrt(nfft) for k != 0 // (use newly-created FFT plan of length nfft_prime) T d = (q->direction == LIQUID_FFT_FORWARD) ? -1.0 : 1.0; for (i=0; i<q->data.rader2.nfft_prime; i++) q->data.rader2.x_prime[i] = cexpf(_Complex_I*d*2*M_PI*q->data.rader2.seq[i%(q->nfft-1)]/(T)(q->nfft)); FFT(_execute)(q->data.rader2.fft); // copy result to R q->data.rader2.R = (TC*)malloc(q->data.rader2.nfft_prime*sizeof(TC)); memmove(q->data.rader2.R, q->data.rader2.X_prime, q->data.rader2.nfft_prime*sizeof(TC)); // return main object return q; }