// Helper function to keep code base small
void qdetector_cccf_bench(struct rusage *     _start,
                          struct rusage *     _finish,
                          unsigned long int * _num_iterations,
                          unsigned int        _n)
{
    // adjust number of iterations
    *_num_iterations *= 4;
    *_num_iterations /= _n;

    // generate sequence (random)
    float complex h[_n];
    unsigned long int i;
    for (i=0; i<_n; i++) {
        h[i] = (rand() % 2 ? 1.0f : -1.0f) +
               (rand() % 2 ? 1.0f : -1.0f)*_Complex_I;
    }

    // generate synchronizer
    int          ftype        = LIQUID_FIRFILT_ARKAISER;
    unsigned int k            =    2;   // samples/symbol
    unsigned int m            =    7;   // filter delay [symbols]
    float        beta         = 0.3f;   // excess bandwidth factor
    float        threshold    = 0.5f;   // threshold for detection
    float        range        = 0.05f;  // carrier offset search range [radians/sample]
    qdetector_cccf q = qdetector_cccf_create_linear(h, _n, ftype, k, m, beta);
    qdetector_cccf_set_threshold(q,threshold);
    qdetector_cccf_set_range    (q, range);

    // input sequence (random)
    float complex x[7];
    for (i=0; i<7; i++) {
        x[i] = (rand() % 2 ? 1.0f : -1.0f) +
               (rand() % 2 ? 1.0f : -1.0f)*_Complex_I;
    }

    // start trials
    getrusage(RUSAGE_SELF, _start);
    int detected = 0;
    for (i=0; i<(*_num_iterations); i++) {
        // push input sequence through synchronizer
        detected ^= qdetector_cccf_execute(q, x[0]) != NULL;
        detected ^= qdetector_cccf_execute(q, x[1]) != NULL;
        detected ^= qdetector_cccf_execute(q, x[2]) != NULL;
        detected ^= qdetector_cccf_execute(q, x[3]) != NULL;
        detected ^= qdetector_cccf_execute(q, x[4]) != NULL;
        detected ^= qdetector_cccf_execute(q, x[5]) != NULL;
        detected ^= qdetector_cccf_execute(q, x[6]) != NULL;
    }
    getrusage(RUSAGE_SELF, _finish);
    *_num_iterations *= 7;

    // clean up allocated objects
    qdetector_cccf_destroy(q);
}
Example #2
0
// execute synchronizer, seeking p/n sequence
//  _q      :   frame synchronizer object
//  _x      :   input sample
//  _sym    :   demodulated symbol
void flexframesync_execute_seekpn(flexframesync _q,
                                  float complex _x)
{
    // push through pre-demod synchronizer
    float complex * v = qdetector_cccf_execute(_q->detector, _x);

    // check if frame has been detected
    if (v != NULL) {
        // get estimates
        _q->tau_hat   = qdetector_cccf_get_tau  (_q->detector);
        _q->gamma_hat = qdetector_cccf_get_gamma(_q->detector);
        _q->dphi_hat  = qdetector_cccf_get_dphi (_q->detector);
        _q->phi_hat   = qdetector_cccf_get_phi  (_q->detector);

#if DEBUG_FLEXFRAMESYNC_PRINT
        printf("***** frame detected! tau-hat:%8.4f, dphi-hat:%8.4f, gamma:%8.2f dB\n",
                _q->tau_hat, _q->dphi_hat, 20*log10f(_q->gamma_hat));
#endif

        // set appropriate filterbank index
        if (_q->tau_hat > 0) {
            _q->pfb_index = (unsigned int)(      _q->tau_hat  * _q->npfb) % _q->npfb;
            _q->mf_counter = 0;
        } else {
            _q->pfb_index = (unsigned int)((1.0f+_q->tau_hat) * _q->npfb) % _q->npfb;
            _q->mf_counter = 1;
        }
        
        // output filter scale (gain estimate, scaled by 1/2 for k=2 samples/symbol)
        firpfb_crcf_set_scale(_q->mf, 0.5f / _q->gamma_hat);

        // set frequency/phase of mixer
        nco_crcf_set_frequency(_q->mixer, _q->dphi_hat);
        nco_crcf_set_phase    (_q->mixer, _q->phi_hat );

        // update state
        _q->state = FLEXFRAMESYNC_STATE_RXPREAMBLE;

#if DEBUG_FLEXFRAMESYNC
        // the debug_qdetector_flush prevents samples from being written twice
        _q->debug_qdetector_flush = 1;
#endif
        // run buffered samples through synchronizer
        unsigned int buf_len = qdetector_cccf_get_buf_len(_q->detector);
        flexframesync_execute(_q, v, buf_len);
#if DEBUG_FLEXFRAMESYNC
        _q->debug_qdetector_flush = 0;
#endif
    }
}
int main(int argc, char*argv[])
{
    // options
    unsigned int sequence_len =   80;   // number of sync symbols
    unsigned int k            =    2;   // samples/symbol
    unsigned int m            =    7;   // filter delay [symbols]
    float        beta         = 0.3f;   // excess bandwidth factor
    int          ftype        = LIQUID_FIRFILT_ARKAISER;
    float        gamma        = 10.0f;  // channel gain
    float        tau          = -0.3f;  // fractional sample timing offset
    float        dphi         = -0.01f; // carrier frequency offset
    float        phi          =  0.5f;  // carrier phase offset
    float        SNRdB        = 20.0f;  // signal-to-noise ratio [dB]
    float        threshold    =  0.5f;  // detection threshold

    int dopt;
    while ((dopt = getopt(argc,argv,"hn:k:m:b:F:T:S:t:")) != EOF) {
        switch (dopt) {
        case 'h': usage();                      return 0;
        case 'n': sequence_len  = atoi(optarg); break;
        case 'k': k             = atoi(optarg); break;
        case 'm': m             = atoi(optarg); break;
        case 'b': beta          = atof(optarg); break;
        case 'F': dphi          = atof(optarg); break;
        case 'T': tau           = atof(optarg); break;
        case 'S': SNRdB         = atof(optarg); break;
        case 't': threshold     = atof(optarg); break;
        default:
            exit(1);
        }
    }

    unsigned int i;

    // validate input
    if (tau < -0.5f || tau > 0.5f) {
        fprintf(stderr,"error: %s, fractional sample offset must be in [-0.5,0.5]\n", argv[0]);
        exit(1);
    }

    // generate synchronization sequence (QPSK symbols)
    float complex sequence[sequence_len];
    for (i=0; i<sequence_len; i++) {
        sequence[i] = (rand() % 2 ? 1.0f : -1.0f) * M_SQRT1_2 +
                      (rand() % 2 ? 1.0f : -1.0f) * M_SQRT1_2 * _Complex_I;
    }

    //
    float tau_hat   = 0.0f;
    float gamma_hat = 0.0f;
    float dphi_hat  = 0.0f;
    float phi_hat   = 0.0f;
    int   frame_detected = 0;

    // create detector
    qdetector_cccf q = qdetector_cccf_create_linear(sequence, sequence_len, ftype, k, m, beta);
    qdetector_cccf_set_threshold(q, threshold);
    qdetector_cccf_print(q);

    //
    unsigned int seq_len     = qdetector_cccf_get_seq_len(q);
    unsigned int buf_len     = qdetector_cccf_get_buf_len(q);
    unsigned int num_samples = 2*buf_len;   // double buffer length to ensure detection
    unsigned int num_symbols = buf_len;

    // arrays
    float complex y[num_samples];       // received signal
    float complex syms_rx[num_symbols]; // recovered symbols

    // get pointer to sequence and generate full sequence
    float complex * v = (float complex*) qdetector_cccf_get_sequence(q);
    unsigned int filter_delay = 15;
    firfilt_crcf filter = firfilt_crcf_create_kaiser(2*filter_delay+1, 0.4f, 60.0f, -tau);
    float        nstd        = 0.1f;
    for (i=0; i<num_samples; i++) {
        // add delay
        firfilt_crcf_push(filter, i < seq_len ? v[i] : 0);
        firfilt_crcf_execute(filter, &y[i]);

        // channel gain
        y[i] *= gamma;

        // carrier offset
        y[i] *= cexpf(_Complex_I*(dphi*i + phi));
        
        // noise
        y[i] += nstd*(randnf() + _Complex_I*randnf())*M_SQRT1_2;
    }
    firfilt_crcf_destroy(filter);

    // run detection on sequence
    for (i=0; i<num_samples; i++) {
        v = qdetector_cccf_execute(q,y[i]);

        if (v != NULL) {
            printf("\nframe detected!\n");
            frame_detected = 1;

            // get statistics
            tau_hat   = qdetector_cccf_get_tau(q);
            gamma_hat = qdetector_cccf_get_gamma(q);
            dphi_hat  = qdetector_cccf_get_dphi(q);
            phi_hat   = qdetector_cccf_get_phi(q);
            break;
        }
    }

    unsigned int num_syms_rx = 0;   // output symbol counter
    unsigned int counter     = 0;   // decimation counter
    if (frame_detected) {
        // recover symbols
        firfilt_crcf mf = firfilt_crcf_create_rnyquist(ftype, k, m, beta, tau_hat);
        firfilt_crcf_set_scale(mf, 1.0f / (float)(k*gamma_hat));
        nco_crcf     nco = nco_crcf_create(LIQUID_VCO);
        nco_crcf_set_frequency(nco, dphi_hat);
        nco_crcf_set_phase    (nco,  phi_hat);

        for (i=0; i<buf_len; i++) {
            // 
            float complex sample;
            nco_crcf_mix_down(nco, v[i], &sample);
            nco_crcf_step(nco);

            // apply decimator
            firfilt_crcf_push(mf, sample);
            counter++;
            if (counter == k-1)
                firfilt_crcf_execute(mf, &syms_rx[num_syms_rx++]);
            counter %= k;
        }

        nco_crcf_destroy(nco);
        firfilt_crcf_destroy(mf);
    }

    // destroy objects
    qdetector_cccf_destroy(q);

    // print results
    printf("\n");
    printf("frame detected  :   %s\n", frame_detected ? "yes" : "no");
    printf("  gamma hat     : %8.3f, actual=%8.3f (error=%8.3f)\n",            gamma_hat, gamma, gamma_hat - gamma);
    printf("  tau hat       : %8.3f, actual=%8.3f (error=%8.3f) samples\n",    tau_hat,   tau,   tau_hat   - tau  );
    printf("  dphi hat      : %8.5f, actual=%8.5f (error=%8.5f) rad/sample\n", dphi_hat,  dphi,  dphi_hat  - dphi );
    printf("  phi hat       : %8.5f, actual=%8.5f (error=%8.5f) radians\n",    phi_hat,   phi,   phi_hat   - phi  );
    printf("  symbols rx    : %u\n", num_syms_rx);
    printf("\n");

    // 
    // export results
    //
    FILE * fid = fopen(OUTPUT_FILENAME,"w");
    fprintf(fid,"%% %s : auto-generated file\n", OUTPUT_FILENAME);
    fprintf(fid,"clear all\n");
    fprintf(fid,"close all\n");
    fprintf(fid,"sequence_len= %u;\n", sequence_len);
    fprintf(fid,"num_samples = %u;\n", num_samples);

    fprintf(fid,"y = zeros(1,num_samples);\n");
    for (i=0; i<num_samples; i++)
        fprintf(fid,"y(%4u) = %12.8f + j*%12.8f;\n", i+1, crealf(y[i]), cimagf(y[i]));

    fprintf(fid,"num_syms_rx = %u;\n", num_syms_rx);
    fprintf(fid,"syms_rx     = zeros(1,num_syms_rx);\n");
    for (i=0; i<num_syms_rx; i++)
        fprintf(fid,"syms_rx(%4u) = %12.8f + j*%12.8f;\n", i+1, crealf(syms_rx[i]), cimagf(syms_rx[i]));

    fprintf(fid,"t=[0:(num_samples-1)];\n");
    fprintf(fid,"figure;\n");
    fprintf(fid,"subplot(4,1,1);\n");
    fprintf(fid,"  plot(t,real(y), t,imag(y));\n");
    fprintf(fid,"  grid on;\n");
    fprintf(fid,"  xlabel('time');\n");
    fprintf(fid,"  ylabel('received signal');\n");
    fprintf(fid,"subplot(4,1,2:4);\n");
    fprintf(fid,"  plot(real(syms_rx), imag(syms_rx), 'x');\n");
    fprintf(fid,"  axis([-1 1 -1 1]*1.5);\n");
    fprintf(fid,"  axis square;\n");
    fprintf(fid,"  grid on;\n");
    fprintf(fid,"  xlabel('real');\n");
    fprintf(fid,"  ylabel('imag');\n");

    fclose(fid);
    printf("results written to '%s'\n", OUTPUT_FILENAME);

    return 0;
}