示例#1
0
// create window buffer object of length _n
WINDOW() WINDOW(_create)(unsigned int _n)
{
    // validate input
    if (_n == 0) {
        fprintf(stderr,"error: window%s_create(), window size must be greater than zero\n",
                EXTENSION);
        exit(1);
    }

    // create initial object
    WINDOW() q = (WINDOW()) malloc(sizeof(struct WINDOW(_s)));

    // set internal parameters
    q->len  = _n;                   // nominal window size
    q->m    = liquid_msb_index(_n); // effectively floor(log2(len))+1
    q->n    = 1<<(q->m);            // 2^m
    q->mask = q->n - 1;             // bit mask

    // number of elements to allocate to memory
    q->num_allocated = q->n + q->len - 1;

    // allocte memory
    q->v = (T*) malloc((q->num_allocated)*sizeof(T));
    q->read_index = 0;

    // reset window
    WINDOW(_reset)(q);

    // return object
    return q;
}
示例#2
0
/*  _m          :   number of correlators                   */
PRESYNC() PRESYNC(_create)(TC *         _v,
                           unsigned int _n,
                           float        _dphi_max,
                           unsigned int _m)
{
    // validate input
    if (_n < 1) {
        fprintf(stderr, "error: bpresync_%s_create(), invalid input length\n", EXTENSION_FULL);
        exit(1);
    } else if (_m == 0) {
        fprintf(stderr, "error: bpresync_%s_create(), number of correlators must be at least 1\n", EXTENSION_FULL);
        exit(1);
    }

    // allocate main object memory and initialize
    PRESYNC() _q = (PRESYNC()) malloc(sizeof(struct PRESYNC(_s)));
    _q->n = _n;
    _q->m = _m;

    _q->n_inv = 1.0f / (float)(_q->n);

    unsigned int i;

    // create internal receive buffers
    _q->rx_i = WINDOW(_create)(_q->n);
    _q->rx_q = WINDOW(_create)(_q->n);

    // create internal array of frequency offsets
    _q->dphi = (float*) malloc( _q->m*sizeof(float) );

    // create internal synchronizers
    _q->sync_i = (DOTPROD()*) malloc( _q->m*sizeof(DOTPROD()) );
    _q->sync_q = (DOTPROD()*) malloc( _q->m*sizeof(DOTPROD()) );

    // buffer
    T vi_prime[_n];
    T vq_prime[_n];
    for (i=0; i<_q->m; i++) {

        // generate signal with frequency offset
        _q->dphi[i] = (float)i / (float)(_q->m-1)*_dphi_max;
        unsigned int k;
        for (k=0; k<_q->n; k++) {
            vi_prime[k] = REAL( _v[k] * cexpf(-_Complex_I*k*_q->dphi[i]) );
            vq_prime[k] = IMAG( _v[k] * cexpf(-_Complex_I*k*_q->dphi[i]) );
        }

        _q->sync_i[i] = DOTPROD(_create)(vi_prime, _q->n);
        _q->sync_q[i] = DOTPROD(_create)(vq_prime, _q->n);
    }

    // allocate memory for cross-correlation
    _q->rxy = (float*) malloc( _q->m*sizeof(float) );

    // reset object
    PRESYNC(_reset)(_q);

    return _q;
}
示例#3
0
文件: resamp2.c 项目: GRDSP/grdsp
// create a resamp2 object
//  _m      :   filter semi-length (effective length: 4*_m+1)
//  _fc     :   center frequency of half-band filter
//  _As     :   stop-band attenuation [dB], _As > 0
RESAMP2() RESAMP2(_create)(unsigned int _m,
                           float        _fc,
                           float        _As)
{
    // validate input
    if (_m < 2) {
        fprintf(stderr,"error: resamp2_%s_create(), filter semi-length must be at least 2\n", EXTENSION_FULL);
        exit(1);
    }

    RESAMP2() q = (RESAMP2()) malloc(sizeof(struct RESAMP2(_s)));
    q->m  = _m;
    q->fc = _fc;
    q->As = _As;
    if ( q->fc < -0.5f || q->fc > 0.5f ) {
        fprintf(stderr,"error: resamp2_%s_create(), fc (%12.4e) must be in (-1,1)\n", EXTENSION_FULL, q->fc);
        exit(1);
    }

    // change filter length as necessary
    q->h_len = 4*(q->m) + 1;
    q->h = (TC *) malloc((q->h_len)*sizeof(TC));

    q->h1_len = 2*(q->m);
    q->h1 = (TC *) malloc((q->h1_len)*sizeof(TC));

    // design filter prototype
    unsigned int i;
    float t, h1, h2;
    TC h3;
    float beta = kaiser_beta_As(q->As);
    for (i=0; i<q->h_len; i++) {
        t = (float)i - (float)(q->h_len-1)/2.0f;
        h1 = sincf(t/2.0f);
        h2 = kaiser(i,q->h_len,beta,0);
#if TC_COMPLEX == 1
        h3 = cosf(2.0f*M_PI*t*q->fc) + _Complex_I*sinf(2.0f*M_PI*t*q->fc);
#else
        h3 = cosf(2.0f*M_PI*t*q->fc);
#endif
        q->h[i] = h1*h2*h3;
    }

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

    // create dotprod object
    q->dp = DOTPROD(_create)(q->h1, 2*q->m);

    // create window buffers
    q->w0 = WINDOW(_create)(2*(q->m));
    q->w1 = WINDOW(_create)(2*(q->m));

    RESAMP2(_clear)(q);

    return q;
}
示例#4
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;
}
示例#5
0
文件: pixmap.c 项目: s-cherepanov/elk
static Object P_Create_Bitmap_From_Data (Object win, Object data, Object pw,
        Object ph) {
    register unsigned int w, h;

    Check_Type (win, T_Window);
    Check_Type (data, T_String);
    w = Get_Integer (pw);
    h = Get_Integer (ph);
    if (w * h > 8 * STRING(data)->size)
        Primitive_Error ("bitmap too small");
    return Make_Pixmap (WINDOW(win)->dpy,
                        XCreateBitmapFromData (WINDOW(win)->dpy, WINDOW(win)->win,
                                STRING(data)->data, w, h));
}
示例#6
0
void spctrm(FILE *fp, float p[], int m, int k, int ovrlap)
{
	void four1(float data[], unsigned long nn, int isign);
	int mm,m44,m43,m4,kk,joffn,joff,j2,j;
	float w,facp,facm,*w1,*w2,sumw=0.0,den=0.0;

	mm=m+m;
	m43=(m4=mm+mm)+3;
	m44=m43+1;
	w1=vector(1,m4);
	w2=vector(1,m);
	facm=m;
	facp=1.0/m;
	for (;j<=mm;j++) sumw += SQR(WINDOW(j,facm,facp));
	for (;j<=m;j++) p[j]=0.0;
	if (ovrlap)
		for (;j<=m;j++) fscanf(fp,"%f",&w2[j]);
	for (;kk<=k;kk++) {
		for (;joff<=0;joff++) {
			if (ovrlap) {
				for (;j<=m;j++) w1[joff+j+j]=w2[j];
				for (;j<=m;j++) fscanf(fp,"%f",&w2[j]);
				joffn=joff+mm;
				for (;j<=m;j++) w1[joffn+j+j]=w2[j];
			} else {
				for (;j<=m4;j+=2)
					fscanf(fp,"%f",&w1[j]);
			}
		}
		for (;j<=mm;j++) {
			j2=j+j;
			w=WINDOW(j,facm,facp);
			w1[j2] *= w;
			w1[j2-1] *= w;
		}
		four1(w1,mm,1);
		p[1] += (SQR(w1[1])+SQR(w1[2]));
		for (;j<=m;j++) {
			j2=j+j;
			p[j] += (SQR(w1[j2])+SQR(w1[j2-1])
				+SQR(w1[m44-j2])+SQR(w1[m43-j2]));
		}
		den += sumw;
	}
	den *= m4;
	for (;j<=m;j++) p[j] /= den;
	free_vector(w2,1,m);
	free_vector(w1,1,m4);
}
示例#7
0
// create least mean-squares (LMS) equalizer object
//  _h      :   initial coefficients [size: _p x 1], default if NULL
//  _p      :   equalizer length (number of taps)
EQLMS() EQLMS(_create)(T *          _h,
                       unsigned int _p)
{
    EQLMS() eq = (EQLMS()) malloc(sizeof(struct EQLMS(_s)));

    // set filter order, other params
    eq->p = _p;
    eq->mu = 0.5f;

    eq->h0 = (T*) malloc((eq->p)*sizeof(T));
    eq->w0 = (T*) malloc((eq->p)*sizeof(T));
    eq->w1 = (T*) malloc((eq->p)*sizeof(T));
    eq->buffer = WINDOW(_create)(eq->p);
    eq->x2     = wdelayf_create(eq->p);

    // copy coefficients (if not NULL)
    if (_h == NULL) {
        // initial coefficients with delta at first index
        unsigned int i;
        for (i=0; i<eq->p; i++)
            eq->h0[i] = (i==0) ? 1.0 : 0.0;
    } else {
        // copy user-defined initial coefficients
        memmove(eq->h0, _h, (eq->p)*sizeof(T));
    }

    // reset equalizer object
    EQLMS(_reset)(eq);

    return eq;
}
示例#8
0
static int
csio_t5_set_mem_win(struct csio_hw *hw, uint32_t win)
{
	u32 mem_win_base;
	/*
	 * Truncation intentional: we only read the bottom 32-bits of the
	 * 64-bit BAR0/BAR1 ...  We use the hardware backdoor mechanism to
	 * read BAR0 instead of using pci_resource_start() because we could be
	 * operating from within a Virtual Machine which is trapping our
	 * accesses to our Configuration Space and we need to set up the PCI-E
	 * Memory Window decoders with the actual addresses which will be
	 * coming across the PCI-E link.
	 */

	/* For T5, only relative offset inside the PCIe BAR is passed */
	mem_win_base = MEMWIN_BASE;

	/*
	 * Set up memory window for accessing adapter memory ranges.  (Read
	 * back MA register to ensure that changes propagate before we attempt
	 * to use the new values.)
	 */
	csio_wr_reg32(hw, mem_win_base | BIR(0) |
			  WINDOW(ilog2(MEMWIN_APERTURE) - 10),
			  PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, win));
	csio_rd_reg32(hw,
		      PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, win));

	return 0;
}
示例#9
0
文件: eqlms.c 项目: Clivia/liquid-dsp
// create least mean-squares (LMS) equalizer object
//  _h      :   initial coefficients [size: _h_len x 1], default if NULL
//  _p      :   equalizer length (number of taps)
EQLMS() EQLMS(_create)(T *          _h,
                       unsigned int _h_len)
{
    EQLMS() q = (EQLMS()) malloc(sizeof(struct EQLMS(_s)));

    // set filter order, other params
    q->h_len = _h_len;
    q->mu    = 0.5f;

    q->h0 = (T*) malloc((q->h_len)*sizeof(T));
    q->w0 = (T*) malloc((q->h_len)*sizeof(T));
    q->w1 = (T*) malloc((q->h_len)*sizeof(T));
    q->buffer = WINDOW(_create)(q->h_len);
    q->x2     = wdelayf_create(q->h_len);

    // copy coefficients (if not NULL)
    if (_h == NULL) {
        // initial coefficients with delta at first index
        unsigned int i;
        for (i=0; i<q->h_len; i++)
            q->h0[i] = (i==0) ? 1.0 : 0.0;
    } else {
        // copy user-defined initial coefficients
        memmove(q->h0, _h, (q->h_len)*sizeof(T));
    }

    // reset equalizer object
    EQLMS(_reset)(q);

    // return main object
    return q;
}
示例#10
0
void firpfbch_analyzer_push(firpfbch _c, float complex _x)
{
    // push sample into the buffer at filter_index
    WINDOW(_push)(_c->w[_c->filter_index], _x);

    // decrement filter index
    _c->filter_index = (_c->filter_index+_c->num_channels-1) % _c->num_channels;
}
示例#11
0
static void gentbl_afsk2400(FILE *f, float tcm3105clk)
{
	int i, sum, v;

	fprintf(f, "\n/*\n * afsk2400 specific tables (tcm3105 clk %7fHz)\n */\n"
		"#define AFSK24_TX_FREQ_LO %d\n"
		"#define AFSK24_TX_FREQ_HI %d\n"
		"#define AFSK24_BITPLL_INC %d\n"
		"#define AFSK24_SAMPLERATE %d\n\n", tcm3105clk, 
		(int)(tcm3105clk/3694.0), (int)(tcm3105clk/2015.0), 
		0x10000*2400/AFSK24_SAMPLERATE, AFSK24_SAMPLERATE);

#define ARGLO(x) 2.0*M_PI*(double)x*(tcm3105clk/3694.0)/(double)AFSK24_SAMPLERATE
#define ARGHI(x) 2.0*M_PI*(double)x*(tcm3105clk/2015.0)/(double)AFSK24_SAMPLERATE
#define WINDOW(x) hamming((float)(x)/(AFSK24_CORRLEN-1.0))

	fprintf(f, "static const int afsk24_tx_lo_i[] = {\n\t");
        for(sum = i = 0; i < AFSK24_CORRLEN; i++) {
		sum += (v = 127.0*cos(ARGLO(i))*WINDOW(i));
                fprintf(f, " %4i%c", v, (i < AFSK24_CORRLEN-1) ? ',' : ' ');
	}
        fprintf(f, "\n};\n#define SUM_AFSK24_TX_LO_I %d\n\n"
		"static const int afsk24_tx_lo_q[] = {\n\t", sum);
        for(sum = i = 0; i < AFSK24_CORRLEN; i++) {
		sum += (v = 127.0*sin(ARGLO(i))*WINDOW(i)); 
                fprintf(f, " %4i%c", v, (i < AFSK24_CORRLEN-1) ? ',' : ' ');
	}
        fprintf(f, "\n};\n#define SUM_AFSK24_TX_LO_Q %d\n\n"
		"static const int afsk24_tx_hi_i[] = {\n\t", sum);
        for(sum = i = 0; i < AFSK24_CORRLEN; i++) {
		sum += (v = 127.0*cos(ARGHI(i))*WINDOW(i)); 
                fprintf(f, " %4i%c", v, (i < AFSK24_CORRLEN-1) ? ',' : ' ');
	}
        fprintf(f, "\n};\n#define SUM_AFSK24_TX_HI_I %d\n\n"
		"static const int afsk24_tx_hi_q[] = {\n\t", sum);
        for(sum = i = 0; i < AFSK24_CORRLEN; i++)  {
		sum += (v = 127.0*sin(ARGHI(i))*WINDOW(i));
                fprintf(f, " %4i%c", v, (i < AFSK24_CORRLEN-1) ? ',' : ' ');
	}
	fprintf(f, "\n};\n#define SUM_AFSK24_TX_HI_Q %d\n\n", sum);
#undef ARGLO
#undef ARGHI
#undef WINDOW
}
示例#12
0
void firpfbch_clear(firpfbch _c)
{
    unsigned int i;
    for (i=0; i<_c->num_channels; i++) {
        WINDOW(_clear)(_c->w[i]);
        _c->x[i] = 0;
        _c->X[i] = 0;
        _c->X_prime[i] = 0;
    }
    _c->filter_index = 0;
}
示例#13
0
void firpfbch_analyzer_run(firpfbch _c, float complex * _y)
{
    // NOTE: The analyzer is different from the synthesizer in
    //       that the invocation of the commutator results in a
    //       delay from the first input sample to the resulting
    //       partitions.  As a result, the inverse DFT is
    //       invoked after the first filter is run, after which
    //       the remaining filters are executed.

    // restore saved IDFT input state X from X_prime
    memmove(_c->X, _c->X_prime, (_c->num_channels)*sizeof(float complex));

    unsigned int i, b;
    unsigned int k = _c->filter_index;

    // push first value and compute output
    float complex * r;
    WINDOW(_read)(_c->w[k], &r);
    DOTPROD(_execute)(_c->dp[0], r, &(_c->X[0]));

    // execute inverse fft, store in buffer _c->x
    FFT_EXECUTE(_c->fft);

    // copy results to output buffer
    memmove(_y, _c->x, (_c->num_channels)*sizeof(float complex));

    // push remaining samples into filter bank and execute in
    // *reverse* order, putting result into the inverse DFT
    // input buffer _c->X
    //for (i=1; i<_c->num_channels; i++) {
    // NOTE : the filter window buffers have already been loaded
    //        in the proper reverse order, so there is no need
    //        to execute the dot products in any particular order,
    //        so long as they are aligned with the proper input
    //        buffer.
    for (i=1; i<_c->num_channels; i++) {
        b = (k+i) % _c->num_channels;
        WINDOW(_read)(_c->w[b], &r);
        DOTPROD(_execute)(_c->dp[i], r, &(_c->X[i]));
    }
}
示例#14
0
tdmInteractor
_dxfAllocateInteractor (tdmInteractorWin W, int size)
{
  int i ;
  tdmInteractor I = (tdmInteractor) 0 ;

  ENTRY(("_dxfAllocateInteractor(0x%x, %d)", W, size));

  if (! W) goto error ;

  if (W->numUsed == W->numAllocated)
      /* create more interactors */
      I = _allocateMoreInteractors(W) ;
  else
      /* find an unused interactor */
      for (i = 0 ; i < W->numAllocated ; i++)
          if (! IS_USED(W->Interactors[i]))
            {
              I = W->Interactors[i] ;
              break ;
            }

  if (! I) goto error ;
  
  if (size) {
      /* allocate interactor private data */
      if (! (PRIVATE(I) = tdmAllocateLocal(size))) {
          goto error ;
      } else {
          bzero ((char *) PRIVATE(I), size) ;
      }
  }

  WINDOW(I) = W ;
  AUX(I) = (tdmInteractor) 0 ;
  IS_AUX(I) = 0 ;
  IS_GROUP(I) = 0 ;
  IS_USED(I) = 1 ;
  W->numUsed++ ;

  /*
   * Default event mask
   */
  I->eventMask =  DXEVENT_LEFT | DXEVENT_MIDDLE | DXEVENT_RIGHT;

  EXIT(("I = 0x%x", I));
  return I ;

 error:

  EXIT(("ERROR"));
  return (tdmInteractor) 0 ;
}
示例#15
0
// create firpfb from external coefficients
//  _M      : number of filters in the bank
//  _h      : coefficients [size: _M*_h_len x 1]
//  _h_len  : filter delay (symbols)
FIRPFB() FIRPFB(_create)(unsigned int _M,
                         TC *         _h,
                         unsigned int _h_len)
{
    // validate input
    if (_M == 0) {
        fprintf(stderr,"error: firpfb_%s_create(), number of filters must be greater than zero\n",
                EXTENSION_FULL);
        exit(1);
    } else if (_h_len == 0) {
        fprintf(stderr,"error: firpfb_%s_create(), filter length must be greater than zero\n",
                EXTENSION_FULL);
        exit(1);
    }

    // create main filter object
    FIRPFB() q = (FIRPFB()) malloc(sizeof(struct FIRPFB(_s)));

    // set user-defined parameters
    q->num_filters = _M;
    q->h_len       = _h_len;

    // each filter is realized as a dotprod object
    q->dp = (DOTPROD()*) malloc((q->num_filters)*sizeof(DOTPROD()));

    // generate bank of sub-samped filters
    // length of each sub-sampled filter
    unsigned int h_sub_len = _h_len / q->num_filters;
    TC h_sub[h_sub_len];
    unsigned int i, n;
    for (i=0; i<q->num_filters; i++) {
        for (n=0; n<h_sub_len; n++) {
            // load filter in reverse order
            h_sub[h_sub_len-n-1] = _h[i + n*(q->num_filters)];
        }

        // create dot product object
        q->dp[i] = DOTPROD(_create)(h_sub,h_sub_len);
    }

    // save sub-sampled filter length
    q->h_sub_len = h_sub_len;

    // create window buffer
    q->w = WINDOW(_create)(q->h_sub_len);

    // set default scaling
    q->scale = 1;

    // reset object and return
    FIRPFB(_reset)(q);
    return q;
}
示例#16
0
void firpfbch_synthesizer_execute(firpfbch _c, float complex * _x, float complex * _y)
{
    unsigned int i;

    // copy samples into ifft input buffer _c->X
    memmove(_c->X, _x, (_c->num_channels)*sizeof(float complex));

    // execute inverse fft, store in buffer _c->x
    FFT_EXECUTE(_c->fft);

    // push samples into filter bank and execute, putting
    // samples into output buffer _y
    float complex * r;
    for (i=0; i<_c->num_channels; i++) {
        WINDOW(_push)(_c->w[i], _c->x[i]);
        WINDOW(_read)(_c->w[i], &r);
        DOTPROD(_execute)(_c->dp[i], r, &(_y[i]));

        // invoke scaling factor
        _y[i] /= (float)(_c->num_channels);
    }
}
示例#17
0
// create auto-correlator object                            
//  _window_size    : size of the correlator window         
//  _delay          : correlator delay [samples]            
AUTOCORR() AUTOCORR(_create)(unsigned int _window_size,
                             unsigned int _delay)
{
    // create main object
    AUTOCORR() q = (AUTOCORR()) malloc(sizeof(struct AUTOCORR(_s)));

    // set user-based parameters
    q->window_size = _window_size;
    q->delay       = _delay;

    // create window objects
    q->w      = WINDOW(_create)(q->window_size);
    q->wdelay = WINDOW(_create)(q->window_size + q->delay);

    // allocate array for squared energy buffer
    q->we2 = (float*) malloc( (q->window_size)*sizeof(float) );

    // clear object
    AUTOCORR(_reset)(q);

    // return main object
    return q;
}
示例#18
0
文件: cmdsub.cpp 项目: dworkin/dgd
/*
 * NAME:	cmdbuf->page()
 * DESCRIPTION:	show a page of lines
 */
