// create nco/vco object NCO() NCO(_create)(liquid_ncotype _type) { NCO() q = (NCO()) malloc(sizeof(struct NCO(_s))); q->type = _type; // initialize sine table unsigned int i; for (i=0; i<1024; i++) q->sintab[i] = SIN(2.0f*M_PI*(float)(i)/1024.0f); // set default pll bandwidth NCO(_pll_set_bandwidth)(q, NCO_PLL_BANDWIDTH_DEFAULT); // reset object and return NCO(_reset)(q); return q; }
// create symtrack object with basic parameters // _ftype : filter type (e.g. LIQUID_FIRFILT_RRC) // _k : samples per symbol // _m : filter delay (symbols) // _beta : filter excess bandwidth // _ms : modulation scheme (e.g. LIQUID_MODEM_QPSK) SYMTRACK() SYMTRACK(_create)(int _ftype, unsigned int _k, unsigned int _m, float _beta, int _ms) { // validate input if (_k < 2) { fprintf(stderr,"error: symtrack_%s_create(), filter samples/symbol must be at least 2\n", EXTENSION_FULL); exit(1); } else if (_m == 0) { fprintf(stderr,"error: symtrack_%s_create(), filter delay must be greater than zero\n", EXTENSION_FULL); exit(1); } else if (_beta <= 0.0f || _beta > 1.0f) { fprintf(stderr,"error: symtrack_%s_create(), filter excess bandwidth must be in (0,1]\n", EXTENSION_FULL); exit(1); } else if (_ms == LIQUID_MODEM_UNKNOWN || _ms >= LIQUID_MODEM_NUM_SCHEMES) { fprintf(stderr,"error: symtrack_%s_create(), invalid modulation scheme\n", EXTENSION_FULL); exit(1); } // allocate memory for main object SYMTRACK() q = (SYMTRACK()) malloc( sizeof(struct SYMTRACK(_s)) ); // set input parameters q->filter_type = _ftype; q->k = _k; q->m = _m; q->beta = _beta; q->mod_scheme = _ms == LIQUID_MODEM_UNKNOWN ? LIQUID_MODEM_BPSK : _ms; // create automatic gain control q->agc = AGC(_create)(); // create symbol synchronizer (output rate: 2 samples per symbol) if (q->filter_type == LIQUID_FIRFILT_UNKNOWN) q->symsync = SYMSYNC(_create_kaiser)(q->k, q->m, 0.9f, 16); else q->symsync = SYMSYNC(_create_rnyquist)(q->filter_type, q->k, q->m, q->beta, 16); SYMSYNC(_set_output_rate)(q->symsync, 2); // create equalizer as default low-pass filter with integer symbol delay (2 samples/symbol) q->eq_len = 2 * 4 + 1; q->eq = EQLMS(_create_lowpass)(q->eq_len,0.45f); // nco and phase-locked loop q->nco = NCO(_create)(LIQUID_VCO); // demodulator q->demod = MODEM(_create)(q->mod_scheme); // set default bandwidth SYMTRACK(_set_bandwidth)(q, 0.9f); // reset and return main object SYMTRACK(_reset)(q); return q; }
struct NCO(_s) { liquid_ncotype type; // NCO type (e.g. LIQUID_VCO) T sintab[1024]; // sine look-up table uint32_t theta; // 32-bit phase [radians] uint32_t d_theta; // 32-bit frequency [radians/sample] // phase-locked loop T alpha; // frequency proportion T beta; // phase proportion }; // constrain phase (or frequency) and convert to fixed-point uint32_t NCO(_constrain)(float _theta); // compute index for sine look-up table unsigned int NCO(_index)(NCO() _q); // create nco/vco object NCO() NCO(_create)(liquid_ncotype _type) { NCO() q = (NCO()) malloc(sizeof(struct NCO(_s))); q->type = _type; // initialize sine table unsigned int i; for (i=0; i<1024; i++) q->sintab[i] = SIN(2.0f*M_PI*(float)(i)/1024.0f); // set default pll bandwidth NCO(_pll_set_bandwidth)(q, NCO_PLL_BANDWIDTH_DEFAULT);
// create dds object // _num_stages : number of halfband stages // _fc : input carrier // _bw : input signal bandwidth // _As : stop-band attenuation DDS() DDS(_create)(unsigned int _num_stages, float _fc, float _bw, float _As) { // create object DDS() q = (DDS()) malloc(sizeof(struct DDS(_s))); q->num_stages = _num_stages; q->rate = 1<<(q->num_stages); q->fc0 = _fc; q->bw0 = _bw; q->As0 = _As; // error checking if (q->fc0 > 0.5f || q->fc0 < -0.5f) { fprintf(stderr,"error: dds_xxxf_create(), frequency %12.4e is out of range [-0.5,0.5]\n", q->fc0); exit(1); } // allocate memory for filter properties q->fc = (float*) malloc((q->num_stages)*sizeof(float)); q->ft = (float*) malloc((q->num_stages)*sizeof(float)); q->As = (float*) malloc((q->num_stages)*sizeof(float)); q->h_len = (unsigned int*) malloc((q->num_stages)*sizeof(unsigned int)); unsigned int i; float fc, bw; fc = 0.5*(1<<q->num_stages)*q->fc0; // filter center frequency bw = q->bw0; // signal bandwidth // TODO : compute/set filter bandwidths, lengths appropriately for (i=0; i<q->num_stages; i++) { q->fc[i] = fc; while (q->fc[i] > 0.5f) q->fc[i] -= 1.0f; while (q->fc[i] < -0.5f) q->fc[i] += 1.0f; // compute transition bandwidth q->ft[i] = 0.5f*(1.0f - bw); if (q->ft[i] > 0.45) q->ft[i] = 0.45f; // set maximum bandwidth q->As[i] = q->As0; // compute (estimate) required filter length //q->h_len[i] = i==0 ? 37 : q->h_len[i-1]*0.7; q->h_len[i] = estimate_req_filter_len(q->ft[i], q->As[i]); if ((q->h_len[i] % 2) == 0) q->h_len[i]++; // ensure h_len[i] is of form 4*m+1 unsigned int m = (q->h_len[i]-1)/4; if (m < 1) m = 1; q->h_len[i] = 4*m+1; // update carrier, bandwidth parameters fc *= 0.5f; bw *= 0.5f; } // allocate memory for buffering q->buffer_len = q->rate; q->buffer0 = (T*) malloc((q->buffer_len)*sizeof(T)); q->buffer1 = (T*) malloc((q->buffer_len)*sizeof(T)); // allocate memory for resampler pointers and create objects q->halfband_resamp = (RESAMP2()*) malloc((q->num_stages)*sizeof(RESAMP()*)); for (i=0; i<q->num_stages; i++) { q->halfband_resamp[i] = RESAMP2(_create)(q->h_len[i], q->fc[i], q->As[i]); } // set down-converter scaling factor q->zeta = 1.0f / ((float)(q->rate)); // create NCO and set frequency q->ncox = NCO(_create)(LIQUID_VCO); // TODO : ensure range is in [-pi,pi] NCO(_set_frequency)(q->ncox, 2*M_PI*(q->rate)*(q->fc0)); return q; }