bool ChannelizerBase::initFFT() { int len; int flags = CXVEC_FLG_FFT_ALIGN; if (fftInput || fftOutput || fftHandle) return false; len = chunkLen * mChanM; fftInput = cxvec_alloc(len, 0, NULL, flags); len = (chunkLen + mFiltLen) * mChanM; fftOutput = cxvec_alloc(len, 0, NULL, flags); if (!fftInput | !fftOutput) { LOG(ERR) << "Memory allocation error"; return false; } cxvec_reset(fftInput); cxvec_reset(fftOutput); fftHandle = init_fft(0, mChanM, chunkLen, chunkLen + mFiltLen, fftInput, fftOutput, mFiltLen); return true; }
/* * Setup filterbank internals */ bool ChannelizerBase::init() { int i; /* * Filterbank coefficients, fft plan, history, and output sample * rate conversion blocks */ if (!initFilters()) { LOG(ERR) << "Failed to initialize channelizing filter"; return false; } mResampler = new Resampler(mP, mQ, mFiltLen, mChanM); if (!mResampler->init()) { LOG(ERR) << "Failed to initialize resampling filter"; return false; } history = (struct cxvec **) malloc(sizeof(struct cxvec *) * mChanM); for (i = 0; i < mChanM; i++) { history[i] = cxvec_alloc(mFiltLen, 0, NULL, 0); cxvec_reset(history[i]); } if (!initFFT()) { LOG(ERR) << "Failed to initialize FFT"; return false; } mapBuffers(); return true; }
/* Initialize I/O specific objects */ bool RadioInterface::init() { int i; chan = new Channelizer(mChanM, CHAN_FILT_LEN, RESAMP_FILT_LEN, RESAMP_INRATE, RESAMP_OUTRATE, CHUNKMUL); if (!chan->init(NULL)) { LOG(ALERT) << "Rx channelizer failed to initialize"; return false; } synth = new Synthesis(mChanM, CHAN_FILT_LEN, RESAMP_FILT_LEN, RESAMP_OUTRATE, RESAMP_INRATE, CHUNKMUL); if (!synth->init(NULL)) { LOG(ALERT) << "Tx channelizer failed to initialize"; return false; } highRateTxBuf = cxvec_alloc(OUTBUFLEN * mChanM, 0, NULL, 0); highRateRxBuf = cxvec_alloc(OUTBUFLEN * mChanM, 0, NULL, 0); /* * Setup per-channel variables. The low rate transmit vectors * feed into the resampler prior to the synthesis filter * and requires headroom equivalent to the filter length. Low * rate buffers are allocated in the main radio interface code. */ for (i = 0; i < mChanM; i++) { if (chanActive[i]) { chan->activateChan(i); synth->activateChan(i); } lowRateRxBufs[i] = cxvec_alloc(2 * 625, 0, (cmplx *) rcvBuffer[i], 0); lowRateTxBufs[i] = cxvec_alloc(2 * 625, RESAMP_FILT_LEN, (cmplx *) sendBuffer[i], 0); } return true; }
/*! \brief Reverse a complex vector * \param[in] in Complex input vector * \param[out] out Complex output vector pointers */ int cxvec_rvrs(struct cxvec *in, struct cxvec *out) { int i; struct cxvec *rev = cxvec_alloc(in->len, 0, NULL, 0); for (i = 0; i < in->len; i++) rev->data[i] = in->data[in->len - 1 - i]; memcpy(out->data, rev->data, in->len * sizeof(float complex)); cxvec_free(rev); return 0; }
/* * Create polyphase filterbank * * Implementation based material found in, * * "harris, fred, Multirate Signal Processing, Upper Saddle River, NJ, * Prentice Hall, 2006." */ bool ChannelizerBase::initFilters() { int i, n; int m = mChanM; int protoLen = m * mFiltLen; float *proto; float sum = 0.0f; float scale = 0.0f; float midpt = protoLen / 2; /* * Allocate 'M' partition filters and the temporary prototype * filter. Coefficients are real only and must be 16-byte memory * aligned for SSE usage. */ int flags = CXVEC_FLG_REAL_ONLY | CXVEC_FLG_MEM_ALIGN; proto = (float *) malloc(protoLen * sizeof(float)); if (!proto) return false; subFilters = (struct cxvec **) malloc(sizeof(struct cxvec *) * m); if (!subFilters) return false; for (i = 0; i < m; i++) { subFilters[i] = cxvec_alloc(mFiltLen, 0, NULL, flags); } /* * Generate the prototype filter with a Blackman-harris window. * Scale coefficients with DC filter gain set to unity divided * by the number of channels. */ float a0 = 0.35875; float a1 = 0.48829; float a2 = 0.14128; float a3 = 0.01168; for (i = 0; i < protoLen; i++) { proto[i] = cxvec_sinc(((float) i - midpt) / m); proto[i] *= a0 - a1 * cos(2 * M_PI * i / (protoLen - 1)) + a2 * cos(4 * M_PI * i / (protoLen - 1)) - a3 * cos(6 * M_PI * i / (protoLen - 1)); sum += proto[i]; } scale = mChanM / sum; /* * Populate partition filters and reverse the coefficients per * convolution requirements. */ for (i = 0; i < mFiltLen; i++) { for (n = 0; n < m; n++) { subFilters[n]->data[i] = proto[i * m + n] * scale; } } for (i = 0; i < m; i++) { cxvec_rvrs(subFilters[i], subFilters[i]); } free(proto); return true; }