int cb_page(cmdbuf *cb)
{
    Int offset, window;

    if (cb->edbuf->lines == 0) {
	error("No lines in buffer");
    }

    window = WINDOW(cb->vars);
    switch (*(cb->cmd)++) {
    default:	/* next line */
	cb->cmd--;
	cb->cthis++;
	/* fall through */
    case '+':	/* top */
	offset = 0;
	break;

    case '-':	/* bottom */
	offset = 1 - window;
	break;

    case '.':	/* middle */
	offset = 1 - (window + 1) / 2;
	break;
    }

    /* set first */
    if (cb->first < 0) {
	cb->first = cb->cthis;
    }
    cb->first += offset;
    if (cb->first <= 0) {
	cb->first = 1;
    } else if (cb->first > cb->edbuf->lines) {
	cb->first = cb->edbuf->lines;
    }

    /* set last */
    cb->last = cb->first + window - 1;
    if (cb->last < cb->first) {
	cb->last = cb->first;
    } else if (cb->last > cb->edbuf->lines) {
	cb->last = cb->edbuf->lines;
    }

    return cb_print(cb);
}
示例#19
0
void firpfbch_destroy(firpfbch _c)
{
    unsigned int i;
    for (i=0; i<_c->num_channels; i++) {
        DOTPROD(_destroy)(_c->dp[i]);
        WINDOW(_destroy)(_c->w[i]);
    }
    free(_c->dp);
    free(_c->w);

    FFT_DESTROY_PLAN(_c->fft);
    free(_c->h);
    free(_c->x);
    free(_c->X);
    free(_c->X_prime);
    free(_c);
}
示例#20
0
// create firfilt object
//  _h      :   coefficients (filter taps) [size: _n x 1]
//  _n      :   filter length
FIRFILT() FIRFILT(_create)(TC * _h,
                           unsigned int _n)
{
    // validate input
    if (_n == 0) {
        fprintf(stderr,"error: firfilt_%s_create(), filter length must be greater than zero\n", EXTENSION_FULL);
        exit(1);
    }

    // create filter object and initialize
    FIRFILT() q = (FIRFILT()) malloc(sizeof(struct FIRFILT(_s)));
    q->h_len = _n;
    q->h = (TC *) malloc((q->h_len)*sizeof(TC));

#if LIQUID_FIRFILT_USE_WINDOW
    // create window (internal buffer)
    q->w = WINDOW(_create)(q->h_len);
#else
    // initialize array for buffering
    q->w_len   = 1<<liquid_msb_index(q->h_len); // effectively 2^{floor(log2(len))+1}
    q->w_mask  = q->w_len - 1;
    q->w       = (TI *) malloc((q->w_len + q->h_len + 1)*sizeof(TI));
    q->w_index = 0;
#endif

    // load filter in reverse order
    unsigned int i;
    for (i=_n; i>0; i--)
        q->h[i-1] = _h[_n-i];

    // create dot product object
    q->dp = DOTPROD(_create)(q->h, q->h_len);

    // set default scaling
    q->scale = 1;

    // reset filter state (clear buffer)
    FIRFILT(_reset)(q);

    return q;
}
示例#21
0
// create recursive least-squares (RLS) equalizer object
//  _h      :   initial coefficients [size: _p x 1], default if NULL
//  _p      :   equalizer length (number of taps)
EQRLS() EQRLS(_create)(T * _h,
                       unsigned int _p)
{
    EQRLS() eq = (EQRLS()) malloc(sizeof(struct EQRLS(_s)));

    // set filter order, other parameters
    eq->p = _p;
    eq->lambda = 0.99f;
    eq->delta = 0.1f;
    eq->n=0;

    // allocate memory for matrices
    eq->h0 =    (T*) malloc((eq->p)*sizeof(T));
    eq->w0 =    (T*) malloc((eq->p)*sizeof(T));
    eq->w1 =    (T*) malloc((eq->p)*sizeof(T));
    eq->P0 =    (T*) malloc((eq->p)*(eq->p)*sizeof(T));
    eq->P1 =    (T*) malloc((eq->p)*(eq->p)*sizeof(T));
    eq->g =     (T*) malloc((eq->p)*sizeof(T));

    eq->xP0 =   (T*) malloc((eq->p)*sizeof(T));
    eq->gxl =   (T*) malloc((eq->p)*(eq->p)*sizeof(T));
    eq->gxlP0 = (T*) malloc((eq->p)*(eq->p)*sizeof(T));

    eq->buffer = WINDOW(_create)(eq->p);

    // copy coefficients (if not NULL)
    if (_h == NULL) {
        // initial coefficients with delta at first index
        unsigned int i;
        for (i=0; i<eq->p; i++)
            eq->h0[i] = (i==0) ? 1.0 : 0.0;
    } else {
        // copy user-defined initial coefficients
        memmove(eq->h0, _h, (eq->p)*sizeof(T));
    }

    EQRLS(_reset)(eq);

    return eq;
}
示例#22
0
void
_dxfDeallocateInteractor (tdmInteractor interactor)
{
  tdmInteractorWin W ;

  ENTRY(("_dxfDeallocateInteractor(0x%x)", interactor));

  if (! interactor || ! (W = WINDOW(interactor)))
    {
      EXIT(("ERROR"));
      return ;
    }
      
  if (PRIVATE(interactor))
      tdmFree((void *) PRIVATE(interactor)) ;

  bzero ((char *) interactor, sizeof(tdmInteractorT)) ;
  IS_USED(interactor) = 0 ;
  W->numUsed-- ;

  EXIT((""));
}
示例#23
0
文件: firdecim.c 项目: GRDSP/grdsp
// create decimator object
//  _M      :   decimation factor
//  _h      :   filter coefficients [size: _h_len x 1]
//  _h_len  :   filter coefficients length
FIRDECIM() FIRDECIM(_create)(unsigned int _M,
                             TC *         _h,
                             unsigned int _h_len)
{
    // validate input
    if (_h_len == 0) {
        fprintf(stderr,"error: decim_%s_create(), filter length must be greater than zero\n", EXTENSION_FULL);
        exit(1);
    } else if (_M == 0) {
        fprintf(stderr,"error: decim_%s_create(), decimation factor must be greater than zero\n", EXTENSION_FULL);
        exit(1);
    }

    FIRDECIM() q = (FIRDECIM()) malloc(sizeof(struct FIRDECIM(_s)));
    q->h_len = _h_len;
    q->M     = _M;

    // allocate memory for coefficients
    q->h = (TC*) malloc((q->h_len)*sizeof(TC));

    // load filter in reverse order
    unsigned int i;
    for (i=0; i<q->h_len; i++)
        q->h[i] = _h[_h_len-i-1];

    // create window (internal buffer)
    q->w = WINDOW(_create)(q->h_len);

    // create dot product object
    q->dp = DOTPROD(_create)(q->h, q->h_len);

    // reset filter state (clear buffer)
    FIRDECIM(_clear)(q);

    return q;
}
示例#24
0
// create FIR polyphase filterbank channelizer object
//  _type   : channelizer type (LIQUID_ANALYZER | LIQUID_SYNTHESIZER)
//  _M      : number of channels
//  _p      : filter length (symbols)
//  _h      : filter coefficients, [size: _M*_p x 1]
FIRPFBCH() FIRPFBCH(_create)(int          _type,
                             unsigned int _M,
                             unsigned int _p,
                             TC *         _h)
{
    // validate input
    if (_type != LIQUID_ANALYZER && _type != LIQUID_SYNTHESIZER) {
        fprintf(stderr,"error: firpfbch_%s_create(), invalid type %d\n", EXTENSION_FULL, _type);
        exit(1);
    } else if (_M == 0) {
        fprintf(stderr,"error: firpfbch_%s_create(), number of channels must be greater than 0\n", EXTENSION_FULL);
        exit(1);
    } else if (_p == 0) {
        fprintf(stderr,"error: firpfbch_%s_create(), invalid filter size (must be greater than 0)\n", EXTENSION_FULL);
        exit(1);
    }

    // create main object
    FIRPFBCH() q = (FIRPFBCH()) malloc(sizeof(struct FIRPFBCH(_s)));

    // set user-defined properties
    q->type         = _type;
    q->num_channels = _M;
    q->p            = _p;

    // derived values
    q->h_len = q->num_channels * q->p;

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

    // copy filter coefficients
    q->h = (TC*) malloc((q->h_len)*sizeof(TC));
    unsigned int i;
    for (i=0; i<q->h_len; i++)
        q->h[i] = _h[i];

    // generate bank of sub-samped filters
    unsigned int n;
    unsigned int h_sub_len = q->p;
    TC h_sub[h_sub_len];
    for (i=0; i<q->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] = q->h[i + n*(q->num_channels)];
        }
        // create window buffer and dotprod object (coefficients
        // loaded in reverse order)
        q->dp[i] = DOTPROD(_create)(h_sub,h_sub_len);
        q->w[i]  = WINDOW(_create)(h_sub_len);
    }

    // allocate memory for buffers
    // TODO : use fftw_malloc if HAVE_FFTW3_H
    q->x = (T*) malloc((q->num_channels)*sizeof(T));
    q->X = (T*) malloc((q->num_channels)*sizeof(T));

    // create fft plan
    if (q->type == LIQUID_ANALYZER)
        q->fft = FFT_CREATE_PLAN(q->num_channels, q->X, q->x, FFT_DIR_FORWARD, FFT_METHOD);
    else
        q->fft = FFT_CREATE_PLAN(q->num_channels, q->X, q->x, FFT_DIR_BACKWARD, FFT_METHOD);

    // reset filterbank object
    FIRPFBCH(_reset)(q);

    // return filterbank object
    return q;
}
示例#25
0
/*
 * csio_t5_memory_rw - read/write EDC 0, EDC 1 or MC via PCIE memory window
 * @hw: the csio_hw
 * @win: PCI-E memory Window to use
 * @mtype: memory type: MEM_EDC0, MEM_EDC1, MEM_MC0 (or MEM_MC) or MEM_MC1
 * @addr: address within indicated memory type
 * @len: amount of memory to transfer
 * @buf: host memory buffer
 * @dir: direction of transfer 1 => read, 0 => write
 *
 * Reads/writes an [almost] arbitrary memory region in the firmware: the
 * firmware memory address, length and host buffer must be aligned on
 * 32-bit boudaries.  The memory is transferred as a raw byte sequence
 * from/to the firmware's memory.  If this memory contains data
 * structures which contain multi-byte integers, it's the callers
 * responsibility to perform appropriate byte order conversions.
 */
