// Helper function to keep code base small
void window_push_bench(struct rusage *_start,
                       struct rusage *_finish,
                       unsigned long int *_num_iterations,
                       unsigned int _n)
{
    // normalize number of iterations
    *_num_iterations *= 8;
    if (*_num_iterations < 1) *_num_iterations = 1;

    // initialize port
    windowcf w = windowcf_create(_n);

    unsigned long int i;

    // start trials:
    //   write to port, read from port
    getrusage(RUSAGE_SELF, _start);
    for (i=0; i<(*_num_iterations); i++) {
        windowcf_push(w, 1.0f);
        windowcf_push(w, 1.0f);
        windowcf_push(w, 1.0f);
        windowcf_push(w, 1.0f);
    }
    getrusage(RUSAGE_SELF, _finish);
    *_num_iterations *= 4;

    windowcf_destroy(w);
}
Exemple #2
0
// create WLAN framing synchronizer object
//  _callback   :   user-defined callback function
//  _userdata   :   user-defined data structure
wlanframesync wlanframesync_create(wlanframesync_callback _callback,
                                   void *                 _userdata)
{
    // allocate main object memory
    wlanframesync q = (wlanframesync) malloc(sizeof(struct wlanframesync_s));
    
    // set callback data
    q->callback = _callback;
    q->userdata = _userdata;

    // create transform object
    q->X = (float complex*) malloc(64*sizeof(float complex));
    q->x = (float complex*) malloc(64*sizeof(float complex));
    q->fft = FFT_CREATE_PLAN(64, q->x, q->X, FFT_DIR_FORWARD, FFT_METHOD);
 
    // create input buffer the length of the transform
    q->input_buffer = windowcf_create(80);

    // synchronizer objects
    q->nco_rx = nco_crcf_create(LIQUID_VCO);
    q->ms_pilot = wlan_lfsr_create(7, 0x91, 0x7f);
    q->mod_scheme = WLAN_MODEM_BPSK;

    // set initial properties
    q->rate   = WLANFRAME_RATE_6;
    q->length = 100;
    q->seed   = 0x5d;

    // allocate memory for encoded message
    q->enc_msg_len = wlan_packet_compute_enc_msg_len(q->rate, q->length);
    q->msg_enc = (unsigned char*) malloc(q->enc_msg_len*sizeof(unsigned char));

    // allocate memory for decoded message
    q->dec_msg_len = 1;
    q->msg_dec = (unsigned char*) malloc(q->dec_msg_len*sizeof(unsigned char));

    // reset object
    wlanframesync_reset(q);
    
#if DEBUG_WLANFRAMESYNC
    // debugging structures
    q->debug_enabled   = 0;
    q->agc_rx          = NULL;
    q->debug_x         = NULL;
    q->debug_rssi      = NULL;
    q->debug_framesyms = NULL;
#endif

    // return object
    return q;
}
int main (int argc, char ** argv) {
    w=windowcf_create(SPECTRUM_FFT_LENGTH);
    wchA = windowcf_create(TRACK_LENGTH);
    wchB = windowcf_create(TRACK_LENGTH);
    wchC = windowcf_create(TRACK_LENGTH);

    wchA_filtered = windowcf_create(TRACK_LENGTH);
    wchB_filtered = windowcf_create(TRACK_LENGTH);
    wchC_filtered = windowcf_create(TRACK_LENGTH);

    wmag_buffer = windowf_create(TRACK_LENGTH);

    nco = nco_crcf_create(LIQUID_NCO);
    std::cout << "hydromath daemon is beginning..." << std::endl;
    std::cout << "NOTE: if this is symhydromath you must pass in a matfile" << std::endl;

    std::cout << argv[1] << std::endl;
    shm_init();
    shm_getg(hydrophones_results_track, shm_results_track);
    shm_getg(hydrophones_results_spectrum, shm_results_spectrum);

    //shm_results_track.tracked_ping_count=0;
    shm_results_track.tracked_ping_time=0; 


    if (argc > 1) {
        udp_init(argv[1]);
    }
    else {
        udp_init("");
    }
    //std::thread track_thread(direction_loop);
    //
    //std::thread spectrum_thread(spectrum_loop);
    track_sample_idx = 0;  

    while (loop(&spt) == 0) {
        shm_getg(hydrophones_settings, shm_settings);
        for (int i = 0; i < 3*CHANNEL_DEPTH; i+=3) {
            windowcf_push(w,    std::complex<float>(spt.data[i+1],0)); //This uses channel B

            windowcf_push(wchA, std::complex<float>(spt.data[i],0));
            windowcf_push(wchB, std::complex<float>(spt.data[i+1],0));
            windowcf_push(wchC, std::complex<float>(spt.data[i+2],0));
        }
        current_sample_count+=CHANNEL_DEPTH;        
        do_spectrum();
        do_track();
    }

    printf("loop done %li =ci\n",current_sample_count/CHANNEL_DEPTH);
    return 0;
}
Exemple #4
0
void wlanframesync_debug_enable(wlanframesync _q)
{
    // create debugging objects if necessary
#if DEBUG_WLANFRAMESYNC
    // agc, rssi
    if (_q->agc_rx == NULL)
        _q->agc_rx = agc_crcf_create();
    agc_crcf_set_bandwidth(_q->agc_rx,  1e-2f);
    agc_crcf_set_gain_limits(_q->agc_rx, 1.0f, 1e7f);

    if (_q->debug_x == NULL)
        _q->debug_x = windowcf_create(DEBUG_WLANFRAMESYNC_BUFFER_LEN);

    if (_q->debug_rssi == NULL)
        _q->debug_rssi = windowf_create(DEBUG_WLANFRAMESYNC_BUFFER_LEN);

    if (_q->debug_framesyms == NULL)
        _q->debug_framesyms = windowcf_create(DEBUG_WLANFRAMESYNC_BUFFER_LEN);

    _q->debug_enabled = 1;
#else
    fprintf(stderr,"wlanframesync_debug_enable(): compile-time debugging disabled\n");
#endif
}
Exemple #5
0
// enable debugging
void ofdmframesync_debug_enable(ofdmframesync _q)
{
    // create debugging objects if necessary
#if DEBUG_OFDMFRAMESYNC
    if (_q->debug_objects_created)
        return;

    _q->debug_x         = windowcf_create(DEBUG_OFDMFRAMESYNC_BUFFER_LEN);
    _q->debug_rssi      = windowf_create(DEBUG_OFDMFRAMESYNC_BUFFER_LEN);
    _q->debug_framesyms = windowcf_create(DEBUG_OFDMFRAMESYNC_BUFFER_LEN);
    _q->G_hat           = (float complex*) malloc((_q->M)*sizeof(float complex));

    _q->px = (float*) malloc((_q->M_pilot)*sizeof(float));
    _q->py = (float*) malloc((_q->M_pilot)*sizeof(float));

    _q->debug_pilot_0 = windowf_create(DEBUG_OFDMFRAMESYNC_BUFFER_LEN);
    _q->debug_pilot_1 = windowf_create(DEBUG_OFDMFRAMESYNC_BUFFER_LEN);

    _q->debug_enabled   = 1;
    _q->debug_objects_created = 1;
#else
    fprintf(stderr,"ofdmframesync_debug_enable(): compile-time debugging disabled\n");
#endif
}
Exemple #6
0
// enable debugging
void flexframesync_debug_enable(flexframesync _q)
{
    // create debugging objects if necessary
#if DEBUG_FLEXFRAMESYNC
    if (_q->debug_objects_created)
        return;

    // create debugging objects
    _q->debug_x = windowcf_create(DEBUG_BUFFER_LEN);

    // set debugging flags
    _q->debug_enabled = 1;
    _q->debug_objects_created = 1;
#else
    fprintf(stderr,"flexframesync_debug_enable(): compile-time debugging disabled\n");
#endif
}
Exemple #7
0
void gmskframesync_debug_enable(gmskframesync _q)
{
    // create debugging objects if necessary
#if DEBUG_GMSKFRAMESYNC
    if (!_q->debug_objects_created) {
        _q->debug_x  = windowcf_create(DEBUG_GMSKFRAMESYNC_BUFFER_LEN);
        _q->debug_fi = windowf_create(DEBUG_GMSKFRAMESYNC_BUFFER_LEN);
        _q->debug_mf = windowf_create(DEBUG_GMSKFRAMESYNC_BUFFER_LEN);
        _q->debug_framesyms  = windowf_create(DEBUG_GMSKFRAMESYNC_BUFFER_LEN);
    }
    
    // set debugging flags
    _q->debug_enabled = 1;
    _q->debug_objects_created = 1;
#else
    fprintf(stderr,"gmskframesync_debug_enable(): compile-time debugging disabled\n");
#endif
}
Exemple #8
0
// create ampmodem object
//  _m                  :   modulation index
//  _fc                 :   carrier frequency
//  _type               :   AM type (e.g. LIQUID_AMPMODEM_DSB)
//  _suppressed_carrier :   carrier suppression flag
ampmodem ampmodem_create(float _m,
                         float _fc,
                         liquid_ampmodem_type _type,
                         int _suppressed_carrier)
{
    ampmodem q = (ampmodem) malloc(sizeof(struct ampmodem_s));
    q->type = _type;
    q->m    = _m;
    q->fc   = _fc;
    q->suppressed_carrier = (_suppressed_carrier == 0) ? 0 : 1;

    // create nco, pll objects
    q->oscillator = nco_crcf_create(LIQUID_NCO);
    nco_crcf_set_frequency(q->oscillator, 2*M_PI*q->fc);
    
    nco_crcf_pll_set_bandwidth(q->oscillator,0.05f);

    // suppressed carrier
    q->ssb_alpha = 0.01f;
    q->ssb_q_hat = 0.0f;

    // single side-band
    q->hilbert = firhilbf_create(9, 60.0f);

    // double side-band

    ampmodem_reset(q);

    // debugging
#if DEBUG_AMPMODEM
    q->debug_x =           windowcf_create(DEBUG_AMPMODEM_BUFFER_LEN);
    q->debug_phase_error =  windowf_create(DEBUG_AMPMODEM_BUFFER_LEN);
    q->debug_freq_error =   windowf_create(DEBUG_AMPMODEM_BUFFER_LEN);
#endif

    return q;
}
int main(int argc, char*argv[])
{
    // options
    int          ftype       = LIQUID_FIRFILT_ARKAISER;
    int          ms          = LIQUID_MODEM_QPSK;
    unsigned int k           = 2;       // samples per symbol
    unsigned int m           = 7;       // filter delay (symbols)
    float        beta        = 0.20f;   // filter excess bandwidth factor
    unsigned int num_symbols = 4000;    // number of data symbols
    unsigned int hc_len      =   4;     // channel filter length
    float        noise_floor = -60.0f;  // noise floor [dB]
    float        SNRdB       = 30.0f;   // signal-to-noise ratio [dB]
    float        bandwidth   =  0.02f;  // loop filter bandwidth
    float        tau         = -0.2f;   // fractional symbol offset
    float        rate        = 1.001f;  // sample rate offset
    float        dphi        =  0.01f;  // carrier frequency offset [radians/sample]
    float        phi         =  2.1f;   // carrier phase offset [radians]

    unsigned int nfft        =   2400;  // spectral periodogram FFT size
    unsigned int num_samples = 200000;  // number of samples

    int dopt;
    while ((dopt = getopt(argc,argv,"hk:m:b:s:w:n:t:r:")) != EOF) {
        switch (dopt) {
        case 'h':   usage();                        return 0;
        case 'k':   k           = atoi(optarg);     break;
        case 'm':   m           = atoi(optarg);     break;
        case 'b':   beta        = atof(optarg);     break;
        case 's':   SNRdB       = atof(optarg);     break;
        case 'w':   bandwidth   = atof(optarg);     break;
        case 'n':   num_symbols = atoi(optarg);     break;
        case 't':   tau         = atof(optarg);     break;
        case 'r':   rate        = atof(optarg);     break;
        default:
            exit(1);
        }
    }

    // validate input
    if (k < 2) {
        fprintf(stderr,"error: k (samples/symbol) must be greater than 1\n");
        exit(1);
    } else if (m < 1) {
        fprintf(stderr,"error: m (filter delay) must be greater than 0\n");
        exit(1);
    } else if (beta <= 0.0f || beta > 1.0f) {
        fprintf(stderr,"error: beta (excess bandwidth factor) must be in (0,1]\n");
        exit(1);
    } else if (bandwidth <= 0.0f) {
        fprintf(stderr,"error: timing PLL bandwidth must be greater than 0\n");
        exit(1);
    } else if (num_symbols == 0) {
        fprintf(stderr,"error: number of symbols must be greater than 0\n");
        exit(1);
    } else if (tau < -1.0f || tau > 1.0f) {
        fprintf(stderr,"error: timing phase offset must be in [-1,1]\n");
        exit(1);
    } else if (rate > 1.02f || rate < 0.98f) {
        fprintf(stderr,"error: timing rate offset must be in [1.02,0.98]\n");
        exit(1);
    }

    unsigned int i;

    // buffers
    unsigned int    buf_len = 400;      // buffer size
    float complex   x   [buf_len];      // original signal
    float complex   y   [buf_len*2];    // channel output (larger to accommodate resampler)
    float complex   syms[buf_len];      // recovered symbols
    // window for saving last few symbols
    windowcf sym_buf = windowcf_create(buf_len);

    // create stream generator
    symstreamcf gen = symstreamcf_create_linear(ftype,k,m,beta,ms);

    // create channel emulator and add impairments
    channel_cccf channel = channel_cccf_create();
    channel_cccf_add_awgn          (channel, noise_floor, SNRdB);
    channel_cccf_add_carrier_offset(channel, dphi, phi);
    channel_cccf_add_multipath     (channel, NULL, hc_len);
    channel_cccf_add_resamp        (channel, 0.0f, rate);

    // create symbol tracking synchronizer
    symtrack_cccf symtrack = symtrack_cccf_create(ftype,k,m,beta,ms);
    symtrack_cccf_set_bandwidth(symtrack,0.05f);

    // create spectral periodogram for estimating spectrum
    spgramcf periodogram = spgramcf_create_default(nfft);

    unsigned int total_samples = 0;
    unsigned int ny;
    unsigned int total_symbols = 0;
    while (total_samples < num_samples)
    {
        // write samples to buffer
        symstreamcf_write_samples(gen, x, buf_len);

        // apply channel
        channel_cccf_execute(channel, x, buf_len, y, &ny);

        // push resulting sample through periodogram
        spgramcf_write(periodogram, y, ny);

        // run resulting stream through synchronizer
        unsigned int num_symbols_sync;
        symtrack_cccf_execute_block(symtrack, y, ny, syms, &num_symbols_sync);
        total_symbols += num_symbols_sync;

        // write resulting symbols to window buffer for plotting
        windowcf_write(sym_buf, syms, num_symbols_sync);

        // accumulated samples
        total_samples += buf_len;
    }
    printf("total samples: %u\n", total_samples);
    printf("total symbols: %u\n", total_symbols);

    // write accumulated power spectral density estimate
    float psd[nfft];
    spgramcf_get_psd(periodogram, psd);

    //
    // export output file
    //

    FILE * fid = fopen(OUTPUT_FILENAME,"w");
    fprintf(fid,"%% %s, auto-generated file\n\n", OUTPUT_FILENAME);
    fprintf(fid,"clear all;\n");
    fprintf(fid,"close all;\n");

    // read buffer and write last symbols to file
    float complex * rc;
    windowcf_read(sym_buf, &rc);
    fprintf(fid,"syms = zeros(1,%u);\n", buf_len);
    for (i=0; i<buf_len; i++)
        fprintf(fid,"syms(%3u) = %12.8f + j*%12.8f;\n", i+1, crealf(rc[i]), cimagf(rc[i]));

    // power spectral density estimate
    fprintf(fid,"nfft = %u;\n", nfft);
    fprintf(fid,"f=[0:(nfft-1)]/nfft - 0.5;\n");
    fprintf(fid,"psd = zeros(1,nfft);\n");
    for (i=0; i<nfft; i++)
        fprintf(fid,"psd(%3u) = %12.8f;\n", i+1, psd[i]);

    fprintf(fid,"figure('Color','white','position',[500 500 1400 400]);\n");
    fprintf(fid,"subplot(1,3,1);\n");
    fprintf(fid,"plot(real(syms),imag(syms),'x','MarkerSize',4);\n");
    fprintf(fid,"  axis square;\n");
    fprintf(fid,"  grid on;\n");
    fprintf(fid,"  axis([-1 1 -1 1]*1.6);\n");
    fprintf(fid,"  xlabel('In-phase');\n");
    fprintf(fid,"  ylabel('Quadrature');\n");
    fprintf(fid,"  title('Last %u symbols');\n", buf_len);
    fprintf(fid,"subplot(1,3,2:3);\n");
    fprintf(fid,"  plot(f, psd, 'LineWidth',1.5,'Color',[0 0.5 0.2]);\n");
    fprintf(fid,"  grid on;\n");
    fprintf(fid,"  pmin = 10*floor(0.1*min(psd - 5));\n");
    fprintf(fid,"  pmax = 10*ceil (0.1*max(psd + 5));\n");
    fprintf(fid,"  axis([-0.5 0.5 pmin pmax]);\n");
    fprintf(fid,"  xlabel('Normalized Frequency [f/F_s]');\n");
    fprintf(fid,"  ylabel('Power Spectral Density [dB]');\n");

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

    // destroy objects
    symstreamcf_destroy  (gen);
    spgramcf_destroy     (periodogram);
    channel_cccf_destroy (channel);
    symtrack_cccf_destroy(symtrack);
    windowcf_destroy     (sym_buf);

    // clean it up
    printf("done.\n");
    return 0;
}
int main() {
    // options
    unsigned int num_channels=64;   // must be even number
    unsigned int num_symbols=16;    // number of symbols
    unsigned int m=3;               // filter delay (symbols)
    float beta = 0.9f;              // filter excess bandwidth factor
    float phi = 0.0f;               // carrier phase offset;
    float dphi = 0.04f;            // carrier frequency offset

    // number of frames (compensate for filter delay)
    unsigned int num_frames = num_symbols + 2*m;
    unsigned int num_samples = num_channels * num_frames;
    unsigned int i;
    unsigned int j;

    // create filter prototype
    unsigned int h_len = 2*num_channels*m + 1;
    float h[h_len];
    float complex hc[h_len];
    float complex gc[h_len];
    liquid_firdes_rkaiser(num_channels, m, beta, 0.0f, h);
    unsigned int g_len = 2*num_channels*m;
    for (i=0; i<g_len; i++) {
        hc[i] = h[i];
        gc[i] = h[g_len-i-1] * cexpf(_Complex_I*dphi*i);
    }

    // data arrays
    float complex s[num_channels];                  // input symbols
    float complex y[num_samples];                   // time-domain samples
    float complex Y0[num_frames][num_channels];     // channelized output
    float complex Y1[num_frames][num_channels];     // channelized output

    // create ofdm/oqam generator object and generate data
    ofdmoqam qs = ofdmoqam_create(num_channels, m, beta, 0.0f, LIQUID_SYNTHESIZER, 0);
    for (i=0; i<num_frames; i++) {
        for (j=0; j<num_channels; j++) {
            if (i<num_symbols) {
#if 0
                // QPSK on all subcarriers
                s[j] = (rand() % 2 ? 1.0f : -1.0f) +
                       (rand() % 2 ? 1.0f : -1.0f) * _Complex_I;
                s[j] *= 1.0f / sqrtf(2.0f);
#else
                // BPSK on even subcarriers
                s[j] =  rand() % 2 ? 1.0f : -1.0f;
                s[j] *= (j%2)==0 ? 1.0f : 0.0f;
#endif
            } else {
                s[j] = 0.0f;
            }
        }

        // run synthesizer
        ofdmoqam_execute(qs, s, &y[i*num_channels]);
    }
    ofdmoqam_destroy(qs);

    // channel
    for (i=0; i<num_samples; i++)
        y[i] *= cexpf(_Complex_I*(phi + dphi*i));


    //
    // analysis filterbank (receiver)
    //

    // create filterbank manually
    dotprod_cccf dp[num_channels];  // vector dot products
    windowcf w[num_channels];       // window buffers

#if DEBUG
    // print coefficients
    printf("h_prototype:\n");
    for (i=0; i<h_len; i++)
        printf("  h[%3u] = %12.8f\n", i, h[i]);
#endif

    // create objects
    unsigned int gc_sub_len = 2*m;
    float complex gc_sub[gc_sub_len];
    for (i=0; i<num_channels; i++) {
        // sub-sample prototype filter, loading coefficients in
        // reverse order
#if 0
        for (j=0; j<gc_sub_len; j++)
            gc_sub[j] = h[j*num_channels+i];
#else
        for (j=0; j<gc_sub_len; j++)
            gc_sub[gc_sub_len-j-1] = gc[j*num_channels+i];
#endif

        // create window buffer and dotprod objects
        dp[i] = dotprod_cccf_create(gc_sub, gc_sub_len);
        w[i]  = windowcf_create(gc_sub_len);

#if DEBUG
        printf("gc_sub[%u] : \n", i);
        for (j=0; j<gc_sub_len; j++)
            printf("  g[%3u] = %12.8f + %12.8f\n", j, crealf(gc_sub[j]), cimagf(gc_sub[j]));
#endif
    }

    // generate DFT object
    float complex x[num_channels];  // time-domain buffer
    float complex X[num_channels];  // freq-domain buffer
#if 0
    fftplan fft = fft_create_plan(num_channels, X, x, FFT_REVERSE, 0);
#else
    fftplan fft = fft_create_plan(num_channels, X, x, FFT_FORWARD, 0);
#endif

    // 
    // run analysis filter bank
    //
#if 0
    unsigned int filter_index = 0;
#else
    unsigned int filter_index = num_channels-1;
#endif
    float complex y_hat;    // input sample
    float complex * r;      // read pointer
    for (i=0; i<num_frames; i++) {

        // load buffers
        for (j=0; j<num_channels; j++) {
            // grab sample
            y_hat = y[i*num_channels + j];

            // push sample into buffer at filter index
            windowcf_push(w[filter_index], y_hat);

            // decrement filter index
            filter_index = (filter_index + num_channels - 1) % num_channels;
            //filter_index = (filter_index + 1) % num_channels;
        }

        // execute filter outputs, reversing order of output (not
        // sure why this is necessary)
        for (j=0; j<num_channels; j++) {
            windowcf_read(w[j], &r);
            dotprod_cccf_execute(dp[j], r, &X[num_channels-j-1]);
        }

#if 1
        // compensate for carrier frequency offset (before transform)
        for (j=0; j<num_channels; j++) {
            X[j] *= cexpf(-_Complex_I*(dphi*i*num_channels));
        }
#endif

        // execute DFT, store result in buffer 'x'
        fft_execute(fft);

#if 0
        // compensate for carrier frequency offset (after transform)
        for (j=0; j<num_channels; j++) {
            x[j] *= cexpf(-_Complex_I*(dphi*i*num_channels));
        }
#endif

        // move to output array
        for (j=0; j<num_channels; j++)
            Y0[i][j] = x[j];
    }


    // destroy objects
    for (i=0; i<num_channels; i++) {
        dotprod_cccf_destroy(dp[i]);
        windowcf_destroy(w[i]);
    }
    fft_destroy_plan(fft);

#if 0
    // print filterbank channelizer
    printf("\n");
    printf("filterbank channelizer:\n");
    for (i=0; i<num_symbols; i++) {
        printf("%3u: ", i);
        for (j=0; j<num_channels; j++) {
            printf("  %8.5f+j%8.5f, ", crealf(Y0[i][j]), cimagf(Y0[i][j]));
        }
        printf("\n");
    }
#endif

    // 
    // export data
    //
    FILE*fid = fopen(OUTPUT_FILENAME,"w");
    fprintf(fid,"%% %s: auto-generated file\n\n", OUTPUT_FILENAME);
    fprintf(fid,"clear all;\nclose all;\n\n");
    fprintf(fid,"num_channels=%u;\n", num_channels);
    fprintf(fid,"num_symbols=%u;\n", num_symbols);
    fprintf(fid,"num_frames = %u;\n", num_frames);
    fprintf(fid,"num_samples = num_frames*num_channels;\n");

    fprintf(fid,"y = zeros(1,%u);\n",  num_samples);
    fprintf(fid,"Y0 = zeros(%u,%u);\n", num_frames, num_channels);
    fprintf(fid,"Y1 = zeros(%u,%u);\n", num_frames, num_channels);
    
    for (i=0; i<num_frames; i++) {
        for (j=0; j<num_channels; j++) {
            fprintf(fid,"Y0(%4u,%4u) = %12.4e + j*%12.4e;\n", i+1, j+1, crealf(Y0[i][j]), cimagf(Y0[i][j]));
            fprintf(fid,"Y1(%4u,%4u) = %12.4e + j*%12.4e;\n", i+1, j+1, crealf(Y1[i][j]), cimagf(Y1[i][j]));
        }
    }

    // plot BPSK results
    fprintf(fid,"figure;\n");
    fprintf(fid,"plot(Y0(:,1:2:end),'x');\n");
    fprintf(fid,"axis([-1 1 -1 1]*1.2*sqrt(num_channels));\n");
    fprintf(fid,"axis square;\n");
    fprintf(fid,"grid on;\n");

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

    printf("done.\n");
    return 0;
}
Exemple #11
0
// main program
int main (int argc, char **argv)
{
    // command-line options
    int verbose = 1;

    int ppm_error = 0;
    int gain = 0;
    unsigned int nfft    = 64;
    float offset         = -65.0f;
    float scale          = 5.0f;
    float fft_rate       = 10.0f;
    float rx_resamp_rate;
    float bandwidth      = 800e3f;
    unsigned int logsize = 4096;
    char filename[256]   = "rtl_asgram.dat";
    int r, n_read;

    uint32_t frequency = 100000000;
    uint32_t samp_rate = DEFAULT_SAMPLE_RATE;
    uint32_t out_block_size = DEFAULT_BUF_LENGTH;
    uint8_t *buffer;

    int dev_index = 0;
    int dev_given = 0;

    struct sigaction sigact;
    normalizer_t *norm;

    //
    int d;
    while ((d = getopt(argc,argv,"hf:b:B:G:n:p:s:o:r:L:F:")) != EOF) {
        switch (d) {
        case 'h':
            usage();
            return 0;
        case 'f':
            frequency   = atof(optarg);
            break;
        case 'b':
            bandwidth   = atof(optarg);
            break;
        case 'B':
            out_block_size = (uint32_t)atof(optarg);
            break;
        case 'G':
            gain = (int)(atof(optarg) * 10);
            break;
        case 'n':
            nfft        = atoi(optarg);
            break;
        case 'o':
            offset      = atof(optarg);
            break;
        case 'p':
            ppm_error = atoi(optarg);
            break;
        case 's':
            samp_rate = (uint32_t)atofs(optarg);
            break;
        case 'r':
            fft_rate    = atof(optarg);
            break;
        case 'L':
            logsize     = atoi(optarg);
            break;
        case 'F':
            strncpy(filename,optarg,255);
            break;
        case 'd':
            dev_index = verbose_device_search(optarg);
            dev_given = 1;
            break;
        default:
            usage();
            return 1;
        }
    }

    // validate parameters
    if (fft_rate <= 0.0f || fft_rate > 100.0f) {
        fprintf(stderr,"error: %s, fft rate must be in (0, 100) Hz\n", argv[0]);
        exit(1);
    }

    if (!dev_given) {
        dev_index = verbose_device_search("0");
    }

    if (dev_index < 0) {
        exit(1);
    }

    r = rtlsdr_open(&dev, (uint32_t)dev_index);
    if (r < 0) {
        fprintf(stderr, "Failed to open rtlsdr device #%d.\n", dev_index);
        exit(1);
    }

    sigact.sa_handler = sighandler;
    sigemptyset(&sigact.sa_mask);
    sigact.sa_flags = 0;
    sigaction(SIGINT, &sigact, NULL);
    sigaction(SIGTERM, &sigact, NULL);
    sigaction(SIGQUIT, &sigact, NULL);
    sigaction(SIGPIPE, &sigact, NULL);

    /* Set the sample rate */
    verbose_set_sample_rate(dev, samp_rate);

    /* Set the frequency */
    verbose_set_frequency(dev, frequency);

    if (0 == gain) {
        /* Enable automatic gain */
        verbose_auto_gain(dev);
    } else {
        /* Enable manual gain */
        gain = nearest_gain(dev, gain);
        verbose_gain_set(dev, gain);
    }

    verbose_ppm_set(dev, ppm_error);

    rx_resamp_rate = bandwidth/samp_rate;

    printf("frequency       :   %10.4f [MHz]\n", frequency*1e-6f);
    printf("bandwidth       :   %10.4f [kHz]\n", bandwidth*1e-3f);
    printf("sample rate     :   %10.4f kHz = %10.4f kHz * %8.6f\n",
           samp_rate * 1e-3f,
           bandwidth    * 1e-3f,
           1.0f / rx_resamp_rate);
    printf("verbosity       :    %s\n", (verbose?"enabled":"disabled"));

    unsigned int i;

    // add arbitrary resampling component
    msresamp_crcf resamp = msresamp_crcf_create(rx_resamp_rate, 60.0f);
    assert(resamp);

    // create buffer for sample logging
    windowcf log = windowcf_create(logsize);

    // create ASCII spectrogram object
    float maxval;
    float maxfreq;
    char ascii[nfft+1];
    ascii[nfft] = '\0'; // append null character to end of string
    asgram q = asgram_create(nfft);
    asgram_set_scale(q, offset, scale);

    // assemble footer
    unsigned int footer_len = nfft + 16;
    char footer[footer_len+1];
    for (i=0; i<footer_len; i++)
        footer[i] = ' ';
    footer[1] = '[';
    footer[nfft/2 + 3] = '+';
    footer[nfft + 4] = ']';
    sprintf(&footer[nfft+6], "%8.3f MHz", frequency*1e-6f);
    unsigned int msdelay = 1000 / fft_rate;

    // create/initialize Hamming window
    float w[nfft];
    for (i=0; i<nfft; i++)
        w[i] = hamming(i,nfft);

    //allocate recv buffer
    buffer = malloc(out_block_size * sizeof(uint8_t));
    assert(buffer);

    // create buffer for arbitrary resamper output
    int b_len = ((int)(out_block_size * rx_resamp_rate) + 64) >> 1;
    complex float buffer_resamp[b_len];
    debug("resamp_buffer_len: %d", b_len);

    // timer to control asgram output
    timer t1 = timer_create();
    timer_tic(t1);

    norm = normalizer_create();

    verbose_reset_buffer(dev);

    while (!do_exit) {
        // grab data from device
        r = rtlsdr_read_sync(dev, buffer, out_block_size, &n_read);
        if (r < 0) {
            fprintf(stderr, "WARNING: sync read failed.\n");
            break;
        }

        if ((bytes_to_read > 0) && (bytes_to_read < (uint32_t)n_read)) {
            n_read = bytes_to_read;
            do_exit = 1;
        }

        // push data through arbitrary resampler and give to frame synchronizer
        // TODO : apply bandwidth-dependent gain
        for (i=0; i<n_read/2; i++) {
            // grab sample from usrp buffer
            complex float rtlsdr_sample = normalizer_normalize(norm, *((uint16_t*)buffer+i));

            // push through resampler (one at a time)
            unsigned int nw;
            msresamp_crcf_execute(resamp, &rtlsdr_sample, 1, buffer_resamp, &nw);

            // push resulting samples into asgram object
            asgram_push(q, buffer_resamp, nw);

            // write samples to log
            windowcf_write(log, buffer_resamp, nw);
        }

        if ((uint32_t)n_read < out_block_size) {
            fprintf(stderr, "Short read, samples lost, exiting!\n");
            break;
        }

        if (bytes_to_read > 0)
            bytes_to_read -= n_read;

        if (timer_toc(t1) > msdelay*1e-3f) {
            // reset timer
            timer_tic(t1);

            // run the spectrogram
            asgram_execute(q, ascii, &maxval, &maxfreq);

            // print the spectrogram
            printf(" > %s < pk%5.1fdB [%5.2f]\n", ascii, maxval, maxfreq);
            printf("%s\r", footer);
            fflush(stdout);
        }
    }

    // try to write samples to file
    FILE * fid = fopen(filename,"w");
    if (fid != NULL) {
        // write header
        fprintf(fid, "# %s : auto-generated file\n", filename);
        fprintf(fid, "#\n");
        fprintf(fid, "# num_samples :   %u\n", logsize);
        fprintf(fid, "# frequency   :   %12.8f MHz\n", frequency*1e-6f);
        fprintf(fid, "# bandwidth   :   %12.8f kHz\n", bandwidth*1e-3f);

        // save results to file
        complex float * rc;   // read pointer
        windowcf_read(log, &rc);
        for (i=0; i<logsize; i++)
            fprintf(fid, "%12.4e %12.4e\n", crealf(rc[i]), cimagf(rc[i]));

        // close it up
        fclose(fid);
        printf("results written to '%s'\n", filename);
    } else {
        fprintf(stderr,"error: %s, could not open '%s' for writing\n", argv[0], filename);
    }

    // destroy objects
    normalizer_destroy(&norm);
    msresamp_crcf_destroy(resamp);
    windowcf_destroy(log);
    asgram_destroy(q);
    timer_destroy(t1);

    rtlsdr_close(dev);
    free (buffer);

    return 0;
}
Exemple #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;

    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;
}
int main() {
    // options
    unsigned int num_channels=4;    // number of channels
    unsigned int m=5;               // filter delay
    unsigned int num_symbols=12;    // number of symbols

    // derived values
    unsigned int num_samples = num_channels * num_symbols;

    unsigned int i;
    unsigned int j;

    // generate filter
    // NOTE : these coefficients can be random; the purpose of this
    //        exercise is to demonstrate mathematical equivalence
    unsigned int h_len = 2*m*num_channels;
    float h[h_len];
    for (i=0; i<h_len; i++) h[i] = randnf();
    //for (i=0; i<h_len; i++) h[i] = 0.1f*i;
    //for (i=0; i<h_len; i++) h[i] = (i<=m) ? 1.0f : 0.0f;
    //for (i=0; i<h_len; i++) h[i] = 1.0f;

    // create filterbank manually
    dotprod_crcf dp[num_channels];  // vector dot products
    windowcf w[num_channels];       // window buffers

#if DEBUG
    // print coefficients
    printf("h_prototype:\n");
    for (i=0; i<h_len; i++)
        printf("  h[%3u] = %12.8f\n", i, h[i]);
#endif

    // create objects
    unsigned int h_sub_len = 2*m;
    float h_sub[h_sub_len];
    for (i=0; i<num_channels; i++) {
        // sub-sample prototype filter, loading coefficients in
        // reverse order
#if 0
        for (j=0; j<h_sub_len; j++)
            h_sub[j] = h[j*num_channels+i];
#else
        for (j=0; j<h_sub_len; j++)
            h_sub[h_sub_len-j-1] = h[j*num_channels+i];
#endif

        // create window buffer and dotprod objects
        dp[i] = dotprod_crcf_create(h_sub, h_sub_len);
        w[i]  = windowcf_create(h_sub_len);

#if DEBUG
        printf("h_sub[%u] : \n", i);
        for (j=0; j<h_sub_len; j++)
            printf("  h[%3u] = %12.8f\n", j, h_sub[j]);
#endif
    }

    // generate DFT object
    float complex x[num_channels];  // time-domain buffer
    float complex X[num_channels];  // freq-domain buffer
#if 0
    fftplan fft = fft_create_plan(num_channels, X, x, LIQUID_FFT_BACKWARD, 0);
#else
    fftplan fft = fft_create_plan(num_channels, X, x, LIQUID_FFT_FORWARD, 0);
#endif

    // generate filter object
    firfilt_crcf f = firfilt_crcf_create(h, h_len);

    float complex y[num_samples];                   // time-domain input
    float complex Y0[num_symbols][num_channels];    // channelized output
    float complex Y1[num_symbols][num_channels];    // channelized output

    // generate input sequence (complex noise)
    for (i=0; i<num_samples; i++)
        y[i] = randnf() * cexpf(_Complex_I*randf()*2*M_PI);

    // 
    // run analysis filter bank
    //
#if 0
    unsigned int filter_index = 0;
#else
    unsigned int filter_index = num_channels-1;
#endif
    float complex y_hat;    // input sample
    float complex * r;      // read pointer
    for (i=0; i<num_symbols; i++) {

        // load buffers
        for (j=0; j<num_channels; j++) {
            // grab sample
            y_hat = y[i*num_channels + j];

            // push sample into buffer at filter index
            windowcf_push(w[filter_index], y_hat);

            // decrement filter index
            filter_index = (filter_index + num_channels - 1) % num_channels;
            //filter_index = (filter_index + 1) % num_channels;
        }

        // execute filter outputs, reversing order of output (not
        // sure why this is necessary)
        for (j=0; j<num_channels; j++) {
            windowcf_read(w[j], &r);
            dotprod_crcf_execute(dp[j], r, &X[num_channels-j-1]);
        }

        // execute DFT, store result in buffer 'x'
        fft_execute(fft);

        // move to output array
        for (j=0; j<num_channels; j++)
            Y0[i][j] = x[j];
    }

    // 
    // run traditional down-converter (inefficient)
    //
    float dphi; // carrier frequency
    unsigned int n=0;
    for (i=0; i<num_channels; i++) {

        // reset filter
        firfilt_crcf_reset(f);

        // set center frequency
        dphi = 2.0f * M_PI * (float)i / (float)num_channels;

        // reset symbol counter
        n=0;

        for (j=0; j<num_samples; j++) {
            // push down-converted sample into filter
            firfilt_crcf_push(f, y[j]*cexpf(-_Complex_I*j*dphi));

            // compute output at the appropriate sample time
            assert(n<num_symbols);
            if ( ((j+1)%num_channels)==0 ) {
                firfilt_crcf_execute(f, &Y1[n][i]);
                n++;
            }
        }
        assert(n==num_symbols);

    }

    // destroy objects
    for (i=0; i<num_channels; i++) {
        dotprod_crcf_destroy(dp[i]);
        windowcf_destroy(w[i]);
    }
    fft_destroy_plan(fft);

    firfilt_crcf_destroy(f);

    // print filterbank channelizer
    printf("\n");
    printf("filterbank channelizer:\n");
    for (i=0; i<num_symbols; i++) {
        printf("%3u: ", i);
        for (j=0; j<num_channels; j++) {
            printf("  %8.5f+j%8.5f, ", crealf(Y0[i][j]), cimagf(Y0[i][j]));
        }
        printf("\n");
    }

    // print traditional channelizer
    printf("\n");
    printf("traditional channelizer:\n");
    for (i=0; i<num_symbols; i++) {
        printf("%3u: ", i);
        for (j=0; j<num_channels; j++) {
            printf("  %8.5f+j%8.5f, ", crealf(Y1[i][j]), cimagf(Y1[i][j]));
        }
        printf("\n");
    }

    // 
    // compare results
    // 
    float mse[num_channels];
    float complex d;
    for (i=0; i<num_channels; i++) {
        mse[i] = 0.0f;
        for (j=0; j<num_symbols; j++) {
            d = Y0[j][i] - Y1[j][i];
            mse[i] += crealf(d*conjf(d));
        }

        mse[i] /= num_symbols;
    }
    printf("\n");
    printf("rmse: ");
    for (i=0; i<num_channels; i++)
        printf("%12.4e          ", sqrt(mse[i]));
    printf("\n");

    printf("done.\n");
    return 0;

}
ofdmoqamframe64sync ofdmoqamframe64sync_create(unsigned int _m,
                                               float _beta,
                                               ofdmoqamframe64sync_callback _callback,
                                               void * _userdata)
{
    ofdmoqamframe64sync q = (ofdmoqamframe64sync) malloc(sizeof(struct ofdmoqamframe64sync_s));
    q->num_subcarriers = 64;

    // validate input
    if (_m < 1) {
        fprintf(stderr,"error: ofdmoqamframe64sync_create(), filter delay must be > 0\n");
        exit(1);
    } else if (_beta < 0.0f) {
        fprintf(stderr,"error: ofdmoqamframe64sync_create(), filter excess bandwidth must be > 0\n");
        exit(1);
    }
    q->m = _m;
    q->beta = _beta;

    // synchronizer parameters
    q->rxx_thresh = 0.60f;  // auto-correlation threshold
    q->rxy_thresh = 0.60f;  // cross-correlation threshold

    q->zeta = 64.0f/sqrtf(52.0f);   // scaling factor
    
    // create analysis filter banks
    q->ca0 = firpfbch_create(q->num_subcarriers, q->m, q->beta, 0.0f /*dt*/,FIRPFBCH_ROOTNYQUIST,0/*gradient*/);
    q->ca1 = firpfbch_create(q->num_subcarriers, q->m, q->beta, 0.0f /*dt*/,FIRPFBCH_ROOTNYQUIST,0/*gradient*/);
    q->X0 = (float complex*) malloc((q->num_subcarriers)*sizeof(float complex));
    q->X1 = (float complex*) malloc((q->num_subcarriers)*sizeof(float complex));
    q->Y0 = (float complex*) malloc((q->num_subcarriers)*sizeof(float complex));
    q->Y1 = (float complex*) malloc((q->num_subcarriers)*sizeof(float complex));
 
    // allocate memory for PLCP arrays
    q->S0 = (float complex*) malloc((q->num_subcarriers)*sizeof(float complex));
    q->S1 = (float complex*) malloc((q->num_subcarriers)*sizeof(float complex));
    q->S2 = (float complex*) malloc((q->num_subcarriers)*sizeof(float complex));
    ofdmoqamframe64_init_S0(q->S0);
    ofdmoqamframe64_init_S1(q->S1);
    ofdmoqamframe64_init_S2(q->S2);
    unsigned int i;
    for (i=0; i<q->num_subcarriers; i++) {
        q->S0[i] *= q->zeta;
        q->S1[i] *= q->zeta;
        q->S2[i] *= q->zeta;
    }
    q->S1a = (float complex*) malloc((q->num_subcarriers)*sizeof(float complex));
    q->S1b = (float complex*) malloc((q->num_subcarriers)*sizeof(float complex));

    // set pilot sequence
    q->ms_pilot = msequence_create_default(8);
    q->x_phase[0] = -21.0f;
    q->x_phase[1] =  -7.0f;
    q->x_phase[2] =   7.0f;
    q->x_phase[3] =  21.0f;

    // create NCO for pilots
    q->nco_pilot = nco_crcf_create(LIQUID_VCO);
    q->pll_pilot = pll_create();
    pll_set_bandwidth(q->pll_pilot,0.01f);
    pll_set_damping_factor(q->pll_pilot,4.0f);

    // create agc | signal detection object
    q->sigdet = agc_crcf_create();
    agc_crcf_set_bandwidth(q->sigdet,0.1f);

    // create NCO for CFO compensation
    q->nco_rx = nco_crcf_create(LIQUID_VCO);

    // create auto-correlator objects
    q->autocorr_length = OFDMOQAMFRAME64SYNC_AUTOCORR_LEN;
    q->autocorr_delay = q->num_subcarriers / 4;
    q->autocorr = autocorr_cccf_create(q->autocorr_length, q->autocorr_delay);

    // create cross-correlator object
    q->hxy = (float complex*) malloc((q->num_subcarriers)*sizeof(float complex));
    ofdmoqam cs = ofdmoqam_create(q->num_subcarriers,q->m,q->beta,
                                  0.0f,   // dt
                                  OFDMOQAM_SYNTHESIZER,
                                  0);     // gradient
    for (i=0; i<2*(q->m); i++)
        ofdmoqam_execute(cs,q->S1,q->hxy);
    // time reverse, complex conjugate (same as fftshift for
    // this particular sequence)
    memmove(q->X0, q->hxy, 64*sizeof(float complex));
    for (i=0; i<64; i++)
        q->hxy[i] = conjf(q->X0[64-i-1]);
    // fftshift
    //fft_shift(q->hxy,64);
    q->crosscorr = firfilt_cccf_create(q->hxy, q->num_subcarriers);
    ofdmoqam_destroy(cs);

    // input buffer
    q->input_buffer = windowcf_create((q->num_subcarriers));

    // gain
    q->g = 1.0f;
    q->G0 = (float complex*) malloc((q->num_subcarriers)*sizeof(float complex));
    q->G1 = (float complex*) malloc((q->num_subcarriers)*sizeof(float complex));
    q->G  = (float complex*) malloc((q->num_subcarriers)*sizeof(float complex));

    q->data = (float complex*) malloc((q->num_subcarriers)*sizeof(float complex));

    // reset object
    ofdmoqamframe64sync_reset(q);

#if DEBUG_OFDMOQAMFRAME64SYNC
    q->debug_x =        windowcf_create(DEBUG_OFDMOQAMFRAME64SYNC_BUFFER_LEN);
    q->debug_rxx=       windowcf_create(DEBUG_OFDMOQAMFRAME64SYNC_BUFFER_LEN);
    q->debug_rxy=       windowcf_create(DEBUG_OFDMOQAMFRAME64SYNC_BUFFER_LEN);
    q->debug_framesyms= windowcf_create(DEBUG_OFDMOQAMFRAME64SYNC_BUFFER_LEN);
    q->debug_pilotphase= windowf_create(DEBUG_OFDMOQAMFRAME64SYNC_BUFFER_LEN);
    q->debug_pilotphase_hat= windowf_create(DEBUG_OFDMOQAMFRAME64SYNC_BUFFER_LEN);
    q->debug_rssi=       windowf_create(DEBUG_OFDMOQAMFRAME64SYNC_BUFFER_LEN);
#endif

    q->callback = _callback;
    q->userdata = _userdata;

    return q;
}
// compute ISI for entire system
//  _gt     :   transmit filter [size: _gt_len x 1]
//  _hc     :   channel filter  [size: _hc_len x 1]
//  _gr     :   receive filter  [size: _gr_len x 1]
float eqlms_cccf_isi(unsigned int    _k,
                     float complex * _gt,
                     unsigned int    _gt_len,
                     float complex * _hc,
                     unsigned int    _hc_len,
                     float complex * _gr,
                     unsigned int    _gr_len)
{
    // generate composite by convolving all filters together
    unsigned int i;
   
#if 0
    printf("\n");
    for (i=0; i<_gt_len; i++)
        printf("  gt(%3u) = %16.12f + j*%16.12f;\n", i+1, crealf(_gt[i]), cimagf(_gt[i]));

    printf("\n");
    for (i=0; i<_hc_len; i++)
        printf("  hc(%3u) = %16.12f + j*%16.12f;\n", i+1, crealf(_hc[i]), cimagf(_hc[i]));

    printf("\n");
    for (i=0; i<_gr_len; i++)
        printf("  gr(%3u) = %16.12f + j*%16.12f;\n", i+1, crealf(_gr[i]), cimagf(_gr[i]));
    
    printf("\n");
#endif

    windowcf w;
    float complex * rc;

    // start by convolving transmit and channel filters
    unsigned int gthc_len = _gt_len + _hc_len - 1;
    float complex gthc[gthc_len];
    w = windowcf_create(_gt_len);
    for (i=0; i<gthc_len; i++) {
        if (i < _hc_len) windowcf_push(w, conjf(_hc[_hc_len-i-1]));
        else             windowcf_push(w, 0.0f);

        windowcf_read(w, &rc);
        dotprod_cccf_run(_gt, rc, _gt_len, &gthc[i]);
    }
    windowcf_destroy(w);

#if 0
    printf("composite filter:\n");
    for (i=0; i<gthc_len; i++)
        printf("  gthc(%3u) = %16.12f + j*%16.12f;\n", i+1, crealf(gthc[i]), cimagf(gthc[i]));
#endif
    
    // convolve result with equalizer
    unsigned int h_len = gthc_len + _gr_len - 1;
    float complex h[h_len];
    w = windowcf_create(gthc_len);
    for (i=0; i<h_len; i++) {
        if (i < _gr_len) windowcf_push(w, conjf(_gr[i]));
        else             windowcf_push(w, 0.0f);

        windowcf_read(w, &rc);
        dotprod_cccf_run(gthc, rc, gthc_len, &h[i]);
    }
    windowcf_destroy(w);

#if 0
    printf("composite filter:\n");
    for (i=0; i<h_len; i++)
        printf("  h(%3u) = %16.12f + j*%16.12f;\n", i+1, crealf(h[i]), cimagf(h[i]));
#endif

    // compute resulting ISI
    unsigned int n0 = (_gt_len + _gr_len + (_gt_len + _gr_len)%2)/2 - 1;
    float isi = 0.0f;
    unsigned int n=0;
    for (i=0; i<h_len; i++) {
        if (i == n0)
            continue;
        else if ( (i%_k)==0 ) {
            isi += crealf( h[i]*conjf(h[i]) );
            n++;
        }
    }
    isi /= crealf( h[n0]*conjf(h[n0]) );
    isi = sqrtf(isi / (float)n);

    return isi;
}
Exemple #16
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;
}
Exemple #17
0
// create OFDM framing synchronizer object
//  _M          :   number of subcarriers, >10 typical
//  _cp_len     :   cyclic prefix length
//  _taper_len  :   taper length (OFDM symbol overlap)
//  _p          :   subcarrier allocation (null, pilot, data), [size: _M x 1]
//  _callback   :   user-defined callback function
//  _userdata   :   user-defined data pointer
ofdmframesync ofdmframesync_create(unsigned int           _M,
                                   unsigned int           _cp_len,
                                   unsigned int           _taper_len,
                                   unsigned char *        _p,
                                   ofdmframesync_callback _callback,
                                   void *                 _userdata)
{
    ofdmframesync q = (ofdmframesync) malloc(sizeof(struct ofdmframesync_s));

    // validate input
    if (_M < 8) {
        fprintf(stderr,"warning: ofdmframesync_create(), less than 8 subcarriers\n");
    } else if (_M % 2) {
        fprintf(stderr,"error: ofdmframesync_create(), number of subcarriers must be even\n");
        exit(1);
    } else if (_cp_len > _M) {
        fprintf(stderr,"error: ofdmframesync_create(), cyclic prefix length cannot exceed number of subcarriers\n");
        exit(1);
    }
    q->M = _M;
    q->cp_len = _cp_len;

    // derived values
    q->M2 = _M/2;

    // subcarrier allocation
    q->p = (unsigned char*) malloc((q->M)*sizeof(unsigned char));
    if (_p == NULL) {
        ofdmframe_init_default_sctype(q->M, q->p);
    } else {
        memmove(q->p, _p, q->M*sizeof(unsigned char));
    }

    // validate and count subcarrier allocation
    ofdmframe_validate_sctype(q->p, q->M, &q->M_null, &q->M_pilot, &q->M_data);
    if ( (q->M_pilot + q->M_data) == 0) {
        fprintf(stderr,"error: ofdmframesync_create(), must have at least one enabled subcarrier\n");
        exit(1);
    } else if (q->M_data == 0) {
        fprintf(stderr,"error: ofdmframesync_create(), must have at least one data subcarriers\n");
        exit(1);
    } else if (q->M_pilot < 2) {
        fprintf(stderr,"error: ofdmframesync_create(), must have at least two pilot subcarriers\n");
        exit(1);
    }

    // create transform object
    q->X = (float complex*) malloc((q->M)*sizeof(float complex));
    q->x = (float complex*) malloc((q->M)*sizeof(float complex));
    q->fft = FFT_CREATE_PLAN(q->M, q->x, q->X, FFT_DIR_FORWARD, FFT_METHOD);
 
    // create input buffer the length of the transform
    q->input_buffer = windowcf_create(q->M + q->cp_len);

    // allocate memory for PLCP arrays
    q->S0 = (float complex*) malloc((q->M)*sizeof(float complex));
    q->s0 = (float complex*) malloc((q->M)*sizeof(float complex));
    q->S1 = (float complex*) malloc((q->M)*sizeof(float complex));
    q->s1 = (float complex*) malloc((q->M)*sizeof(float complex));
    ofdmframe_init_S0(q->p, q->M, q->S0, q->s0, &q->M_S0);
    ofdmframe_init_S1(q->p, q->M, q->S1, q->s1, &q->M_S1);

    // compute scaling factor
    q->g_data = sqrtf(q->M) / sqrtf(q->M_pilot + q->M_data);
    q->g_S0   = sqrtf(q->M) / sqrtf(q->M_S0);
    q->g_S1   = sqrtf(q->M) / sqrtf(q->M_S1);

    // gain
    q->g0 = 1.0f;
    q->G0 = (float complex*) malloc((q->M)*sizeof(float complex));
    q->G1 = (float complex*) malloc((q->M)*sizeof(float complex));
    q->G  = (float complex*) malloc((q->M)*sizeof(float complex));
    q->B  = (float complex*) malloc((q->M)*sizeof(float complex));
    q->R  = (float complex*) malloc((q->M)*sizeof(float complex));

#if 1
    memset(q->G0, 0x00, q->M*sizeof(float complex));
    memset(q->G1, 0x00, q->M*sizeof(float complex));
    memset(q->G , 0x00, q->M*sizeof(float complex));
    memset(q->B,  0x00, q->M*sizeof(float complex));
#endif

    // timing backoff
    q->backoff = q->cp_len < 2 ? q->cp_len : 2;
    float phi = (float)(q->backoff)*2.0f*M_PI/(float)(q->M);
    unsigned int i;
    for (i=0; i<q->M; i++)
        q->B[i] = liquid_cexpjf(i*phi);

    // set callback data
    q->callback = _callback;
    q->userdata = _userdata;

    // 
    // synchronizer objects
    //

    // numerically-controlled oscillator
    q->nco_rx = nco_crcf_create(LIQUID_NCO);

    // set pilot sequence
    q->ms_pilot = msequence_create_default(8);

#if OFDMFRAMESYNC_ENABLE_SQUELCH
    // coarse detection
    q->squelch_threshold = -25.0f;
    q->squelch_enabled = 0;
#endif

    // reset object
    ofdmframesync_reset(q);

#if DEBUG_OFDMFRAMESYNC
    q->debug_enabled = 0;
    q->debug_objects_created = 0;

    q->debug_x =        NULL;
    q->debug_rssi =     NULL;
    q->debug_framesyms =NULL;
    
    q->G_hat = NULL;
    q->px    = NULL;
    q->py    = NULL;
    
    q->debug_pilot_0 = NULL;
    q->debug_pilot_1 = NULL;
#endif

    // return object
    return q;
}
int main(int argc, char*argv[])
{
    // options
    unsigned int num_channels=6;    // number of channels (must be even)
    unsigned int m=4;               // filter delay
    unsigned int num_symbols=4*m;   // number of symbols

    // validate input
    if (num_channels%2) {
        fprintf(stderr,"error: %s, number of channels must be even\n", argv[0]);
        exit(1);
    }

    // derived values
    unsigned int num_samples = num_channels * num_symbols;

    unsigned int i;
    unsigned int j;

    // generate filter
    // NOTE : these coefficients can be random; the purpose of this
    //        exercise is to demonstrate mathematical equivalence
#if 0
    unsigned int h_len = 2*m*num_channels;
    float h[h_len];
    for (i=0; i<h_len; i++) h[i] = randnf();
#else
    unsigned int h_len = 2*m*num_channels+1;
    float h[h_len];
    // NOTE: 81.29528 dB > beta = 8.00000 (6 channels, m=4)
    liquid_firdes_kaiser(h_len, 1.0f/(float)num_channels, 81.29528f, 0.0f, h);
#endif
    // normalize
    float hsum = 0.0f;
    for (i=0; i<h_len; i++) hsum += h[i];
    for (i=0; i<h_len; i++) h[i] = h[i] * num_channels / hsum;

    // sub-sampled filters for M=6 channels, m=4, beta=8.0
    //  -3.2069e-19  -6.7542e-04  -1.3201e-03   2.2878e-18   3.7613e-03   5.8033e-03
    //  -7.2899e-18  -1.2305e-02  -1.7147e-02   1.6510e-17   3.1187e-02   4.0974e-02
    //  -3.0032e-17  -6.8026e-02  -8.6399e-02   4.6273e-17   1.3732e-01   1.7307e-01
    //  -6.2097e-17  -2.8265e-01  -3.7403e-01   7.3699e-17   8.0663e-01   1.6438e+00
    //   2.0001e+00   1.6438e+00   8.0663e-01   7.3699e-17  -3.7403e-01  -2.8265e-01
    //  -6.2097e-17   1.7307e-01   1.3732e-01   4.6273e-17  -8.6399e-02  -6.8026e-02
    //  -3.0032e-17   4.0974e-02   3.1187e-02   1.6510e-17  -1.7147e-02  -1.2305e-02
    //  -7.2899e-18   5.8033e-03   3.7613e-03   2.2878e-18  -1.3201e-03  -6.7542e-04

    // create filterbank manually
    dotprod_crcf dp[num_channels];  // vector dot products
    windowcf w[num_channels];       // window buffers

#if DEBUG
    // print coefficients
    printf("h_prototype:\n");
    for (i=0; i<h_len; i++)
        printf("  h[%3u] = %12.8f\n", i, h[i]);
#endif

    // create objects
    unsigned int h_sub_len = 2*m;
    float h_sub[h_sub_len];
    for (i=0; i<num_channels; i++) {
        // sub-sample prototype filter
#if 0
        for (j=0; j<h_sub_len; j++)
            h_sub[j] = h[j*num_channels+i];
#else
        // load coefficients in reverse order
        for (j=0; j<h_sub_len; j++)
            h_sub[h_sub_len-j-1] = h[j*num_channels+i];
#endif

        // create window buffer and dotprod objects
        dp[i] = dotprod_crcf_create(h_sub, h_sub_len);
        w[i]  = windowcf_create(h_sub_len);

#if DEBUG
        printf("h_sub[%u] : \n", i);
        for (j=0; j<h_sub_len; j++)
            printf("  h[%3u] = %12.8f\n", j, h_sub[j]);
#endif
    }

    // generate DFT object
    float complex x[num_channels];  // time-domain buffer
    float complex X[num_channels];  // freq-domain buffer
#if 1
    fftplan fft = fft_create_plan(num_channels, X, x, LIQUID_FFT_BACKWARD, 0);
#else
    fftplan fft = fft_create_plan(num_channels, X, x, LIQUID_FFT_FORWARD, 0);
#endif

    float complex y[num_samples];                   // time-domain input
    float complex Y0[2*num_symbols][num_channels];  // channelizer output
    float complex Y1[2*num_symbols][num_channels];  // conventional output

    // generate input sequence
    for (i=0; i<num_samples; i++) {
        //y[i] = randnf() * cexpf(_Complex_I*randf()*2*M_PI);
        y[i] = (i==0) ? 1.0f : 0.0f;
        y[i] = cexpf(_Complex_I*sqrtf(2.0f)*i*i);
        printf("y[%3u] = %12.8f + %12.8fj\n", i, crealf(y[i]), cimagf(y[i]));
    }

    // 
    // run analysis filter bank
    //
#if 0
    unsigned int filter_index = 0;
#else
    unsigned int filter_index = num_channels/2-1;
#endif
    float complex y_hat;    // input sample
    float complex * r;      // buffer read pointer
    int toggle = 0;         // flag indicating buffer/filter alignment

    //
    for (i=0; i<2*num_symbols; i++) {

        // load buffers in blocks of num_channels/2
        for (j=0; j<num_channels/2; j++) {
            // grab sample
            y_hat = y[i*num_channels/2 + j];

            // push sample into buffer at filter index
            windowcf_push(w[filter_index], y_hat);

            // decrement filter index
            filter_index = (filter_index + num_channels - 1) % num_channels;
            //filter_index = (filter_index + 1) % num_channels;
        }

        // execute filter outputs
        // reversing order of output (not sure why this is necessary)
        unsigned int offset = toggle ? num_channels/2 : 0;
        toggle = 1-toggle;
        for (j=0; j<num_channels; j++) {
            unsigned int buffer_index  = (offset+j)%num_channels;
            unsigned int dotprod_index = j;

            windowcf_read(w[buffer_index], &r);
            //dotprod_crcf_execute(dp[dotprod_index], r, &X[num_channels-j-1]);
            dotprod_crcf_execute(dp[dotprod_index], r, &X[buffer_index]);
        }

        printf("***** i = %u\n", i);
        for (j=0; j<num_channels; j++)
            printf("  v2[%4u] = %12.8f + %12.8fj\n", j, crealf(X[j]), cimagf(X[j]));
        // execute DFT, store result in buffer 'x'
        fft_execute(fft);
        // scale fft output
        for (j=0; j<num_channels; j++)
            x[j] *= 1.0f / (num_channels);

        // move to output array
        for (j=0; j<num_channels; j++)
            Y0[i][j] = x[j];
    }
    // destroy objects
    for (i=0; i<num_channels; i++) {
        dotprod_crcf_destroy(dp[i]);
        windowcf_destroy(w[i]);
    }
    fft_destroy_plan(fft);


    // 
    // run traditional down-converter (inefficient)
    //
    // generate filter object
    firfilt_crcf f = firfilt_crcf_create(h, h_len);

    float dphi; // carrier frequency
    unsigned int n=0;
    for (i=0; i<num_channels; i++) {

        // reset filter
        firfilt_crcf_clear(f);

        // set center frequency
        dphi = 2.0f * M_PI * (float)i / (float)num_channels;

        // reset symbol counter
        n=0;

        for (j=0; j<num_samples; j++) {
            // push down-converted sample into filter
            firfilt_crcf_push(f, y[j]*cexpf(-_Complex_I*j*dphi));

            // compute output at the appropriate sample time
            assert(n<2*num_symbols);
            if ( ((j+1)%(num_channels/2))==0 ) {
                firfilt_crcf_execute(f, &Y1[n][i]);
                n++;
            }
        }
        assert(n==2*num_symbols);

    }
    firfilt_crcf_destroy(f);

    // print filterbank channelizer
    printf("\n");
    printf("filterbank channelizer:\n");
    for (i=0; i<2*num_symbols; i++) {
        printf("%2u:", i);
        for (j=0; j<num_channels; j++) {
            printf("%6.3f+%6.3fj, ", crealf(Y0[i][j]), cimagf(Y0[i][j]));
        }
        printf("\n");
    }

#if 0
    // print traditional channelizer
    printf("\n");
    printf("traditional channelizer:\n");
    for (i=0; i<2*num_symbols; i++) {
        printf("%2u:", i);
        for (j=0; j<num_channels; j++) {
            printf("%6.3f+%6.3fj, ", crealf(Y1[i][j]), cimagf(Y1[i][j]));
        }
        printf("\n");
    }

    // 
    // compare results
    // 
    float mse[num_channels];
    float complex d;
    for (i=0; i<num_channels; i++) {
        mse[i] = 0.0f;
        for (j=0; j<2*num_symbols; j++) {
            d = Y0[j][i] - Y1[j][i];
            mse[i] += crealf(d*conjf(d));
        }

        mse[i] /= num_symbols;
    }
    printf("\n");
    printf(" e:");
    for (i=0; i<num_channels; i++)
        printf("%12.4e    ", sqrt(mse[i]));
    printf("\n");
#endif

    printf("done.\n");
    return 0;

}