// create an arbitrary modem object MODEM() MODEM(_create_arb)(unsigned int _bits_per_symbol) { MODEM() q = (MODEM()) malloc( sizeof(struct MODEM(_s)) ); q->scheme = LIQUID_MODEM_ARB; MODEM(_init)(q, _bits_per_symbol); q->M = q->M; q->symbol_map = (TC*) calloc( q->M, sizeof(TC) ); q->modulate_func = &MODEM(_modulate_arb); q->demodulate_func = &MODEM(_demodulate_arb); 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; }
// create a 'square' 128-QAM modem object MODEM() MODEM(_create_sqam128)() { MODEM() q = (MODEM()) malloc( sizeof(struct MODEM(_s)) ); q->scheme = LIQUID_MODEM_SQAM128; MODEM(_init)(q, 7); // allocate memory for 32-point symbol map q->data.sqam128.map = (TC*) malloc( 32*sizeof(TC) ); #if T == float memmove(q->data.sqam128.map, modem_arb_sqam128, 32*sizeof(TC)); #endif // set modulation, demodulation functions q->modulate_func = &MODEM(_modulate_sqam128); q->demodulate_func = &MODEM(_demodulate_sqam128); return q; }
// create arbitrary digital modem object MODEM() MODEM(_create_arbitrary)(TC * _table, unsigned int _M) { // strip out bits/symbol unsigned int m = liquid_nextpow2(_M); if ( (1<<m) != _M ) { // TODO : eventually support non radix-2 constellation sizes fprintf(stderr,"error: modem_create_arbitrary(), input constellation size must be power of 2\n"); exit(1); } // create arbitrary modem object, not initialized MODEM() q = MODEM(_create_arb)(m); // initialize object from table MODEM(_arb_init)(q, _table, _M); // return object return q; }
// create a psk (phase-shift keying) modem object MODEM() MODEM(_create_psk)(unsigned int _bits_per_symbol) { MODEM() q = (MODEM()) malloc( sizeof(struct MODEM(_s)) ); switch (_bits_per_symbol) { case 1: q->scheme = LIQUID_MODEM_PSK2; break; case 2: q->scheme = LIQUID_MODEM_PSK4; break; case 3: q->scheme = LIQUID_MODEM_PSK8; break; case 4: q->scheme = LIQUID_MODEM_PSK16; break; case 5: q->scheme = LIQUID_MODEM_PSK32; break; case 6: q->scheme = LIQUID_MODEM_PSK64; break; case 7: q->scheme = LIQUID_MODEM_PSK128; break; case 8: q->scheme = LIQUID_MODEM_PSK256; break; default: fprintf(stderr,"error: modem_create_psk(), cannot support PSK with m > 8\n"); exit(1); } // initialize basic modem structure MODEM(_init)(q, _bits_per_symbol); // compute alpha q->data.psk.alpha = M_PI/(T)(q->M); // initialize demodulation array reference unsigned int k; for (k=0; k<(q->m); k++) q->ref[k] = (1<<k) * q->data.psk.alpha; // compute phase offset (half of phase difference between symbols) q->data.psk.d_phi = M_PI*(1.0f - 1.0f/(T)(q->M)); // set modulation/demodulation functions q->modulate_func = &MODEM(_modulate_psk); q->demodulate_func = &MODEM(_demodulate_psk); // initialize symbol map q->symbol_map = (TC*)malloc(q->M*sizeof(TC)); MODEM(_init_map)(q); q->modulate_using_map = 1; // initialize soft-demodulation look-up table if (q->m >= 3) MODEM(_demodsoft_gentab)(q, 2); return q; }
// create a qpsk (quaternary phase-shift keying) modem object MODEM() MODEM(_create_qpsk)() { MODEM() q = (MODEM()) malloc( sizeof(struct MODEM(_s)) ); q->scheme = LIQUID_MODEM_QPSK; MODEM(_init)(q, 2); q->modulate_func = &MODEM(_modulate_qpsk); q->demodulate_func = &MODEM(_demodulate_qpsk); // reset and return MODEM(_reset)(q); return q; }
// create digital modem of a specific scheme and bits/symbol MODEM() MODEM(_create)(modulation_scheme _scheme) { switch (_scheme) { // Phase-shift keying (PSK) case LIQUID_MODEM_PSK2: return MODEM(_create_psk)(1); case LIQUID_MODEM_PSK4: return MODEM(_create_psk)(2); case LIQUID_MODEM_PSK8: return MODEM(_create_psk)(3); case LIQUID_MODEM_PSK16: return MODEM(_create_psk)(4); case LIQUID_MODEM_PSK32: return MODEM(_create_psk)(5); case LIQUID_MODEM_PSK64: return MODEM(_create_psk)(6); case LIQUID_MODEM_PSK128: return MODEM(_create_psk)(7); case LIQUID_MODEM_PSK256: return MODEM(_create_psk)(8); // Differential phase-shift keying (DPSK) case LIQUID_MODEM_DPSK2: return MODEM(_create_dpsk)(1); case LIQUID_MODEM_DPSK4: return MODEM(_create_dpsk)(2); case LIQUID_MODEM_DPSK8: return MODEM(_create_dpsk)(3); case LIQUID_MODEM_DPSK16: return MODEM(_create_dpsk)(4); case LIQUID_MODEM_DPSK32: return MODEM(_create_dpsk)(5); case LIQUID_MODEM_DPSK64: return MODEM(_create_dpsk)(6); case LIQUID_MODEM_DPSK128: return MODEM(_create_dpsk)(7); case LIQUID_MODEM_DPSK256: return MODEM(_create_dpsk)(8); // amplitude-shift keying (ASK) case LIQUID_MODEM_ASK2: return MODEM(_create_ask)(1); case LIQUID_MODEM_ASK4: return MODEM(_create_ask)(2); case LIQUID_MODEM_ASK8: return MODEM(_create_ask)(3); case LIQUID_MODEM_ASK16: return MODEM(_create_ask)(4); case LIQUID_MODEM_ASK32: return MODEM(_create_ask)(5); case LIQUID_MODEM_ASK64: return MODEM(_create_ask)(6); case LIQUID_MODEM_ASK128: return MODEM(_create_ask)(7); case LIQUID_MODEM_ASK256: return MODEM(_create_ask)(8); // rectangular quadrature amplitude-shift keying (QAM) case LIQUID_MODEM_QAM4: return MODEM(_create_qam)(2); case LIQUID_MODEM_QAM8: return MODEM(_create_qam)(3); case LIQUID_MODEM_QAM16: return MODEM(_create_qam)(4); case LIQUID_MODEM_QAM32: return MODEM(_create_qam)(5); case LIQUID_MODEM_QAM64: return MODEM(_create_qam)(6); case LIQUID_MODEM_QAM128: return MODEM(_create_qam)(7); case LIQUID_MODEM_QAM256: return MODEM(_create_qam)(8); // amplitude phase-shift keying (APSK) case LIQUID_MODEM_APSK4: return MODEM(_create_apsk)(2); case LIQUID_MODEM_APSK8: return MODEM(_create_apsk)(3); case LIQUID_MODEM_APSK16: return MODEM(_create_apsk)(4); case LIQUID_MODEM_APSK32: return MODEM(_create_apsk)(5); case LIQUID_MODEM_APSK64: return MODEM(_create_apsk)(6); case LIQUID_MODEM_APSK128: return MODEM(_create_apsk)(7); case LIQUID_MODEM_APSK256: return MODEM(_create_apsk)(8); // specific modems case LIQUID_MODEM_BPSK: return MODEM(_create_bpsk)(); case LIQUID_MODEM_QPSK: return MODEM(_create_qpsk)(); case LIQUID_MODEM_OOK: return MODEM(_create_ook)(); case LIQUID_MODEM_SQAM32: return MODEM(_create_sqam32)(); case LIQUID_MODEM_SQAM128: return MODEM(_create_sqam128)(); case LIQUID_MODEM_V29: return MODEM(_create_V29)(); case LIQUID_MODEM_ARB16OPT: return MODEM(_create_arb16opt)(); case LIQUID_MODEM_ARB32OPT: return MODEM(_create_arb32opt)(); case LIQUID_MODEM_ARB64OPT: return MODEM(_create_arb64opt)(); case LIQUID_MODEM_ARB128OPT: return MODEM(_create_arb128opt)(); case LIQUID_MODEM_ARB256OPT: return MODEM(_create_arb256opt)(); case LIQUID_MODEM_ARB64VT: return MODEM(_create_arb64vt)(); // arbitrary modem case LIQUID_MODEM_ARB: fprintf(stderr,"error: modem_create(), cannot create arbitrary modem (LIQUID_MODEM_ARB) without specifying constellation\n"); exit(1); // unknown modulation scheme default: fprintf(stderr,"error: modem_create(), unknown/unsupported modulation scheme : %u\n", _scheme); exit(1); } // should never get to this point, but adding return statment // to keep compiler happy return NULL; }
fprintf(stderr,"error: modem_create(), cannot create arbitrary modem (LIQUID_MODEM_ARB) without specifying constellation\n"); exit(1); // unknown modulation scheme default: fprintf(stderr,"error: modem_create(), unknown/unsupported modulation scheme : %u\n", _scheme); exit(1); } // should never get to this point, but adding return statment // to keep compiler happy return NULL; } // recreate modulation scheme, re-allocating memory as necessary MODEM() MODEM(_recreate)(MODEM() _q, modulation_scheme _scheme) { // TODO : regenerate modem only when truly necessary if (_q->scheme != _scheme) { // destroy and re-create modem MODEM(_destroy)(_q); _q = MODEM(_create)(_scheme); } // return object return _q; } // destroy a modem object void MODEM(_destroy)(MODEM() _q)
// allocate memory for 32-point symbol map q->data.sqam128.map = (TC*) malloc( 32*sizeof(TC) ); #if T == float memmove(q->data.sqam128.map, modem_arb_sqam128, 32*sizeof(TC)); #endif // set modulation, demodulation functions q->modulate_func = &MODEM(_modulate_sqam128); q->demodulate_func = &MODEM(_demodulate_sqam128); return q; } // modulate symbol with 'square' 128-QAM void MODEM(_modulate_sqam128)(MODEM() _q, unsigned int _sym_in, TC * _y) { // strip off most-significant two bits (quadrant) unsigned int quad = (_sym_in >> 5) & 0x03; // strip off least-significant 5 bits unsigned int s = _sym_in & 0x1f; TC p = _q->data.sqam128.map[s]; switch (quad) { case 0: *_y = p; return; case 1: *_y = conjf(p); return; case 2: *_y = -conjf(p); return; case 3: *_y = -p; return;
// create an apsk (amplitude/phase-shift keying) modem object MODEM() MODEM(_create_apsk)(unsigned int _bits_per_symbol) { // pointer to APSK definition container struct liquid_apsk_s * apskdef = NULL; switch (_bits_per_symbol) { case 2: apskdef = &liquid_apsk4; break; case 3: apskdef = &liquid_apsk8; break; case 4: apskdef = &liquid_apsk16; break; case 5: apskdef = &liquid_apsk32; break; case 6: apskdef = &liquid_apsk64; break; case 7: apskdef = &liquid_apsk128; break; case 8: apskdef = &liquid_apsk256; break; default: fprintf(stderr,"error: modem_create_apsk(), unsupported modulation level (%u)\n", _bits_per_symbol); exit(1); } MODEM() q = (MODEM()) malloc( sizeof(struct MODEM(_s)) ); q->scheme = apskdef->scheme; MODEM(_init)(q, _bits_per_symbol); // set APSK internals unsigned int i; q->data.apsk.num_levels = apskdef->num_levels; for (i=0; i<q->data.apsk.num_levels; i++) { q->data.apsk.p[i] = apskdef->p[i]; q->data.apsk.r[i] = apskdef->r[i]; q->data.apsk.phi[i] = apskdef->phi[i]; } // radius slicer for (i=0; i<q->data.apsk.num_levels-1; i++) q->data.apsk.r_slicer[i] = apskdef->r_slicer[i]; // copy symbol map q->data.apsk.map = (unsigned char *) malloc(q->M*sizeof(unsigned char)); memmove(q->data.apsk.map, apskdef->map, q->M*sizeof(unsigned char)); // set modulation/demodulation function pointers q->modulate_func = &MODEM(_modulate_apsk); q->demodulate_func = &MODEM(_demodulate_apsk); // initialize soft-demodulation look-up table switch (q->m) { case 2: MODEM(_demodsoft_gentab)(q, 3); break; case 3: MODEM(_demodsoft_gentab)(q, 3); break; case 4: MODEM(_demodsoft_gentab)(q, 4); break; case 5: MODEM(_demodsoft_gentab)(q, 4); break; case 6: MODEM(_demodsoft_gentab)(q, 4); break; case 7: MODEM(_demodsoft_gentab)(q, 5); break; case 8: MODEM(_demodsoft_gentab)(q, 5); break; default:; } // initialize symbol map q->symbol_map = (TC*)malloc(q->M*sizeof(TC)); MODEM(_init_map)(q); q->modulate_using_map = 1; return q; }
case 6: MODEM(_demodsoft_gentab)(q, 4); break; case 7: MODEM(_demodsoft_gentab)(q, 5); break; case 8: MODEM(_demodsoft_gentab)(q, 5); break; default:; } // initialize symbol map q->symbol_map = (TC*)malloc(q->M*sizeof(TC)); MODEM(_init_map)(q); q->modulate_using_map = 1; return q; } // modulate APSK void MODEM(_modulate_apsk)(MODEM() _q, unsigned int _sym_in, TC * _y) { if (_sym_in >= _q->M) { fprintf(stderr,"error: modem_modulate_apsk(), input symbol exceeds maximum\n"); return; } // map input symbol to constellation symbol unsigned int i; unsigned int s = _q->data.apsk.map[_sym_in]; // determine in which level the symbol is located unsigned int p=0; // level unsigned int t=0; // accumulated number of points per level
MODEM() q = (MODEM()) malloc( sizeof(struct MODEM(_s)) ); q->scheme = LIQUID_MODEM_ARB; MODEM(_init)(q, _bits_per_symbol); q->M = q->M; q->symbol_map = (TC*) calloc( q->M, sizeof(TC) ); q->modulate_func = &MODEM(_modulate_arb); q->demodulate_func = &MODEM(_demodulate_arb); return q; } // modulate arbitrary modem type void MODEM(_modulate_arb)(MODEM() _q, unsigned int _sym_in, TC * _y) { if (_sym_in >= _q->M) { fprintf(stderr,"error: modulate_arb(), input symbol exceeds maximum\n"); exit(1); } // map sample directly to output *_y = _q->symbol_map[_sym_in]; } // demodulate arbitrary modem type void MODEM(_demodulate_arb)(MODEM() _q, TC _x,