static int
csio_t5_memory_rw(struct csio_hw *hw, u32 win, int mtype, u32 addr,
		u32 len, uint32_t *buf, int dir)
{
	u32 pos, start, offset, memoffset;
	u32 edc_size, mc_size, win_pf, mem_reg, mem_aperture, mem_base;

	/*
	 * Argument sanity checks ...
	 */
	if ((addr & 0x3) || (len & 0x3))
		return -EINVAL;

	/* Offset into the region of memory which is being accessed
	 * MEM_EDC0 = 0
	 * MEM_EDC1 = 1
	 * MEM_MC   = 2 -- T4
	 * MEM_MC0  = 2 -- For T5
	 * MEM_MC1  = 3 -- For T5
	 */
	edc_size  = EDRAM_SIZE_GET(csio_rd_reg32(hw, MA_EDRAM0_BAR));
	if (mtype != MEM_MC1)
		memoffset = (mtype * (edc_size * 1024 * 1024));
	else {
		mc_size = EXT_MEM_SIZE_GET(csio_rd_reg32(hw,
							 MA_EXT_MEMORY_BAR));
		memoffset = (MEM_MC0 * edc_size + mc_size) * 1024 * 1024;
	}

	/* Determine the PCIE_MEM_ACCESS_OFFSET */
	addr = addr + memoffset;

	/*
	 * Each PCI-E Memory Window is programmed with a window size -- or
	 * "aperture" -- which controls the granularity of its mapping onto
	 * adapter memory.  We need to grab that aperture in order to know
	 * how to use the specified window.  The window is also programmed
	 * with the base address of the Memory Window in BAR0's address
	 * space.  For T4 this is an absolute PCI-E Bus Address.  For T5
	 * the address is relative to BAR0.
	 */
	mem_reg = csio_rd_reg32(hw,
			PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, win));
	mem_aperture = 1 << (WINDOW(mem_reg) + 10);
	mem_base = GET_PCIEOFST(mem_reg) << 10;

	start = addr & ~(mem_aperture-1);
	offset = addr - start;
	win_pf = V_PFNUM(hw->pfn);

	csio_dbg(hw, "csio_t5_memory_rw: mem_reg: 0x%x, mem_aperture: 0x%x\n",
		 mem_reg, mem_aperture);
	csio_dbg(hw, "csio_t5_memory_rw: mem_base: 0x%x, mem_offset: 0x%x\n",
		 mem_base, memoffset);
	csio_dbg(hw, "csio_t5_memory_rw: start:0x%x, offset:0x%x, win_pf:%d\n",
		 start, offset, win_pf);
	csio_dbg(hw, "csio_t5_memory_rw: mtype: %d, addr: 0x%x, len: %d\n",
		 mtype, addr, len);

	for (pos = start; len > 0; pos += mem_aperture, offset = 0) {
		/*
		 * Move PCI-E Memory Window to our current transfer
		 * position.  Read it back to ensure that changes propagate
		 * before we attempt to use the new value.
		 */
		csio_wr_reg32(hw, pos | win_pf,
			PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET, win));
		csio_rd_reg32(hw,
			PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET, win));

		while (offset < mem_aperture && len > 0) {
			if (dir)
				*buf++ = csio_rd_reg32(hw, mem_base + offset);
			else
				csio_wr_reg32(hw, *buf++, mem_base + offset);

			offset += sizeof(__be32);
			len -= sizeof(__be32);
		}
	}
	return 0;
}
示例#26
0
    // allocte memory
    q->v = (T*) malloc((q->num_allocated)*sizeof(T));
    q->read_index = 0;

    // reset window
    WINDOW(_reset)(q);

    // return object
    return q;
}

