// create least mean-squares (LMS) equalizer object // _h : initial coefficients [size: _p x 1], default if NULL // _p : equalizer length (number of taps) EQLMS() EQLMS(_create)(T * _h, unsigned int _p) { EQLMS() eq = (EQLMS()) malloc(sizeof(struct EQLMS(_s))); // set filter order, other params eq->p = _p; eq->mu = 0.5f; eq->h0 = (T*) malloc((eq->p)*sizeof(T)); eq->w0 = (T*) malloc((eq->p)*sizeof(T)); eq->w1 = (T*) malloc((eq->p)*sizeof(T)); eq->buffer = WINDOW(_create)(eq->p); eq->x2 = wdelayf_create(eq->p); // copy coefficients (if not NULL) if (_h == NULL) { // initial coefficients with delta at first index unsigned int i; for (i=0; i<eq->p; i++) eq->h0[i] = (i==0) ? 1.0 : 0.0; } else { // copy user-defined initial coefficients memmove(eq->h0, _h, (eq->p)*sizeof(T)); } // reset equalizer object EQLMS(_reset)(eq); return eq; }
// create least mean-squares (LMS) equalizer object // _h : initial coefficients [size: _h_len x 1], default if NULL // _p : equalizer length (number of taps) EQLMS() EQLMS(_create)(T * _h, unsigned int _h_len) { EQLMS() q = (EQLMS()) malloc(sizeof(struct EQLMS(_s))); // set filter order, other params q->h_len = _h_len; q->mu = 0.5f; q->h0 = (T*) malloc((q->h_len)*sizeof(T)); q->w0 = (T*) malloc((q->h_len)*sizeof(T)); q->w1 = (T*) malloc((q->h_len)*sizeof(T)); q->buffer = WINDOW(_create)(q->h_len); q->x2 = wdelayf_create(q->h_len); // copy coefficients (if not NULL) if (_h == NULL) { // initial coefficients with delta at first index unsigned int i; for (i=0; i<q->h_len; i++) q->h0[i] = (i==0) ? 1.0 : 0.0; } else { // copy user-defined initial coefficients memmove(q->h0, _h, (q->h_len)*sizeof(T)); } // reset equalizer object EQLMS(_reset)(q); // return main object return q; }
// create LMS EQ initialized with low-pass filter // _h_len : filter length // _fc : filter cut-off, _fc in (0,0.5] EQLMS() EQLMS(_create_lowpass)(unsigned int _h_len, float _fc) { // validate input if (_h_len == 0) { fprintf(stderr,"error: eqlms_%s_create_lowpass(), filter length must be greater than 0\n", EXTENSION_FULL); exit(1); } else if (_fc <= 0.0f || _fc > 0.5f) { fprintf(stderr,"error: eqlms_%s_create_rnyquist(), filter cutoff must be in (0,0.5]\n", EXTENSION_FULL); exit(1); } // generate low-pass filter prototype float h[_h_len]; liquid_firdes_kaiser(_h_len, _fc, 40.0f, 0.0f, h); // copy coefficients to type-specific array (e.g. float complex) unsigned int i; T hc[_h_len]; for (i=0; i<_h_len; i++) hc[i] = h[i]; // return equalizer object return EQLMS(_create)(hc, _h_len); }
// 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; }
// create square-root Nyquist interpolator // _type : filter type (e.g. LIQUID_RNYQUIST_RRC) // _k : samples/symbol _k > 1 // _m : filter delay (symbols), _m > 0 // _beta : excess bandwidth factor, 0 < _beta < 1 // _dt : fractional sample delay, 0 <= _dt < 1 EQLMS() EQLMS(_create_rnyquist)(int _type, unsigned int _k, unsigned int _m, float _beta, float _dt) { // validate input if (_k < 2) { fprintf(stderr,"error: eqlms_%s_create_rnyquist(), samples/symbol must be greater than 1\n", EXTENSION_FULL); exit(1); } else if (_m == 0) { fprintf(stderr,"error: eqlms_%s_create_rnyquist(), filter delay must be greater than 0\n", EXTENSION_FULL); exit(1); } else if (_beta < 0.0f || _beta > 1.0f) { fprintf(stderr,"error: eqlms_%s_create_rnyquist(), filter excess bandwidth factor must be in [0,1]\n", EXTENSION_FULL); exit(1); } else if (_dt < -1.0f || _dt > 1.0f) { fprintf(stderr,"error: eqlms_%s_create_rnyquist(), filter fractional sample delay must be in [-1,1]\n", EXTENSION_FULL); exit(1); } // generate square-root Nyquist filter unsigned int h_len = 2*_k*_m + 1; float h[h_len]; liquid_firdes_rnyquist(_type,_k,_m,_beta,_dt,h); // copy coefficients to type-specific array (e.g. float complex) // and scale by samples/symbol unsigned int i; T hc[h_len]; for (i=0; i<h_len; i++) hc[i] = h[i] / (float)_k; // return equalizer object return EQLMS(_create)(hc, h_len); }
struct EQLMS(_s) { unsigned int p; // filter order float mu; // LMS step size // internal matrices T * h0; // initial coefficients T * w0, * w1; // weights [px1] unsigned int n; // input counter WINDOW() buffer; // input buffer wdelayf x2; // buffer of |x|^2 values float x2_sum; // sum{ |x|^2 } }; // update sum{|x|^2} void EQLMS(_update_sumsq)(EQLMS() _eq, T _x); // create least mean-squares (LMS) equalizer object // _h : initial coefficients [size: _p x 1], default if NULL // _p : equalizer length (number of taps) EQLMS() EQLMS(_create)(T * _h, unsigned int _p) { EQLMS() eq = (EQLMS()) malloc(sizeof(struct EQLMS(_s))); // set filter order, other params eq->p = _p; eq->mu = 0.5f; eq->h0 = (T*) malloc((eq->p)*sizeof(T)); eq->w0 = (T*) malloc((eq->p)*sizeof(T));