예제 #1
0
void DestroyMinimumPhaseAnalysis(MinimumPhaseAnalysis *minimum_phase) {
  fft_destroy_plan(minimum_phase->forward_fft);
  fft_destroy_plan(minimum_phase->inverse_fft);
  delete[] minimum_phase->cepstrum;
  delete[] minimum_phase->log_spectrum;
  delete[] minimum_phase->minimum_phase_spectrum;
}
예제 #2
0
// Compute spectral response
void liquid_doc_freqz(float * _b,
                      unsigned int _nb,
                      float * _a,
                      unsigned int _na,
                      unsigned int _nfft,
                      float complex * _H)
{
    unsigned int i;

    float complex x[_nfft];
    float complex B[_nfft];
    float complex A[_nfft];
    float complex X[_nfft];
    fftplan fft = fft_create_plan(_nfft,x,X,FFT_FORWARD,0);

    // numerator
    for (i=0; i<_nfft; i++)
        x[i] = i < _nb ? _b[i] : 0.0f;
    fft_execute(fft);
    memmove(B,X,_nfft*sizeof(float complex));

    // denominator
    for (i=0; i<_nfft; i++)
        x[i] = i < _na ? _a[i] : 0.0f;
    fft_execute(fft);
    memmove(A,X,_nfft*sizeof(float complex));

    fft_destroy_plan(fft);

    for (i=0; i<_nfft; i++)
        X[i] = B[i] / A[i];

    memmove(_H, X, _nfft*sizeof(float complex));
}
예제 #3
0
// autotest helper function
void fft_r2r_test(float *      _x,
                  float *      _test,
                  unsigned int _n,
                  unsigned int _kind)
{
    int _flags = 0;
    float tol=1e-4f;

    unsigned int i;

    float y[_n];

    // compute real even/odd FFT
    fftplan q = fft_create_plan_r2r_1d(_n, _x, y, _kind, _flags);
    fft_execute(q);

    // print results
    if (liquid_autotest_verbose) {
        printf("%12s %12s\n", "expected", "actual");
        for (i=0; i<_n; i++)
            printf("%12.8f %12.8f\n", _test[i], y[i]);
    }

    // validate results
    for (i=0; i<_n; i++)
        CONTEND_DELTA( y[i], _test[i], tol);

    // destroy plans
    fft_destroy_plan(q);
}
예제 #4
0
// autotest helper function
//  _x      :   fft input array
//  _test   :   expected fft output
//  _n      :   fft size
void fft_test(float complex * _x,
              float complex * _test,
              unsigned int    _n)
{
    int _method = 0;
    float tol=2e-4f;

    unsigned int i;

    float complex y[_n], z[_n];

    // compute FFT
    fftplan pf = fft_create_plan(_n, _x, y, LIQUID_FFT_FORWARD, _method);
    fft_execute(pf);

    // compute IFFT
    fftplan pr = fft_create_plan(_n, y, z, LIQUID_FFT_BACKWARD, _method);
    fft_execute(pr);

    // normalize inverse
    for (i=0; i<_n; i++)
        z[i] /= (float) _n;

    // validate results
    float fft_error, ifft_error;
    for (i=0; i<_n; i++) {
        fft_error = cabsf( y[i] - _test[i] );
        ifft_error = cabsf( _x[i] - z[i] );
        CONTEND_DELTA( fft_error, 0, tol);
        CONTEND_DELTA( ifft_error, 0, tol);
    }

    // destroy plans
    fft_destroy_plan(pf);
    fft_destroy_plan(pr);
}
void liquid_doc_compute_psdcf(float complex * _x,
                              unsigned int _n,
                              float complex * _X,
                              unsigned int _nfft,
                              liquid_doc_psdwindow _wtype,
                              int _normalize)
{
    unsigned int i;

    // compute window and norm
    float w[_n];
    float wnorm=0.0f;
    for (i=0; i<_n; i++) {
        switch (_wtype) {
        case LIQUID_DOC_PSDWINDOW_NONE:     w[i] = 1.0f;            break;
        case LIQUID_DOC_PSDWINDOW_HANN:     w[i] = hann(i,_n);      break;
        case LIQUID_DOC_PSDWINDOW_HAMMING:  w[i] = hamming(i,_n);   break;
            break;
        default:
            fprintf(stderr,"error: liquid_doc_compute_psd(), invalid window type\n");
            exit(1);
        }
        wnorm += w[i];
    }
    wnorm /= (float)(_n);

    float complex x[_nfft];
    fftplan fft = fft_create_plan(_nfft,x,_X,FFT_FORWARD,0);
    for (i=0; i<_nfft; i++) {
        x[i] = i < _n ? _x[i] * w[i] / wnorm : 0.0f;

    }
    fft_execute(fft);
    fft_destroy_plan(fft);

    // normalize spectrum by maximum
    if (_normalize) {
        float X_max = 0.0f;
        for (i=0; i<_nfft; i++)
            X_max = cabsf(_X[i]) > X_max ? cabsf(_X[i]) : X_max;

        for (i=0; i<_nfft; i++)
            _X[i] /= X_max;
    }
}
예제 #6
0
void WorldSynthesis::_destroy()
{
    if(_minimumPhase)
    {
        DestroyMinimumPhaseAnalysis(_minimumPhase);
    }
    delete _minimumPhase;
    delete[] _spectrum;
    delete[] _impulse;

    if(_plan)
    {
        fft_destroy_plan(*_plan);
        _plan = NULL;
    }
    _fftLength = 0;
    _spectrum = NULL;
    _impulse = NULL;
}
예제 #7
0
void SpectrumVisualProcessor::setup(unsigned int fftSize_in) {

    std::lock_guard < std::mutex > busy_lock(busy_run);    

    fftSize = fftSize_in;
    fftSizeInternal = fftSize_in * SPECTRUM_VZM;
    lastDataSize = 0;

    int memSize = sizeof(liquid_float_complex) * fftSizeInternal;
    
    if (fftInput) {
        free(fftInput);
    }
    fftInput = (liquid_float_complex*)malloc(memSize);
    memset(fftInput,0,memSize);
    
    if (fftInData) {
        free(fftInData);
    }
    fftInData = (liquid_float_complex*)malloc(memSize);
    memset(fftInput,0,memSize);
    
    if (fftLastData) {
        free(fftLastData);
    }
    fftLastData = (liquid_float_complex*)malloc(memSize);
    memset(fftInput,0,memSize);
    
    if (fftOutput) {
        free(fftOutput);
    }
    fftOutput = (liquid_float_complex*)malloc(memSize);
    memset(fftInput,0,memSize);
    
    if (fftPlan) {
        fft_destroy_plan(fftPlan);
    }
    fftPlan = fft_create_plan(fftSizeInternal, fftInput, fftOutput, LIQUID_FFT_FORWARD, 0);
    
}
예제 #8
0
void do_spectrum() {
    std::complex<float> *data_in;
    windowcf_read(w, &data_in);
    fftplan q = fft_create_plan(SPECTRUM_FFT_LENGTH,data_in,spectrum_fft_output,LIQUID_FFT_FORWARD,0);

    fft_execute(q);
    fft_destroy_plan(q);

    spectrum_fft_magnitude[0] = 0.0; //Do not consider DC comp

    int maxIdx = 0;
    float maxVal = 0;
    double total_power = 0;
    double psd = 0;
    for (int i = 1; i < SPECTRUM_FFT_LENGTH/2; i++) {
        spectrum_fft_magnitude[i] = std::norm(spectrum_fft_output[i]);
        total_power += spectrum_fft_magnitude[i];
        if (spectrum_fft_magnitude[i] > maxVal) {
            maxIdx = i;
            maxVal = spectrum_fft_magnitude[i];
        } 
    }
    // TODO normalize so window size does not affect this threshold.
    psd = maxVal / total_power;

    if (shm_settings.auto_magnitude_thresholding == 0) {
        if (psd > shm_settings.spectrum_magnitude_threshold && (current_sample_count - old_spectrum_sample_count > shm_settings.spectrum_cooldown_samples)) {
            shm_results_spectrum.most_recent_ping_magnitude = maxVal;
            shm_results_spectrum.most_recent_ping_frequency = (double) SAMPLING_FREQUENCY / (double) SPECTRUM_FFT_LENGTH * (double) maxIdx;
            shm_results_spectrum.most_recent_ping_count++;
            old_spectrum_sample_count = current_sample_count;
            shm_setg(hydrophones_results_spectrum, shm_results_spectrum);
        }
        prev_psd = psd;
    }
    else {
        //IMPLEMENTE AUTO THRESHOLDING AND ASSOCIATED PING STUFF
    } 
}
예제 #9
0
// Helper function to keep code base small
void fft_runbench(struct rusage *     _start,
                  struct rusage *     _finish,
                  unsigned long int * _num_iterations,
                  unsigned int        _nfft,
                  int                 _direction)
{
    // initialize arrays, plan
    float complex * x = (float complex *) malloc(_nfft*sizeof(float complex));
    float complex * y = (float complex *) malloc(_nfft*sizeof(float complex));
    int _method = 0;
    fftplan q = fft_create_plan(_nfft, x, y, _direction, _method);
    
    unsigned long int i;

    // initialize input with random values
    for (i=0; i<_nfft; i++)
        x[i] = randnf() + randnf()*_Complex_I;

    // scale number of iterations to keep execution time
    // relatively linear
    *_num_iterations /= _nfft;

    // start trials
    getrusage(RUSAGE_SELF, _start);
    for (i=0; i<(*_num_iterations); i++) {
        fft_execute(q);
        fft_execute(q);
        fft_execute(q);
        fft_execute(q);
    }
    getrusage(RUSAGE_SELF, _finish);
    *_num_iterations *= 4;

    fft_destroy_plan(q);
    free(x);
    free(y);
}
예제 #10
0
// Helper function to keep code base small
void fft_r2r_bench(struct rusage *_start,
                   struct rusage *_finish,
                   unsigned long int *_num_iterations,
                   unsigned int _n,
                   int _kind)
{
    // initialize arrays, plan
    float x[_n], y[_n];
    int _flags = 0;
    fftplan p = fft_create_plan_r2r_1d(_n, x, y, _kind, _flags);
    
    unsigned long int i;

    // initialize input with random values
    for (i=0; i<_n; i++)
        x[i] = randnf();

    // scale number of iterations to keep execution time
    // relatively linear
    *_num_iterations /= _n * _n;
    *_num_iterations *= 10;
    *_num_iterations += 1;

    // start trials
    getrusage(RUSAGE_SELF, _start);
    for (i=0; i<(*_num_iterations); i++) {
        fft_execute(p);
        fft_execute(p);
        fft_execute(p);
        fft_execute(p);
    }
    getrusage(RUSAGE_SELF, _finish);
    *_num_iterations *= 4;

    fft_destroy_plan(p);
}
예제 #11
0
void DestroyInverseRealFFT(InverseRealFFT *inverse_real_fft) {
  fft_destroy_plan(inverse_real_fft->inverse_fft);
  delete[] inverse_real_fft->spectrum;
  delete[] inverse_real_fft->waveform;
}
예제 #12
0
void DestroyForwardRealFFT(ForwardRealFFT *forward_real_fft) {
  fft_destroy_plan(forward_real_fft->forward_fft);
  delete[] forward_real_fft->spectrum;
  delete[] forward_real_fft->waveform;
}
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;
}
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;

}
예제 #15
0
int main(int argc, char*argv[])
{
    // options
    unsigned int m           =   3;     // number of bits/symbol
    unsigned int k           =   0;     // filter samples/symbol
    unsigned int num_symbols = 200;     // number of data symbols
    float        SNRdB       = 40.0f;   // signal-to-noise ratio [dB]
    float        cfo         = 0.0f;    // carrier frequency offset
    float        cpo         = 0.0f;    // carrier phase offset
    float        tau         = 0.0f;    // fractional symbol timing offset
    float        bandwidth   = 0.20;    // frequency spacing

    int dopt;
    while ((dopt = getopt(argc,argv,"hm:k:b:n:s:F:P:T:")) != EOF) {
        switch (dopt) {
        case 'h': usage();                      return 0;
        case 'm': m           = atoi(optarg);   break;
        case 'k': k           = atoi(optarg);   break;
        case 'b': bandwidth   = atof(optarg);   break;
        case 'n': num_symbols = atoi(optarg);   break;
        case 's': SNRdB       = atof(optarg);   break;
        case 'F': cfo         = atof(optarg);   break;
        case 'P': cpo         = atof(optarg);   break;
        case 'T': tau         = atof(optarg);   break;
        default:
            exit(1);
        }
    }

    unsigned int i;
    unsigned int j;

    // derived values
    if (k == 0) k = 2 << m; // set samples per symbol if not otherwise specified
    unsigned int num_samples = k*num_symbols;
    unsigned int M           = 1 << m;
    float        nstd        = powf(10.0f, -SNRdB/20.0f);
    float        M2          = 0.5f*(float)(M-1);

    // validate input
    if (k < M) {
        fprintf(stderr,"errors: %s, samples/symbol must be at least modulation size (M=%u)\n", __FILE__,M);
        exit(1);
    } else if (k > 2048) {
        fprintf(stderr,"errors: %s, samples/symbol exceeds maximum (2048)\n", __FILE__);
        exit(1);
    } else if (M > 1024) {
        fprintf(stderr,"errors: %s, modulation size (M=%u) exceeds maximum (1024)\n", __FILE__, M);
        exit(1);
    } else if (bandwidth <= 0.0f || bandwidth >= 0.5f) {
        fprintf(stderr,"errors: %s, bandwidht must be in (0,0.5)\n", __FILE__);
        exit(1);
    }

    // compute demodulation FFT size such that FFT output bin frequencies are
    // as close to modulated frequencies as possible
    unsigned int K = 0;                 // demodulation FFT size
    float        df = bandwidth / M2;   // frequency spacing
    float        err_min = 1e9f;
    unsigned int K_min = k;                     // minimum FFT size
    unsigned int K_max = k*4 < 16 ? 16 : k*4;   // maximum FFT size
    unsigned int K_hat;
    for (K_hat=K_min; K_hat<=K_max; K_hat++) {
        // compute candidate FFT size
        float v     = 0.5f*df * (float)K_hat;   // bin spacing
        float err = fabsf( roundf(v) - v );     // fractional bin spacing

        // print results
        printf("  K_hat = %4u : v = %12.8f, err=%12.8f %s\n", K_hat, v, err, err < err_min ? "*" : "");

        // save best result
        if (K_hat==K_min || err < err_min) {
            K = K_hat;
            err_min = err;
        }

        // perfect match; no need to continue searching
        if (err < 1e-6f)
            break;
    }

    // arrays
    unsigned int  sym_in[num_symbols];      // input symbols
    float complex x[num_samples];           // transmitted signal
    float complex y[num_samples];           // received signal
    unsigned int  sym_out[num_symbols];     // output symbols

    // determine demodulation mapping between tones and frequency bins
    // TODO: use gray coding
    unsigned int demod_map[M];
    for (i=0; i<M; i++) {
        // print frequency bins
        float freq = ((float)i - M2) * bandwidth / M2;
        float idx  = freq * (float)K;
        unsigned int index = (unsigned int) (idx < 0 ? roundf(idx + K) : roundf(idx));
        demod_map[i] = index;
        printf("  s=%3u, f = %12.8f, index=%3u\n", i, freq, index);
    }

    // check for uniqueness
    for (i=1; i<M; i++) {
        if (demod_map[i] == demod_map[i-1]) {
            fprintf(stderr,"warning: demod map is not unique; consider increasing bandwidth\n");
            break;
        }
    }

    // generate message symbols and modulate
    // TODO: use gray coding
    for (i=0; i<num_symbols; i++) {
        // generate random symbol
        sym_in[i] = rand() % M;

        // compute frequency
        float dphi = 2*M_PI*((float)sym_in[i] - M2) * bandwidth / M2;

        // generate random phase
        float phi  = randf() * 2 * M_PI;
        
        // modulate symbol
        for (j=0; j<k; j++)
            x[i*k+j] = cexpf(_Complex_I*phi + _Complex_I*j*dphi);
    }

    // push through channel
    for (i=0; i<num_samples; i++)
        y[i] = x[i] + nstd*(randnf() + _Complex_I*randnf())*M_SQRT1_2;

#if 0
    // demodulate signal: high SNR method
    float complex buf_time[k];
    unsigned int n = 0;
    j = 0;
    for (i=0; i<num_samples; i++) {
        // start filling time buffer with samples (assume perfect symbol timing)
        buf_time[n++] = y[i];

        // demodulate symbol
        if (n==k) {
            // reset counter
            n = 0;

            // estimate frequency
            float complex metric = 0;
            unsigned int s;
            for (s=1; s<k; s++)
                metric += buf_time[s] * conjf(buf_time[s-1]);
            float dphi_hat = cargf(metric) / (2*M_PI);
            unsigned int v=( (unsigned int) roundf(dphi_hat*M2/bandwidth + M2) ) % M;
            sym_out[j++] = v;
            printf("%3u : %12.8f : %u\n", j, dphi_hat, v);
        }
    }
#else
    // demodulate signal: least-squares method
    float complex buf_time[K];
    float complex buf_freq[K];
    fftplan fft = fft_create_plan(K, buf_time, buf_freq, LIQUID_FFT_FORWARD, 0);

    for (i=0; i<K; i++)
        buf_time[i] = 0.0f;
    unsigned int n = 0;
    j = 0;
    for (i=0; i<num_samples; i++) {
        // start filling time buffer with samples (assume perfect symbol timing)
        buf_time[n++] = y[i];

        // demodulate symbol
        if (n==k) {
            // reset counter
            n = 0;

            // compute transform, storing result in 'buf_freq'
            fft_execute(fft);

            // find maximum by looking at particular bins
            float vmax = 0;
            unsigned int s;
            unsigned int s_opt = 0;
            for (s=0; s<M; s++) {
                float v = cabsf( buf_freq[demod_map[s]] );
                if (s==0 || v > vmax) {
                    s_opt = s;
                    vmax  =v;
                }
            }

            // save best result
            sym_out[j++] = s_opt;
        }
    }
    // destroy fft object
    fft_destroy_plan(fft);
#endif

    // count errors
    unsigned int num_symbol_errors = 0;
    for (i=0; i<num_symbols; i++)
        num_symbol_errors += (sym_in[i] == sym_out[i]) ? 0 : 1;

    printf("symbol errors: %u / %u\n", num_symbol_errors, num_symbols);

    // compute power spectral density of received signal
    unsigned int nfft = 1200;
    float psd[nfft];
    spgramcf_estimate_psd(nfft, y, num_samples, psd);

    // 
    // export results
    //
    
    // truncate to at most 10 symbols
    if (num_symbols > 10)
        num_symbols = 10;
    num_samples = k*num_symbols;
    FILE * fid = fopen(OUTPUT_FILENAME,"w");
    fprintf(fid,"%% %s : auto-generated file\n", OUTPUT_FILENAME);
    fprintf(fid,"clear all\n");
    fprintf(fid,"close all\n");
    fprintf(fid,"k = %u;\n", k);
    fprintf(fid,"M = %u;\n", M);
    fprintf(fid,"num_symbols = %u;\n", num_symbols);
    fprintf(fid,"num_samples = %u;\n", num_samples);
    fprintf(fid,"nfft        = %u;\n", nfft);

    fprintf(fid,"x   = zeros(1,num_samples);\n");
    fprintf(fid,"y   = zeros(1,num_samples);\n");
    for (i=0; i<num_samples; i++) {
        fprintf(fid,"x(%4u) = %12.8f + j*%12.8f;\n", i+1, crealf(x[i]), cimagf(x[i]));
        fprintf(fid,"y(%4u) = %12.8f + j*%12.8f;\n", i+1, crealf(y[i]), cimagf(y[i]));
    }
    // save power spectral density
    fprintf(fid,"psd = zeros(1,nfft);\n");
    for (i=0; i<nfft; i++)
        fprintf(fid,"psd(%4u) = %12.8f;\n", i+1, psd[i]);

    fprintf(fid,"t=[0:(num_samples-1)]/k;\n");
    fprintf(fid,"i = 1:k:num_samples;\n");
    fprintf(fid,"figure;\n");

    // plot time signal
    fprintf(fid,"subplot(2,1,1),\n");
    fprintf(fid,"hold on;\n");
    fprintf(fid,"  plot(t,real(y),'-', 'Color',[0 0.3 0.5]);\n");
    fprintf(fid,"  plot(t,imag(y),'-', 'Color',[0 0.5 0.3]);\n");
    fprintf(fid,"hold off;\n");
    fprintf(fid,"ymax = ceil(max(abs(y))*5)/5;\n");
    fprintf(fid,"axis([0 num_symbols -ymax ymax]);\n");
    fprintf(fid,"xlabel('time');\n");
    fprintf(fid,"ylabel('x(t)');\n");
    fprintf(fid,"grid on;\n");

    // plot PSD
    fprintf(fid,"subplot(2,1,2),\n");
    fprintf(fid,"f = [0:(nfft-1)]/nfft - 0.5;\n");
    fprintf(fid,"plot(f,psd,'LineWidth',1.5,'Color',[0.5 0 0]);\n");
    fprintf(fid,"axis([-0.5 0.5 -40 40]);\n");
    fprintf(fid,"xlabel('Normalized Frequency [f/F_s]');\n");
    fprintf(fid,"ylabel('PSD [dB]');\n");
    fprintf(fid,"grid on;\n");

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

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

}