// recreate window buffer object with new length
//  _q      : old window object
//  _n      : new window length
WINDOW() WINDOW(_recreate)(WINDOW() _q, unsigned int _n)
{
    // TODO: only create new window if old is too small

    if (_n == _q->len)
        return _q;

    // create new window
    WINDOW() w = WINDOW(_create)(_n);

    // copy old values
    T* r;
    WINDOW(_read)(_q, &r);
    //memmove(q->v, ...);
    unsigned int i;
    if (_n > _q->len) {
示例#27
0
文件: main.cpp 项目: FoamyPop/Arctic
int main(int argc, char* argv[])
{
	sf::RenderWindow WINDOW(sf::VideoMode(1280, 720, 32), "Arctic", sf::Style::Close);
	WINDOW.SetFramerateLimit(60);

	Levels* levels;
	levels->setLevels();
	sf::Clock clock;
	float time = clock.GetElapsedTime();
	state = Ingame;
	prevState = Menu;

	/* Main Menu Buttons */
	BUTTON play(440, 200, "PLAY");
	BUTTON options(440, 320, "OPTIONS");
	BUTTON quit(440, 440, "QUIT");

	/* Pause Buttons */
	BUTTON resume(440, 200, "RESUME");
	BUTTON pauseOptions(440, 320, "OPTIONS");
	BUTTON quitToMenu(440, 440, "QUIT TO MENU");	

	/* Strings */
	STRING str("Arctic - Sprite Testing", 5, 2, sf::Color(255, 255, 255));

	while(WINDOW.IsOpened())
	{
		sf::Event event;
		sf::Vector2i mouse(WINDOW.GetInput().GetMouseX(), WINDOW.GetInput().GetMouseY());
		time = clock.GetElapsedTime();

		while(WINDOW.GetEvent(event))
		{
			switch(event.Type)
			{
			case sf::Event::Closed:
				WINDOW.Close();
				break;
			case sf::Event::KeyPressed:
				if(event.Key.Code == sf::Key::Escape)
				{
					if(state == Menu)
					{					
						WINDOW.Close();		
					}
					else if(state == Ingame)
					{
						state = Paused;
						prevState = Ingame;
					}
					else if(state == Options)
					{
						state = prevState;
						prevState = Options;
					}
					else if(state == Paused)
					{
						state = prevState;
						prevState = Paused;
					}
				}
				if(event.Key.Code == sf::Key::Space)
				{
					for(int i = 0; i < ice.size(); i++)
					{
						if(ice[i]->state != Ice::IceState::Rock)
						{
							ice[i]->state = Ice::IceState::Reg;
						}
					}
				}
				break;
				case sf::Event::MouseButtonReleased:
				if(event.MouseButton.Button == sf::Mouse::Button::Left)
				{
					if(state == Menu)
					{
						if(play.contains(mouse))
						{
							state = Ingame;
						}
						else if(options.contains(mouse))
						{
							state = Options;
							prevState = Menu;
						}
						else if(quit.contains(mouse))
						{
							WINDOW.Close();
						}
					}
					else if(state == Paused)
					{
						if(resume.contains(mouse))
						{
							state = Ingame;
						}
						else if(pauseOptions.contains(mouse))
						{
							state = Options;
							prevState = Paused;
						}
						else if(quitToMenu.contains(mouse))
						{
							state = Menu;
							prevState = Paused;
						}
					}
				}
				break;
			}
		}
		WINDOW.Clear(sf::Color(80, 80, 80, 0));
		/* DRAWING CODE */
		if(state == Ingame)
		{
			/* Tiles */
			levels->draw(currentLevel, WINDOW);			

			/* HUD Elements */
			str.Draw(WINDOW);
		}
		else if(state == Menu)
		{
			play.Draw(WINDOW);
			options.Draw(WINDOW);
			quit.Draw(WINDOW);
			play.Update(mouse);
			options.Update(mouse);
			quit.Update(mouse);
		}
		else if(state == Options)
		{

		}
		else if(state == Paused)
		{
			resume.Draw(WINDOW);
			pauseOptions.Draw(WINDOW);
			quitToMenu.Draw(WINDOW);
			resume.Update(mouse);
			pauseOptions.Update(mouse);
			quitToMenu.Update(mouse);
		}

		/* END OF DRAWING */
		WINDOW.Display();
	}
	return EXIT_SUCCESS;
}
示例#28
0
// create spgram object
//  _nfft       : FFT size
//  _wtype      : window type, e.g. LIQUID_WINDOW_HAMMING
//  _window_len : window length
//  _delay      : delay between transforms, _delay > 0
SPGRAM() SPGRAM(_create)(unsigned int _nfft,
                         int          _wtype,
                         unsigned int _window_len,
                         unsigned int _delay)
{
    // validate input
    if (_nfft < 2) {
        fprintf(stderr,"error: spgram%s_create(), fft size must be at least 2\n", EXTENSION);
        exit(1);
    } else if (_window_len > _nfft) {
        fprintf(stderr,"error: spgram%s_create(), window size cannot exceed fft size\n", EXTENSION);
        exit(1);
    } else if (_window_len == 0) {
        fprintf(stderr,"error: spgram%s_create(), window size must be greater than zero\n", EXTENSION);
        exit(1);
    } else if (_wtype == LIQUID_WINDOW_KBD && _window_len % 2) {
        fprintf(stderr,"error: spgram%s_create(), KBD window length must be even\n", EXTENSION);
        exit(1);
    } else if (_delay == 0) {
        fprintf(stderr,"error: spgram%s_create(), delay must be greater than 0\n", EXTENSION);
        exit(1);
    }

    // allocate memory for main object
    SPGRAM() q = (SPGRAM()) malloc(sizeof(struct SPGRAM(_s)));

    // set input parameters
    q->nfft       = _nfft;
    q->wtype      = _wtype;
    q->window_len = _window_len;
    q->delay      = _delay;
    q->frequency  =  0;
    q->sample_rate= -1;

    // set object for full accumulation
    SPGRAM(_set_alpha)(q, -1.0f);

    // create FFT arrays, object
    q->buf_time = (TC*) malloc((q->nfft)*sizeof(TC));
    q->buf_freq = (TC*) malloc((q->nfft)*sizeof(TC));
    q->psd      = (T *) malloc((q->nfft)*sizeof(T ));
    q->fft      = FFT_CREATE_PLAN(q->nfft, q->buf_time, q->buf_freq, FFT_DIR_FORWARD, FFT_METHOD);

    // create buffer
    q->buffer = WINDOW(_create)(q->window_len);

    // create window
    q->w = (T*) malloc((q->window_len)*sizeof(T));
    unsigned int i;
    unsigned int n = q->window_len;
    float beta = 10.0f;
    float zeta =  3.0f;
    for (i=0; i<n; i++) {
        switch (q->wtype) {
        case LIQUID_WINDOW_HAMMING:         q->w[i] = hamming(i,n);         break;
        case LIQUID_WINDOW_HANN:            q->w[i] = hann(i,n);            break;
        case LIQUID_WINDOW_BLACKMANHARRIS:  q->w[i] = blackmanharris(i,n);  break;
        case LIQUID_WINDOW_BLACKMANHARRIS7: q->w[i] = blackmanharris7(i,n); break;
        case LIQUID_WINDOW_KAISER:          q->w[i] = kaiser(i,n,beta,0);   break;
        case LIQUID_WINDOW_FLATTOP:         q->w[i] = flattop(i,n);         break;
        case LIQUID_WINDOW_TRIANGULAR:      q->w[i] = triangular(i,n,n);    break;
        case LIQUID_WINDOW_RCOSTAPER:       q->w[i] = liquid_rcostaper_windowf(i,n/3,n); break;
        case LIQUID_WINDOW_KBD:             q->w[i] = liquid_kbd(i,n,zeta); break;
        default:
            fprintf(stderr,"error: spgram%s_create(), invalid window\n", EXTENSION);
            exit(1);
        }
    }

    // scale by window magnitude, FFT size
    float g = 0.0f;
    for (i=0; i<q->window_len; i++)
        g += q->w[i] * q->w[i];
    g = M_SQRT2 / ( sqrtf(g / q->window_len) * sqrtf((float)(q->nfft)) );

    // scale window and copy
    for (i=0; i<q->window_len; i++)
        q->w[i] = g * q->w[i];

    // reset the spgram object
    q->num_samples_total    = 0;
    q->num_transforms_total = 0;
    SPGRAM(_reset)(q);

    // return new object
    return q;
}
示例#29
0
QMFB() QMFB(_create)(unsigned int _h_len, float _beta, int _type)
{
    QMFB() q = (QMFB()) malloc(sizeof(struct QMFB(_s)));

    // compute filter length
    q->h_len = _h_len;
    q->beta = _beta;
    q->type = _type;

    float h_prim[20] = {
        0.1605476e+0,
        0.4156381e+0,
        0.4591917e+0,
        0.1487153e+0,
        -0.1642893e+0,
        -0.1245206e+0,
        0.8252419e-1,
        0.8875733e-1,
        -0.5080163e-1,
        -0.6084593e-1,
        0.3518087e-1,
        0.3989182e-1,
        -0.2561513e-1,
        -0.2440664e-1,
        0.1860065e-1,
        0.1354778e-1,
        -0.1308061e-1,
        -0.7449561e-2,
        0.1293440e-1,
        -0.4995356e-2
    };
    q->m = 5;

#if 0
    // use rrc filter
    design_rrc_filter(2,5,f->beta,0,h_prim);
    unsigned int j;
    for (j=0; j<20; j++)
        h_prim[j] *= 0.5f;
#endif

    //q->h_len = 4*(q->m);
    q->h_len = 20;
    q->h = (float*) malloc((q->h_len)*sizeof(float));

    //q->h_sub_len = 2*(q->m);
    q->h_sub_len = 20;
    q->h0 = (TC *) malloc((q->h_sub_len)*sizeof(TC));
    q->h1 = (TC *) malloc((q->h_sub_len)*sizeof(TC));

    // compute analysis/synthesis filters: paraconjugation of primitive
    // filter, also reverse direction for convolution
    unsigned int i, n;
    for (i=0; i<q->h_sub_len; i++) {
        // inverted filter coefficient index
        n = q->h_sub_len-i-1;

        if (q->type == LIQUID_QMFB_ANALYZER) {
            // analysis
            q->h0[n] =      h_prim[i];
            q->h1[n] = conj(h_prim[n]) * ((i%2)==0 ? 1.0f : -1.0f);
        } else if (q->type == LIQUID_QMFB_SYNTHESIZER) {
            // synthesis
            q->h0[n] = conj(h_prim[n]);
            q->h1[n] = conj(h_prim[i]) * ((n%2)==0 ? 1.0f : -1.0f);
        } else {
            fprintf(stderr,"error: qmfb_%s_create(), unknown type %d\n", EXTENSION_FULL, q->type);
            exit(1);
        }
    }

    q->w0 = WINDOW(_create)(q->h_sub_len);
    q->w1 = WINDOW(_create)(q->h_sub_len);
    WINDOW(_clear)(q->w0);
    WINDOW(_clear)(q->w1);
    return q;
}
示例#30
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;
}