Beispiel #1
0
// write OFDM symbol
//  _q      :   framing generator object
//  _x      :   input symbols, [size: _M x 1]
//  _y      :   output samples, [size: _M x 1]
void ofdmframegen_writesymbol(ofdmframegen    _q,
                              float complex * _x,
                              float complex * _y)
{
    // move frequency data to internal buffer
    unsigned int i;
    unsigned int k;
    int sctype;
    for (i=0; i<_q->M; i++) {
        // start at mid-point (effective fftshift)
        k = (i + _q->M/2) % _q->M;

        sctype = _q->p[k];
        if (sctype==OFDMFRAME_SCTYPE_NULL) {
            // disabled subcarrier
            _q->X[k] = 0.0f;
        } else if (sctype==OFDMFRAME_SCTYPE_PILOT) {
            // pilot subcarrier
            _q->X[k] = (msequence_advance(_q->ms_pilot) ? 1.0f : -1.0f) * _q->g_data;
        } else {
            // data subcarrier
            _q->X[k] = _x[k] * _q->g_data;
        }

        //printf("X[%3u] = %12.8f + j*%12.8f;\n",i+1,crealf(_q->X[i]),cimagf(_q->X[i]));
    }

    // execute transform
    FFT_EXECUTE(_q->ifft);

    // copy result to output, adding cyclic prefix and tapering window
    ofdmframegen_gensymbol(_q, _y);
}
Beispiel #2
0
void bpacketsync_assemble_pnsequence(bpacketsync _q)
{
    // reset m-sequence generator
    msequence_reset(_q->ms);

    unsigned int i;
    for (i=0; i<8*_q->pnsequence_len; i++)
        bsequence_push(_q->bpn, msequence_advance(_q->ms));
}
Beispiel #3
0
// TODO : test this method
BSYNC() BSYNC(_create_msequence)(unsigned int _g,
                                 unsigned int _k)
{
    // validate input
    if (_k == 0) {
        fprintf(stderr,"bsync_xxxt_create_msequence(), samples/symbol must be greater than zero\n");
        exit(1);
    }
    unsigned int m = liquid_msb_index(_g) - 1;

    // create/initialize msequence
    msequence ms = msequence_create(m, _g, 1);

    BSYNC() fs = (BSYNC()) malloc(sizeof(struct BSYNC(_s)));
    unsigned int n = msequence_get_length(ms);

    fs->sync_i  = bsequence_create(n * _k);
#ifdef TC_COMPLEX
    fs->sync_q  = bsequence_create(n * _k);
#endif

    fs->sym_i   = bsequence_create(n * _k);
#ifdef TI_COMPLEX
    fs->sym_q   = bsequence_create(n * _k);
#endif

    msequence_reset(ms);

#if 0
    bsequence_init_msequence(fs->sync_i,ms);
#ifdef TC_COMPLEX
    msequence_reset(ms);
    bsequence_init_msequence(fs->sync_q,ms);
#endif
#else
    unsigned int i;
    unsigned int j;
    for (i=0; i<n; i++) {
        unsigned int bit = msequence_advance(ms);

        for (j=0; j<_k; j++) {
            bsequence_push(fs->sync_i, bit);
#ifdef TC_COMPLEX
            bsequence_push(fs->sync_q, bit);
#endif
        }
    }
#endif

    msequence_destroy(ms);

    fs->n = _k*n;

    return fs;
}
Beispiel #4
0
// generate pseudo-random symbol from shift register
//  _ms     :   m-sequence object
//  _bps    :   bits per symbol of output
unsigned int msequence_generate_symbol(msequence _ms,
                                       unsigned int _bps)
{
    unsigned int i;
    unsigned int s = 0;
    for (i=0; i<_bps; i++) {
        s <<= 1;
        s |= msequence_advance(_ms);
    }
    return s;
}
Beispiel #5
0
// generate p/n sequence
void bpacketgen_assemble_pnsequence(bpacketgen _q)
{
    // reset m-sequence generator
    msequence_reset(_q->ms);

    unsigned int i;
    unsigned int j;
    for (i=0; i<_q->pnsequence_len; i++) {
        unsigned char byte = 0;
        for (j=0; j<8; j++) {
            byte <<= 1;
            byte |= msequence_advance(_q->ms);
        }
        _q->pnsequence[i] = byte;
    }
}
Beispiel #6
0
// initialize a bsequence object on an msequence object
//  _bs     :   bsequence object
//  _ms     :   msequence object
void bsequence_init_msequence(bsequence _bs,
                              msequence _ms)
{
#if 0
    if (_ms->n > LIQUID_MAX_MSEQUENCE_LENGTH) {
        fprintf(stderr,"error: bsequence_init_msequence(), msequence length exceeds maximum\n");
        exit(1);
    }
#endif

    // clear binary sequence
    bsequence_clear(_bs);

    unsigned int i;
    for (i=0; i<(_ms->n); i++)
        bsequence_push(_bs, msequence_advance(_ms));
}
Beispiel #7
0
void gmskframegen_write_preamble(gmskframegen    _q,
                                 float complex * _y)
{
    unsigned char bit = msequence_advance(_q->ms_preamble);
    gmskmod_modulate(_q->mod, bit, _y);

    // apply ramping window to first 'm' symbols
    if (_q->symbol_counter < _q->m) {
        unsigned int i;
        for (i=0; i<_q->k; i++)
            _y[i] *= hamming(_q->symbol_counter*_q->k + i, 2*_q->m*_q->k);
    }

    _q->symbol_counter++;

    if (_q->symbol_counter == _q->preamble_len) {
        msequence_reset(_q->ms_preamble);
        _q->symbol_counter = 0;
        _q->state = STATE_HEADER;
    }
}
Beispiel #8
0
// recover symbol, correcting for gain, pilot phase, etc.
void ofdmframesync_rxsymbol(ofdmframesync _q)
{
    // apply gain
    unsigned int i;
    for (i=0; i<_q->M; i++)
        _q->X[i] *= _q->R[i];

    // polynomial curve-fit
    float x_phase[_q->M_pilot];
    float y_phase[_q->M_pilot];
    float p_phase[2];

    unsigned int n=0;
    unsigned int k;
    float complex pilot = 1.0f;
    for (i=0; i<_q->M; i++) {

        // start at mid-point (effective fftshift)
        k = (i + _q->M2) % _q->M;

        if (_q->p[k]==OFDMFRAME_SCTYPE_PILOT) {
            if (n == _q->M_pilot) {
                fprintf(stderr,"warning: ofdmframesync_rxsymbol(), pilot subcarrier mismatch\n");
                return;
            }
            pilot = (msequence_advance(_q->ms_pilot) ? 1.0f : -1.0f);
#if 0
            printf("pilot[%3u] = %12.4e + j*%12.4e (expected %12.4e + j*%12.4e)\n",
                    k,
                    crealf(_q->X[k]), cimagf(_q->X[k]),
                    crealf(pilot),    cimagf(pilot));
#endif
            // store resulting...
            x_phase[n] = (k > _q->M2) ? (float)k - (float)(_q->M) : (float)k;
            y_phase[n] = cargf(_q->X[k]*conjf(pilot));

            // update counter
            n++;

        }
    }

    if (n != _q->M_pilot) {
        fprintf(stderr,"warning: ofdmframesync_rxsymbol(), pilot subcarrier mismatch\n");
        return;
    }

    // try to unwrap phase
    for (i=1; i<_q->M_pilot; i++) {
        while ((y_phase[i] - y_phase[i-1]) >  M_PI)
            y_phase[i] -= 2*M_PI;
        while ((y_phase[i] - y_phase[i-1]) < -M_PI)
            y_phase[i] += 2*M_PI;
    }

    // fit phase to 1st-order polynomial (2 coefficients)
    polyf_fit(x_phase, y_phase, _q->M_pilot, p_phase, 2);

    // filter slope estimate (timing offset)
    float alpha = 0.3f;
    p_phase[1] = alpha*p_phase[1] + (1-alpha)*_q->p1_prime;
    _q->p1_prime = p_phase[1];

#if DEBUG_OFDMFRAMESYNC
    if (_q->debug_enabled) {
        // save pilots
        memmove(_q->px, x_phase, _q->M_pilot*sizeof(float));
        memmove(_q->py, y_phase, _q->M_pilot*sizeof(float));

        // NOTE : swapping values for octave
        _q->p_phase[0] = p_phase[1];
        _q->p_phase[1] = p_phase[0];

        windowf_push(_q->debug_pilot_0, p_phase[0]);
        windowf_push(_q->debug_pilot_1, p_phase[1]);
    }
#endif

    // compensate for phase offset
    // TODO : find more computationally efficient way to do this
    for (i=0; i<_q->M; i++) {
        // only apply to data/pilot subcarriers
        if (_q->p[i] == OFDMFRAME_SCTYPE_NULL) {
            _q->X[i] = 0.0f;
        } else {
            float fx    = (i > _q->M2) ? (float)i - (float)(_q->M) : (float)i;
            float theta = polyf_val(p_phase, 2, fx);
            _q->X[i] *= liquid_cexpjf(-theta);
        }
    }

    // adjust NCO frequency based on differential phase
    if (_q->num_symbols > 0) {
        // compute phase error (unwrapped)
        float dphi_prime = p_phase[0] - _q->phi_prime;
        while (dphi_prime >  M_PI) dphi_prime -= M_2_PI;
        while (dphi_prime < -M_PI) dphi_prime += M_2_PI;

        // adjust NCO proportionally to phase error
        nco_crcf_adjust_frequency(_q->nco_rx, 1e-3f*dphi_prime);
    }
    // set internal phase state
    _q->phi_prime = p_phase[0];
    //printf("%3u : theta : %12.8f, nco freq: %12.8f\n", _q->num_symbols, p_phase[0], nco_crcf_get_frequency(_q->nco_rx));
    
    // increment symbol counter
    _q->num_symbols++;

#if 0
    for (i=0; i<_q->M_pilot; i++)
        printf("x_phase(%3u) = %12.8f; y_phase(%3u) = %12.8f;\n", i+1, x_phase[i], i+1, y_phase[i]);
    printf("poly : p0=%12.8f, p1=%12.8f\n", p_phase[0], p_phase[1]);
#endif
}
Beispiel #9
0
// create GMSK frame synchronizer
//  _callback   :   callback function
//  _userdata   :   user data pointer passed to callback function
gmskframesync gmskframesync_create(framesync_callback _callback,
                                   void *             _userdata)
{
    gmskframesync q = (gmskframesync) malloc(sizeof(struct gmskframesync_s));
    q->callback = _callback;
    q->userdata = _userdata;
    q->k        = 2;        // samples/symbol
    q->m        = 3;        // filter delay (symbols)
    q->BT       = 0.5f;     // filter bandwidth-time product

#if GMSKFRAMESYNC_PREFILTER
    // create default low-pass Butterworth filter
    q->prefilter = iirfilt_crcf_create_lowpass(3, 0.5f*(1 + q->BT) / (float)(q->k));
#endif

    unsigned int i;

    // frame detector
    q->preamble_len = 63;
    q->preamble_pn = (float*)malloc(q->preamble_len*sizeof(float));
    q->preamble_rx = (float*)malloc(q->preamble_len*sizeof(float));
    float complex preamble_samples[q->preamble_len*q->k];
    msequence ms = msequence_create(6, 0x6d, 1);
    gmskmod mod = gmskmod_create(q->k, q->m, q->BT);

    for (i=0; i<q->preamble_len + q->m; i++) {
        unsigned char bit = msequence_advance(ms);

        // save p/n sequence
        if (i < q->preamble_len)
            q->preamble_pn[i] = bit ? 1.0f : -1.0f;
        
        // modulate/interpolate
        if (i < q->m) gmskmod_modulate(mod, bit, &preamble_samples[0]);
        else          gmskmod_modulate(mod, bit, &preamble_samples[(i-q->m)*q->k]);
    }

    gmskmod_destroy(mod);
    msequence_destroy(ms);

#if 0
    // print sequence
    for (i=0; i<q->preamble_len*q->k; i++)
        printf("preamble(%3u) = %12.8f + j*%12.8f;\n", i+1, crealf(preamble_samples[i]), cimagf(preamble_samples[i]));
#endif
    // create frame detector
    float threshold = 0.5f;     // detection threshold
    float dphi_max  = 0.05f;    // maximum carrier offset allowable
    q->frame_detector = detector_cccf_create(preamble_samples, q->preamble_len*q->k, threshold, dphi_max);
    q->buffer = windowcf_create(q->k*(q->preamble_len+q->m));

    // create symbol timing recovery filters
    q->npfb = 32;   // number of filters in the bank
    q->mf   = firpfb_rrrf_create_rnyquist( LIQUID_FIRFILT_GMSKRX,q->npfb,q->k,q->m,q->BT);
    q->dmf  = firpfb_rrrf_create_drnyquist(LIQUID_FIRFILT_GMSKRX,q->npfb,q->k,q->m,q->BT);

    // create down-coverters for carrier phase tracking
    q->nco_coarse = nco_crcf_create(LIQUID_NCO);

    // create/allocate header objects/arrays
    q->header_mod = (unsigned char*)malloc(GMSKFRAME_H_SYM*sizeof(unsigned char));
    q->header_enc = (unsigned char*)malloc(GMSKFRAME_H_ENC*sizeof(unsigned char));
    q->header_dec = (unsigned char*)malloc(GMSKFRAME_H_DEC*sizeof(unsigned char));
    q->p_header   = packetizer_create(GMSKFRAME_H_DEC,
                                      GMSKFRAME_H_CRC,
                                      GMSKFRAME_H_FEC,
                                      LIQUID_FEC_NONE);

    // create/allocate payload objects/arrays
    q->payload_dec_len = 1;
    q->check           = LIQUID_CRC_32;
    q->fec0            = LIQUID_FEC_NONE;
    q->fec1            = LIQUID_FEC_NONE;
    q->p_payload = packetizer_create(q->payload_dec_len,
                                     q->check,
                                     q->fec0,
                                     q->fec1);
    q->payload_enc_len = packetizer_get_enc_msg_len(q->p_payload);
    q->payload_dec = (unsigned char*) malloc(q->payload_dec_len*sizeof(unsigned char));
    q->payload_enc = (unsigned char*) malloc(q->payload_enc_len*sizeof(unsigned char));

#if DEBUG_GMSKFRAMESYNC
    // debugging structures
    q->debug_enabled         = 0;
    q->debug_objects_created = 0;
    q->debug_x               = NULL;
    q->debug_fi              = NULL;
    q->debug_mf              = NULL;
    q->debug_framesyms       = NULL;
#endif

    // reset synchronizer
    gmskframesync_reset(q);

    // return synchronizer object
    return q;
}
Beispiel #10
0
// create flexframesync object
//  _callback       :   callback function invoked when frame is received
//  _userdata       :   user-defined data object passed to callback
flexframesync flexframesync_create(framesync_callback _callback,
                                   void *             _userdata)
{
    flexframesync q = (flexframesync) malloc(sizeof(struct flexframesync_s));
    q->callback = _callback;
    q->userdata = _userdata;

    unsigned int i;

    // generate p/n sequence
    msequence ms = msequence_create(6, 0x005b, 1);
    for (i=0; i<64; i++)
        q->preamble_pn[i] = (msequence_advance(ms)) ? 1.0f : -1.0f;
    msequence_destroy(ms);

    // interpolate p/n sequence with matched filter
    q->k    = 2;        // samples/symbol
    q->m    = 7;        // filter delay (symbols)
    q->beta = 0.25f;    // excess bandwidth factor
    float complex seq[q->k*64];
    firinterp_crcf interp = firinterp_crcf_create_rnyquist(LIQUID_FIRFILT_ARKAISER,q->k,q->m,q->beta,0);
    for (i=0; i<64+q->m; i++) {
        // compensate for filter delay
        if (i < q->m) firinterp_crcf_execute(interp, q->preamble_pn[i],    &seq[0]);
        else          firinterp_crcf_execute(interp, q->preamble_pn[i%64], &seq[q->k*(i-q->m)]);
    }
    firinterp_crcf_destroy(interp);

    // create frame detector
    float threshold = 0.4f;     // detection threshold
    float dphi_max  = 0.05f;    // maximum carrier offset allowable
    q->frame_detector = detector_cccf_create(seq, q->k*64, threshold, dphi_max);
    q->buffer = windowcf_create(q->k*(64+q->m));

    // create symbol timing recovery filters
    q->npfb = 32;   // number of filters in the bank
    q->mf   = firpfb_crcf_create_rnyquist(LIQUID_FIRFILT_ARKAISER, q->npfb,q->k,q->m,q->beta);
    q->dmf  = firpfb_crcf_create_drnyquist(LIQUID_FIRFILT_ARKAISER,q->npfb,q->k,q->m,q->beta);

    // create down-coverters for carrier phase tracking
    q->nco_coarse = nco_crcf_create(LIQUID_NCO);
    q->nco_fine   = nco_crcf_create(LIQUID_VCO);
    nco_crcf_pll_set_bandwidth(q->nco_fine, 0.05f);
    
    // create header objects
    q->demod_header = modem_create(LIQUID_MODEM_BPSK);
    q->p_header   = packetizer_create(FLEXFRAME_H_DEC,
                                      FLEXFRAME_H_CRC,
                                      FLEXFRAME_H_FEC0,
                                      FLEXFRAME_H_FEC1);
    assert(packetizer_get_enc_msg_len(q->p_header)==FLEXFRAME_H_ENC);

    // frame properties (default values to be overwritten when frame
    // header is received and properly decoded)
    q->ms_payload      = LIQUID_MODEM_QPSK;
    q->bps_payload     = 2;
    q->payload_dec_len = 1;
    q->check           = LIQUID_CRC_NONE;
    q->fec0            = LIQUID_FEC_NONE;
    q->fec1            = LIQUID_FEC_NONE;

    // create payload objects (overridden by received properties)
    q->demod_payload   = modem_create(LIQUID_MODEM_QPSK);
    q->p_payload       = packetizer_create(q->payload_dec_len, q->check, q->fec0, q->fec1);
    q->payload_enc_len = packetizer_get_enc_msg_len(q->p_payload);
    q->payload_mod_len = 4 * q->payload_enc_len;
    q->payload_mod     = (unsigned char*) malloc(q->payload_mod_len*sizeof(unsigned char));
    q->payload_enc     = (unsigned char*) malloc(q->payload_enc_len*sizeof(unsigned char));
    q->payload_dec     = (unsigned char*) malloc(q->payload_dec_len*sizeof(unsigned char));

#if DEBUG_FLEXFRAMESYNC
    // set debugging flags, objects to NULL
    q->debug_enabled         = 0;
    q->debug_objects_created = 0;
    q->debug_x               = NULL;
#endif

    // reset state
    flexframesync_reset(q);

    return q;
}
Beispiel #11
0
// 
// AUTOTEST: static channel filter, blind equalization on QPSK symbols
//
void autotest_eqlms_cccf_blind()
{
    // parameters
    float           tol         = 2e-2f;    // error tolerance
    unsigned int    k           =  2;       // samples/symbol
    unsigned int    m           =  7;       // filter delay
    float           beta        =  0.3f;    // excess bandwidth factor
    unsigned int    p           =  7;       // equalizer order
    float           mu          =  0.7f;    // equalizer bandwidth
    unsigned int    num_symbols = 400;      // number of symbols to observe

    // create sequence generator for repeatability
    msequence ms = msequence_create_default(12);

    // create interpolating filter
    firinterp_crcf interp = firinterp_crcf_create_prototype(LIQUID_FIRFILT_ARKAISER,k,m,beta,0);

    // create equalizer
    eqlms_cccf eq = eqlms_cccf_create_rnyquist(LIQUID_FIRFILT_ARKAISER,k,p,beta,0);
    eqlms_cccf_set_bw(eq, mu);

    // create channel filter
    float complex h[5] = {
        { 1.00f,  0.00f},
        { 0.00f, -0.01f},
        {-0.11f,  0.02f},
        { 0.02f,  0.01f},
        {-0.09f, -0.04f} };
    firfilt_cccf fchannel = firfilt_cccf_create(h,5);

    // arrays
    float complex buf[k];               // filter buffer
    float complex sym_in [num_symbols]; // input symbols
    float complex sym_out[num_symbols]; // equalized symbols

    // run equalization
    unsigned int i;
    unsigned int j;
    for (i=0; i<num_symbols; i++) {
        // generate input symbol
        sym_in[i] = ( msequence_advance(ms) ? M_SQRT1_2 : -M_SQRT1_2 ) +
                    ( msequence_advance(ms) ? M_SQRT1_2 : -M_SQRT1_2 ) * _Complex_I;

        // interpolate
        firinterp_crcf_execute(interp, sym_in[i], buf);

        // apply channel filter (in place)
        firfilt_cccf_execute_block(fchannel, buf, k, buf);

        // apply equalizer as filter
        for (j=0; j<k; j++) {
            eqlms_cccf_push(eq, buf[j]);

            // decimate by k
            if ( (j%k) != 0 ) continue;

            eqlms_cccf_execute(eq, &sym_out[i]);

            // update equalization (blind operation)
            if (i > m + p)
                eqlms_cccf_step(eq, sym_out[i]/cabsf(sym_out[i]), sym_out[i]);
        }
    }

    // compare input, output
    unsigned int settling_delay = 285;
    for (i=m+p; i<num_symbols; i++) {
        // compensate for delay
        j = i-m-p;

        // absolute error
        float error = cabsf(sym_in[j]-sym_out[i]);

        if (liquid_autotest_verbose) {
            printf("x[%3u] = {%12.8f,%12.8f}, y[%3u] = {%12.8f,%12.8f}, error=%12.8f %s\n",
                    j, crealf(sym_in [j]), cimagf(sym_in [j]),
                    i, crealf(sym_out[i]), cimagf(sym_out[i]),
                    error, error > tol ? "*" : "");
            if (i == settling_delay + m + p)
                printf("--- start of test ---\n");
        }

        // check error
        if (i > settling_delay + m + p)
            CONTEND_DELTA(error, 0.0f, tol);
    }

    // clean up objects
    firfilt_cccf_destroy(fchannel);
    eqlms_cccf_destroy(eq);
    msequence_destroy(ms);
}
Beispiel #12
0
// create flexframesync object
//  _callback       :   callback function invoked when frame is received
//  _userdata       :   user-defined data object passed to callback
flexframesync flexframesync_create(framesync_callback _callback,
                                   void *             _userdata)
{
    flexframesync q = (flexframesync) malloc(sizeof(struct flexframesync_s));
    q->callback = _callback;
    q->userdata = _userdata;
    q->m        = 7;    // filter delay (symbols)
    q->beta     = 0.3f; // excess bandwidth factor

    unsigned int i;

    // generate p/n sequence
    q->preamble_pn = (float complex*) malloc(64*sizeof(float complex));
    q->preamble_rx = (float complex*) malloc(64*sizeof(float complex));
    msequence ms = msequence_create(7, 0x0089, 1);
    for (i=0; i<64; i++) {
        q->preamble_pn[i] = (msequence_advance(ms) ? M_SQRT1_2 : -M_SQRT1_2) +
                            (msequence_advance(ms) ? M_SQRT1_2 : -M_SQRT1_2)*_Complex_I;
    }
    msequence_destroy(ms);

    // create frame detector
    unsigned int k = 2; // samples/symbol
    q->detector = qdetector_cccf_create_linear(q->preamble_pn, 64, LIQUID_FIRFILT_ARKAISER, k, q->m, q->beta);
    qdetector_cccf_set_threshold(q->detector, 0.5f);

    // create symbol timing recovery filters
    q->npfb = 32;   // number of filters in the bank
    q->mf   = firpfb_crcf_create_rnyquist(LIQUID_FIRFILT_ARKAISER, q->npfb,k,q->m,q->beta);

#if FLEXFRAMESYNC_ENABLE_EQ
    // create equalizer
    unsigned int p = 3;
    q->equalizer = eqlms_cccf_create_lowpass(2*k*p+1, 0.4f);
    eqlms_cccf_set_bw(q->equalizer, 0.05f);
#endif

    // create down-coverters for carrier phase tracking
    q->mixer = nco_crcf_create(LIQUID_NCO);
    q->pll   = nco_crcf_create(LIQUID_NCO);
    nco_crcf_pll_set_bandwidth(q->pll, 1e-4f); // very low bandwidth
    
    // header demodulator/decoder
    q->header_dec     = (unsigned char *) malloc(FLEXFRAME_H_DEC*sizeof(unsigned char));
    q->header_decoder = qpacketmodem_create();
    qpacketmodem_configure(q->header_decoder,
                           FLEXFRAME_H_DEC,
                           FLEXFRAME_H_CRC,
                           FLEXFRAME_H_FEC0,
                           FLEXFRAME_H_FEC1,
                           LIQUID_MODEM_QPSK);
    q->header_mod_len = qpacketmodem_get_frame_len(q->header_decoder);
    q->header_mod     = (float complex*) malloc(q->header_mod_len*sizeof(float complex));

    // header pilot synchronizer
    q->header_pilotsync = qpilotsync_create(q->header_mod_len, 16);
    q->header_sym_len   = qpilotsync_get_frame_len(q->header_pilotsync);
    q->header_sym       = (float complex*) malloc(q->header_sym_len*sizeof(float complex));
    
    // payload demodulator for phase recovery
    q->payload_demod = modem_create(LIQUID_MODEM_QPSK);

    // create payload demodulator/decoder object
    q->payload_dec_len = 64;
    int check      = LIQUID_CRC_24;
    int fec0       = LIQUID_FEC_NONE;
    int fec1       = LIQUID_FEC_GOLAY2412;
    int mod_scheme = LIQUID_MODEM_QPSK;
    q->payload_decoder = qpacketmodem_create();
    qpacketmodem_configure(q->payload_decoder, q->payload_dec_len, check, fec0, fec1, mod_scheme);
    //qpacketmodem_print(q->payload_decoder);
    //assert( qpacketmodem_get_frame_len(q->payload_decoder)==600 );
    q->payload_sym_len = qpacketmodem_get_frame_len(q->payload_decoder);

    // allocate memory for payload symbols and recovered data bytes
    q->payload_sym = (float complex*) malloc(q->payload_sym_len*sizeof(float complex));
    q->payload_dec = (unsigned char*) malloc(q->payload_dec_len*sizeof(unsigned char));

    // reset global data counters
    flexframesync_reset_framedatastats(q);

#if DEBUG_FLEXFRAMESYNC
    // set debugging flags, objects to NULL
    q->debug_enabled         = 0;
    q->debug_objects_created = 0;
    q->debug_qdetector_flush = 0;
    q->debug_x               = NULL;
#endif

    // reset state and return
    flexframesync_reset(q);
    return q;
}
int main(int argc, char*argv[]) {
    // options
    unsigned int m=5;       // shift register length, n=2^m - 1
    char filename[64] = ""; // output filename

    int dopt;
    while ((dopt = getopt(argc,argv,"uhm:f:")) != EOF) {
        switch (dopt) {
        case 'u':
        case 'h':   usage();            return 0;
        case 'm':   m = atoi(optarg);   break;
        case 'f':
            // copy output filename string
            strncpy(filename,optarg,64);
            filename[63] = '\0';
            break;
        default:
            exit(1);
        }
    }

    // ensure output filename is set
    if (strcmp(filename,"")==0) {
        fprintf(stderr,"error: %s, filename not set\n", argv[0]);
        exit(1);
    }

    // validate m
    if (m < 2) {
        fprintf(stderr,"error: %s, m is out of range\n", argv[0]);
        exit(1);
    }

    // create and initialize m-sequence
    msequence ms = msequence_create_default(m);
    msequence_print(ms);
    unsigned int n = msequence_get_length(ms);
    unsigned int sequence[n];   // sequence
    signed int rxx[n];          // auto-correlation
    
    // initialize sequence
    unsigned int i;
    for (i=0; i<n; i++)
        sequence[i] = msequence_advance(ms);

    // reset sequence
    msequence_reset(ms);

    // create and initialize first binary sequence on m-sequence
    bsequence bs1 = bsequence_create(n);
    bsequence_init_msequence(bs1, ms);

    // create and initialize second binary sequence on same m-sequence
    bsequence bs2 = bsequence_create(n);
    bsequence_init_msequence(bs2, ms);

    // when sequences are aligned, autocorrelation is equal to length
    unsigned int k=0;
    rxx[k++] = 2*bsequence_correlate(bs1, bs2) - n;

    // when sequences are misaligned, autocorrelation is equal to -1
    for (i=0; i<n-1; i++) {
        bsequence_push(bs2, msequence_advance(ms));
        rxx[k++] = 2*bsequence_correlate(bs1, bs2)-n;
    }

    // clean up memory
    bsequence_destroy(bs1);
    bsequence_destroy(bs2);
    msequence_destroy(ms);

    // 
    // generate auto-correlation plot
    //

    // open output file
    FILE * fid = fopen(filename,"w");
    if (fid == NULL) {
        fprintf(stderr,"error: %s, could not open file \"%s\" for writing.\n", argv[0], filename);
        exit(1);
    }
    // print header
    fprintf(fid,"# %s : auto-generated file (do not edit)\n", filename);
    fprintf(fid,"# invoked as :");
    for (i=0; i<argc; i++)
        fprintf(fid," %s",argv[i]);
    fprintf(fid,"reset\n");
    fprintf(fid,"set terminal postscript eps enhanced color solid rounded\n");
    fprintf(fid,"set xrange [-1:%u];\n", n+1);
    fprintf(fid,"set size ratio 0.3\n");
    fprintf(fid,"set xlabel 'delay (number of samples)'\n");
    fprintf(fid,"set nokey # disable legned\n");
    //fprintf(fid,"set grid xtics ytics\n");
    //fprintf(fid,"set grid linetype 1 linecolor rgb '%s' lw 1\n", LIQUID_DOC_COLOR_GRID);
    fprintf(fid,"set multiplot layout 2,1 scale 1.0,1.0\n");

    fprintf(fid,"# sequence\n");
    fprintf(fid,"set ylabel 'sequence'\n");
    fprintf(fid,"set yrange [-0.1:1.1]\n");
    fprintf(fid,"plot '-' using 1:2 with steps linetype 1 linewidth 4 linecolor rgb '%s'\n",LIQUID_DOC_COLOR_BLUE);
    for (i=0; i<n; i++) {
        fprintf(fid,"  %6u %6u\n", i, sequence[i]);
    }
    fprintf(fid,"e\n");

    fprintf(fid,"# auto-correlation\n");
    fprintf(fid,"set ylabel 'auto-correlation'\n");
    fprintf(fid,"set yrange [%f:1.1]\n", -5.0f / (float)n);
    fprintf(fid,"plot '-' using 1:2 with lines linetype 1 linewidth 4 linecolor rgb '%s'\n",LIQUID_DOC_COLOR_GREEN);
    for (i=0; i<n; i++) {
        fprintf(fid,"  %6u %12.4e\n", i, (float)rxx[i] / (float)n);
    }
    fprintf(fid,"e\n");
    fprintf(fid,"unset multiplot\n");

    // close output file
    fclose(fid);
    printf("results written to %s.\n", filename);

    return 0;
}
void ofdmoqamframe64sync_rxpayload(ofdmoqamframe64sync _q,
                                   float complex * _Y0,
                                   float complex * _Y1)
{
    unsigned int j=0;
    unsigned int t=0;
    int sctype;
    unsigned int pilot_phase = msequence_advance(_q->ms_pilot);

    // gain correction (equalizer)
    unsigned int i;
    for (i=0; i<_q->num_subcarriers; i++) {
        _Y0[i] *= _q->G[i];// * _q->zeta;
        _Y1[i] *= _q->G[i];// * _q->zeta;
    }

    // TODO : extract pilots
    for (i=0; i<_q->num_subcarriers; i++) {
        sctype = ofdmoqamframe64_getsctype(i);
        if (sctype==OFDMOQAMFRAME64_SCTYPE_PILOT) {
            // pilot subcarrier : use p/n sequence for pilot phase
            float complex y0 = ((i%2)==0 ? _Y0[i] : _Y1[i]) / _q->zeta;
            float complex y1 = ((i%2)==0 ? _Y1[i] : _Y0[i]) / _q->zeta;
            float complex p = (pilot_phase ? 1.0f : -1.0f);
            float phi_hat =
            ofdmoqamframe64sync_estimate_pilot_phase(y0,y1,p);
            _q->y_phase[t] = phi_hat;
            t++;
#if DEBUG_OFDMOQAMFRAME64SYNC_PRINT
            printf("i = %u\n", i);
            printf("y0 = %12.8f + j*%12.8f;\n", crealf(y0),cimagf(y0));
            printf("y1 = %12.8f + j*%12.8f;\n", crealf(y1),cimagf(y1));
            printf("phi_hat = %12.8f\n", phi_hat);
#endif
            /*
            printf("exiting prematurely\n");
            ofdmoqamframe64sync_destroy(_q);
            exit(1);
            */
        }
    }
    assert(t==4);
 
    // pilot phase correction
    /*
    _q->y_phase[0] = cargf(_q->X[11]);  // -21
    _q->y_phase[1] = cargf(_q->X[25]);  //  -7
    _q->y_phase[2] = cargf(_q->X[39]);  //   7
    _q->y_phase[3] = cargf(_q->X[53]);  //  21
    */

    // try to unwrap phase
    for (i=1; i<4; i++) {
        while ((_q->y_phase[i] - _q->y_phase[i-1]) >  M_PI)
            _q->y_phase[i] -= 2*M_PI;
        while ((_q->y_phase[i] - _q->y_phase[i-1]) < -M_PI)
            _q->y_phase[i] += 2*M_PI;
    }

    // fit phase to 1st-order polynomial (2 coefficients)
    polyf_fit(_q->x_phase, _q->y_phase, 4, _q->p_phase, 2);

    //nco_crcf_step(_q->nco_pilot);
    float theta_hat = nco_crcf_get_phase(_q->nco_pilot);
    float phase_error = _q->p_phase[0] - theta_hat;
    while (phase_error >  M_PI) phase_error -= 2.0f*M_PI;
    while (phase_error < -M_PI) phase_error += 2.0f*M_PI;
    pll_step(_q->pll_pilot, _q->nco_pilot, 0.1f*phase_error);

#if DEBUG_OFDMOQAMFRAME64SYNC_PRINT
    // print phase results
    for (i=0; i<4; i++) {
        printf("x(%3u) = %12.8f; y(%3u) = %12.8f;\n", i+1, _q->x_phase[i], i+1, _q->y_phase[i]);
    }
    printf("p(1) = %12.8f\n", _q->p_phase[0]);
    printf("p(2) = %12.8f\n", _q->p_phase[1]);
#endif

#if DEBUG_OFDMOQAMFRAME64SYNC
    windowf_push(_q->debug_pilotphase,      _q->p_phase[0]);
    windowf_push(_q->debug_pilotphase_hat,  theta_hat);
#endif

    // compensate for phase shift due to timing offset
    float theta;
    _q->p_phase[0] = theta_hat;
    _q->p_phase[1] = 0.0f;
    for (i=0; i<_q->num_subcarriers; i++) {
        // TODO : compute phase for delayed symbol (different from non-delayed symbol)
        theta = polyf_val(_q->p_phase, 2, (float)(i)-32.0f);
        _Y0[i] *= liquid_cexpjf(-theta);
        _Y1[i] *= liquid_cexpjf(-theta);
    }
    nco_crcf_step(_q->nco_pilot);

    // strip data subcarriers
    for (i=0; i<_q->num_subcarriers; i++) {
        sctype = ofdmoqamframe64_getsctype(i);
        if (sctype==OFDMOQAMFRAME64_SCTYPE_NULL) {
            // disabled subcarrier
        } else if (sctype==OFDMOQAMFRAME64_SCTYPE_PILOT) {
            // pilot subcarrier
        } else {
            // data subcarrier
            if ((i%2)==0) {
                // even subcarrier
                _q->data[j] = crealf(_Y0[i]) + 
                              cimagf(_Y1[i]) * _Complex_I;
            } else {
                // odd subcarrier
                _q->data[j] = cimagf(_Y0[i]) * _Complex_I +
                              crealf(_Y1[i]);
            }
            // scaling factor
            _q->data[j] /= _q->zeta;
            j++;
        }
    }
    assert(j==48);

#if DEBUG_OFDMOQAMFRAME64SYNC
    for (i=0; i<48; i++)
        windowcf_push(_q->debug_framesyms,_q->data[i]);
#endif

    if (_q->callback != NULL) {
        int retval = _q->callback(_q->data, _q->userdata);
        if (retval == -1) {
            printf("exiting prematurely\n");
            ofdmoqamframe64sync_destroy(_q);
            exit(0);
        } else if (retval == 1) {
#if DEBUG_OFDMOQAMFRAME64SYNC_PRINT
            printf("resetting synchronizer\n");
#endif
            ofdmoqamframe64sync_reset(_q);
        } else {
            // do nothing
        }
    }

}
Beispiel #15
0
// autotest helper function
//  _n      :   sequence length
//  _dt     :   fractional sample offset
//  _dphi   :   carrier frequency offset
void detector_cccf_runtest(unsigned int _n,
                           float        _dt,
                           float        _dphi)
{
    // TODO: validate input

    unsigned int i;

    // fixed values
    float noise_floor = -80.0f;     // noise floor [dB]
    float SNRdB       =  30.0f;     // signal-to-noise ratio [dB]
    unsigned int m    =  11;        // resampling filter semi-length
    float threshold   =  0.3f;      // detection threshold

    // derived values
    unsigned int num_samples = _n + 2*m + 1;
    float nstd = powf(10.0f, noise_floor/20.0f);
    float gamma = powf(10.0f, (SNRdB + noise_floor)/20.0f);
    float delay = (float)(_n + m) + _dt;    // expected delay

    // arrays
    float complex s[_n];            // synchronization pattern (samples)
    float complex x[num_samples];   // resampled signal with noise and offsets

    // generate synchronization pattern (two samples per symbol)
    unsigned int n2 = (_n - (_n%2)) / 2;    // n2 = floor(n/2)
    unsigned int mm = liquid_nextpow2(n2);  // mm = ceil( log2(n2) )
    msequence ms = msequence_create_default(mm);
    float complex v = 0.0f;
    for (i=0; i<_n; i++) {
        if ( (i%2)==0 )
            v = msequence_advance(ms) ? 1.0f : -1.0f;
        s[i] = v;
    }
    msequence_destroy(ms);

    // create fractional sample interpolator
    firfilt_crcf finterp = firfilt_crcf_create_kaiser(2*m+1, 0.45f, 40.0f, _dt);

    // generate sequence
    for (i=0; i<num_samples; i++) {
        // add fractional sample timing offset
        if (i < _n) firfilt_crcf_push(finterp, s[i]);
        else        firfilt_crcf_push(finterp, 0.0f);

        // compute output
        firfilt_crcf_execute(finterp, &x[i]);

        // add channel gain
        x[i] *= gamma;

        // add carrier offset
        x[i] *= cexpf(_Complex_I*_dphi*i);

        // add noise
        x[i] += nstd * ( randnf() + _Complex_I*randnf() ) * M_SQRT1_2;
    }
    
    // destroy fractional sample interpolator
    firfilt_crcf_destroy(finterp);

    // create detector
    detector_cccf sync = detector_cccf_create(s, _n, threshold, 2*_dphi);
    
    // push signal through detector
    float tau_hat   = 0.0f;     // fractional sample offset estimate
    float dphi_hat  = 0.0f;     // carrier offset estimate
    float gamma_hat = 1.0f;     // signal level estimate (linear)
    float delay_hat = 0.0f;     // total delay offset estimate
    int signal_detected = 0;    // signal detected flag
    for (i=0; i<num_samples; i++) {
        
        // correlate
        int detected = detector_cccf_correlate(sync, x[i], &tau_hat, &dphi_hat, &gamma_hat);

        if (detected) {
            signal_detected = 1;
            delay_hat = (float)i + (float)tau_hat;
            if (liquid_autotest_verbose) {
                printf("****** preamble found, tau_hat=%8.6f, dphi_hat=%8.6f, gamma_hat=%8.6f\n",
                        tau_hat, dphi_hat, gamma_hat);
            }
        }
    }
    
    // destroy objects
    detector_cccf_destroy(sync);

    // 
    // run tests
    //
    
    // convert to dB
    gamma     = 20*log10f(gamma);
    gamma_hat = 20*log10f(gamma_hat);

    if (liquid_autotest_verbose) {
        printf("detector autotest [%3u]: signal detected? %s\n", _n, signal_detected ? "yes" : "no");
        printf("    dphi    :   estimate = %12.6f (expected %12.6f)\n", dphi_hat,  _dphi);
        printf("    delay   :   estimate = %12.6f (expected %12.6f)\n", delay_hat, delay);
        printf("    gamma   :   estimate = %12.6f (expected %12.6f)\n", gamma_hat, gamma);
    }

    // ensure signal was detected
    CONTEND_EXPRESSION( signal_detected );

    // check carrier offset estimate
    CONTEND_DELTA( dphi_hat, _dphi, 0.01f );
    
    // check delay estimate
    CONTEND_DELTA( delay_hat, delay, 0.2f );
    
    // check signal level estimate
    CONTEND_DELTA( gamma_hat, gamma, 2.0f );
}