// 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);
}
Example #2
0
// execute framing synchronizer on input buffer
//  _q      :   framing synchronizer object
//  _buffer :   input buffer [size: _n x 1]
//  _n      :   input buffer size
void wlanframesync_execute(wlanframesync          _q,
                           liquid_float_complex * _buffer,
                           unsigned int           _n)
{
    unsigned int i;
    float complex x;
    for (i=0; i<_n; i++) {
        x = _buffer[i];

        // correct for carrier frequency offset (only if not in
        // initial 'seek PLCP' state)
        if (_q->state != WLANFRAMESYNC_STATE_SEEKPLCP) {
            nco_crcf_mix_down(_q->nco_rx, x, &x);
            nco_crcf_step(_q->nco_rx);
        }

        // save input sample to buffer
        windowcf_push(_q->input_buffer,x);

#if DEBUG_WLANFRAMESYNC
        if (_q->debug_enabled) {
            // apply agc (estimate initial signal gain)
            float complex y;
            agc_crcf_execute(_q->agc_rx, x, &y);

            windowcf_push(_q->debug_x, x);
            windowf_push(_q->debug_rssi, agc_crcf_get_rssi(_q->agc_rx));
        }
#endif

        switch (_q->state) {
        case WLANFRAMESYNC_STATE_SEEKPLCP:
            wlanframesync_execute_seekplcp(_q);
            break;
        case WLANFRAMESYNC_STATE_RXSHORT0:
            wlanframesync_execute_rxshort0(_q);
            break;
        case WLANFRAMESYNC_STATE_RXSHORT1:
            wlanframesync_execute_rxshort1(_q);
            break;
        case WLANFRAMESYNC_STATE_RXLONG0:
            wlanframesync_execute_rxlong0(_q);
            break;
        case WLANFRAMESYNC_STATE_RXLONG1:
            wlanframesync_execute_rxlong1(_q);
            break;
        case WLANFRAMESYNC_STATE_RXSIGNAL:
            wlanframesync_execute_rxsignal(_q);
            break;
        case WLANFRAMESYNC_STATE_RXDATA:
            wlanframesync_execute_rxdata(_q);
            break;
        default:;
            // should never get to this point
            fprintf(stderr,"error: wlanframesync_execute(), invalid state\n");
            exit(1);
        }
    } // for (i=0; i<_n; i++)
}
Example #3
0
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;
}
Example #4
0
// execute frame synchronizer
//  _q  :   frame synchronizer object
//  _x  :   input sample array [size: _n x 1]
//  _n  :   number of input samples
void flexframesync_execute(flexframesync   _q,
                           float complex * _x,
                           unsigned int    _n)
{
    unsigned int i;
    for (i=0; i<_n; i++) {
#if DEBUG_FLEXFRAMESYNC
        // write samples to debug buffer
        // NOTE: the debug_qdetector_flush prevents samples from being written twice
        if (_q->debug_enabled && !_q->debug_qdetector_flush)
            windowcf_push(_q->debug_x, _x[i]);
#endif
        switch (_q->state) {
        case FLEXFRAMESYNC_STATE_DETECTFRAME:
            // detect frame (look for p/n sequence)
            flexframesync_execute_seekpn(_q, _x[i]);
            break;
        case FLEXFRAMESYNC_STATE_RXPREAMBLE:
            // receive p/n sequence symbols
            flexframesync_execute_rxpreamble(_q, _x[i]);
            break;
        case FLEXFRAMESYNC_STATE_RXHEADER:
            // receive header symbols
            flexframesync_execute_rxheader(_q, _x[i]);
            break;
        case FLEXFRAMESYNC_STATE_RXPAYLOAD:
            // receive payload symbols
            flexframesync_execute_rxpayload(_q, _x[i]);
            break;
        default:
            fprintf(stderr,"error: flexframesync_exeucte(), unknown/unsupported state\n");
            exit(1);
        }
    }
}
Example #5
0
// execute frame synchronizer
//  _q     :   frame synchronizer object
//  _x      :   input sample array [size: _n x 1]
//  _n      :   number of input samples
void flexframesync_execute(flexframesync   _q,
                           float complex * _x,
                           unsigned int    _n)
{
    unsigned int i;
    for (i=0; i<_n; i++) {
#if DEBUG_FLEXFRAMESYNC
        if (_q->debug_enabled)
            windowcf_push(_q->debug_x, _x[i]);
#endif
        switch (_q->state) {
        case STATE_DETECTFRAME:
            // detect frame (look for p/n sequence)
            flexframesync_execute_seekpn(_q, _x[i]);
            break;
        case STATE_RXPN:
            // receive p/n sequence symbols
            flexframesync_execute_rxpn(_q, _x[i]);
            break;
        case STATE_RXHEADER:
            // receive header sequence symbols
            flexframesync_execute_rxheader(_q, _x[i]);
            break;
        case STATE_RXPAYLOAD:
            // receive payload symbols
            flexframesync_execute_rxpayload(_q, _x[i]);
            break;
        default:
            fprintf(stderr,"error: flexframesync_exeucte(), unknown/unsupported state\n");
            exit(1);
        }
    }
}
void ofdmoqamframe64sync_execute(ofdmoqamframe64sync _q,
                                 float complex * _x,
                                 unsigned int _n)
{
    unsigned int i;
    float complex x;
    for (i=0; i<_n; i++) {
        x = _x[i];
#if DEBUG_OFDMOQAMFRAME64SYNC
        windowcf_push(_q->debug_x,x);
#endif
        _q->num_samples++;

        // coarse gain correction
        //x *= _q->g;
        
        // compensate for CFO
        nco_crcf_mix_down(_q->nco_rx, x, &x);

        // push sample into analysis filter banks
        float complex x_delay0;
        float complex x_delay1;
        windowcf_index(_q->input_buffer,0, &x_delay0); // full symbol delay
        windowcf_index(_q->input_buffer,32,&x_delay1); // half symbol delay

        windowcf_push(_q->input_buffer,x);
        firpfbch_analyzer_push(_q->ca0, x_delay0);  // push input sample
        firpfbch_analyzer_push(_q->ca1, x_delay1);  // push delayed sample

        switch (_q->state) {
        case OFDMOQAMFRAME64SYNC_STATE_PLCPSHORT:
            ofdmoqamframe64sync_execute_plcpshort(_q,x);
            break;
        case OFDMOQAMFRAME64SYNC_STATE_PLCPLONG0:
            ofdmoqamframe64sync_execute_plcplong0(_q,x);
            break;
        case OFDMOQAMFRAME64SYNC_STATE_PLCPLONG1:
            ofdmoqamframe64sync_execute_plcplong1(_q,x);
            break;
        case OFDMOQAMFRAME64SYNC_STATE_RXSYMBOLS:
            ofdmoqamframe64sync_execute_rxsymbols(_q,x);
            break;
        default:;
        }

    } // for (i=0; i<_n; i++)
} // ofdmoqamframe64sync_execute()
void ofdmoqamframe64sync_execute_plcplong1(ofdmoqamframe64sync _q, float complex _x)
{
    // cross-correlator
    float complex rxy;
    firfilt_cccf_push(_q->crosscorr, _x);
    firfilt_cccf_execute(_q->crosscorr, &rxy);

    rxy *= _q->g;

#if DEBUG_OFDMOQAMFRAME64SYNC
    windowcf_push(_q->debug_rxy, rxy);
#endif

    _q->timer++;
    if (_q->timer < _q->num_subcarriers-8) {
        return;
    } else if (_q->timer > _q->num_subcarriers+8) {
#if DEBUG_OFDMOQAMFRAME64SYNC_PRINT
        printf("warning: ofdmoqamframe64sync could not find second PLCP long sequence; resetting synchronizer\n");
#endif
        ofdmoqamframe64sync_reset(_q);
        return;
    }

    if (cabsf(rxy) > 0.7f*(_q->rxy_thresh)*(_q->num_subcarriers)) {
#if DEBUG_OFDMOQAMFRAME64SYNC_PRINT
        printf("rxy[1] : %12.8f at input[%3u]\n", cabsf(rxy), _q->num_samples);
#endif

        // 
        float complex * rc;
        windowcf_read(_q->input_buffer, &rc);
        memmove(_q->S1b, rc, 64*sizeof(float complex));

        // estimate frequency offset
        float complex rxy_hat=0.0f;
        unsigned int j;
        for (j=0; j<64; j++) {
            rxy_hat += _q->S1a[j] * conjf(_q->S1b[j]) * hamming(j,64);
        }
        float nu_hat1 = -cargf(rxy_hat);
        if (nu_hat1 >  M_PI) nu_hat1 -= 2.0f*M_PI;
        if (nu_hat1 < -M_PI) nu_hat1 += 2.0f*M_PI;
        nu_hat1 /= 64.0f;
#if DEBUG_OFDMOQAMFRAME64SYNC_PRINT
        printf("nu_hat[0] = %12.8f\n", _q->nu_hat);
        printf("nu_hat[1] = %12.8f\n", nu_hat1);
#endif
        nco_crcf_adjust_frequency(_q->nco_rx, nu_hat1);

        /*
        printf("exiting prematurely\n");
        ofdmoqamframe64sync_destroy(_q);
        exit(1);
        */
        _q->state = OFDMOQAMFRAME64SYNC_STATE_RXSYMBOLS;
    }

}
Example #8
0
void ofdmframesync_execute(ofdmframesync _q,
                           float complex * _x,
                           unsigned int _n)
{
    unsigned int i;
    float complex x;
    for (i=0; i<_n; i++) {
        x = _x[i];

        // correct for carrier frequency offset
        if (_q->state != OFDMFRAMESYNC_STATE_SEEKPLCP) {
            nco_crcf_mix_down(_q->nco_rx, x, &x);
            nco_crcf_step(_q->nco_rx);
        }

        // save input sample to buffer
        windowcf_push(_q->input_buffer,x);

#if DEBUG_OFDMFRAMESYNC
        if (_q->debug_enabled) {
            windowcf_push(_q->debug_x, x);
            windowf_push(_q->debug_rssi, crealf(x)*crealf(x) + cimagf(x)*cimagf(x));
        }
#endif

        switch (_q->state) {
        case OFDMFRAMESYNC_STATE_SEEKPLCP:
            ofdmframesync_execute_seekplcp(_q);
            break;
        case OFDMFRAMESYNC_STATE_PLCPSHORT0:
            ofdmframesync_execute_S0a(_q);
            break;
        case OFDMFRAMESYNC_STATE_PLCPSHORT1:
            ofdmframesync_execute_S0b(_q);
            break;
        case OFDMFRAMESYNC_STATE_PLCPLONG:
            ofdmframesync_execute_S1(_q);
            break;
        case OFDMFRAMESYNC_STATE_RXSYMBOLS:
            ofdmframesync_execute_rxsymbols(_q);
            break;
        default:;
        }

    } // for (i=0; i<_n; i++)
} // ofdmframesync_execute()
void ofdmoqamframe64sync_execute_plcpshort(ofdmoqamframe64sync _q, float complex _x)
{
    // run AGC, clip output
    float complex y;
    agc_crcf_execute(_q->sigdet, _x, &y);
    //if (agc_crcf_get_signal_level(_q->sigdet) < -15.0f)
    //    return;
    if (cabsf(y) > 2.0f)
        y = 2.0f*liquid_cexpjf(cargf(y));

    // auto-correlators
    //autocorr_cccf_push(_q->autocorr, _x);
    autocorr_cccf_push(_q->autocorr, y);
    autocorr_cccf_execute(_q->autocorr, &_q->rxx);

#if DEBUG_OFDMOQAMFRAME64SYNC
    windowcf_push(_q->debug_rxx, _q->rxx);

    windowf_push(_q->debug_rssi, agc_crcf_get_signal_level(_q->sigdet));
#endif
    float rxx_mag = cabsf(_q->rxx);

    float threshold = (_q->rxx_thresh)*(_q->autocorr_length);

    if (rxx_mag > threshold) {
        // wait for auto-correlation to peak before changing state
        if (rxx_mag > _q->rxx_mag_max) {
            _q->rxx_mag_max = rxx_mag;
            return;
        }

        // estimate CFO
        _q->nu_hat = cargf(_q->rxx);
        if (_q->nu_hat >  M_PI/2.0f) _q->nu_hat -= M_PI;
        if (_q->nu_hat < -M_PI/2.0f) _q->nu_hat += M_PI;
        _q->nu_hat *= 4.0f / (float)(_q->num_subcarriers);

#if DEBUG_OFDMOQAMFRAME64SYNC_PRINT
        printf("rxx = |%12.8f| arg{%12.8f}\n", cabsf(_q->rxx),cargf(_q->rxx));
        printf("nu_hat =  %12.8f\n", _q->nu_hat);
#endif

        nco_crcf_set_frequency(_q->nco_rx, _q->nu_hat);
        _q->state = OFDMOQAMFRAME64SYNC_STATE_PLCPLONG0;

        _q->g = agc_crcf_get_gain(_q->sigdet);

#if DEBUG_OFDMOQAMFRAME64SYNC_PRINT
        printf("gain : %f\n", _q->g);
#endif
        _q->timer=0;
    }
}
Example #10
0
void ampmodem_demodulate(ampmodem _q,
                         float complex _y,
                         float *_x)
{
#if DEBUG_AMPMODEM
    windowcf_push(_q->debug_x, _y);
#endif

    if (_q->suppressed_carrier) {
        // single side-band suppressed carrier
        if (_q->type != LIQUID_AMPMODEM_DSB) {
            *_x = crealf(_y);
            return;
        }

        // coherent demodulation
        
        // mix signal down
        float complex y_hat;
        nco_crcf_mix_down(_q->oscillator, _y, &y_hat);

        // compute phase error
        float phase_error = tanhf( crealf(y_hat) * cimagf(y_hat) );
#if DEBUG_AMPMODEM
        // compute frequency error
        float nco_freq   = nco_crcf_get_frequency(_q->oscillator);
        float freq_error = nco_freq/(2*M_PI) - _q->fc/(2*M_PI);

        // retain phase and frequency errors
        windowf_push(_q->debug_phase_error, phase_error);
        windowf_push(_q->debug_freq_error, freq_error);
#endif

        // adjust nco, pll objects
        nco_crcf_pll_step(_q->oscillator, phase_error);

        // step NCO
        nco_crcf_step(_q->oscillator);

        // set output
        *_x = crealf(y_hat);
    } else {
        // non-coherent demodulation (peak detector)
        float t = cabsf(_y);

        // remove DC bias
        _q->ssb_q_hat = (    _q->ssb_alpha)*t +
                        (1 - _q->ssb_alpha)*_q->ssb_q_hat;
        *_x = 2.0f*(t - _q->ssb_q_hat);
    }
}
void ofdmoqamframe64sync_execute_plcplong0(ofdmoqamframe64sync _q, float complex _x)
{
    // cross-correlator
    float complex rxy;
    firfilt_cccf_push(_q->crosscorr, _x);
    firfilt_cccf_execute(_q->crosscorr, &rxy);

    rxy *= _q->g;

#if DEBUG_OFDMOQAMFRAME64SYNC
    windowcf_push(_q->debug_rxy, rxy);
#endif

    _q->timer++;
    if (_q->timer > 10*(_q->num_subcarriers)) {
#if DEBUG_OFDMOQAMFRAME64SYNC_PRINT
        printf("warning: ofdmoqamframe64sync could not find first PLCP long sequence; resetting synchronizer\n");
#endif
        ofdmoqamframe64sync_reset(_q);
        return;
    }

    if (cabsf(rxy) > (_q->rxy_thresh)*(_q->num_subcarriers)) {
#if DEBUG_OFDMOQAMFRAME64SYNC_PRINT
        printf("rxy[0] : %12.8f at input[%3u]\n", cabsf(rxy), _q->num_samples);
#endif

        // run analyzers
        //firpfbch_analyzer_run(_q->ca0, _q->S1a);
        //firpfbch_analyzer_run(_q->ca1, _q->S1b);

        _q->sample_phase = (_q->num_samples + (_q->num_subcarriers)/2) % _q->num_subcarriers;
        //_q->sample_phase = (_q->num_samples) % _q->num_subcarriers;
#if DEBUG_OFDMOQAMFRAME64SYNC_PRINT
        printf("sample phase : %u\n",_q->sample_phase);
#endif
        // 
        float complex * rc;
        windowcf_read(_q->input_buffer, &rc);
        memmove(_q->S1a, rc, 64*sizeof(float complex));

        _q->state = OFDMOQAMFRAME64SYNC_STATE_PLCPLONG1;
        _q->timer = 0;
    }
}
Example #12
0
// execute frame synchronizer
//  _q      :   frame synchronizer object
//  _x      :   input sample array [size: _n x 1]
//  _n      :   number of input samples
void gmskframesync_execute(gmskframesync   _q,
                           float complex * _x,
                           unsigned int    _n)
{
    // push through synchronizer
    unsigned int i;
    for (i=0; i<_n; i++) {
        float complex xf;   // input sample
#if GMSKFRAMESYNC_PREFILTER
        iirfilt_crcf_execute(_q->prefilter, _x[i], &xf);
#else
        xf = _x[i];
#endif

#if DEBUG_GMSKFRAMESYNC
        if (_q->debug_enabled)
            windowcf_push(_q->debug_x, xf);
#endif

        switch (_q->state) {
        case STATE_DETECTFRAME:
            // look for p/n sequence
            gmskframesync_execute_detectframe(_q, xf);
            break;

        case STATE_RXPREAMBLE:
            // receive p/n sequence symbols
            gmskframesync_execute_rxpreamble(_q, xf);
            break;

        case STATE_RXHEADER:
            // receive header
            gmskframesync_execute_rxheader(_q, xf);
            break;

        case STATE_RXPAYLOAD:
            // receive payload
            gmskframesync_execute_rxpayload(_q, xf);
            break;
        }
    }
}
Example #13
0
void ofdmframesync_execute_rxsymbols(ofdmframesync _q)
{
    // wait for timeout
    _q->timer--;

    if (_q->timer == 0) {

        // run fft
        float complex * rc;
        windowcf_read(_q->input_buffer, &rc);
        memmove(_q->x, &rc[_q->cp_len-_q->backoff], (_q->M)*sizeof(float complex));
        FFT_EXECUTE(_q->fft);

        // recover symbol in internal _q->X buffer
        ofdmframesync_rxsymbol(_q);

#if DEBUG_OFDMFRAMESYNC
        if (_q->debug_enabled) {
            unsigned int i;
            for (i=0; i<_q->M; i++) {
                if (_q->p[i] == OFDMFRAME_SCTYPE_DATA)
                    windowcf_push(_q->debug_framesyms, _q->X[i]);
            }
        }
#endif
        // invoke callback
        if (_q->callback != NULL) {
            int retval = _q->callback(_q->X, _q->p, _q->M, _q->userdata);

            if (retval != 0)
                ofdmframesync_reset(_q);
        }

        // reset timer
        _q->timer = _q->M + _q->cp_len;
    }

}
Example #14
0
void gmskframesync_execute_detectframe(gmskframesync _q,
                                       float complex _x)
{
    // push sample into pre-demod p/n sequence buffer
    windowcf_push(_q->buffer, _x);

    // push through pre-demod synchronizer
    int detected = detector_cccf_correlate(_q->frame_detector,
                                           _x,
                                           &_q->tau_hat,
                                           &_q->dphi_hat,
                                           &_q->gamma_hat);

    // check if frame has been detected
    if (detected) {
        //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));

        // push buffered samples through synchronizer
        // NOTE: state will be updated to STATE_RXPREAMBLE internally
        gmskframesync_pushpn(_q);
    }
}
Example #15
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 sample into pre-demod p/n sequence buffer
    windowcf_push(_q->buffer, _x);

    // push through pre-demod synchronizer
    int detected = detector_cccf_correlate(_q->frame_detector,
                                           _x,
                                           &_q->tau_hat,
                                           &_q->dphi_hat,
                                           &_q->gamma_hat);

    // check if frame has been detected
    if (detected) {
        //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));

        // push buffered samples through synchronizer
        // NOTE: this will set internal state appropriately
        //       to STATE_DETECTFRAME
        flexframesync_pushpn(_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;

}
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
        }
    }

}
Example #18
0
// receive data symbols
void wlanframesync_execute_rxdata(wlanframesync _q)
{
    _q->timer++;
    if (_q->timer < 80)
        return;

    //printf("    receiving symbol %u...\n", _q->num_symbols);

    // reset timer
    _q->timer = 0;

    // run fft
    float complex * rc;
    windowcf_read(_q->input_buffer, &rc);
    memmove(_q->x, &rc[16-2], 64*sizeof(float complex));

    // compute fft, storing result into _q->X
    FFT_EXECUTE(_q->fft);
  
    // recover symbol, correcting for gain, pilot phase, etc.
    wlanframesync_rxsymbol(_q);
   
    // demodulate and pack
    unsigned int i;
    unsigned int n=0;
    unsigned int sym;
    for (i=0; i<64; i++) {
        unsigned int k = (i + 32) % 64;

        if ( k==0 || (k > 26 && k < 38) ) {
            // NULL subcarrier
        } else if (k==43 || k==57 || k==7 || k==21) {
            // PILOT subcarrier
        } else {
            // DATA subcarrier
            assert(n<48);
            sym = wlan_demodulate(_q->mod_scheme, _q->X[k]);
            _q->modem_syms[n] = sym;
            n++;
#if DEBUG_WLANFRAMESYNC
            // TODO : move this outside loop
            if (_q->debug_enabled)
                windowcf_push(_q->debug_framesyms, _q->X[k]);
#endif

        }
    }
    assert(n==48);

    // pack modem symbols
    //printf("  %3u = %3u * %3u\n", _q->enc_msg_len, _q->nsym, _q->bytes_per_symbol);
    unsigned int num_written;
    liquid_wlan_repack_bytes(_q->modem_syms, _q->nbpsc, 48,
                             &_q->msg_enc[_q->num_symbols * _q->bytes_per_symbol], 8, _q->bytes_per_symbol,
                             &num_written);
    assert(num_written == _q->bytes_per_symbol);

    // increment number of received symbols
    _q->num_symbols++;

    // check number of symbols
    if (_q->num_symbols == _q->nsym) {
        // decode message
        wlan_packet_decode(_q->rate, _q->seed, _q->length, _q->msg_enc, _q->msg_dec);

        // assemble RX vector
        struct wlan_rxvector_s rxvector;
        rxvector.LENGTH     = _q->length;
        rxvector.RSSI       = 200 + (unsigned int) (10*log10f(_q->g0));
        rxvector.DATARATE   = _q->rate;
        rxvector.SERVICE    = 0;

        // invoke callback
        if (_q->callback != NULL) {
            //int retval = 
            _q->callback(_q->msg_dec, rxvector, _q->userdata);
        }

        // reset and return
        wlanframesync_reset(_q);
    }
}
Example #19
0
void do_track(){
    if (local_track_freq != shm_settings.track_frequency_target) {
       if (ff.sosMap.count(shm_settings.track_frequency_target)) { //frequency key exists
            if (track_filterA != NULL)
                iirfilt_crcf_destroy(track_filterA);
            if (track_filterB != NULL)
                iirfilt_crcf_destroy(track_filterB);
            if (track_filterC != NULL)
                iirfilt_crcf_destroy(track_filterC);

            float *b = &((ff.sosMap[shm_settings.track_frequency_target]->b)[0]);
            float *a = &((ff.sosMap[shm_settings.track_frequency_target]->a)[0]);
            track_filterA = iirfilt_crcf_create_sos(b,a,NUMBER_OF_SECTIONS);
            track_filterB = iirfilt_crcf_create_sos(b,a,NUMBER_OF_SECTIONS);
            track_filterC = iirfilt_crcf_create_sos(b,a,NUMBER_OF_SECTIONS);

            shm_results_track.track_state = 0;

            local_track_freq = shm_settings.track_frequency_target;
            float normalized_frequency = (float) shm_settings.track_frequency_target / (float) SAMPLING_FREQUENCY;
            nco_crcf_set_frequency(nco,2*M_PI*normalized_frequency);
        }
        else { //frequency key does not exist. Trigger error state
            shm_results_track.track_state = -1;
            std::cerr << shm_settings.track_frequency_target << " WARN TRACK FREQ NOT IN SOS TABLE" << std::endl;
        }

        shm_setg(hydrophones_results_track, shm_results_track);
    }

    std::complex<float> *chA_ptr, *chA_filtered_ptr;
    std::complex<float> *chB_ptr, *chB_filtered_ptr;
    std::complex<float> *chC_ptr, *chC_filtered_ptr;

    float *mag_ptr;
    windowcf_read(wchA,&chA_ptr);
    windowcf_read(wchB,&chB_ptr);
    windowcf_read(wchC,&chC_ptr);

    std::complex<float> filtOutA, filtOutB, filtOutC;

    for (int i = 0; i < SAMPLING_DEPTH; i++) {
        iirfilt_crcf_execute(track_filterA,chA_ptr[i],&filtOutA);
        iirfilt_crcf_execute(track_filterB,chB_ptr[i],&filtOutB);
        iirfilt_crcf_execute(track_filterC,chC_ptr[i],&filtOutC);
        
        windowcf_read(wchA_filtered,&chA_filtered_ptr);
        windowcf_read(wchB_filtered,&chB_filtered_ptr);
        windowcf_read(wchC_filtered,&chC_filtered_ptr);

        windowcf_push(wchA_filtered,filtOutA);
        windowcf_push(wchB_filtered,filtOutB);
        windowcf_push(wchC_filtered,filtOutC);

        float b_sqrd = std::pow(std::real(filtOutB),2);

        pwr_sum += b_sqrd;
        windowf_read(wmag_buffer,&mag_ptr);
        pwr_sum -= mag_ptr[0];
        windowf_push(wmag_buffer,b_sqrd);

        double normalized_pwr = pwr_sum / (double)TRACK_LENGTH;
        if (normalized_pwr > shm_settings.track_magnitude_threshold &&
            (track_sample_idx - shm_results_track.tracked_ping_time) >= shm_settings.track_cooldown_samples) {
            std::complex<float> dtft_coeff_A = goertzelNonInteger(chA_filtered_ptr,TRACK_LENGTH,shm_settings.track_frequency_target,SAMPLING_FREQUENCY);
            std::complex<float> dtft_coeff_B = goertzelNonInteger(chB_filtered_ptr,TRACK_LENGTH,shm_settings.track_frequency_target,SAMPLING_FREQUENCY);
            std::complex<float> dtft_coeff_C = goertzelNonInteger(chC_filtered_ptr,TRACK_LENGTH,shm_settings.track_frequency_target,SAMPLING_FREQUENCY);
             
            float phaseA = std::arg(dtft_coeff_A);
            float phaseB = std::arg(dtft_coeff_B);
            float phaseC = std::arg(dtft_coeff_C);

            shm_results_track.diff_phase_y = phase_difference(phaseC,phaseB);
            shm_results_track.diff_phase_x = phase_difference(phaseA,phaseB);

            float kx = SOUND_SPEED * shm_results_track.diff_phase_x / (NIPPLE_DISTANCE * 2 * M_PI * shm_settings.track_frequency_target);
            float ky = SOUND_SPEED * shm_results_track.diff_phase_y / (NIPPLE_DISTANCE * 2 * M_PI * shm_settings.track_frequency_target);

            float kz_2 = 1 - kx * kx - ky * ky;
            if (kz_2 < 0) {
              std::cerr << "WARNING: z mag is negative! " << kz_2 << std::endl;
              kz_2 = 0;
            }

            shm_results_track.tracked_ping_heading_radians = std::atan2(ky, kx);
            shm_results_track.tracked_ping_elevation_radians = std::acos(std::sqrt(kz_2));

            shm_results_track.tracked_ping_count++;
            shm_results_track.tracked_ping_frequency = shm_results_spectrum.most_recent_ping_frequency;  
            shm_results_track.tracked_ping_time = track_sample_idx; 

            std::cout << "PING DETECTED @ n=" << track_sample_idx << " w/ pwr="<< normalized_pwr<< std::endl;
            std::cout << "@ HEADING=" << shm_results_track.tracked_ping_heading_radians*(180.0f/M_PI) << std::endl; 

            shm_setg(hydrophones_results_track, shm_results_track);
        }
        track_sample_idx++;

    }
}
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;

}
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;
}
Example #22
0
// 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;
}