Beispiel #1
0
// compute filter coefficients and determine resulting ISI
//  
//  _k      :   filter over-sampling rate (samples/symbol)
//  _m      :   filter delay (symbols)
//  _beta   :   filter excess bandwidth factor (0,1)
//  _dt     :   filter fractional sample delay
//  _rho    :   transition bandwidth adjustment, 0 < _rho < 1
//  _h      :   filter buffer [size: 2*_k*_m+1]
float liquid_firdes_rkaiser_internal_isi(unsigned int _k,
                                         unsigned int _m,
                                         float _beta,
                                         float _dt,
                                         float _rho,
                                         float * _h)
{
    // validate input
    if (_rho < 0.0f) {
        fprintf(stderr,"warning: liquid_firdes_rkaiser_internal_isi(), rho < 0\n");
    } else if (_rho > 1.0f) {
        fprintf(stderr,"warning: liquid_firdes_rkaiser_internal_isi(), rho > 1\n");
    }

    unsigned int n=2*_k*_m+1;                   // filter length
    float kf = (float)_k;                       // samples/symbol (float)
    float del = _beta*_rho / kf;                // transition bandwidth
    float As = estimate_req_filter_As(del, n);  // stop-band suppression
    float fc = 0.5f*(1 + _beta*(1.0f-_rho))/kf; // filter cutoff

    // evaluate performance (ISI)
    float isi_max;
    float isi_rms;

    // compute filter
    liquid_firdes_kaiser(n,fc,As,_dt,_h);

    // compute filter ISI
    liquid_filter_isi(_h,_k,_m,&isi_rms,&isi_max);

    // return RMS of ISI
    return isi_rms;
}
Beispiel #2
0
// create FIR polyphase filterbank channelizer object with
// prototype filter based on windowed Kaiser design
//  _type   : channelizer type (LIQUID_ANALYZER | LIQUID_SYNTHESIZER)
//  _M      : number of channels
//  _m      : filter delay (symbols)
//  _As     : stop-band attentuation [dB]
FIRPFBCH() FIRPFBCH(_create_kaiser)(int          _type,
                                    unsigned int _M,
                                    unsigned int _m,
                                    float        _As)
{
    // validate input
    if (_M == 0) {
        fprintf(stderr,"error: firpfbch_%s_create_kaiser(), number of channels must be greater than 0\n", EXTENSION_FULL);
        exit(1);
    } else if (_m == 0) {
        fprintf(stderr,"error: firpfbch_%s_create_kaiser(), invalid filter size (must be greater than 0)\n", EXTENSION_FULL);
        exit(1);
    }

    _As = fabsf(_As);

    // design filter
    unsigned int h_len = 2*_M*_m + 1;
    float h[h_len];
    float fc = 0.5f / (float)_M; // TODO : check this value
    liquid_firdes_kaiser(h_len, fc, _As, 0.0f, h);

    // copy coefficients to type-specfic array
    TC hc[h_len];
    unsigned int i;
    for (i=0; i<h_len; i++)
        hc[i] = h[i];

    // create filterbank object
    unsigned int p = 2*_m;
    FIRPFBCH() q = FIRPFBCH(_create)(_type, _M, p, hc);

    // return filterbank object
    return q;
}
Beispiel #3
0
// create LMS EQ initialized with low-pass filter
//  _h_len  : filter length
//  _fc     : filter cut-off, _fc in (0,0.5]
EQLMS() EQLMS(_create_lowpass)(unsigned int _h_len,
                               float        _fc)
{
    // validate input
    if (_h_len == 0) {
        fprintf(stderr,"error: eqlms_%s_create_lowpass(), filter length must be greater than 0\n", EXTENSION_FULL);
        exit(1);
    } else if (_fc <= 0.0f || _fc > 0.5f) {
        fprintf(stderr,"error: eqlms_%s_create_rnyquist(), filter cutoff must be in (0,0.5]\n", EXTENSION_FULL);
        exit(1);
    }

    // generate low-pass filter prototype
    float h[_h_len];
    liquid_firdes_kaiser(_h_len, _fc, 40.0f, 0.0f, h);

    // copy coefficients to type-specific array (e.g. float complex)
    unsigned int i;
    T hc[_h_len];
    for (i=0; i<_h_len; i++)
        hc[i] = h[i];

    // return equalizer object
    return EQLMS(_create)(hc, _h_len);
}
Beispiel #4
0
// create decimator from prototype
//  _M      :   decimolation factor
//  _m      :   symbol delay
//  _As     :   stop-band attenuation [dB]
FIRDECIM() FIRDECIM(_create_prototype)(unsigned int _M,
                                       unsigned int _m,
                                       float        _As)
{
    // validate input
    if (_M < 2) {
        fprintf(stderr,"error: decim_%s_create_prototype(), decim factor must be greater than 1\n", EXTENSION_FULL);
        exit(1);
    } else if (_m == 0) {
        fprintf(stderr,"error: decim_%s_create_prototype(), filter delay must be greater than 0\n", EXTENSION_FULL);
        exit(1);
    } else if (_As < 0.0f) {
        fprintf(stderr,"error: decim_%s_create_prototype(), stop-band attenuation must be positive\n", EXTENSION_FULL);
        exit(1);
    }

    // compute filter coefficients (floating point precision)
    unsigned int h_len = 2*_M*_m + 1;
    float hf[h_len];
    float fc = 0.5f / (float) (_M);
    liquid_firdes_kaiser(h_len, fc, _As, 0.0f, hf);

    // copy coefficients to type-specific array (e.g. float complex)
    TC hc[h_len];
    unsigned int i;
    for (i=0; i<h_len; i++)
        hc[i] = hf[i];
    
    // return decimator object
    return FIRDECIM(_create)(_M, hc, 2*_M*_m);
}
Beispiel #5
0
// create arbitrary resampler
//  _rate   :   resampling rate
//  _m      :   prototype filter semi-length
//  _fc     :   prototype filter cutoff frequency, fc in (0, 0.5)
//  _As     :   prototype filter stop-band attenuation [dB] (e.g. 60)
//  _npfb   :   number of filters in polyphase filterbank
RESAMP() RESAMP(_create)(float        _rate,
                         unsigned int _m,
                         float        _fc,
                         float        _As,
                         unsigned int _npfb)
{
    // validate input
    if (_rate <= 0) {
        fprintf(stderr,"error: resamp_%s_create(), resampling rate must be greater than zero\n", EXTENSION_FULL);
        exit(1);
    } else if (_m == 0) {
        fprintf(stderr,"error: resamp_%s_create(), filter semi-length must be greater than zero\n", EXTENSION_FULL);
        exit(1);
    } else if (_fc <= 0.0f || _fc >= 0.5f) {
        fprintf(stderr,"error: resamp_%s_create(), filter cutoff must be in (0,0.5)\n", EXTENSION_FULL);
        exit(1);
    } else if (_As <= 0.0f) {
        fprintf(stderr,"error: resamp_%s_create(), filter stop-band suppression must be greater than zero\n", EXTENSION_FULL);
        exit(1);
    } else if (_npfb == 0) {
        fprintf(stderr,"error: resamp_%s_create(), number of filter banks must be greater than zero\n", EXTENSION_FULL);
        exit(1);
    }

    // allocate memory for resampler
    RESAMP() q = (RESAMP()) malloc(sizeof(struct RESAMP(_s)));

    // set rate using formal method (specifies output stride
    // value 'del')
    RESAMP(_set_rate)(q, _rate);

    // set properties
    q->m    = _m;       // prototype filter semi-length
    q->fc   = _fc;      // prototype filter cutoff frequency
    q->As   = _As;      // prototype filter stop-band attenuation
    q->npfb = _npfb;    // number of filters in bank

    // design filter
    unsigned int n = 2*q->m*q->npfb+1;
    float hf[n];
    TC h[n];
    liquid_firdes_kaiser(n,q->fc/((float)(q->npfb)),q->As,0.0f,hf);

    // normalize filter coefficients by DC gain
    unsigned int i;
    float gain=0.0f;
    for (i=0; i<n; i++)
        gain += hf[i];
    gain = (q->npfb)/(gain);

    // copy to type-specific array, applying gain
    for (i=0; i<n; i++)
        h[i] = hf[i]*gain;
    q->f = FIRPFB(_create)(q->npfb,h,n-1);

    // reset object and return
    RESAMP(_reset)(q);
    return q;
}
Beispiel #6
0
ModemKit *ModemFMStereo::buildKit(long long sampleRate, int audioSampleRate) {
    ModemKitFMStereo *kit = new ModemKitFMStereo;
    
    kit->audioResampleRatio = double(audioSampleRate) / double(sampleRate);
    kit->sampleRate = sampleRate;
    kit->audioSampleRate = audioSampleRate;
   
    float As = 60.0f;         // stop-band attenuation [dB]
    
    kit->audioResampler = msresamp_rrrf_create(kit->audioResampleRatio, As);
    kit->stereoResampler = msresamp_rrrf_create(kit->audioResampleRatio, As);
    
    // Stereo filters / shifters
    double firStereoCutoff = 16000.0 / double(audioSampleRate);
    // filter transition
    float ft = 1000.0f / double(audioSampleRate);
    // fractional timing offset
    float mu = 0.0f;
    
    if (firStereoCutoff < 0) {
        firStereoCutoff = 0;
    }
    
    if (firStereoCutoff > 0.5) {
        firStereoCutoff = 0.5;
    }
    
    unsigned int h_len = estimate_req_filter_len(ft, As);
    float *h = new float[h_len];
    liquid_firdes_kaiser(h_len, firStereoCutoff, As, mu, h);
    
    kit->firStereoLeft = firfilt_rrrf_create(h, h_len);
    kit->firStereoRight = firfilt_rrrf_create(h, h_len);
    
    // stereo pilot filter
    float bw = float(sampleRate);
    if (bw < 100000.0) {
        bw = 100000.0;
    }
    unsigned int order =   5;       // filter order
    float        f0    =   ((float) 19000 / bw);
    float        fc    =   ((float) 19500 / bw);
    float        Ap    =   1.0f;
    
    kit->iirStereoPilot = iirfilt_crcf_create_prototype(LIQUID_IIRDES_CHEBY2, LIQUID_IIRDES_BANDPASS, LIQUID_IIRDES_SOS, order, fc, f0, Ap, As);
    
    kit->firStereoR2C = firhilbf_create(5, 60.0f);
    kit->firStereoC2R = firhilbf_create(5, 60.0f);
    
    kit->stereoPilot = nco_crcf_create(LIQUID_VCO);
    nco_crcf_reset(kit->stereoPilot);
    nco_crcf_pll_set_bandwidth(kit->stereoPilot, 0.25f);
    
    return kit;
}
Beispiel #7
0
// create firhilb object
//  _m      :   filter semi-length (delay: 2*m+1)
//  _As     :   stop-band attenuation [dB]
FIRHILB() FIRHILB(_create)(unsigned int _m,
                           float        _As)
{
    // validate firhilb inputs
    if (_m < 2) {
        fprintf(stderr,"error: firhilb_create(), filter semi-length (m) must be at least 2\n");
        exit(1);
    }

    // allocate memory for main object
    FIRHILB() q = (FIRHILB()) malloc(sizeof(struct FIRHILB(_s)));
    q->m  = _m;         // filter semi-length
    q->As = fabsf(_As); // stop-band attenuation

    // set filter length and allocate memory for coefficients
    q->h_len = 4*(q->m) + 1;
    q->h     = (T *)         malloc((q->h_len)*sizeof(T));
    q->hc    = (T complex *) malloc((q->h_len)*sizeof(T complex));

    // allocate memory for quadrature filter component
    q->hq_len = 2*(q->m);
    q->hq     = (T *) malloc((q->hq_len)*sizeof(T));

    // compute filter coefficients for half-band filter
    liquid_firdes_kaiser(q->h_len, 0.25f, q->As, 0.0f, q->h);

    // alternate sign of non-zero elements
    unsigned int i;
    for (i=0; i<q->h_len; i++) {
        float t = (float)i - (float)(q->h_len-1)/2.0f;
        q->hc[i] = q->h[i] * cexpf(_Complex_I*0.5f*M_PI*t);
        q->h[i]  = cimagf(q->hc[i]);
    }

    // resample, reverse direction
    unsigned int j=0;
    for (i=1; i<q->h_len; i+=2)
        q->hq[j++] = q->h[q->h_len - i - 1];

    // create windows for upper and lower polyphase filter branches
    q->w1 = WINDOW(_create)(2*(q->m));
    q->w0 = WINDOW(_create)(2*(q->m));
    WINDOW(_clear)(q->w0);
    WINDOW(_clear)(q->w1);

    // create internal dot product object
    q->dpq = DOTPROD(_create)(q->hq, q->hq_len);

    // reset internal state and return object
    FIRHILB(_reset)(q);
    return q;
}
void DemodulatorPreThread::initialize() {
    initialized = false;

    iqResampleRatio = (double) (params.bandwidth) / (double) params.sampleRate;
    audioResampleRatio = (double) (params.audioSampleRate) / (double) params.bandwidth;

    float As = 120.0f;         // stop-band attenuation [dB]

    iqResampler = msresamp_crcf_create(iqResampleRatio, As);
    audioResampler = msresamp_rrrf_create(audioResampleRatio, As);
    stereoResampler = msresamp_rrrf_create(audioResampleRatio, As);

    // Stereo filters / shifters
    double firStereoCutoff = ((double) 16000 / (double) params.audioSampleRate);
    float ft = ((double) 1000 / (double) params.audioSampleRate);         // filter transition
    float mu = 0.0f;         // fractional timing offset

    if (firStereoCutoff < 0) {
        firStereoCutoff = 0;
    }

    if (firStereoCutoff > 0.5) {
        firStereoCutoff = 0.5;
    }

    unsigned int h_len = estimate_req_filter_len(ft, As);
    float *h = new float[h_len];
    liquid_firdes_kaiser(h_len, firStereoCutoff, As, mu, h);

    firStereoLeft = firfilt_rrrf_create(h, h_len);
    firStereoRight = firfilt_rrrf_create(h, h_len);

    // stereo pilot filter
    float bw = params.bandwidth;
    if (bw < 100000.0) {
        bw = 100000.0;
    }
    unsigned int order =   5;       // filter order
    float        f0    =   ((double) 19000 / bw);
    float        fc    =   ((double) 19500 / bw);
    float        Ap    =   1.0f;
    As    =  60.0f;
    iirStereoPilot = iirfilt_crcf_create_prototype(LIQUID_IIRDES_CHEBY2, LIQUID_IIRDES_BANDPASS, LIQUID_IIRDES_SOS, order, fc, f0, Ap, As);

    initialized = true;
    lastParams = params;
}
Beispiel #9
0
// create symsync using Kaiser filter interpolator; useful
// when the input signal has matched filter applied already
//  _k      : input samples/symbol
//  _m      : symbol delay
//  _beta   : rolloff factor, beta in (0,1]
//  _M      : number of filters in the bank
SYMSYNC() SYMSYNC(_create_kaiser)(unsigned int _k,
                                  unsigned int _m,
                                  float        _beta,
                                  unsigned int _M)
{
    // validate input
    if (_k < 2) {
        fprintf(stderr,"error: symsync_%s_create_kaiser(), samples/symbol must be at least 2\n", EXTENSION_FULL);
        exit(1);
    } else if (_m == 0) {
        fprintf(stderr,"error: symsync_%s_create_kaiser(), filter delay (m) must be greater than zero\n", EXTENSION_FULL);
        exit(1);
    } else if (_beta < 0.0f || _beta > 1.0f) {
        fprintf(stderr,"error: symsync_%s_create_kaiser(), filter excess bandwidth must be in [0,1]\n", EXTENSION_FULL);
        exit(1);
    }

    // allocate memory for filter coefficients
    unsigned int H_len = 2*_M*_k*_m + 1;
    float Hf[H_len];

    // design interpolating filter whose bandwidth is outside the cut-off
    // frequency of input signal
    // TODO: use _beta to compute more accurate cut-off frequency
    float fc = 0.75f;   // filter cut-off frequency (nominal)
    float As = 40.0f;   // filter stop-band attenuation
    liquid_firdes_kaiser(H_len, fc / (float)(_k*_M), As, 0.0f, Hf);

    // copy coefficients to type-specific array, adjusting to relative
    // filter gain
    unsigned int i;
    TC H[H_len];
    for (i=0; i<H_len; i++)
        H[i] = Hf[i] * 2.0f * fc;

    // create object and return
    return SYMSYNC(_create)(_k, _M, H, H_len);
}
Beispiel #10
0
// create filter using Kaiser-Bessel windowed sinc method
//  _n      : filter length, _n > 0
//  _fc     : cutoff frequency, 0 < _fc < 0.5
//  _As     : stop-band attenuation [dB], _As > 0
//  _mu     : fractional sample offset, -0.5 < _mu < 0.5
FIRFILT() FIRFILT(_create_kaiser)(unsigned int _n,
                                  float        _fc,
                                  float        _As,
                                  float        _mu)
{
    // validate input
    if (_n == 0) {
        fprintf(stderr,"error: firfilt_%s_create_kaiser(), filter length must be greater than zero\n", EXTENSION_FULL);
        exit(1);
    }

    // compute temporary array for holding coefficients
    float hf[_n];
    liquid_firdes_kaiser(_n, _fc, _As, _mu, hf);

    // copy coefficients to type-specific array
    TC h[_n];
    unsigned int i;
    for (i=0; i<_n; i++)
        h[i] = (TC) hf[i];

    // 
    return FIRFILT(_create)(h, _n);
}
int main() {
    float r=sqrtf(19);  // resampling rate (output/input)
    unsigned int n=37;  // number of input samples
    float As=60.0f;     // stop-band attenuation [dB]

    unsigned int i;

    // derived values: number of input, output samples (adjusted for filter delay)
    unsigned int nx = 1.4*n;
    unsigned int ny_alloc = (unsigned int) (2*(float)nx * r);  // allocation for output

    // allocate memory for arrays
    float complex x[nx];
    float complex y[ny_alloc];

    // generate input signal (filter pulse with frequency offset)
    float hf[n];
    liquid_firdes_kaiser(n, 0.08f, 80.0f, 0, hf);
    for (i=0; i<nx; i++)
        x[i] = (i < n) ? hf[i]*cexpf(_Complex_I*1.17f*i) : 0.0f;

    // create resampler
    msresamp_crcf q = msresamp_crcf_create(r,As);
    float delay = msresamp_crcf_get_delay(q);

    // execute resampler, storing in output buffer
    unsigned int ny;
    msresamp_crcf_execute(q, x, nx, y, &ny);

    // print basic results
    printf("input samples   : %u\n", nx);
    printf("output samples  : %u\n", ny);
    printf("delay           : %f samples\n", delay);

    // clean up allocated objects
    msresamp_crcf_destroy(q);


    // 
    // export output files
    //
    FILE * fid;

    // 
    // export time plot
    //
    fid = fopen(OUTPUT_FILENAME_TIME,"w");
    fprintf(fid,"# %s: auto-generated file\n\n", OUTPUT_FILENAME_TIME);
    fprintf(fid,"reset\n");
    fprintf(fid,"set terminal postscript eps enhanced color solid rounded\n");
    //fprintf(fid,"set xrange [0:%u];\n",n);
    fprintf(fid,"set yrange [-1.2:1.2]\n");
    fprintf(fid,"set size ratio 0.3\n");
    fprintf(fid,"set xlabel 'Input Sample Index'\n");
    fprintf(fid,"set key top right nobox\n");
    fprintf(fid,"set ytics -5,1,5\n");
    fprintf(fid,"set grid xtics ytics\n");
    fprintf(fid,"set grid linetype 1 linecolor rgb '%s' lw 1\n", LIQUID_DOC_COLOR_GRID);
    fprintf(fid,"set multiplot layout 2,1 scale 1.0,1.0\n");

    fprintf(fid,"# real\n");
    fprintf(fid,"set ylabel 'Real'\n");
    fprintf(fid,"plot '-' using 1:2 with linespoints pointtype 6 pointsize 0.9 linetype 1 linewidth 1 linecolor rgb '#666666' title 'original',\\\n");
    fprintf(fid,"     '-' using 1:2 with points pointtype 7 pointsize 0.6 linecolor rgb '#008000' title 'resampled'\n");
    // export input signal
    for (i=0; i<nx; i++)
        fprintf(fid,"%12.4e %12.4e %12.4e\n", (float)i, crealf(x[i]), cimagf(x[i]));
    fprintf(fid,"e\n");

    // export output signal
    for (i=0; i<ny; i++)
        fprintf(fid,"%12.4e %12.4e %12.4e\n", (float)(i)/r - delay, crealf(y[i]), cimagf(y[i]));
    fprintf(fid,"e\n");

    fprintf(fid,"# imag\n");
    fprintf(fid,"set ylabel 'Imag'\n");
    fprintf(fid,"plot '-' using 1:3 with linespoints pointtype 6 pointsize 0.9 linetype 1 linewidth 1 linecolor rgb '#666666' title 'original',\\\n");
    fprintf(fid,"     '-' using 1:3 with points pointtype 7 pointsize 0.6 linecolor rgb '#800000' title 'resampled'\n");

    // export input signal
    for (i=0; i<nx; i++)
        fprintf(fid,"%12.4e %12.4e %12.4e\n", (float)i, crealf(x[i]), cimagf(x[i]));
    fprintf(fid,"e\n");

    // export output signal
    for (i=0; i<ny; i++)
        fprintf(fid,"%12.4e %12.4e %12.4e\n", (float)(i)/r - delay, crealf(y[i]), cimagf(y[i]));
    fprintf(fid,"e\n");

    fprintf(fid,"unset multiplot\n");

    // close output file
    fclose(fid);


    // 
    // export spectrum plot
    //
    fid = fopen(OUTPUT_FILENAME_FREQ,"w");
    unsigned int nfft = 512;
    float complex X[nfft];
    float complex Y[nfft];
    liquid_doc_compute_psdcf(x, nx, X, nfft, LIQUID_DOC_PSDWINDOW_NONE, 1);
    liquid_doc_compute_psdcf(y, ny, Y, nfft, LIQUID_DOC_PSDWINDOW_NONE, 1);
    fft_shift(X,nfft);
    fft_shift(Y,nfft);

    fprintf(fid,"# %s: auto-generated file\n\n", OUTPUT_FILENAME_FREQ);
    fprintf(fid,"reset\n");
    fprintf(fid,"set terminal postscript eps enhanced color solid rounded\n");
    fprintf(fid,"set xrange [-0.5:0.5];\n");
    fprintf(fid,"set yrange [-120:20]\n");
    fprintf(fid,"set size ratio 0.6\n");
    fprintf(fid,"set xlabel 'Normalized Output Frequency'\n");
    fprintf(fid,"set ylabel 'Power Spectral Density [dB]'\n");
    fprintf(fid,"set key top right nobox\n");
    fprintf(fid,"set grid xtics ytics\n");
    fprintf(fid,"set pointsize 0.6\n");
    fprintf(fid,"set grid linetype 1 linecolor rgb '%s' lw 1\n",LIQUID_DOC_COLOR_GRID);

    fprintf(fid,"# real\n");
    fprintf(fid,"plot '-' using 1:2 with lines linetype 1 linewidth 4 linecolor rgb '#999999' title 'original',\\\n");
    fprintf(fid,"     '-' using 1:2 with lines linetype 1 linewidth 4 linecolor rgb '#004080' title 'resampled'\n");
    // export output
    for (i=0; i<nfft; i++) {
        float fx = ((float)(i) / (float)nfft - 0.5f) / r;
        fprintf(fid,"%12.8f %12.4e\n", fx, 20*log10f(cabsf(X[i])));
    }
    fprintf(fid,"e\n");
    for (i=0; i<nfft; i++) {
        float fy = ((float)(i) / (float)nfft - 0.5f);
        fprintf(fid,"%12.8f %12.4e\n", fy, 20*log10f(cabsf(Y[i])));
    }
    fprintf(fid,"e\n");

    fclose(fid);

    printf("done.\n");
    return 0;
}
Beispiel #12
0
RESAMP() RESAMP(_create)(float _r,
                         unsigned int _h_len,
                         float _fc,
                         float _As,
                         unsigned int _npfb)
{
    // validate input
    if (_r <= 0) {
        fprintf(stderr,"error: resamp_%s_create(), resampling rate must be greater than zero\n", EXTENSION_FULL);
        exit(1);
    } else if (_h_len == 0) {
        fprintf(stderr,"error: resamp_%s_create(), filter length must be greater than zero\n", EXTENSION_FULL);
        exit(1);
    } else if (_npfb == 0) {
        fprintf(stderr,"error: resamp_%s_create(), number of filter banks must be greater than zero\n", EXTENSION_FULL);
        exit(1);
    } else if (_fc <= 0.0f || _fc >= 0.5f) {
        fprintf(stderr,"error: resamp_%s_create(), filter cutoff must be in (0,0.5)\n", EXTENSION_FULL);
        exit(1);
    } else if (_As <= 0.0f) {
        fprintf(stderr,"error: resamp_%s_create(), filter stop-band suppression must be greater than zero\n", EXTENSION_FULL);
        exit(1);
    }

    RESAMP() q = (RESAMP()) malloc(sizeof(struct RESAMP(_s)));
    q->r     = _r;
    q->As    = _As;
    q->fc    = _fc;
    q->h_len = _h_len;

    q->b   = 0;
    q->del = 1.0f / q->r;

#if RESAMP_USE_FIXED_POINT_PHASE
    q->num_bits_npfb = liquid_nextpow2(_npfb);
    q->npfb = 1<<q->num_bits_npfb;
    q->num_bits_phase = 20;
    q->max_phase = 1 << q->num_bits_phase;
    q->num_shift_bits = q->num_bits_phase - q->num_bits_npfb;
    q->theta = 0;
    q->d_theta = (unsigned int)( q->max_phase * q->del );
#else
    q->npfb = _npfb;
    q->tau = 0.0f;
    q->bf  = 0.0f;
#endif

    // design filter
    unsigned int n = 2*_h_len*q->npfb+1;
    float hf[n];
    TC h[n];
    liquid_firdes_kaiser(n,q->fc/((float)(q->npfb)),q->As,0.0f,hf);

    // normalize filter coefficients by DC gain
    unsigned int i;
    float gain=0.0f;
    for (i=0; i<n; i++)
        gain += hf[i];
    gain = (q->npfb)/(gain);

    // copy to type-specific array
    for (i=0; i<n; i++)
        h[i] = hf[i]*gain;
    q->f = FIRPFB(_create)(q->npfb,h,n-1);

    //for (i=0; i<n; i++)
    //    PRINTVAL_TC(h[i],%12.8f);
    //exit(0);

    return q;
}
int main() {
    // options
    unsigned int h_len=17;  // filter length
    float fc=0.2f;          // filter cutoff
    float As=30.0f;         // stop-band attenuation [dB]
    float mu=0.0f;          // timing offset
    unsigned int n=64;      // number of random input samples

    // derived values
    unsigned int num_samples = n + h_len;

    // arrays
    float x[num_samples];   // filter input
    float y[num_samples];   // filter output

    unsigned int i;
    float h[h_len];
    liquid_firdes_kaiser(h_len,fc,As,mu,h);
    firfilt_rrrf f = firfilt_rrrf_create(h,h_len);
    firfilt_rrrf_print(f);

    for (i=0; i<num_samples; i++) {
        // generate noise
        x[i] = (i<n) ? randnf()/sqrtf(n/2) : 0.0f;

        firfilt_rrrf_push(f, x[i]);
        firfilt_rrrf_execute(f, &y[i]); 

        printf("x[%4u] = %12.8f, y[%4u] = %12.8f;\n", i, x[i], i, y[i]);
    }   

    // destroy filter object
    firfilt_rrrf_destroy(f);

    // 
    // export results
    //
    FILE*fid = fopen(OUTPUT_FILENAME,"w");
    fprintf(fid,"%% firfilt_rrrf_example.m: auto-generated file\n\n");
    fprintf(fid,"clear all;\nclose all;\n\n");
    fprintf(fid,"h_len=%u;\nn=%u;\n", h_len, n);
    
    for (i=0; i<h_len; i++)
        fprintf(fid,"h(%4u) = %12.4e;\n", i+1, h[i]);

    for (i=0; i<num_samples; i++)
        fprintf(fid,"x(%4u) = %12.4e; y(%4u) = %12.4e;\n", i+1, x[i], i+1, y[i]);

    fprintf(fid,"nfft=512;\n");
    fprintf(fid,"H=20*log10(abs(fftshift(fft(h,nfft))));\n");
    fprintf(fid,"X=20*log10(abs(fftshift(fft(x,nfft))));\n");
    fprintf(fid,"Y=20*log10(abs(fftshift(fft(y,nfft))));\n");
    fprintf(fid,"f=[0:(nfft-1)]/nfft-0.5;\n");
    fprintf(fid,"figure;\n");
    fprintf(fid,"plot(f,X,'Color',[0.3 0.3 0.3],...\n");
    fprintf(fid,"     f,Y,'LineWidth',2,...\n");
    fprintf(fid,"     f,H,'-b','LineWidth',2);\n");
    fprintf(fid,"axis([-0.5 0.5 -80 40]);\n");
    fprintf(fid,"grid on;\nxlabel('normalized frequency');\nylabel('PSD [dB]');\n");
    fprintf(fid,"legend('noise','filtered noise','filter prototype',1);");

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

    printf("done.\n");
    return 0;
}
Beispiel #14
0
firpfbch firpfbch_create(unsigned int _num_channels,
                         unsigned int _m,
                         float _beta,
                         float _dt,
                         int _nyquist,
                         int _gradient)
{
    firpfbch c = (firpfbch) malloc(sizeof(struct firpfbch_s));
    c->num_channels = _num_channels;
    c->m            = _m;
    c->beta         = _beta;
    c->dt           = _dt;
    c->nyquist      = _nyquist;

    // validate inputs
    if (_m < 1) {
        printf("error: firpfbch_create(), invalid filter delay (must be greater than 0)\n");
        exit(1);
    }

    // create bank of filters
    c->dp   = (DOTPROD()*) malloc((c->num_channels)*sizeof(DOTPROD()));
    c->w    = (WINDOW()*) malloc((c->num_channels)*sizeof(WINDOW()));

    // design filter
    // TODO: use filter prototype object
    c->h_len = 2*(c->m)*(c->num_channels);
    c->h = (float*) malloc((c->h_len+1)*sizeof(float));

    if (c->nyquist == FIRPFBCH_NYQUIST) {
        float fc = 0.5f/(float)(c->num_channels);  // cutoff frequency
        liquid_firdes_kaiser(c->h_len+1, fc, c->beta, 0.0f, c->h);
    } else if (c->nyquist == FIRPFBCH_ROOTNYQUIST) {
        design_rkaiser_filter(c->num_channels, c->m, c->beta, c->dt, c->h);
    } else {
        printf("error: firpfbch_create(), unsupported nyquist flag: %d\n", _nyquist);
        exit(1);
    }
    
    unsigned int i;
    if (_gradient) {
        float dh[c->h_len];
        for (i=0; i<c->h_len; i++) {
            if (i==0) {
                dh[i] = c->h[i+1] - c->h[c->h_len-1];
            } else if (i==c->h_len-1) {
                dh[i] = c->h[0]   - c->h[i-1];
            } else {
                dh[i] = c->h[i+1] - c->h[i-1];
            }
        }
        memmove(c->h, dh, (c->h_len)*sizeof(float));
    }

    // generate bank of sub-samped filters
    unsigned int n;
    unsigned int h_sub_len = 2*(c->m);  // length of each sub-sampled filter
    float h_sub[h_sub_len];
    for (i=0; i<c->num_channels; i++) {
        // sub-sample prototype filter, loading coefficients in reverse order
        for (n=0; n<h_sub_len; n++) {
            h_sub[h_sub_len-n-1] = c->h[i + n*(c->num_channels)];
        }
        // create window buffer and dotprod object (coefficients
        // loaded in reverse order)
        c->dp[i] = DOTPROD(_create)(h_sub,h_sub_len);
        c->w[i]  = WINDOW(_create)(h_sub_len);

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

#if DEBUG_FIRPFBCH_PRINT
    for (i=0; i<c->h_len+1; i++)
        printf("h(%4u) = %12.4e;\n", i+1, c->h[i]);
#endif

    // allocate memory for buffers
    // TODO : use fftw_malloc if HAVE_FFTW3_H
    c->x = (float complex*) malloc((c->num_channels)*sizeof(float complex));
    c->X = (float complex*) malloc((c->num_channels)*sizeof(float complex));
    c->X_prime = (float complex*) malloc((c->num_channels)*sizeof(float complex));
    firpfbch_clear(c);

    // create fft plan
    c->fft = FFT_CREATE_PLAN(c->num_channels, c->X, c->x, FFT_DIR_BACKWARD, FFT_METHOD);

    return c;
}
int main(int argc, char*argv[])
{
    // options
    float mod_index = 0.5f;         // modulation index (bandwidth)
    float fc = 0.0f;                // FM carrier
    liquid_freqmodem_type type = LIQUID_FREQMODEM_DELAYCONJ;
    unsigned int num_samples = 256; // number of samples
    float SNRdB = 30.0f;            // signal-to-noise ratio [dB]

    int dopt;
    while ((dopt = getopt(argc,argv,"hn:S:f:m:t:")) != EOF) {
        switch (dopt) {
        case 'h':   usage();                    return 0;
        case 'n':   num_samples = atoi(optarg); break;
        case 'S':   SNRdB = atof(optarg);       break;
        case 'f':   fc = atof(optarg);          break;
        case 'm':   mod_index = atof(optarg);   break;
        case 't':
            if (strcmp(optarg,"delayconj")==0) {
                type = LIQUID_FREQMODEM_DELAYCONJ;
            } else if (strcmp(optarg,"pll")==0) {
                type = LIQUID_FREQMODEM_PLL;
            } else {
                fprintf(stderr,"error: %s, invalid FM type: %s\n", argv[0], optarg);
                exit(1);
            }
            break;
        default:
            exit(1);
        }
    }

    // create mod/demod objects
    freqmodem mod   = freqmodem_create(mod_index,fc,type);
    freqmodem demod = freqmodem_create(mod_index,fc,type);
    freqmodem_print(mod);

    unsigned int i;
    float x[num_samples];
    float complex y[num_samples];
    float z[num_samples];

    // generate un-modulated signal (band-limited pulse)
    liquid_firdes_kaiser(num_samples, 0.05f, -40.0f, 0.0f, x);

    // modulate signal
    for (i=0; i<num_samples; i++)
        freqmodem_modulate(mod, x[i], &y[i]);

    // add channel impairments
    float nstd = powf(10.0f,-SNRdB/20.0f);
    for (i=0; i<num_samples; i++)
        y[i] += nstd*( randnf() + _Complex_I*randnf() ) * M_SQRT1_2;

    // demodulate signal
    for (i=0; i<num_samples; i++)
        freqmodem_demodulate(demod, y[i], &z[i]);

    // write results to output file
    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,"n=%u;\n",num_samples);
    for (i=0; i<num_samples; i++) {
        fprintf(fid,"x(%3u) = %12.4e;\n", i+1, x[i]);
        fprintf(fid,"y(%3u) = %12.4e + j*%12.4e;\n", i+1, crealf(y[i]), cimagf(y[i]));
        fprintf(fid,"z(%3u) = %12.4e;\n", i+1, z[i]);
    }
    // plot results
    fprintf(fid,"t=0:(n-1);\n");
    fprintf(fid,"figure;\n");
    fprintf(fid,"plot(t,x,t,z);\n");
    fprintf(fid,"axis([0 n -1.2 1.2]);\n");
    // spectrum
    fprintf(fid,"nfft=1024;\n");
    fprintf(fid,"f=[0:(nfft-1)]/nfft - 0.5;\n");
    fprintf(fid,"Y = 20*log10(abs(fftshift(fft(y/n,nfft))));\n");
    fprintf(fid,"figure;\n");
    fprintf(fid,"plot(f,Y);\n");
    fprintf(fid,"axis([-0.5 0.5 -60 20]);\n");
    fprintf(fid,"grid on;\n");
    fclose(fid);
    printf("results written to %s\n", OUTPUT_FILENAME);

    freqmodem_destroy(mod);
    freqmodem_destroy(demod);
    return 0;
}
int main(int argc, char*argv[])
{
    // options
    unsigned int num_channels=16;   // number of channels
    unsigned int m = 5;             // filter semi-length (symbols)
    unsigned int num_symbols=25;    // number of symbols
    float As = 80.0f;               // filter stop-band attenuation
    
    int dopt;
    while ((dopt = getopt(argc,argv,"hM:m:s:n:")) != EOF) {
        switch (dopt) {
        case 'h':   usage();                     return 0;
        case 'M':   num_channels = atoi(optarg); break;
        case 'm':   m            = atoi(optarg); break;
        case 's':   As           = atof(optarg); break;
        case 'n':   num_symbols  = atof(optarg); break;
        default:
            exit(1);
        }
    }

    unsigned int i;

    // validate input
    if (num_channels < 2 || num_channels % 2) {
        fprintf(stderr,"error: %s, number of channels must be greater than 2 and even\n", argv[0]);
        exit(1);
    } else if (m == 0) {
        fprintf(stderr,"error: %s, filter semi-length must be greater than zero\n", argv[0]);
        exit(1);
    } else if (num_symbols == 0) {
        fprintf(stderr,"error: %s, number of symbols must be greater than zero", argv[0]);
        exit(1);
    }

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

    // allocate arrays
    float complex x[num_samples];
    float complex y[num_samples];

    // generate input signal
    unsigned int w_len = (unsigned int)(0.4*num_samples);
    for (i=0; i<num_samples; i++) {
        //x[i] = (i==0) ? 1.0f : 0.0f;
        //x[i] = cexpf( (-0.05f + 0.07f*_Complex_I)*i );  // decaying complex exponential
        x[i] = cexpf( _Complex_I * (1.3f*i - 0.007f*i*i) );
        x[i] *= i < w_len ? hamming(i,w_len) : 0.0f;
        //x[i] = (i==0) ? 1.0f : 0.0f;
    }

    // create filterbank objects from prototype
    firpfbch2_crcf qa = firpfbch2_crcf_create_kaiser(LIQUID_ANALYZER,    num_channels, m, As);
    firpfbch2_crcf qs = firpfbch2_crcf_create_kaiser(LIQUID_SYNTHESIZER, num_channels, m, As);
    firpfbch2_crcf_print(qa);
    firpfbch2_crcf_print(qs);

    // run channelizer
    float complex Y[num_channels];
    for (i=0; i<num_samples; i+=num_channels/2) {
        // run analysis filterbank
        firpfbch2_crcf_execute(qa, &x[i], Y);

        // run synthesis filterbank
        firpfbch2_crcf_execute(qs, Y, &y[i]);
    }

    // destroy fiterbank objects
    firpfbch2_crcf_destroy(qa); // analysis fitlerbank
    firpfbch2_crcf_destroy(qs); // synthesis filterbank

    // print output
    for (i=0; i<num_samples; i++)
        printf("%4u : %12.8f + %12.8fj\n", i, crealf(y[i]), cimagf(y[i]));

    // compute RMSE
    float rmse = 0.0f;
    unsigned int delay = 2*num_channels*m - num_channels/2 + 1;
    for (i=0; i<num_samples; i++) {
        float complex err = y[i] - (i < delay ? 0.0f : x[i-delay]);
        rmse += crealf( err*conjf(err) );
    }
    rmse = sqrtf( rmse/(float)num_samples );
    printf("rmse : %12.4e\n", rmse);

    //
    // EXPORT DATA TO FILES
    //
    FILE * fid = NULL;
    fid = fopen(OUTPUT_FILENAME_TIME,"w");
    fprintf(fid,"# %s: auto-generated file\n", OUTPUT_FILENAME_TIME);
    fprintf(fid,"#\n");
    fprintf(fid,"# %8s %12s %12s %12s %12s %12s %12s\n",
            "time", "real(x)", "imag(x)", "real(y)", "imag(y)", "real(e)", "imag(e)");

    // save input and output arrays
    for (i=0; i<num_samples; i++) {
        float complex e = (i < delay) ? 0.0f : y[i] - x[i-delay];
        fprintf(fid,"  %8.1f %12.4e %12.4e %12.4e %12.4e %12.4e %12.4e\n",
                (float)i,
                crealf(x[i]), cimagf(x[i]),
                crealf(y[i]), cimagf(y[i]),
                crealf(e),    cimagf(e));
    }
    fclose(fid);
    printf("results written to '%s'\n", OUTPUT_FILENAME_TIME);

    // 
    // export frequency data
    //
    unsigned int nfft = 2048;
    float complex y_time[nfft];
    float complex y_freq[nfft];
    for (i=0; i<nfft; i++)
        y_time[i] = i < num_samples ? y[i] : 0.0f;
    fft_run(nfft, y_time, y_freq, LIQUID_FFT_FORWARD, 0);

    // filter spectrum
    unsigned int h_len = 2*num_channels*m+1;
    float h[h_len];
    float fc = 0.5f/(float)num_channels;
    liquid_firdes_kaiser(h_len, fc, As, 0.0f, h);
    float complex h_time[nfft];
    float complex h_freq[nfft];
    for (i=0; i<nfft; i++)
        h_time[i] = i < h_len ? 2*h[i]*fc : 0.0f;
    fft_run(nfft, h_time, h_freq, LIQUID_FFT_FORWARD, 0);

    // error spectrum
    float complex e_time[nfft];
    float complex e_freq[nfft];
    for (i=0; i<nfft; i++)
        e_time[i] = i < delay || i > num_samples ? 0.0f : y[i] - x[i-delay];
    fft_run(nfft, e_time, e_freq, LIQUID_FFT_FORWARD, 0);

    fid = fopen(OUTPUT_FILENAME_FREQ,"w");
    fprintf(fid,"# %s: auto-generated file\n", OUTPUT_FILENAME_FREQ);
    fprintf(fid,"#\n");
    fprintf(fid,"# nfft = %u\n", nfft);
    fprintf(fid,"# %12s %12s %12s %12s\n", "freq", "PSD [dB]", "filter [dB]", "error [dB]");

    // save input and output arrays
    for (i=0; i<nfft; i++) {
        float f = (float)i/(float)nfft - 0.5f;
        unsigned int k = (i + nfft/2)%nfft;
        fprintf(fid,"  %12.8f %12.8f %12.8f %12.8f\n",
                f,
                20*log10f(cabsf(y_freq[k])),
                20*log10f(cabsf(h_freq[k])),
                20*log10f(cabsf(e_freq[k])));
    }
    fclose(fid);
    printf("results written to '%s'\n", OUTPUT_FILENAME_FREQ);

    printf("done.\n");
    return 0;
}
void DemodulatorWorkerThread::threadMain() {

    std::cout << "Demodulator worker thread started.." << std::endl;

    while (!terminated) {
        bool filterChanged = false;
        DemodulatorWorkerThreadCommand filterCommand;
        DemodulatorWorkerThreadCommand command;

        bool done = false;
        while (!done) {
            commandQueue->pop(command);
            switch (command.cmd) {
            case DemodulatorWorkerThreadCommand::DEMOD_WORKER_THREAD_CMD_BUILD_FILTERS:
                filterChanged = true;
                filterCommand = command;
                break;
            default:
                break;
            }
            done = commandQueue->empty();
        }
        

        if (filterChanged && !terminated) {
            DemodulatorWorkerThreadResult result(DemodulatorWorkerThreadResult::DEMOD_WORKER_THREAD_RESULT_FILTERS);

            float As = 60.0f;         // stop-band attenuation [dB]

            if (filterCommand.sampleRate && filterCommand.bandwidth) {
                result.iqResampleRatio = (double) (filterCommand.bandwidth) / (double) filterCommand.sampleRate;
                result.iqResampler = msresamp_crcf_create(result.iqResampleRatio, As);
            }

            if (filterCommand.bandwidth && filterCommand.audioSampleRate) {
                result.audioResamplerRatio = (double) (filterCommand.audioSampleRate) / (double) filterCommand.bandwidth;
                result.audioResampler = msresamp_rrrf_create(result.audioResamplerRatio, As);
                result.stereoResampler = msresamp_rrrf_create(result.audioResamplerRatio, As);
                result.audioSampleRate = filterCommand.audioSampleRate;

                // Stereo filters / shifters
                double firStereoCutoff = ((double) 16000 / (double) filterCommand.audioSampleRate);
                float ft = ((double) 1000 / (double) filterCommand.audioSampleRate);        // filter transition
                float mu = 0.0f;         // fractional timing offset

                if (firStereoCutoff < 0) {
                    firStereoCutoff = 0;
                }

                if (firStereoCutoff > 0.5) {
                    firStereoCutoff = 0.5;
                }

                unsigned int h_len = estimate_req_filter_len(ft, As);
                float *h = new float[h_len];
                liquid_firdes_kaiser(h_len, firStereoCutoff, As, mu, h);

                result.firStereoLeft = firfilt_rrrf_create(h, h_len);
                result.firStereoRight = firfilt_rrrf_create(h, h_len);

                float bw = filterCommand.bandwidth;
                if (bw < 100000.0) {
                    bw = 100000.0;
                }
                // stereo pilot filter
                unsigned int order =   5;       // filter order
                float        f0    =   ((double) 19000 / bw);
                float        fc    =   ((double) 19500 / bw);
                float        Ap    =   1.0f;
                As    =  60.0f;
                
                result.iirStereoPilot = iirfilt_crcf_create_prototype(LIQUID_IIRDES_CHEBY2, LIQUID_IIRDES_BANDPASS, LIQUID_IIRDES_SOS, order, fc, f0, Ap, As);
            }

            if (filterCommand.bandwidth) {
                result.bandwidth = filterCommand.bandwidth;
            }

            if (filterCommand.sampleRate) {
                result.sampleRate = filterCommand.sampleRate;
            }

            resultQueue->push(result);
        }

    }

    std::cout << "Demodulator worker thread done." << std::endl;
}
int main(int argc, char*argv[]) {
    // options
    unsigned int k=4;       // samples/symbol
    unsigned int m=3;       // filter delay [symbols]
    float BT = 0.3f;        // bandwidth-time product

    // read properties from command line
    int dopt;
    while ((dopt = getopt(argc,argv,"uhk:m:b:")) != EOF) {
        switch (dopt) {
        case 'u':
        case 'h':   usage();            return 0;
        case 'k':   k  = atoi(optarg);  break;
        case 'm':   m  = atoi(optarg);  break;
        case 'b':   BT = atof(optarg);  break;
        default:
            exit(1);
        }
    }


    // validate input
    if (k < 2) {
        fprintf(stderr,"error: %s, k must be at least 2\n", argv[0]);
        exit(1);
    } else if (m < 1) {
        fprintf(stderr,"error: %s, m must be at least 1\n", argv[0]);
        exit(1);
    } else if (BT <= 0.0f || BT >= 1.0f) {
        fprintf(stderr,"error: %s, BT must be in (0,1)\n", argv[0]);
        exit(1);
    }


    unsigned int i;

    // derived values
    unsigned int h_len = 2*k*m+1;   // filter length

    // arrays
    float ht[h_len];         // transmit filter coefficients
    float hr[h_len];         // recieve filter coefficients

    // design transmit filter
    liquid_firdes_gmsktx(k,m,BT,0.0f,ht);

    // print results to screen
    printf("gmsk transmit filter:\n");
    for (i=0; i<h_len; i++)
        printf("  ht(%3u) = %12.8f;\n", i+1, ht[i]);

    //
    // start of filter design procedure
    //

    float beta = BT;        // prototype filter cut-off
    float delta = 1e-2f;    // filter design correction factor

    // temporary arrays
    float h_primef[h_len];          // temporary buffer for real coefficients
    float g_primef[h_len];          // 

    float complex h_tx[h_len];      // impulse response of transmit filter
    float complex h_prime[h_len];   // impulse response of 'prototype' filter
    float complex g_prime[h_len];   // impulse response of 'gain' filter
    float complex h_hat[h_len];     // impulse response of receive filter
    
    float complex H_tx[h_len];      // frequency response of transmit filter
    float complex H_prime[h_len];   // frequency response of 'prototype' filter
    float complex G_prime[h_len];   // frequency response of 'gain' filter
    float complex H_hat[h_len];     // frequency response of receive filter

    // create 'prototype' matched filter
    // for now use raised-cosine
    liquid_firdes_nyquist(LIQUID_NYQUIST_RCOS,k,m,beta,0.0f,h_primef);

    // create 'gain' filter to improve stop-band rejection
    float fc = (0.7f + 0.1*beta) / (float)k;
    float As = 60.0f;
    liquid_firdes_kaiser(h_len, fc, As, 0.0f, g_primef);

    // copy to fft input buffer, shifting appropriately
    for (i=0; i<h_len; i++) {
        h_prime[i] = h_primef[ (i+k*m)%h_len ];
        g_prime[i] = g_primef[ (i+k*m)%h_len ];
        h_tx[i]    = ht[       (i+k*m)%h_len ];
    }

    // run ffts
    fft_run(h_len, h_prime, H_prime, FFT_FORWARD, 0);
    fft_run(h_len, g_prime, G_prime, FFT_FORWARD, 0);
    fft_run(h_len, h_tx,    H_tx,    FFT_FORWARD, 0);

#if 0
    // print results
    for (i=0; i<h_len; i++)
        printf("Ht(%3u) = %12.8f + j*%12.8f;\n", i+1, crealf(H_tx[i]), cimagf(H_tx[i]));
    for (i=0; i<h_len; i++)
        printf("H_prime(%3u) = %12.8f + j*%12.8f;\n", i+1, crealf(H_prime[i]), cimagf(H_prime[i]));
    for (i=0; i<h_len; i++)
        printf("G_prime(%3u) = %12.8f + j*%12.8f;\n", i+1, crealf(G_prime[i]), cimagf(G_prime[i]));
#endif

    // find minimum of reponses
    float H_tx_min = 0.0f;
    float H_prime_min = 0.0f;
    float G_prime_min = 0.0f;
    for (i=0; i<h_len; i++) {
        if (i==0 || crealf(H_tx[i])    < H_tx_min)    H_tx_min    = crealf(H_tx[i]);
        if (i==0 || crealf(H_prime[i]) < H_prime_min) H_prime_min = crealf(H_prime[i]);
        if (i==0 || crealf(G_prime[i]) < G_prime_min) G_prime_min = crealf(G_prime[i]);
    }

    // compute 'prototype' response, removing minima, and add correction factor
    for (i=0; i<h_len; i++) {
        // compute response necessary to yeild prototype response (not exact, but close)
        H_hat[i] = crealf(H_prime[i] - H_prime_min + delta) / crealf(H_tx[i] - H_tx_min + delta);

        // include additional term to add stop-band suppression
        H_hat[i] *= crealf(G_prime[i] - G_prime_min) / crealf(G_prime[0]);
    }

    // compute ifft and copy response
    fft_run(h_len, H_hat, h_hat, FFT_REVERSE, 0);
    for (i=0; i<h_len; i++)
        hr[i] = crealf( h_hat[(i+k*m+1)%h_len] ) / (float)(k*h_len);

    //
    // end of filter design procedure
    //

    // print results to screen
    printf("gmsk receive filter:\n");
    for (i=0; i<h_len; i++)
        printf("  hr(%3u) = %12.8f;\n", i+1, hr[i]);

    // compute isi
    float rxy0 = liquid_filter_crosscorr(ht,h_len, hr,h_len, 0);
    float isi_rms = 0.0f;
    for (i=1; i<2*m; i++) {
        float e = liquid_filter_crosscorr(ht,h_len, hr,h_len, i*k) / rxy0;
        isi_rms += e*e;
    }
    isi_rms = sqrtf(isi_rms / (float)(2*m-1));
    printf("\n");
    printf("ISI (RMS) = %12.8f dB\n", 20*log10f(isi_rms));
    

    // 
    // export output file
    //
    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,"\n\n");
    fprintf(fid,"k = %u;\n", k);
    fprintf(fid,"m = %u;\n", m);
    fprintf(fid,"beta = %f;\n", BT);
    fprintf(fid,"h_len = 2*k*m+1;\n");
    fprintf(fid,"nfft = 1024;\n");
    fprintf(fid,"ht = zeros(1,h_len);\n");
    fprintf(fid,"hp = zeros(1,h_len);\n");
    fprintf(fid,"hr = zeros(1,h_len);\n");

    // print results
    for (i=0; i<h_len; i++)   fprintf(fid,"ht(%3u) = %12.4e;\n", i+1, ht[i] / k);
    for (i=0; i<h_len; i++)   fprintf(fid,"hr(%3u) = %12.4e;\n", i+1, hr[i] * k);
    for (i=0; i<h_len; i++)   fprintf(fid,"hp(%3u) = %12.4e;\n", i+1, h_primef[i]);
    
    fprintf(fid,"hc = k*conv(ht,hr);\n");

    // plot results
    fprintf(fid,"f = [0:(nfft-1)]/nfft - 0.5;\n");
    fprintf(fid,"Ht = 20*log10(abs(fftshift(fft(ht,  nfft))));\n");
    fprintf(fid,"Hp = 20*log10(abs(fftshift(fft(hp/k,nfft))));\n");
    fprintf(fid,"Hr = 20*log10(abs(fftshift(fft(hr,  nfft))));\n");
    fprintf(fid,"Hc = 20*log10(abs(fftshift(fft(hc/k,nfft))));\n");
    fprintf(fid,"\n");
    fprintf(fid,"figure;\n");
    fprintf(fid,"plot(f,Ht,'LineWidth',1,'Color',[0.00 0.25 0.50],...\n");
    fprintf(fid,"     f,Hp,'LineWidth',1,'Color',[0.80 0.80 0.80],...\n");
    fprintf(fid,"     f,Hr,'LineWidth',1,'Color',[0.00 0.50 0.25],...\n");
    fprintf(fid,"     f,Hc,'LineWidth',2,'Color',[0.50 0.00 0.00],...\n");
    fprintf(fid,"     [-0.5/k 0.5/k], [1 1]*20*log10(0.5),'or');\n");
    fprintf(fid,"legend('transmit','prototype','receive','composite','alias points',1);\n");
    fprintf(fid,"xlabel('Normalized Frequency');\n");
    fprintf(fid,"ylabel('PSD');\n");
    fprintf(fid,"grid on;\n");
    fprintf(fid,"axis([-0.5 0.5 -100 20]);\n");

    fprintf(fid,"\n");
    fprintf(fid,"figure;\n");
    fprintf(fid,"tr = [  -k*m:k*m]/k;\n");
    fprintf(fid,"tc = [-2*k*m:2*k*m]/k;\n");
    fprintf(fid,"ic = [0:k:(4*k*m)]+1;\n");
    fprintf(fid,"subplot(2,1,1);\n");
    fprintf(fid,"  plot(tr,ht,'-x', tr,hr,'-x');\n");
    fprintf(fid,"  legend('transmit','receive',1);\n");
    fprintf(fid,"  xlabel('Time');\n");
    fprintf(fid,"  ylabel('GMSK Tx/Rx Filters');\n");
    fprintf(fid,"  grid on;\n");
    fprintf(fid,"  axis([-2*m 2*m floor(5*min([hr ht]))/5 ceil(5*max([hr ht]))/5]);\n");
    fprintf(fid,"subplot(2,1,2);\n");
    fprintf(fid,"  plot(tc,hc,'-x', tc(ic),hc(ic),'or');\n");
    fprintf(fid,"  xlabel('Time');\n");
    fprintf(fid,"  ylabel('GMSK Composite Response');\n");
    fprintf(fid,"  grid on;\n");
    fprintf(fid,"  axis([-2*m 2*m -0.2 1.2]);\n");
    fprintf(fid,"  axis([-2*m 2*m floor(5*min(hc))/5 ceil(5*max(hc))/5]);\n");

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

    return 0;
}
Beispiel #19
0
int main() {
    // options
    unsigned int num_channels=8;    // number of channels
    unsigned int m=4;               // filter delay
    float As=60;                    // stop-band attenuation
    unsigned int num_frames=25;     // number of frames

    //
    unsigned int i;
    unsigned int k;

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

    // data arrays
    float complex x[num_samples];  // time-domain input  [size: num_samples  x 1         ]
    float complex y[num_samples];  // channelized output [size: num_channels x num_frames]

    // initialize input with zeros
    for (i=0; i<num_samples; i++)
        x[i] = 0.0f;

    // generate input signal(s)
    unsigned int num_signals = 4;
    float fc[4] = {0.0f,   0.25f,  0.375f, -0.375f}; // center frequencies
    float bw[4] = {0.035f, 0.035f, 0.035f,  0.035f}; // bandwidths
    unsigned int pulse_len = 137;
    float pulse[pulse_len];
    for (i=0; i<num_signals; i++) {
        // create pulse
        liquid_firdes_kaiser(pulse_len, bw[i], 50.0f, 0.0f, pulse);

        // add pulse to input signal with carrier offset
        for (k=0; k<pulse_len; k++)
            x[k] += pulse[k] * cexpf(_Complex_I*2*M_PI*fc[i]*k) * bw[i];
    }

    // create prototype filter
    unsigned int h_len = 2*num_channels*m + 1;
    float h[h_len];
    liquid_firdes_kaiser(h_len, 0.5f/(float)num_channels, As, 0.0f, h);

#if 0
    // create filterbank channelizer object using internal method for filter
    firpfbch_crcf q = firpfbch_crcf_create_kaiser(LIQUID_ANALYZER, num_channels, m, As);
#else
    // create filterbank channelizer object using external filter coefficients
    firpfbch_crcf q = firpfbch_crcf_create(LIQUID_ANALYZER, num_channels, 2*m, h);
#endif

    // channelize input data
    for (i=0; i<num_frames; i++) {
        // execute analysis filter bank
        firpfbch_crcf_analyzer_execute(q, &x[i*num_channels], &y[i*num_channels]);
    }

    // destroy channelizer object
    firpfbch_crcf_destroy(q);
    
    // 
    // export results to file
    //
    FILE * fid = fopen(OUTPUT_FILENAME,"w");
    fprintf(fid,"%% %s: auto-generated file\n\n", OUTPUT_FILENAME);
    fprintf(fid,"clear all;\n");
    fprintf(fid,"close all;\n");
    fprintf(fid,"num_channels = %u;\n", num_channels);
    fprintf(fid,"m            = %u;\n", m);
    fprintf(fid,"num_frames   = %u;\n", num_frames);
    fprintf(fid,"h_len        = 2*num_channels*m+1;\n");
    fprintf(fid,"num_samples  = num_frames*num_channels;\n");

    fprintf(fid,"h = zeros(1,h_len);\n");
    fprintf(fid,"x = zeros(1,num_samples);\n");
    fprintf(fid,"y = zeros(num_channels, num_frames);\n");

    // save prototype filter
    for (i=0; i<h_len; i++)
        fprintf(fid,"  h(%6u) = %12.4e;\n", i+1, h[i]);

    // save input signal
    for (i=0; i<num_samples; i++)
        fprintf(fid,"  x(%6u) = %12.4e + 1i*%12.4e;\n", i+1, crealf(x[i]), cimagf(x[i]));

    // save channelized output signals
    for (i=0; i<num_frames; i++) {
        for (k=0; k<num_channels; k++) {
            float complex v = y[i*num_channels + k];
            fprintf(fid,"  y(%3u,%6u) = %12.4e + 1i*%12.4e;\n", k+1, i+1, crealf(v), cimagf(v));
        }
    }

    // plot results
    fprintf(fid,"\n");
    fprintf(fid,"nfft = 1024;\n"); // TODO: use nextpow2
    fprintf(fid,"f = [0:(nfft-1)]/nfft - 0.5;\n");
    fprintf(fid,"H = 20*log10(abs(fftshift(fft(h/num_channels,nfft))));\n");
    fprintf(fid,"X = 20*log10(abs(fftshift(fft(x,nfft))));\n");
    fprintf(fid,"figure;\n");
    fprintf(fid,"subplot(2,1,1);\n");
    fprintf(fid,"  plot(f, H, 'Color', [0 0.5 0.25], 'LineWidth', 2);\n");
    fprintf(fid,"  axis([-0.5 0.5 -100 10]);\n");
    fprintf(fid,"  grid on;\n");
    fprintf(fid,"  xlabel('Normalized Frequency [f/F_s]');\n");
    fprintf(fid,"  ylabel('Prototype Filter PSD');\n");
    fprintf(fid,"subplot(2,1,2);\n");
    fprintf(fid,"  plot(f, X, 'Color', [0 0.25 0.5], 'LineWidth', 2);\n");
    fprintf(fid,"  axis([-0.5 0.5 -100 0]);\n");
    fprintf(fid,"  grid on;\n");
    fprintf(fid,"  xlabel('Normalized Frequency [f/F_s]');\n");
    fprintf(fid,"  ylabel('Input PSD');\n");

    // compute the PSD of each output and plot results on a square grid
    fprintf(fid,"n = ceil(sqrt(num_channels));\n");
    fprintf(fid,"figure;\n");
    fprintf(fid,"for i=1:num_channels,\n");
    fprintf(fid,"  Y = 20*log10(abs(fftshift(fft(y(i,:),nfft))));\n");
    fprintf(fid,"  subplot(n,n,i);\n");
    fprintf(fid,"  plot(f, Y, 'Color', [0.25 0 0.25], 'LineWidth', 1.5);\n");
    fprintf(fid,"  axis([-0.5 0.5 -120 20]);\n");
    fprintf(fid,"  grid on;\n");
    fprintf(fid,"  title(num2str(i-1));\n");
    fprintf(fid,"end;\n");

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

    printf("done.\n");
    return 0;
}
Beispiel #20
0
// Design (root-)Nyquist filter from prototype
//  _type   : filter type (e.g. LIQUID_FIRFILT_RRRC)
//  _k      : samples/symbol
//  _m      : symbol delay
//  _beta   : excess bandwidth factor, _beta in [0,1]
//  _dt     : fractional sample delay
//  _h      : output coefficient buffer (length: 2*k*m+1)
void liquid_firdes_prototype(liquid_firfilt_type _type,
                             unsigned int        _k,
                             unsigned int        _m,
                             float               _beta,
                             float               _dt,
                             float *             _h)
{
    // compute filter parameters
    unsigned int h_len = 2*_k*_m + 1;   // length
    float fc = 0.5f / (float)_k;        // cut-off frequency
    float df = _beta / (float)_k;       // transition bandwidth
    float As = estimate_req_filter_As(df,h_len);   // stop-band attenuation

    // Parks-McClellan algorithm parameters
    float bands[6] = {  0.0f,       fc-0.5f*df,
                        fc,         fc,
                        fc+0.5f*df, 0.5f};
    float des[3] = { (float)_k, 0.5f*_k, 0.0f };
    float weights[3] = {1.0f, 1.0f, 1.0f};
    liquid_firdespm_wtype wtype[3] = {  LIQUID_FIRDESPM_FLATWEIGHT,
                                        LIQUID_FIRDESPM_FLATWEIGHT,
                                        LIQUID_FIRDESPM_FLATWEIGHT};

    switch (_type) {
    
    // Nyquist filter prototypes

    case LIQUID_FIRFILT_KAISER:
        liquid_firdes_kaiser(h_len, fc, As, _dt, _h);
        break;
    case LIQUID_FIRFILT_PM:
        // WARNING: input timing offset is ignored here
        firdespm_run(h_len, 3, bands, des, weights, wtype, LIQUID_FIRDESPM_BANDPASS, _h);
        break;
    case LIQUID_FIRFILT_RCOS:
        liquid_firdes_rcos(_k, _m, _beta, _dt, _h);
        break;
    case LIQUID_FIRFILT_FEXP:
        liquid_firdes_fexp(_k, _m, _beta, _dt, _h);
        break;
    case LIQUID_FIRFILT_FSECH:
        liquid_firdes_fsech(_k, _m, _beta, _dt, _h);
        break;
    case LIQUID_FIRFILT_FARCSECH:
        liquid_firdes_farcsech(_k, _m, _beta, _dt, _h);
        break;

    // root-Nyquist filter prototypes

    case LIQUID_FIRFILT_ARKAISER:
        liquid_firdes_arkaiser(_k, _m, _beta, _dt, _h);
        break;
    case LIQUID_FIRFILT_RKAISER:
        liquid_firdes_rkaiser(_k, _m, _beta, _dt, _h);
        break;
    case LIQUID_FIRFILT_RRC:
        liquid_firdes_rrcos(_k, _m, _beta, _dt, _h);
        break;
    case LIQUID_FIRFILT_hM3:
        liquid_firdes_hM3(_k, _m, _beta, _dt, _h);
        break;
    case LIQUID_FIRFILT_GMSKTX:
        liquid_firdes_gmsktx(_k, _m, _beta, _dt, _h);
        break;
    case LIQUID_FIRFILT_GMSKRX:
        liquid_firdes_gmskrx(_k, _m, _beta, _dt, _h);
        break;
    case LIQUID_FIRFILT_RFEXP:
        liquid_firdes_rfexp(_k, _m, _beta, _dt, _h);
        break;
    case LIQUID_FIRFILT_RFSECH:
        liquid_firdes_rfsech(_k, _m, _beta, _dt, _h);
        break;
    case LIQUID_FIRFILT_RFARCSECH:
        liquid_firdes_rfarcsech(_k, _m, _beta, _dt, _h);
        break;
    default:
        fprintf(stderr,"error: liquid_firdes_prototype(), invalid root-Nyquist filter type '%d'\n", _type);
        exit(1);
    }
}
int main() {
    // options
    unsigned int num_channels = 16;     // number of channels
    unsigned int m            =  5;     // filter delay
    float        As           = 60;     // stop-band attenuation
    unsigned int num_frames   = 25;     // number of frames

    //
    unsigned int i;
    unsigned int k;

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

    // data arrays
    float complex x[num_channels][num_frames];  // channelized input
    float complex y[num_samples];               // time-domain output [size: num_samples  x 1]

    // create narrow-band pulse
    unsigned int pulse_len = 17;        // pulse length [samples]
    float        bw        = 0.30f;     // pulse width (bandwidth)
    float        pulse[pulse_len];      // buffer
    liquid_firdes_kaiser(pulse_len, bw, 50.0f, 0.0f, pulse);

    // generate input signal(s)
    int enabled[num_channels];  // signal enabled?
    for (i=0; i<num_channels; i++) {
        // pseudo-random channel enabled flag
        enabled[i] = ((i*37)%101)%2;

        if (enabled[i]) {
            // move pulse to input buffer
            for (k=0; k<num_frames; k++)
                x[i][k] = k < pulse_len ? bw*pulse[k] : 0.0f;
        } else {
            // channel disabled; set as nearly zero (-100 dB impulse)
            for (k=0; k<num_frames; k++)
                x[i][k] = (k == 0) ? 1e-5f : 0.0f;
        }
    }

    // create prototype filter
    unsigned int h_len = 2*num_channels*m + 1;
    float h[h_len];
    liquid_firdes_kaiser(h_len, 0.5f/(float)num_channels, As, 0.0f, h);

#if 0
    // create filterbank channelizer object using internal method for filter
    firpfbch_crcf q = firpfbch_crcf_create_kaiser(LIQUID_SYNTHESIZER, num_channels, m, As);
#else
    // create filterbank channelizer object using external filter coefficients
    firpfbch_crcf q = firpfbch_crcf_create(LIQUID_SYNTHESIZER, num_channels, 2*m, h);
#endif

    // channelize input data
    float complex v[num_channels];
    for (i=0; i<num_frames; i++) {
        // assemble input vector
        for (k=0; k<num_channels; k++)
            v[k] = x[k][i];

        // execute synthesis filter bank
        firpfbch_crcf_synthesizer_execute(q, v, &y[i*num_channels]);
    }

    // destroy channelizer object
    firpfbch_crcf_destroy(q);
    
    // 
    // export results to file
    //
    FILE * fid = fopen(OUTPUT_FILENAME,"w");
    fprintf(fid,"%% %s: auto-generated file\n\n", OUTPUT_FILENAME);
    fprintf(fid,"clear all;\n");
    fprintf(fid,"close all;\n");
    fprintf(fid,"num_channels = %u;\n", num_channels);
    fprintf(fid,"m            = %u;\n", m);
    fprintf(fid,"num_frames   = %u;\n", num_frames);
    fprintf(fid,"h_len        = 2*num_channels*m+1;\n");
    fprintf(fid,"num_samples  = num_frames*num_channels;\n");

    fprintf(fid,"h = zeros(1,h_len);\n");
    fprintf(fid,"x = zeros(num_channels, num_frames);\n");
    fprintf(fid,"y = zeros(1,num_samples);\n");

    // save prototype filter
    for (i=0; i<h_len; i++)
        fprintf(fid,"  h(%6u) = %12.4e;\n", i+1, h[i]);

    // save channelized input signals
    for (i=0; i<num_frames; i++) {
        for (k=0; k<num_channels; k++) {
            float complex v = x[k][i];
            fprintf(fid,"  x(%3u,%6u) = %12.4e + 1i*%12.4e;\n", k+1, i+1, crealf(v), cimagf(v));
        }
    }

    // save output time signal
    for (i=0; i<num_samples; i++)
        fprintf(fid,"  y(%6u) = %12.4e + 1i*%12.4e;\n", i+1, crealf(y[i]), cimagf(y[i]));

    // compute the PSD of each input and plot results on a square grid
    fprintf(fid,"nfft = 1024;\n"); // TODO: use nextpow2
    fprintf(fid,"f = [0:(nfft-1)]/nfft - 0.5;\n");
    fprintf(fid,"n = ceil(sqrt(num_channels));\n");
    fprintf(fid,"figure;\n");
    fprintf(fid,"for i=1:num_channels,\n");
    fprintf(fid,"  X = 20*log10(abs(fftshift(fft(x(i,:),nfft))));\n");
    fprintf(fid,"  subplot(n,n,i);\n");
    fprintf(fid,"  plot(f, X, 'Color', [0.25 0 0.25], 'LineWidth', 1.5);\n");
    fprintf(fid,"  axis([-0.5 0.5 -120 20]);\n");
    fprintf(fid,"  grid on;\n");
    fprintf(fid,"  title(num2str(i-1));\n");
    fprintf(fid,"end;\n");

    // plot results
    fprintf(fid,"\n");
    fprintf(fid,"H = 20*log10(abs(fftshift(fft(h/num_channels,nfft))));\n");
    fprintf(fid,"Y = 20*log10(abs(fftshift(fft(y/num_channels,nfft))));\n");
    fprintf(fid,"figure;\n");
    fprintf(fid,"subplot(2,1,1);\n");
    fprintf(fid,"  plot(f, H, 'Color', [0 0.5 0.25], 'LineWidth', 2);\n");
    fprintf(fid,"  axis([-0.5 0.5 -100 10]);\n");
    fprintf(fid,"  grid on;\n");
    fprintf(fid,"  xlabel('Normalized Frequency [f/F_s]');\n");
    fprintf(fid,"  ylabel('Prototype Filter PSD');\n");
    fprintf(fid,"subplot(2,1,2);\n");
    fprintf(fid,"  plot(f, Y, 'Color', [0 0.25 0.5], 'LineWidth', 2);\n");
    fprintf(fid,"  axis([-0.5 0.5 -100 0]);\n");
    fprintf(fid,"  grid on;\n");
    fprintf(fid,"  xlabel('Normalized Frequency [f/F_s]');\n");
    fprintf(fid,"  ylabel('Output PSD');\n");

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

    printf("done.\n");
    return 0;
}
Beispiel #22
0
int main() {
    // spectral periodogram options
    unsigned int nfft        =   1024;  // spectral periodogram FFT size
    unsigned int num_samples =   4000;  // number of samples
    float        beta        =  10.0f;  // Kaiser-Bessel window parameter
    float        noise_floor = -60.0f;  // noise floor [dB]
    float        alpha       =   0.1f;  // PSD estimate bandwidth

    unsigned int i;

    // derived values
    float nstd = powf(10.0f, noise_floor/20.0f);

    // create spectral periodogram
    unsigned int window_size = nfft/2;  // spgramf window size
    spgramf q = spgramf_create_kaiser(nfft, window_size, beta);

    // generate signal (filter with frequency offset)
    unsigned int  h_len = 91;       // filter length
    float         fc    = 0.07f;    // filter cut-off frequency
    float         f0    = 0.20f;    // filter center frequency
    float         As    = 60.0f;    // filter stop-band attenuation
    float         h[h_len];         // filter coefficients
    liquid_firdes_kaiser(h_len, fc, As, 0, h);
    // add frequency offset
    for (i=0; i<h_len; i++)
        h[i] *= cosf(2*M_PI*f0*i);
    firfilt_rrrf filter = firfilt_rrrf_create(h, h_len);
    firfilt_rrrf_set_scale(filter, 2.0f*fc);

    for (i=0; i<num_samples; i++) {
        // generate random sample
        float x = randnf();

        // filter
        float y = 0;
        firfilt_rrrf_push(filter, x);
        firfilt_rrrf_execute(filter, &y);

        // add noise
        y += nstd * randnf();

        // push resulting sample through periodogram
        spgramf_accumulate_psd(q, &y, alpha, 1);
    }

    // compute power spectral density output
    float psd[nfft];
    spgramf_write_accumulation(q, psd);

    // destroy objects
    firfilt_rrrf_destroy(filter);
    spgramf_destroy(q);

    // 
    // export output file
    //
    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\n");
    fprintf(fid,"nfft = %u;\n", nfft);
    fprintf(fid,"f    = [0:(nfft-1)]/nfft - 0.5;\n");
    fprintf(fid,"H    = zeros(1,nfft);\n");
    fprintf(fid,"noise_floor = %12.6f;\n", noise_floor);
    
    for (i=0; i<nfft; i++)
        fprintf(fid,"H(%6u) = %12.4e;\n", i+1, psd[i]);

    fprintf(fid,"figure;\n");
    fprintf(fid,"plot(f, H, '-', 'LineWidth',1.5);\n");
    fprintf(fid,"xlabel('Normalized Frequency [f/F_s]');\n");
    fprintf(fid,"ylabel('Power Spectral Density [dB]');\n");
    fprintf(fid,"grid on;\n");
    fprintf(fid,"ymin = 10*floor([noise_floor-20]/10);\n");
    fprintf(fid,"ymax = 10*floor([noise_floor+80]/10);\n");
    fprintf(fid,"axis([-0.5 0.5 ymin ymax]);\n");

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

    printf("done.\n");
    return 0;
}
Beispiel #23
0
// Design frequency-shifted root-Nyquist filter based on
// the Kaiser-windowed sinc using approximation for rho.
//
//  _k      :   filter over-sampling rate (samples/symbol)
//  _m      :   filter delay (symbols)
//  _beta   :   filter excess bandwidth factor (0,1)
//  _dt     :   filter fractional sample delay
//  _h      :   resulting filter [size: 2*_k*_m+1]
void liquid_firdes_arkaiser(unsigned int _k,
                            unsigned int _m,
                            float _beta,
                            float _dt,
                            float * _h)
{
    // validate input
    if (_k < 2) {
        fprintf(stderr,"error: liquid_firdes_arkaiser(), k must be at least 2\n");
        exit(1);
    } else if (_m < 1) {
        fprintf(stderr,"error: liquid_firdes_arkaiser(), m must be at least 1\n");
        exit(1);
    } else if (_beta <= 0.0f || _beta >= 1.0f) {
        fprintf(stderr,"error: liquid_firdes_arkaiser(), beta must be in (0,1)\n");
        exit(1);
    } else if (_dt < -1.0f || _dt > 1.0f) {
        fprintf(stderr,"error: liquid_firdes_arkaiser(), dt must be in [-1,1]\n");
        exit(1);
    }

#if 0
    // compute bandwidth adjustment estimate
    float rho_hat = rkaiser_approximate_rho(_m,_beta);  // bandwidth correction factor
#else
    // rho ~ c0 + c1*log(_beta) + c2*log^2(_beta)

    // c0 ~ 0.762886 + 0.067663*log(m)
    // c1 ~ 0.065515
    // c2 ~ log( 1 - 0.088*m^-1.6 )

    float c0 = 0.762886 + 0.067663*logf(_m);
    float c1 = 0.065515;
    float c2 = logf( 1 - 0.088*powf(_m,-1.6 ) );

    float log_beta = logf(_beta);

    float rho_hat = c0 + c1*log_beta + c2*log_beta*log_beta;

    // ensure range is valid
    if (rho_hat <= 0.0f || rho_hat >= 1.0f)
        rho_hat = rkaiser_approximate_rho(_m,_beta);
#endif

    unsigned int n=2*_k*_m+1;                       // filter length
    float kf = (float)_k;                           // samples/symbol (float)
    float del = _beta*rho_hat / kf;                 // transition bandwidth
    float As = estimate_req_filter_As(del, n);      // stop-band suppression
    float fc  = 0.5f*(1 + _beta*(1.0f-rho_hat))/kf; // filter cutoff
    
#if DEBUG_RKAISER
    printf("rho-hat : %12.8f (compare to %12.8f)\n", rho_hat, rkaiser_approximate_rho(_m,_beta));
    printf("fc      : %12.8f\n", fc);
    printf("delta-f : %12.8f\n", del);
    printf("As      : %12.8f dB\n", As);
    printf("alpha   : %12.8f\n", kaiser_beta_As(As));
#endif

    // compute filter coefficients
    liquid_firdes_kaiser(n,fc,As,_dt,_h);

    // normalize coefficients
    float e2 = 0.0f;
    unsigned int i;
    for (i=0; i<n; i++) e2 += _h[i]*_h[i];
    for (i=0; i<n; i++) _h[i] *= sqrtf(_k/e2);
}
Beispiel #24
0
// Design GMSK receive filter
//  _k      : samples/symbol
//  _m      : symbol delay
//  _beta   : rolloff factor (0 < beta <= 1)
//  _dt     : fractional sample delay
//  _h      : output coefficient buffer (length: 2*k*m+1)
void liquid_firdes_gmskrx(unsigned int _k,
                          unsigned int _m,
                          float        _beta,
                          float        _dt,
                          float *      _h)
{
    // validate input
    if ( _k < 1 ) {
        fprintf(stderr,"error: liquid_firdes_gmskrx(): k must be greater than 0\n");
        exit(1);
    } else if ( _m < 1 ) {
        fprintf(stderr,"error: liquid_firdes_gmskrx(): m must be greater than 0\n");
        exit(1);
    } else if ( (_beta < 0.0f) || (_beta > 1.0f) ) {
        fprintf(stderr,"error: liquid_firdes_gmskrx(): beta must be in [0,1]\n");
        exit(1);
    } else;

    unsigned int k = _k;
    unsigned int m = _m;
    float BT = _beta;

    // internal options
    float beta = BT;                // prototype filter cut-off
    float delta = 1e-3f;            // filter design correction factor
    liquid_firfilt_type prototype = LIQUID_FIRFILT_KAISER;    // Nyquist prototype

    unsigned int i;

    // derived values
    unsigned int h_len = 2*k*m+1;   // filter length

    // arrays
    float ht[h_len];         // transmit filter coefficients
    float hr[h_len];         // recieve filter coefficients

    // design transmit filter
    liquid_firdes_gmsktx(k,m,BT,0.0f,ht);

    //
    // start of filter design procedure
    //

    // 'internal' arrays
    float h_primef[h_len];          // temporary buffer for real 'prototype' coefficients
    float g_primef[h_len];          // temporary buffer for real 'gain' coefficient

    float complex h_tx[h_len];      // impulse response of transmit filter
    float complex h_prime[h_len];   // impulse response of 'prototype' filter
    float complex g_prime[h_len];   // impulse response of 'gain' filter
    float complex h_hat[h_len];     // impulse response of receive filter
    
    float complex H_tx[h_len];      // frequency response of transmit filter
    float complex H_prime[h_len];   // frequency response of 'prototype' filter
    float complex G_prime[h_len];   // frequency response of 'gain' filter
    float complex H_hat[h_len];     // frequency response of receive filter

    // create 'prototype' matched filter
    liquid_firdes_nyquist(prototype,k,m,beta,0.0f,h_primef);

    // create 'gain' filter to improve stop-band rejection
    float fc = (0.7f + 0.1*beta) / (float)k;
    float As = 60.0f;
    liquid_firdes_kaiser(h_len, fc, As, 0.0f, g_primef);

    // copy to fft input buffer, shifting appropriately
    for (i=0; i<h_len; i++) {
        h_prime[i] = h_primef[ (i+k*m)%h_len ];
        g_prime[i] = g_primef[ (i+k*m)%h_len ];
        h_tx[i]    = ht[       (i+k*m)%h_len ];
    }

    // run ffts
    fft_run(h_len, h_prime, H_prime, LIQUID_FFT_FORWARD, 0);
    fft_run(h_len, g_prime, G_prime, LIQUID_FFT_FORWARD, 0);
    fft_run(h_len, h_tx,    H_tx,    LIQUID_FFT_FORWARD, 0);

    // find minimum of reponses
    float H_tx_min = 0.0f;
    float H_prime_min = 0.0f;
    float G_prime_min = 0.0f;
    for (i=0; i<h_len; i++) {
        if (i==0 || crealf(H_tx[i])    < H_tx_min)    H_tx_min    = crealf(H_tx[i]);
        if (i==0 || crealf(H_prime[i]) < H_prime_min) H_prime_min = crealf(H_prime[i]);
        if (i==0 || crealf(G_prime[i]) < G_prime_min) G_prime_min = crealf(G_prime[i]);
    }

    // compute 'prototype' response, removing minima, and add correction factor
    for (i=0; i<h_len; i++) {
        // compute response necessary to yeild prototype response (not exact, but close)
        H_hat[i] = crealf(H_prime[i] - H_prime_min + delta) / crealf(H_tx[i] - H_tx_min + delta);

        // include additional term to add stop-band suppression
        H_hat[i] *= crealf(G_prime[i] - G_prime_min) / crealf(G_prime[0]);
    }

    // compute ifft and copy response
    fft_run(h_len, H_hat, h_hat, LIQUID_FFT_BACKWARD, 0);
    for (i=0; i<h_len; i++)
        hr[i] = crealf( h_hat[(i+k*m+1)%h_len] ) / (float)(k*h_len);

    // copy result, scaling by (samples/symbol)^2
    for (i=0; i<h_len; i++)
        _h[i] = hr[i]*_k*_k;
}
int main(int argc, char*argv[])
{
    // options
    unsigned int h_len=19;          // filter length
    unsigned int p=5;               // polynomial order
    float fc=0.45f;                 // filter cutoff
    float As=60.0f;                 // stop-band attenuation [dB]
    float mu=0.1f;                  // fractional sample delay
    unsigned int num_samples=60;    // number of samples to evaluate
    int verbose = 0;                // verbose output?

    int dopt;
    while ((dopt = getopt(argc,argv,"hvt:")) != EOF) {
        switch (dopt) {
        case 'h': usage();              return 0;
        case 'v': verbose = 1;          break;
        case 't': mu = atof(optarg);    break;
        default:
            exit(1);
        }
    }

    // data arrays
    float x[num_samples];           // input data array
    float y[num_samples];           // output data array

    // create and initialize Farrow filter object
    firfarrow_rrrf f = firfarrow_rrrf_create(h_len, p, fc, As);
    firfarrow_rrrf_set_delay(f, mu);

    unsigned int i;

    // generate input (filtered noise)
    float hx[21];
    liquid_firdes_kaiser(15, 0.1, 60, 0, hx);
    firfilt_rrrf fx = firfilt_rrrf_create(hx, 15);
    for (i=0; i<num_samples; i++) {
        firfilt_rrrf_push(fx, i < 40 ? randnf() : 0.0f);
        firfilt_rrrf_execute(fx, &x[i]);
    }
    firfilt_rrrf_destroy(fx);

    // push input through filter
    for (i=0; i<num_samples; i++) {
        firfarrow_rrrf_push(f, x[i]);
        firfarrow_rrrf_execute(f, &y[i]);
    }

    // destroy Farrow filter object
    firfarrow_rrrf_destroy(f);

    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,"h_len = %u;\n", h_len);
    fprintf(fid,"mu = %f;\n", mu);
    fprintf(fid,"num_samples = %u;\n", num_samples);

    for (i=0; i<num_samples; i++) {
        fprintf(fid,"x(%4u) = %12.4e; y(%4u) = %12.4e;\n", i+1, x[i], i+1, y[i]);
    }

    // plot the results
    fprintf(fid,"\n\n");
    fprintf(fid,"figure;\n");
    fprintf(fid,"tx = 0:(num_samples-1);     %% input time scale\n");
    fprintf(fid,"ty = tx - (h_len-1)/2 + mu; %% output time scale\n");
    fprintf(fid,"plot(tx, x,'-s','MarkerSize',3, ...\n");
    fprintf(fid,"     ty, y,'-s','MarkerSize',3);\n");
    fprintf(fid,"legend('input','output',0);\n");

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

    printf("done.\n");
    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;

}