// create WLAN framing synchronizer object // _callback : user-defined callback function // _userdata : user-defined data structure wlanframesync wlanframesync_create(wlanframesync_callback _callback, void * _userdata) { // allocate main object memory wlanframesync q = (wlanframesync) malloc(sizeof(struct wlanframesync_s)); // set callback data q->callback = _callback; q->userdata = _userdata; // create transform object q->X = (float complex*) malloc(64*sizeof(float complex)); q->x = (float complex*) malloc(64*sizeof(float complex)); q->fft = FFT_CREATE_PLAN(64, q->x, q->X, FFT_DIR_FORWARD, FFT_METHOD); // create input buffer the length of the transform q->input_buffer = windowcf_create(80); // synchronizer objects q->nco_rx = nco_crcf_create(LIQUID_VCO); q->ms_pilot = wlan_lfsr_create(7, 0x91, 0x7f); q->mod_scheme = WLAN_MODEM_BPSK; // set initial properties q->rate = WLANFRAME_RATE_6; q->length = 100; q->seed = 0x5d; // allocate memory for encoded message q->enc_msg_len = wlan_packet_compute_enc_msg_len(q->rate, q->length); q->msg_enc = (unsigned char*) malloc(q->enc_msg_len*sizeof(unsigned char)); // allocate memory for decoded message q->dec_msg_len = 1; q->msg_dec = (unsigned char*) malloc(q->dec_msg_len*sizeof(unsigned char)); // reset object wlanframesync_reset(q); #if DEBUG_WLANFRAMESYNC // debugging structures q->debug_enabled = 0; q->agc_rx = NULL; q->debug_x = NULL; q->debug_rssi = NULL; q->debug_framesyms = NULL; #endif // return object return q; }
void FFTransformer::fillComplexSub() { auto plan = FFT_CREATE_PLAN(m_bufferSize, m_complexSub, m_complexSub, FFTW_FORWARD, FFTW_ESTIMATE); double speed = Options::getInstance()->getSignalSpeed(); double rxRate = Options::getInstance()->getBand(); for(size_t i = 0; i < m_bufferSize; i++) { double t = i / rxRate; t *= t; auto iter = *(m_complexSub + i); iter[0] = cos(M_PI * t * speed); iter[1] = sin(M_PI * t * speed); } FFT_EXECUTE(plan); for(size_t i = 0; i < m_bufferSize; i++) m_complexSub[i][1] *= -1; FFT_DESTROY_PLAN(plan); }
// create OFDM framing synchronizer object // _M : number of subcarriers, >10 typical // _cp_len : cyclic prefix length // _taper_len : taper length (OFDM symbol overlap) // _p : subcarrier allocation (null, pilot, data), [size: _M x 1] // _callback : user-defined callback function // _userdata : user-defined data pointer ofdmframesync ofdmframesync_create(unsigned int _M, unsigned int _cp_len, unsigned int _taper_len, unsigned char * _p, ofdmframesync_callback _callback, void * _userdata) { ofdmframesync q = (ofdmframesync) malloc(sizeof(struct ofdmframesync_s)); // validate input if (_M < 8) { fprintf(stderr,"warning: ofdmframesync_create(), less than 8 subcarriers\n"); } else if (_M % 2) { fprintf(stderr,"error: ofdmframesync_create(), number of subcarriers must be even\n"); exit(1); } else if (_cp_len > _M) { fprintf(stderr,"error: ofdmframesync_create(), cyclic prefix length cannot exceed number of subcarriers\n"); exit(1); } q->M = _M; q->cp_len = _cp_len; // derived values q->M2 = _M/2; // subcarrier allocation q->p = (unsigned char*) malloc((q->M)*sizeof(unsigned char)); if (_p == NULL) { ofdmframe_init_default_sctype(q->M, q->p); } else { memmove(q->p, _p, q->M*sizeof(unsigned char)); } // validate and count subcarrier allocation ofdmframe_validate_sctype(q->p, q->M, &q->M_null, &q->M_pilot, &q->M_data); if ( (q->M_pilot + q->M_data) == 0) { fprintf(stderr,"error: ofdmframesync_create(), must have at least one enabled subcarrier\n"); exit(1); } else if (q->M_data == 0) { fprintf(stderr,"error: ofdmframesync_create(), must have at least one data subcarriers\n"); exit(1); } else if (q->M_pilot < 2) { fprintf(stderr,"error: ofdmframesync_create(), must have at least two pilot subcarriers\n"); exit(1); } // create transform object q->X = (float complex*) malloc((q->M)*sizeof(float complex)); q->x = (float complex*) malloc((q->M)*sizeof(float complex)); q->fft = FFT_CREATE_PLAN(q->M, q->x, q->X, FFT_DIR_FORWARD, FFT_METHOD); // create input buffer the length of the transform q->input_buffer = windowcf_create(q->M + q->cp_len); // allocate memory for PLCP arrays q->S0 = (float complex*) malloc((q->M)*sizeof(float complex)); q->s0 = (float complex*) malloc((q->M)*sizeof(float complex)); q->S1 = (float complex*) malloc((q->M)*sizeof(float complex)); q->s1 = (float complex*) malloc((q->M)*sizeof(float complex)); ofdmframe_init_S0(q->p, q->M, q->S0, q->s0, &q->M_S0); ofdmframe_init_S1(q->p, q->M, q->S1, q->s1, &q->M_S1); // compute scaling factor q->g_data = sqrtf(q->M) / sqrtf(q->M_pilot + q->M_data); q->g_S0 = sqrtf(q->M) / sqrtf(q->M_S0); q->g_S1 = sqrtf(q->M) / sqrtf(q->M_S1); // gain q->g0 = 1.0f; q->G0 = (float complex*) malloc((q->M)*sizeof(float complex)); q->G1 = (float complex*) malloc((q->M)*sizeof(float complex)); q->G = (float complex*) malloc((q->M)*sizeof(float complex)); q->B = (float complex*) malloc((q->M)*sizeof(float complex)); q->R = (float complex*) malloc((q->M)*sizeof(float complex)); #if 1 memset(q->G0, 0x00, q->M*sizeof(float complex)); memset(q->G1, 0x00, q->M*sizeof(float complex)); memset(q->G , 0x00, q->M*sizeof(float complex)); memset(q->B, 0x00, q->M*sizeof(float complex)); #endif // timing backoff q->backoff = q->cp_len < 2 ? q->cp_len : 2; float phi = (float)(q->backoff)*2.0f*M_PI/(float)(q->M); unsigned int i; for (i=0; i<q->M; i++) q->B[i] = liquid_cexpjf(i*phi); // set callback data q->callback = _callback; q->userdata = _userdata; // // synchronizer objects // // numerically-controlled oscillator q->nco_rx = nco_crcf_create(LIQUID_NCO); // set pilot sequence q->ms_pilot = msequence_create_default(8); #if OFDMFRAMESYNC_ENABLE_SQUELCH // coarse detection q->squelch_threshold = -25.0f; q->squelch_enabled = 0; #endif // reset object ofdmframesync_reset(q); #if DEBUG_OFDMFRAMESYNC q->debug_enabled = 0; q->debug_objects_created = 0; q->debug_x = NULL; q->debug_rssi = NULL; q->debug_framesyms =NULL; q->G_hat = NULL; q->px = NULL; q->py = NULL; q->debug_pilot_0 = NULL; q->debug_pilot_1 = NULL; #endif // return object return q; }
// create OFDM framing generator object // _M : number of subcarriers, >10 typical // _cp_len : cyclic prefix length // _taper_len : taper length (OFDM symbol overlap) // _p : subcarrier allocation (null, pilot, data), [size: _M x 1] ofdmframegen ofdmframegen_create(unsigned int _M, unsigned int _cp_len, unsigned int _taper_len, unsigned char * _p) { // validate input if (_M < 2) { fprintf(stderr,"error: ofdmframegen_create(), number of subcarriers must be at least 2\n"); exit(1); } else if (_M % 2) { fprintf(stderr,"error: ofdmframegen_create(), number of subcarriers must be even\n"); exit(1); } else if (_cp_len > _M) { fprintf(stderr,"error: ofdmframegen_create(), cyclic prefix cannot exceed symbol length\n"); exit(1); } else if (_taper_len > _cp_len) { fprintf(stderr,"error: ofdmframegen_create(), taper length cannot exceed cyclic prefix\n"); exit(1); } ofdmframegen q = (ofdmframegen) malloc(sizeof(struct ofdmframegen_s)); q->M = _M; q->cp_len = _cp_len; q->taper_len = _taper_len; // allocate memory for subcarrier allocation IDs q->p = (unsigned char*) malloc((q->M)*sizeof(unsigned char)); if (_p == NULL) { // initialize default subcarrier allocation ofdmframe_init_default_sctype(q->M, q->p); } else { // copy user-defined subcarrier allocation memmove(q->p, _p, q->M*sizeof(unsigned char)); } // validate and count subcarrier allocation ofdmframe_validate_sctype(q->p, q->M, &q->M_null, &q->M_pilot, &q->M_data); if ( (q->M_pilot + q->M_data) == 0) { fprintf(stderr,"error: ofdmframegen_create(), must have at least one enabled subcarrier\n"); exit(1); } else if (q->M_data == 0) { fprintf(stderr,"error: ofdmframegen_create(), must have at least one data subcarriers\n"); exit(1); } else if (q->M_pilot < 2) { fprintf(stderr,"error: ofdmframegen_create(), must have at least two pilot subcarriers\n"); exit(1); } unsigned int i; // allocate memory for transform objects q->X = (float complex*) malloc((q->M)*sizeof(float complex)); q->x = (float complex*) malloc((q->M)*sizeof(float complex)); q->ifft = FFT_CREATE_PLAN(q->M, q->X, q->x, FFT_DIR_BACKWARD, FFT_METHOD); // allocate memory for PLCP arrays q->S0 = (float complex*) malloc((q->M)*sizeof(float complex)); q->s0 = (float complex*) malloc((q->M)*sizeof(float complex)); q->S1 = (float complex*) malloc((q->M)*sizeof(float complex)); q->s1 = (float complex*) malloc((q->M)*sizeof(float complex)); ofdmframe_init_S0(q->p, q->M, q->S0, q->s0, &q->M_S0); ofdmframe_init_S1(q->p, q->M, q->S1, q->s1, &q->M_S1); // create tapering window and transition buffer q->taper = (float*) malloc(q->taper_len * sizeof(float)); q->postfix = (float complex*) malloc(q->taper_len * sizeof(float complex)); for (i=0; i<q->taper_len; i++) { float t = ((float)i + 0.5f) / (float)(q->taper_len); float g = sinf(M_PI_2*t); q->taper[i] = g*g; } #if 0 // validate window symmetry for (i=0; i<q->taper_len; i++) { printf(" taper[%2u] = %12.8f (%12.8f)\n", i, q->taper[i], q->taper[i] + q->taper[q->taper_len - i - 1]); } #endif // compute scaling factor q->g_data = 1.0f / sqrtf(q->M_pilot + q->M_data); // set pilot sequence q->ms_pilot = msequence_create_default(8); return q; }
// create fskdem object (frequency demodulator) // _m : bits per symbol, _m > 0 // _k : samples/symbol, _k >= 2^_m // _bandwidth : total signal bandwidth, (0,0.5) fskdem fskdem_create(unsigned int _m, unsigned int _k, float _bandwidth) { // validate input if (_m == 0) { fprintf(stderr,"error: fskdem_create(), bits/symbol must be greater than 0\n"); exit(1); } else if (_k < 2 || _k > 2048) { fprintf(stderr,"error: fskdem_create(), samples/symbol must be in [2^_m, 2048]\n"); exit(1); } else if (_bandwidth <= 0.0f || _bandwidth >= 0.5f) { fprintf(stderr,"error: fskdem_create(), bandwidth must be in (0,0.5)\n"); exit(1); } // create main object memory fskdem q = (fskdem) malloc(sizeof(struct fskdem_s)); // set basic internal properties q->m = _m; // bits per symbol q->k = _k; // samples per symbol q->bandwidth = _bandwidth; // signal bandwidth // derived values q->M = 1 << q->m; // constellation size q->M2 = 0.5f*(float)(q->M-1); // (M-1)/2 // compute demodulation FFT size such that FFT output bin frequencies are // as close to modulated frequencies as possible float df = q->bandwidth / q->M2; // frequency spacing float err_min = 1e9f; // minimum error value unsigned int K_min = q->k; // minimum FFT size unsigned int K_max = q->k*4 < 16 ? 16 : q->k*4; // maximum FFT size unsigned int K_hat; for (K_hat=K_min; K_hat<=K_max; K_hat++) { // compute candidate FFT size float v = 0.5f*df*(float)K_hat; // bin spacing float err = fabsf( roundf(v) - v ); // fractional bin spacing #if DEBUG_FSKDEM // print results printf(" K_hat = %4u : v = %12.8f, err=%12.8f %s\n", K_hat, v, err, err < err_min ? "*" : ""); #endif // save best result if (K_hat==K_min || err < err_min) { q->K = K_hat; err_min = err; } // perfect match; no need to continue searching if (err < 1e-6f) break; } // determine demodulation mapping between tones and frequency bins // TODO: use gray coding q->demod_map = (unsigned int *) malloc(q->M * sizeof(unsigned int)); unsigned int i; for (i=0; i<q->M; i++) { // print frequency bins float freq = ((float)i - q->M2) * q->bandwidth / q->M2; float idx = freq * (float)(q->K); unsigned int index = (unsigned int) (idx < 0 ? roundf(idx + q->K) : roundf(idx)); q->demod_map[i] = index; #if DEBUG_FSKDEM printf(" s=%3u, f = %12.8f, index=%3u\n", i, freq, index); #endif } // check for uniqueness for (i=1; i<q->M; i++) { if (q->demod_map[i] == q->demod_map[i-1]) { fprintf(stderr,"warning: fskdem_create(), demod map is not unique; consider increasing bandwidth\n"); break; } } // allocate memory for transform q->buf_time = (float complex*) malloc(q->K * sizeof(float complex)); q->buf_freq = (float complex*) malloc(q->K * sizeof(float complex)); q->fft = FFT_CREATE_PLAN(q->K, q->buf_time, q->buf_freq, FFT_DIR_FORWARD, 0); // reset modem object fskdem_reset(q); // return main object return q; }
firpfbch firpfbch_create(unsigned int _num_channels, unsigned int _m, float _beta, float _dt, int _nyquist, int _gradient) { firpfbch c = (firpfbch) malloc(sizeof(struct firpfbch_s)); c->num_channels = _num_channels; c->m = _m; c->beta = _beta; c->dt = _dt; c->nyquist = _nyquist; // validate inputs if (_m < 1) { printf("error: firpfbch_create(), invalid filter delay (must be greater than 0)\n"); exit(1); } // create bank of filters c->dp = (DOTPROD()*) malloc((c->num_channels)*sizeof(DOTPROD())); c->w = (WINDOW()*) malloc((c->num_channels)*sizeof(WINDOW())); // design filter // TODO: use filter prototype object c->h_len = 2*(c->m)*(c->num_channels); c->h = (float*) malloc((c->h_len+1)*sizeof(float)); if (c->nyquist == FIRPFBCH_NYQUIST) { float fc = 0.5f/(float)(c->num_channels); // cutoff frequency liquid_firdes_kaiser(c->h_len+1, fc, c->beta, 0.0f, c->h); } else if (c->nyquist == FIRPFBCH_ROOTNYQUIST) { design_rkaiser_filter(c->num_channels, c->m, c->beta, c->dt, c->h); } else { printf("error: firpfbch_create(), unsupported nyquist flag: %d\n", _nyquist); exit(1); } unsigned int i; if (_gradient) { float dh[c->h_len]; for (i=0; i<c->h_len; i++) { if (i==0) { dh[i] = c->h[i+1] - c->h[c->h_len-1]; } else if (i==c->h_len-1) { dh[i] = c->h[0] - c->h[i-1]; } else { dh[i] = c->h[i+1] - c->h[i-1]; } } memmove(c->h, dh, (c->h_len)*sizeof(float)); } // generate bank of sub-samped filters unsigned int n; unsigned int h_sub_len = 2*(c->m); // length of each sub-sampled filter float h_sub[h_sub_len]; for (i=0; i<c->num_channels; i++) { // sub-sample prototype filter, loading coefficients in reverse order for (n=0; n<h_sub_len; n++) { h_sub[h_sub_len-n-1] = c->h[i + n*(c->num_channels)]; } // create window buffer and dotprod object (coefficients // loaded in reverse order) c->dp[i] = DOTPROD(_create)(h_sub,h_sub_len); c->w[i] = WINDOW(_create)(h_sub_len); #if DEBUG_FIRPFBCH_PRINT printf("h_sub[%u] :\n", i); for (n=0; n<h_sub_len; n++) printf(" h[%3u] = %8.4f\n", n, h_sub[n]); #endif } #if DEBUG_FIRPFBCH_PRINT for (i=0; i<c->h_len+1; i++) printf("h(%4u) = %12.4e;\n", i+1, c->h[i]); #endif // allocate memory for buffers // TODO : use fftw_malloc if HAVE_FFTW3_H c->x = (float complex*) malloc((c->num_channels)*sizeof(float complex)); c->X = (float complex*) malloc((c->num_channels)*sizeof(float complex)); c->X_prime = (float complex*) malloc((c->num_channels)*sizeof(float complex)); firpfbch_clear(c); // create fft plan c->fft = FFT_CREATE_PLAN(c->num_channels, c->X, c->x, FFT_DIR_BACKWARD, FFT_METHOD); return c; }
// create FFT-based FIR filter using external coefficients // _h : filter coefficients [size: _h_len x 1] // _h_len : filter length, _h_len > 0 // _n : block size = nfft/2, at least _h_len-1 FFTFILT() FFTFILT(_create)(TC * _h, unsigned int _h_len, unsigned int _n) { // validate input if (_h_len == 0) { fprintf(stderr,"error: fftfilt_%s_create(), filter length must be greater than zero\n", EXTENSION_FULL); exit(1); } else if (_n < _h_len-1) { fprintf(stderr,"error: fftfilt_%s_create(), block length must be greater than _h_len-1 (%u)\n", EXTENSION_FULL, _h_len-1); exit(1); } // create filter object and initialize FFTFILT() q = (FFTFILT()) malloc(sizeof(struct FFTFILT(_s))); q->h_len = _h_len; q->n = _n; // copy filter coefficients q->h = (TC *) malloc((q->h_len)*sizeof(TC)); memmove(q->h, _h, _h_len*sizeof(TC)); // allocate internal memory arrays q->time_buf = (float complex *) malloc((2*q->n)* sizeof(float complex)); // time buffer q->freq_buf = (float complex *) malloc((2*q->n)* sizeof(float complex)); // frequency buffer q->H = (float complex *) malloc((2*q->n)* sizeof(float complex)); // FFT{ h } q->w = (float complex *) malloc(( q->n)* sizeof(float complex)); // delay buffer // create internal FFT objects #ifdef LIQUID_FFTOVERRIDE q->fft = fft_create_plan(2*q->n, q->time_buf, q->freq_buf, LIQUID_FFT_FORWARD, 0); q->ifft = fft_create_plan(2*q->n, q->freq_buf, q->time_buf, LIQUID_FFT_BACKWARD, 0); #else q->fft = FFT_CREATE_PLAN(2*q->n, q->time_buf, q->freq_buf, FFT_DIR_FORWARD, FFT_METHOD); q->ifft = FFT_CREATE_PLAN(2*q->n, q->freq_buf, q->time_buf, FFT_DIR_BACKWARD, FFT_METHOD); #endif // compute FFT of filter coefficients and copy to internal H array unsigned int i; for (i=0; i<2*q->n; i++) q->time_buf[i] = (i < q->h_len) ? q->h[i] : 0; // time_buf > {FFT} > freq_buf #ifdef LIQUID_FFTOVERRIDE fft_execute(q->fft); #else FFT_EXECUTE(q->fft); #endif memmove(q->H, q->freq_buf, 2*q->n*sizeof(float complex)); // set default scaling FFTFILT(_set_scale)(q, 1); // reset filter state (clear buffer) FFTFILT(_reset)(q); // return object return q; }
// create spgram object // _nfft : FFT size // _wtype : window type, e.g. LIQUID_WINDOW_HAMMING // _window_len : window length // _delay : delay between transforms, _delay > 0 SPGRAM() SPGRAM(_create)(unsigned int _nfft, int _wtype, unsigned int _window_len, unsigned int _delay) { // validate input if (_nfft < 2) { fprintf(stderr,"error: spgram%s_create(), fft size must be at least 2\n", EXTENSION); exit(1); } else if (_window_len > _nfft) { fprintf(stderr,"error: spgram%s_create(), window size cannot exceed fft size\n", EXTENSION); exit(1); } else if (_window_len == 0) { fprintf(stderr,"error: spgram%s_create(), window size must be greater than zero\n", EXTENSION); exit(1); } else if (_wtype == LIQUID_WINDOW_KBD && _window_len % 2) { fprintf(stderr,"error: spgram%s_create(), KBD window length must be even\n", EXTENSION); exit(1); } else if (_delay == 0) { fprintf(stderr,"error: spgram%s_create(), delay must be greater than 0\n", EXTENSION); exit(1); } // allocate memory for main object SPGRAM() q = (SPGRAM()) malloc(sizeof(struct SPGRAM(_s))); // set input parameters q->nfft = _nfft; q->wtype = _wtype; q->window_len = _window_len; q->delay = _delay; q->frequency = 0; q->sample_rate= -1; // set object for full accumulation SPGRAM(_set_alpha)(q, -1.0f); // create FFT arrays, object q->buf_time = (TC*) malloc((q->nfft)*sizeof(TC)); q->buf_freq = (TC*) malloc((q->nfft)*sizeof(TC)); q->psd = (T *) malloc((q->nfft)*sizeof(T )); q->fft = FFT_CREATE_PLAN(q->nfft, q->buf_time, q->buf_freq, FFT_DIR_FORWARD, FFT_METHOD); // create buffer q->buffer = WINDOW(_create)(q->window_len); // create window q->w = (T*) malloc((q->window_len)*sizeof(T)); unsigned int i; unsigned int n = q->window_len; float beta = 10.0f; float zeta = 3.0f; for (i=0; i<n; i++) { switch (q->wtype) { case LIQUID_WINDOW_HAMMING: q->w[i] = hamming(i,n); break; case LIQUID_WINDOW_HANN: q->w[i] = hann(i,n); break; case LIQUID_WINDOW_BLACKMANHARRIS: q->w[i] = blackmanharris(i,n); break; case LIQUID_WINDOW_BLACKMANHARRIS7: q->w[i] = blackmanharris7(i,n); break; case LIQUID_WINDOW_KAISER: q->w[i] = kaiser(i,n,beta,0); break; case LIQUID_WINDOW_FLATTOP: q->w[i] = flattop(i,n); break; case LIQUID_WINDOW_TRIANGULAR: q->w[i] = triangular(i,n,n); break; case LIQUID_WINDOW_RCOSTAPER: q->w[i] = liquid_rcostaper_windowf(i,n/3,n); break; case LIQUID_WINDOW_KBD: q->w[i] = liquid_kbd(i,n,zeta); break; default: fprintf(stderr,"error: spgram%s_create(), invalid window\n", EXTENSION); exit(1); } } // scale by window magnitude, FFT size float g = 0.0f; for (i=0; i<q->window_len; i++) g += q->w[i] * q->w[i]; g = M_SQRT2 / ( sqrtf(g / q->window_len) * sqrtf((float)(q->nfft)) ); // scale window and copy for (i=0; i<q->window_len; i++) q->w[i] = g * q->w[i]; // reset the spgram object q->num_samples_total = 0; q->num_transforms_total = 0; SPGRAM(_reset)(q); // return new object return q; }
// create FIR polyphase filterbank channelizer object // _type : channelizer type (LIQUID_ANALYZER | LIQUID_SYNTHESIZER) // _M : number of channels // _p : filter length (symbols) // _h : filter coefficients, [size: _M*_p x 1] FIRPFBCH() FIRPFBCH(_create)(int _type, unsigned int _M, unsigned int _p, TC * _h) { // validate input if (_type != LIQUID_ANALYZER && _type != LIQUID_SYNTHESIZER) { fprintf(stderr,"error: firpfbch_%s_create(), invalid type %d\n", EXTENSION_FULL, _type); exit(1); } else if (_M == 0) { fprintf(stderr,"error: firpfbch_%s_create(), number of channels must be greater than 0\n", EXTENSION_FULL); exit(1); } else if (_p == 0) { fprintf(stderr,"error: firpfbch_%s_create(), invalid filter size (must be greater than 0)\n", EXTENSION_FULL); exit(1); } // create main object FIRPFBCH() q = (FIRPFBCH()) malloc(sizeof(struct FIRPFBCH(_s))); // set user-defined properties q->type = _type; q->num_channels = _M; q->p = _p; // derived values q->h_len = q->num_channels * q->p; // create bank of filters q->dp = (DOTPROD()*) malloc((q->num_channels)*sizeof(DOTPROD())); q->w = (WINDOW()*) malloc((q->num_channels)*sizeof(WINDOW())); // copy filter coefficients q->h = (TC*) malloc((q->h_len)*sizeof(TC)); unsigned int i; for (i=0; i<q->h_len; i++) q->h[i] = _h[i]; // generate bank of sub-samped filters unsigned int n; unsigned int h_sub_len = q->p; TC h_sub[h_sub_len]; for (i=0; i<q->num_channels; i++) { // sub-sample prototype filter, loading coefficients in reverse order for (n=0; n<h_sub_len; n++) { h_sub[h_sub_len-n-1] = q->h[i + n*(q->num_channels)]; } // create window buffer and dotprod object (coefficients // loaded in reverse order) q->dp[i] = DOTPROD(_create)(h_sub,h_sub_len); q->w[i] = WINDOW(_create)(h_sub_len); } // allocate memory for buffers // TODO : use fftw_malloc if HAVE_FFTW3_H q->x = (T*) malloc((q->num_channels)*sizeof(T)); q->X = (T*) malloc((q->num_channels)*sizeof(T)); // create fft plan if (q->type == LIQUID_ANALYZER) q->fft = FFT_CREATE_PLAN(q->num_channels, q->X, q->x, FFT_DIR_FORWARD, FFT_METHOD); else q->fft = FFT_CREATE_PLAN(q->num_channels, q->X, q->x, FFT_DIR_BACKWARD, FFT_METHOD); // reset filterbank object FIRPFBCH(_reset)(q); // return filterbank object return q; }