void sc_kaiser_Sinc(double *x,int N,double *y) { for (register int i=0;i<N;i++) { y[i] = sinc(x[i])*kaiser(x[i],N/2,3); } }
// Design FIR doppler filter // _n : filter length // _fd : normalized doppler frequency (0 < _fd < 0.5) // _K : Rice fading factor (K >= 0) // _theta : LoS component angle of arrival // _h : output coefficient buffer void liquid_firdes_doppler(unsigned int _n, float _fd, float _K, float _theta, float * _h) { float t, J, r, w; float beta = 4; // kaiser window parameter unsigned int i; for (i=0; i<_n; i++) { // time sample t = (float)i - (float)(_n-1)/2; // Bessel J = 1.5*liquid_besselj0f(fabsf((float)(2*M_PI*_fd*t))); // Rice-K component r = 1.5*_K/(_K+1)*cosf(2*M_PI*_fd*t*cosf(_theta)); // Window w = kaiser(i, _n, beta, 0); // composite _h[i] = (J+r)*w; //printf("t=%f, J=%f, r=%f, w=%f\n", t, J, r, w); } }
// 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; }
// Generate polyphase coefficients for channeliser float *generatePolyphaseCoefficients(unsigned nchans, unsigned ntaps, FirWindow windowType) { unsigned n = nchans * ntaps; double* window = new double[n]; switch (windowType) { case HAMMING: { hamming(n, window); break; } case BLACKMAN: { blackman(n, window); break; } case GAUSSIAN: { double alpha = 3.5; gaussian(n, alpha, window); break; } case KAISER: { double beta = 9.0695; kaiser(n, beta, window); break; } default: { fprintf(stderr, "Invalid PFB window type. Exiting\n"); exit(-1); } } double* result = new double[n]; generateFirFilter(n - 1, 1.0 / nchans, window, result); delete[] window; float *coeff = (float *) malloc(nchans * ntaps * sizeof(float)); for(unsigned t = 0; t < ntaps; ++t) { for(unsigned c = 0; c < nchans; ++c) { unsigned index = t * nchans + c; coeff[index] = result[index] / nchans; if (c % 2 == 0) coeff[index] = result[index] / nchans; else coeff[index] = -result[index] / nchans; } } delete[] result; return coeff; }
void direct_calib(const long dims[5], complex float* sens, const long caldims[5], const complex float* data) { complex float* tmp = md_alloc(5, caldims, CFL_SIZE); assert(1 == caldims[4]); assert(1 == dims[4]); md_copy(5, caldims, tmp, data, CFL_SIZE); // apply Kaiser-Bessel Window beta=4 for (int z = 0; z < caldims[2]; z++) for (int y = 0; y < caldims[1]; y++) for (int x = 0; x < caldims[0]; x++) for (int c = 0; c < caldims[3]; c++) tmp[((c * caldims[2] + z) * caldims[1] + y) * caldims[0] + x] *= kaiser(4., caldims[2], z) * kaiser(4., caldims[1], y) * kaiser(4., caldims[0], x); md_resize_center(5, dims, sens, caldims, tmp, CFL_SIZE); ifftc(5, dims, 7, sens, sens); long dims1[5]; md_select_dims(5, ~MD_BIT(COIL_DIM), dims1, dims); complex float* img = md_alloc(5, dims1, CFL_SIZE); md_zrss(5, dims, COIL_FLAG, img, sens); #if 1 long T = md_calc_size(5, dims1); for (int i = 0; i < T; i++) for (int j = 0; j < dims[COIL_DIM]; j++) sens[j * T + i] *= (cabs(img[i]) == 0.) ? 0. : (1. / cabs(img[i])); #endif md_free(img); }
/* * Returns a pointer to an array of length len representing one half of a * Kaiser sequence of size (len - 1) * 2 with shape alpha. */ double * kaiser_table(double alpha, int len) { double *ret; int i; int M = (len - 1) * 2; if ((ret = (double *)calloc(len, sizeof(double))) == NULL) return NULL; for (i = 0; i < len; i++) ret[i] = kaiser(alpha, M, len - i - 1); return ret; }
static double * make_low_pass_filter(double omega_pass, double omega_stop, double error, int *length_p) { struct filter_param p = filter(omega_pass, omega_stop, error); int length; int n; double *lpf; length = p.M + 1; lpf = calloc (length, sizeof(double)); for (n = 0; n < length; n++) lpf[n] = lowpass(n, p.M, omega_pass) * kaiser(n, p.M, p.beta); *length_p = length; return lpf; }
static Resample_Real kaiser_filter(Resample_Real t) { if (t < 0.0f) t = -t; if (t < KAISER_SUPPORT) { // db atten const Resample_Real att = 40.0f; const Resample_Real alpha = (Resample_Real)(exp(log((double)0.58417 * (att - 20.96)) * 0.4) + 0.07886 * (att - 20.96)); //const Resample_Real alpha = KAISER_ALPHA; return (Resample_Real)clean(sinc(t) * kaiser(alpha, KAISER_SUPPORT, t)); } return 0.0f; }
static float kaiser_filter(float t) { if (t < 0.0f) t = -t; if (t < KAISER_SUPPORT) { // db atten const float att = 40.0f; const float alpha = (float)(exp(log((double)0.58417 * (att - 20.96)) * 0.4) + 0.07886 * (att - 20.96)); //const float alpha = KAISER_ALPHA; return (float)clean(sinc(t) * kaiser(alpha, KAISER_SUPPORT, t)); } return 0.0f; }
// Kaiser-Bessel derived window (full window function) void liquid_kbd_window(unsigned int _n, float _beta, float * _w) { unsigned int i; // TODO add reference // validate input if (_n == 0) { fprintf(stderr,"error: liquid_kbd_window(), window length must be greater than zero\n"); exit(1); } else if ( _n % 2 ) { fprintf(stderr,"error: liquid_kbd_window(), window length must be odd\n"); exit(1); } else if ( _beta < 0.0f ) { fprintf(stderr,"error: liquid_kbd_window(), _beta must be positive\n"); exit(1); } // compute half length unsigned int M = _n / 2; // generate regular Kaiser window, length M+1 float w_kaiser[M+1]; for (i=0; i<=M; i++) w_kaiser[i] = kaiser(i,M+1,_beta,0.0f); // compute sum(wk[]) float w_sum = 0.0f; for (i=0; i<=M; i++) w_sum += w_kaiser[i]; // accumulate window float w_acc = 0.0f; for (i=0; i<M; i++) { w_acc += w_kaiser[i]; _w[i] = sqrtf(w_acc / w_sum); } // window has even symmetry; flip around index M for (i=0; i<M; i++) _w[_n-i-1] = _w[i]; }
double *xtract_init_window(const int N, const int type) { double *window; window = malloc(N * sizeof(double)); switch (type) { case XTRACT_GAUSS: gauss(window, N, 0.4); break; case XTRACT_HAMMING: hamming(window, N); break; case XTRACT_HANN: hann(window, N); break; case XTRACT_BARTLETT: bartlett(window, N); break; case XTRACT_TRIANGULAR: triangular(window, N); break; case XTRACT_BARTLETT_HANN: bartlett_hann(window, N); break; case XTRACT_BLACKMAN: blackman(window, N); break; case XTRACT_KAISER: kaiser(window, N, 3 * PI); break; case XTRACT_BLACKMAN_HARRIS: blackman_harris(window, N); break; default: hann(window, N); break; } return window; }
double window(int type,int n,int i,double beta) { /* 函数名称: * 窗口函数 * */ int k; double pi,w; pi=4.0*atan(1.0); w=1.0; switch(type) { case 1: w=1.0;break; case 2: k=(n-2)/10; if(i<=k) w=0.5*(1.0-cos(i*pi/(k+1))); if(i>n-k-2) w=0.5*(1.0-cos((n-i-1)*pi/(k+1))); break; case 3: w=1.0-fabs(1.0-2*i/(n-1.0)); break; case 4: w=0.5*(1.0-cos(2*pi*i/(n-1))); break; case 5: w=0.54-0.46*cos(2*pi*i/(n-1)); break; case 6: w=0.42-0.5*cos(2*i*pi/(n-1))+0.08*cos(4*i*pi/(n-1)); break; case 7: w=kaiser(i,n,beta); break; } return w; }
/* * fir coef in g, cuttoff frequency in fc */ static void designfir(float *g , float fc) { int i; float xi, omega, att, beta ; float w[ORDER2]; for (i =0; i < ORDER2 ; i++) { xi = (float) i + 0.5; omega = PI * xi; g[i] = sin( (double) omega * fc) / omega; } att = 40.; /* attenuation in db */ beta = (float) exp(log((double)0.58417 * (att - 20.96)) * 0.4) + 0.07886 * (att - 20.96); kaiser( w, ORDER2, beta); /* Matrix product */ for (i =0; i < ORDER2 ; i++) g[i] = g[i] * w[i]; }
// Design FIR using kaiser window // _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 // _h : output coefficient buffer, [size: _n x 1] void liquid_firdes_kaiser(unsigned int _n, float _fc, float _As, float _mu, float *_h) { // validate inputs if (_mu < -0.5f || _mu > 0.5f) { fprintf(stderr,"error: liquid_firdes_kaiser(), _mu (%12.4e) out of range [-0.5,0.5]\n", _mu); exit(1); } else if (_fc < 0.0f || _fc > 0.5f) { fprintf(stderr,"error: liquid_firdes_kaiser(), cutoff frequency (%12.4e) out of range (0, 0.5)\n", _fc); exit(1); } else if (_n == 0) { fprintf(stderr,"error: liquid_firdes_kaiser(), filter length must be greater than zero\n"); exit(1); } // choose kaiser beta parameter (approximate) float beta = kaiser_beta_As(_As); float t, h1, h2; unsigned int i; for (i=0; i<_n; i++) { t = (float)i - (float)(_n-1)/2 + _mu; // sinc prototype h1 = sincf(2.0f*_fc*t); // kaiser window h2 = kaiser(i,_n,beta,_mu); //printf("t = %f, h1 = %f, h2 = %f\n", t, h1, h2); // composite _h[i] = h1*h2; } }
// Kaiser-Bessel derived window float liquid_kbd(unsigned int _n, unsigned int _N, float _beta) { // TODO add reference // validate input if (_n >= _N) { fprintf(stderr,"error: liquid_kbd(), index exceeds maximum\n"); exit(1); } else if (_N == 0) { fprintf(stderr,"error: liquid_kbd(), window length must be greater than zero\n"); exit(1); } else if ( _N % 2 ) { fprintf(stderr,"error: liquid_kbd(), window length must be odd\n"); exit(1); } unsigned int M = _N / 2; if (_n >= M) return liquid_kbd(_N-_n-1,_N,_beta); float w0 = 0.0f; float w1 = 0.0f; float w; unsigned int i; for (i=0; i<=M; i++) { // compute Kaiser window w = kaiser(i,M+1,_beta,0.0f); // accumulate window sums w1 += w; if (i <= _n) w0 += w; } //printf("%12.8f / %12.8f = %12.8f\n", w0, w1, w0/w1); return sqrtf(w0 / w1); }
// 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; }
int main(int argc, char*argv[]) { // options float r=1.2f; // resampling rate (output/input) float As=80.0f; // resampling filter stop-band attenuation [dB] unsigned int nx=400; // number of input samples float fc=0.40f; // complex sinusoid frequency int dopt; while ((dopt = getopt(argc,argv,"hr:s:n:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'r': r = atof(optarg); break; case 's': As = atof(optarg); break; case 'n': nx = atoi(optarg); break; default: exit(1); } } // validate input if (nx == 0) { fprintf(stderr,"error: %s, number of input samples must be greater than zero\n", argv[0]); exit(1); } else if (r <= 0.0f) { fprintf(stderr,"error: %s, resampling rate must be greater than zero\n", argv[0]); exit(1); } else if ( fabsf(log2f(r)) > 10 ) { fprintf(stderr,"error: %s, resampling rate unreasonable\n", argv[0]); exit(1); } unsigned int i; // derived values 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 unsigned int window_len = (3*nx)/4; for (i=0; i<nx; i++) x[i] = i < window_len ? cexpf(_Complex_I*2*M_PI*fc*i) * kaiser(i,window_len,10.0f,0.0f) : 0.0f; // create multi-stage arbitrary resampler object msresamp_crcf q = msresamp_crcf_create(r,As); msresamp_crcf_print(q); float delay = msresamp_crcf_get_delay(q); // run resampler 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 // // open/initialize 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"); fprintf(fid,"r=%12.8f;\n", r); fprintf(fid,"delay = %f;\n", delay); // save input series fprintf(fid,"nx = %u;\n", nx); fprintf(fid,"x = zeros(1,nx);\n"); for (i=0; i<nx; i++) fprintf(fid,"x(%6u) = %12.4e + j*%12.4e;\n", i+1, crealf(x[i]), cimagf(x[i])); // save output series fprintf(fid,"ny = %u;\n", ny); fprintf(fid,"y = zeros(1,ny);\n"); for (i=0; i<ny; i++) fprintf(fid,"y(%6u) = %12.4e + j*%12.4e;\n", i+1, crealf(y[i]), cimagf(y[i])); // output results fprintf(fid,"\n\n"); fprintf(fid,"%% plot frequency-domain result\n"); fprintf(fid,"nfft=1024;\n"); fprintf(fid,"%% estimate PSD, normalize by array length\n"); fprintf(fid,"X=20*log10(abs(fftshift(fft(x,nfft)/length(x))));\n"); fprintf(fid,"Y=20*log10(abs(fftshift(fft(y,nfft)/length(y))));\n"); fprintf(fid,"G = max(X);\n"); fprintf(fid,"X = X - G;\n"); fprintf(fid,"Y = Y - G;\n"); fprintf(fid,"f=[0:(nfft-1)]/nfft-0.5;\n"); fprintf(fid,"figure;\n"); fprintf(fid,"if r>1, fx = f/r; fy = f; %% interpolated\n"); fprintf(fid,"else, fx = f; fy = f*r; %% decimated\n"); fprintf(fid,"end;\n"); fprintf(fid,"plot(fx,X,'Color',[0.5 0.5 0.5],fy,Y,'LineWidth',2);\n"); fprintf(fid,"grid on;\n\n"); fprintf(fid,"xlabel('normalized frequency');\n"); fprintf(fid,"ylabel('PSD [dB]');\n"); fprintf(fid,"legend('original','resampled','location','northeast');"); fprintf(fid,"axis([-0.5 0.5 -120 10]);\n"); fprintf(fid,"\n\n"); fprintf(fid,"%% plot time-domain result\n"); fprintf(fid,"tx=[0:(length(x)-1)];\n"); fprintf(fid,"ty=[0:(length(y)-1)]/r-delay;\n"); fprintf(fid,"figure;\n"); fprintf(fid,"subplot(2,1,1);\n"); fprintf(fid," plot(tx,real(x),'-s','Color',[0.5 0.5 0.5],'MarkerSize',1,...\n"); fprintf(fid," ty,real(y),'-s','Color',[0.5 0 0], 'MarkerSize',1);\n"); fprintf(fid," legend('original','resampled','location','northeast');"); fprintf(fid," xlabel('time');\n"); fprintf(fid," ylabel('real');\n"); fprintf(fid," grid on;\n\n"); fprintf(fid,"subplot(2,1,2);\n"); fprintf(fid," plot(tx,imag(x),'-s','Color',[0.5 0.5 0.5],'MarkerSize',1,...\n"); fprintf(fid," ty,imag(y),'-s','Color',[0 0.5 0], 'MarkerSize',1);\n"); fprintf(fid," legend('original','resampled','location','northeast');"); fprintf(fid," xlabel('time');\n"); fprintf(fid," ylabel('imag');\n"); fprintf(fid," grid on;\n\n"); fclose(fid); printf("results written to %s\n",OUTPUT_FILENAME); printf("done.\n"); return 0; }
int main(int argc, char*argv[]) { unsigned int m=5; // filter semi-length float fc=0.037f; // input tone frequency unsigned int num_samples = 64; // number of output samples float As=60.0f; // stop-band attenuation [dB] int dopt; while ((dopt = getopt(argc,argv,"hn:m:s:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'n': num_samples = atoi(optarg); break; case 'm': m = atoi(optarg); break; case 's': As = atof(optarg); break; default: exit(1); } } unsigned int i; // allocate arrays float complex x[2*num_samples]; // input array float complex y[ num_samples]; // output array // generate input unsigned int w_len = 2*num_samples - 4*m; // window length float beta = 8.0f; // kaiser window factor float w_sum = 0.0f; // gain due to window for (i=0; i<2*num_samples; i++) { // compute windowing function and keep track of gain float w = (i < w_len ? kaiser(i,w_len,beta,0) : 0.0f); w_sum += w; // compute windowed complex sinusoid x[i] = w * cexpf(_Complex_I*2*M_PI*fc*i); } // create/print the half-band resampler resamp2_crcf q = resamp2_crcf_create(m,0,As); resamp2_crcf_print(q); unsigned int delay = resamp2_crcf_get_delay(q); // run the resampler for (i=0; i<num_samples; i++) { // execute the decimator resamp2_crcf_decim_execute(q, &x[2*i], &y[i]); // print results to screen printf("y(%3u) = %8.4f + j*%8.4f;\n", i+1, crealf(y[i]), cimagf(y[i])); } // destroy half-band resampler resamp2_crcf_destroy(q); // // export results // FILE*fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s : auto-generated file\n", OUTPUT_FILENAME); fprintf(fid,"clear all;\nclose all;\n\n"); fprintf(fid,"h_len=%u;\n", 4*m+1); fprintf(fid,"num_samples=%u;\n", num_samples); fprintf(fid,"delay =%u;\n", delay); fprintf(fid,"w_sum =%12.8f;\n", w_sum); for (i=0; i<num_samples; i++) { // save results to output file fprintf(fid,"x(%3u) = %12.8f + j*%12.8f;\n", 2*i+1, crealf(x[2*i+0]), cimagf(x[2*i+0])); fprintf(fid,"x(%3u) = %12.8f + j*%12.8f;\n", 2*i+2, crealf(x[2*i+1]), cimagf(x[2*i+1])); fprintf(fid,"y(%3u) = %12.8f + j*%12.8f;\n", i+1, 0.5f*crealf(y[i ]), 0.5f*cimagf(y[i ])); } // plot time series fprintf(fid,"tx = 0:(2*num_samples-1);\n"); fprintf(fid,"ty = [0:( num_samples-1)]*2 - delay;\n"); fprintf(fid,"figure;\n"); fprintf(fid,"subplot(2,1,1);\n"); fprintf(fid," plot(tx,real(x),'-s','Color',[0.5 0.5 0.5],'MarkerSize',1,...\n"); fprintf(fid," ty,real(y),'-s','Color',[0.5 0.0 0.0],'MarkerSize',1);\n"); fprintf(fid," legend('original','decimated','location','northeast');"); fprintf(fid," axis([-delay 2*num_samples -1.2 1.2]);\n"); fprintf(fid," grid on;\n"); fprintf(fid," xlabel('Normalized Time [t/T_s]');\n"); fprintf(fid," ylabel('real');\n"); fprintf(fid,"subplot(2,1,2);\n"); fprintf(fid," plot(tx,imag(x),'-s','Color',[0.5 0.5 0.5],'MarkerSize',1,...\n"); fprintf(fid," ty,imag(y),'-s','Color',[0.0 0.5 0.0],'MarkerSize',1);\n"); fprintf(fid," legend('original','decimated','location','northeast');"); fprintf(fid," axis([-delay 2*num_samples -1.2 1.2]);\n"); fprintf(fid," grid on;\n"); fprintf(fid," xlabel('Normalized Time [t/T_s]');\n"); fprintf(fid," ylabel('imag');\n"); // plot spectrum fprintf(fid,"nfft=512;\n"); fprintf(fid,"g = 1/w_sum;\n"); fprintf(fid,"X=20*log10(abs(fftshift(fft( x*g,nfft))));\n"); fprintf(fid,"Y=20*log10(abs(fftshift(fft(2*y*g,nfft))));\n"); fprintf(fid,"f=[0:(nfft-1)]/nfft-0.5;\n"); fprintf(fid,"figure;\n"); fprintf(fid,"plot(f, X,'LineWidth',1, 'Color',[0.5 0.5 0.5],...\n"); fprintf(fid," f/2,Y,'LineWidth',1.5,'Color',[0.1 0.3 0.5]);\n"); fprintf(fid,"grid on;\n"); fprintf(fid,"xlabel('Normalized Frequency [f/F_s]');\n"); fprintf(fid,"ylabel('PSD [dB]');\n"); fprintf(fid,"legend('original','decimated','location','northeast');"); fprintf(fid,"axis([-0.5 0.5 -100 10]);\n"); fclose(fid); printf("results written to %s\n", OUTPUT_FILENAME); printf("done.\n"); return 0; }
/* Design FIR filter using the Window method n filter length must be odd for HP and BS filters w buffer for the filter taps (must be n long) fc cutoff frequencies (1 for LP and HP, 2 for BP and BS) 0 < fc < 1 where 1 <=> Fs/2 flags window and filter type as defined in filter.h variables are ored together: i.e. LP|HAMMING will give a low pass filter designed using a hamming window opt beta constant used only when designing using kaiser windows returns 0 if OK, -1 if fail */ TfirFilter::_ftype_t* TfirFilter::design_fir(unsigned int *n, _ftype_t* fc, int type, int window, _ftype_t opt) { unsigned int o = *n & 1; // Indicator for odd filter length unsigned int end = ((*n + 1) >> 1) - o; // Loop end unsigned int i; // Loop index _ftype_t k1 = 2 * _ftype_t(M_PI); // 2*pi*fc1 _ftype_t k2 = 0.5f * (_ftype_t)(1 - o);// Constant used if the filter has even length _ftype_t k3; // 2*pi*fc2 Constant used in BP and BS design _ftype_t g = 0.0f; // Gain _ftype_t t1,t2,t3; // Temporary variables _ftype_t fc1,fc2; // Cutoff frequencies // Sanity check if(*n==0) return NULL; fc[0]=limit(fc[0],_ftype_t(0.001),_ftype_t(1)); if (!o && (type==TfirSettings::BANDSTOP || type==TfirSettings::HIGHPASS)) (*n)++; _ftype_t *w=(_ftype_t*)aligned_calloc(sizeof(_ftype_t),*n); // Get window coefficients switch(window){ case(TfirSettings::WINDOW_BOX): boxcar(*n,w); break; case(TfirSettings::WINDOW_TRIANGLE): triang(*n,w); break; case(TfirSettings::WINDOW_HAMMING): hamming(*n,w); break; case(TfirSettings::WINDOW_HANNING): hanning(*n,w); break; case(TfirSettings::WINDOW_BLACKMAN): blackman(*n,w); break; case(TfirSettings::WINDOW_FLATTOP): flattop(*n,w); break; case(TfirSettings::WINDOW_KAISER): kaiser(*n,w,opt); break; default: { delete []w; return NULL; } } if(type==TfirSettings::LOWPASS || type==TfirSettings::HIGHPASS){ fc1=*fc; // Cutoff frequency must be < 0.5 where 0.5 <=> Fs/2 fc1 = ((fc1 <= 1.0) && (fc1 > 0.0)) ? fc1/2 : 0.25f; k1 *= fc1; if(type==TfirSettings::LOWPASS){ // Low pass filter // If the filter length is odd, there is one point which is exactly // in the middle. The value at this point is 2*fCutoff*sin(x)/x, // where x is zero. To make sure nothing strange happens, we set this // value separately. if (o){ w[end] = fc1 * w[end] * 2.0f; g=w[end]; } // Create filter for (i=0 ; i<end ; i++){ t1 = (_ftype_t)(i+1) - k2; w[end-i-1] = w[*n-end+i] = _ftype_t(w[end-i-1] * sin(k1 * t1)/(M_PI * t1)); // Sinc g += 2*w[end-i-1]; // Total gain in filter } } else{ // High pass filter //if (!o) // High pass filters must have odd length // return -1; w[end] = _ftype_t(1.0 - (fc1 * w[end] * 2.0)); g= w[end]; // Create filter for (i=0 ; i<end ; i++){ t1 = (_ftype_t)(i+1); w[end-i-1] = w[*n-end+i] = _ftype_t(-1 * w[end-i-1] * sin(k1 * t1)/(M_PI * t1)); // Sinc g += ((i&1) ? (2*w[end-i-1]) : (-2*w[end-i-1])); // Total gain in filter } } } if(type==TfirSettings::BANDPASS || type==TfirSettings::BANDSTOP){ fc1=fc[0]; fc2=limit(fc[1],_ftype_t(0.001),_ftype_t(1)); // Cutoff frequencies must be < 1.0 where 1.0 <=> Fs/2 fc1 = ((fc1 <= 1.0) && (fc1 > 0.0)) ? fc1/2 : 0.25f; fc2 = ((fc2 <= 1.0) && (fc2 > 0.0)) ? fc2/2 : 0.25f; k3 = k1 * fc2; // 2*pi*fc2 k1 *= fc1; // 2*pi*fc1 if(type==TfirSettings::BANDPASS){ // Band pass // Calculate center tap if (o){ g=w[end]*(fc1+fc2); w[end] = (fc2 - fc1) * w[end] * 2.0f; } // Create filter for (i=0 ; i<end ; i++){ t1 = (_ftype_t)(i+1) - k2; t2 = _ftype_t(sin(k3 * t1)/(M_PI * t1)); // Sinc fc2 t3 = _ftype_t(sin(k1 * t1)/(M_PI * t1)); // Sinc fc1 g += w[end-i-1] * (t3 + t2); // Total gain in filter w[end-i-1] = w[*n-end+i] = w[end-i-1] * (t2 - t3); } } else{ // Band stop //if (!o) // Band stop filters must have odd length // return -1; w[end] = _ftype_t(1.0 - (fc2 - fc1) * w[end] * 2.0); g= w[end]; // Create filter for (i=0 ; i<end ; i++){ t1 = (_ftype_t)(i+1); t2 = _ftype_t(sin(k1 * t1)/(M_PI * t1)); // Sinc fc1 t3 = _ftype_t(sin(k3 * t1)/(M_PI * t1)); // Sinc fc2 w[end-i-1] = w[*n-end+i] = w[end-i-1] * (t2 - t3); g += 2*w[end-i-1]; // Total gain in filter } } } // Normalize gain g=1/g; for (i=0; i<*n; i++) w[i] *= g; return w; }
static int srconv(CSOUND *csound, int argc, char **argv) { MYFLT *input, /* pointer to start of input buffer */ *output, /* pointer to start of output buffer */ *nextIn, /* pointer to next empty word in input */ *nextOut, /* pointer to next empty word in output */ *fxval = 0, /* pointer to start of time-array for time-vary function */ *fyval = 0, /* pointer to start of P-scale-array for time-vary func */ *i0, /* pointer */ *i1; /* pointer */ float *window, /* pointer to center of analysis window */ *wj, /* pointer to window */ *wj1; /* pointer to window */ int M = 2401, /* length of window impulse response */ N = 120, /* length of sinc period */ L = 120, /* internal sample rate is L*Rin */ m, /* current input sample in buffer */ o, /* current input at L*Rin mod L */ del, /* increment */ WinLen, /* half-length of window at L*Rin */ wLen, /* half-length of window at Rin */ jMin, /* initial offset in window */ mMax; /* maximum valid m */ long n, /* current input sample */ nMax = 2000000000; /* last input sample (unless EOF) */ MYFLT beta = FL(6.8), /* parameter for Kaiser window */ sum, /* scale factor for renormalizing windows */ fdel, /* float del */ idel, /* float del */ fo, /* float o */ of, /* fractional o */ fL = (MYFLT) L, /* float L */ iw, /* interpolated window */ tvx0 = 0, /* current x value of time-var function */ tvx1 = 0, /* next x value of time-var function */ tvdx, /* tvx1 - tvx0 */ tvy0 = 0, /* current y value of time-var function */ tvy1 = 0, /* next y value of time-var function */ tvdy, /* tvy1 - tvy0 */ tvslope = 0, /* tvdy / tvdx */ time, /* n / Rin */ invRin, /* 1. / Rin */ P = FL(0.0), /* Rin / Rout */ Rin = FL(0.0), /* input sampling rate */ Rout = FL(0.0); /* output sample rate */ int i,k, /* index variables */ nread, /* number of bytes read */ tvflg = 0, /* flag for time-varying time-scaling */ tvnxt = 0, /* counter for stepping thru time-var func */ tvlen, /* length of time-varying function */ Chans = 1, /* number of channels */ chan, /* current channel */ Q = 2; /* quality factor */ FILE *tvfp = NULL; /* time-vary function file */ SOUNDIN *p; int channel = ALLCHNLS; MYFLT beg_time = FL(0.0), input_dur = FL(0.0), sr = FL(0.0); char *infile = NULL, *bfile = NULL; SNDFILE *inf = NULL; char c, *s; const char *envoutyp; char outformch = 's'; unsigned outbufsiz = 0U; SNDFILE *outfd = NULL; OPARMS O; int block = 0; char err_msg[256]; O.outformat = AE_SHORT; /* csound->e0dbfs = csound->dbfs_to_float = FL(1.0);*/ if ((envoutyp = csound->GetEnv(csound, "SFOUTYP")) != NULL) { if (strcmp(envoutyp, "AIFF") == 0) O.filetyp = TYP_AIFF; else if (strcmp(envoutyp, "WAV") == 0) O.filetyp = TYP_WAV; else if (strcmp(envoutyp, "IRCAM") == 0) O.filetyp = TYP_IRCAM; else { snprintf(err_msg, 256, Str("%s not a recognized SFOUTYP env setting"), envoutyp); dieu(csound, err_msg); return -1; } } /* call getopt to interpret commandline */ ++argv; while (--argc > 0) { s = *argv++; if (*s++ == '-') { /* read all flags: */ while ((c = *s++) != '\0') { switch (c) { case 'o': FIND(Str("no outfilename")) O.outfilename = s; /* soundout name */ for ( ; *s != '\0'; s++) ; if (strcmp(O.outfilename, "stdin") == 0) { csound->ErrorMsg(csound, Str("-o cannot be stdin")); return -1; } #if defined WIN32 if (strcmp(O.outfilename, "stdout") == 0) { csound->ErrorMsg(csound, Str("stdout audio not supported")); return -1; } #endif break; case 'A': O.filetyp = TYP_AIFF; /* AIFF output request*/ break; case 'J': O.filetyp = TYP_IRCAM; /* IRCAM output request */ break; case 'W': O.filetyp = TYP_WAV; /* WAV output request */ break; case 'h': O.filetyp = TYP_RAW; /* skip sfheader */ break; case 'c': case '8': case 'a': case 'u': case 's': case 'l': case '3': case 'f': outformch = set_output_format(csound, c, outformch, &O); break; case 'R': O.rewrt_hdr = 1; break; case 'H': if (isdigit(*s)) { int n; sscanf(s, "%d%n", &O.heartbeat, &n); s += n; } else O.heartbeat = 1; break; case 'N': O.ringbell = 1; /* notify on completion */ break; case 'Q': FIND(Str("No Q argument")) sscanf(s,"%d", &Q); while (*++s); break; case 'P': FIND(Str("No P argument")) #if defined(USE_DOUBLE) csound->sscanf(s,"%lf", &P); #else csound->sscanf(s,"%f", &P); #endif while (*++s); break; case 'r': FIND(Str("No r argument")) #if defined(USE_DOUBLE) csound->sscanf(s,"%lf", &Rout); #else csound->sscanf(s,"%f", &Rout); #endif while (*++s); break; case 'i': FIND(Str("No break file")) tvflg = 1; bfile = s; while ((*s++)) {}; s--; break; default: csound->Message(csound, Str("Looking at %c\n"), c); usage(csound); /* this exits with error */ return -1; } } } else if (infile == NULL) { infile = --s; csound->Message(csound, Str("Infile set to %s\n"), infile); } else { csound->Message(csound, Str("End with %s\n"), s); usage(csound); return -1; } } if (infile == NULL) { csound->Message(csound, Str("No input given\n")); usage(csound); return -1; } if ((inf = csound->SAsndgetset(csound, infile, &p, &beg_time, &input_dur, &sr, channel)) == NULL) { csound->ErrorMsg(csound, Str("error while opening %s"), infile); return -1; } if (Rin == FL(0.0)) Rin = (MYFLT)p->sr; if (Chans == 0) Chans = (int) p->nchanls; if (Chans == 0) Chans = 1; if ((P != FL(0.0)) && (Rout != FL(0.0))) { strncpy(err_msg, Str("srconv: cannot specify both -r and -P"), 256); goto err_rtn_msg; } if (P != FL(0.0)) Rout = Rin / P; else if (Rout == FL(0.0)) Rout = Rin; if (tvflg) { P = FL(0.0); /* will be reset to max in time-vary function */ if ((tvfp = fopen(bfile, "r")) == NULL) { strncpy(err_msg, Str("srconv: cannot open time-vary function file"), 256); goto err_rtn_msg; } /* register file to be closed by csoundReset() */ (void) csound->CreateFileHandle(csound, &tvfp, CSFILE_STD, bfile); if (UNLIKELY(fscanf(tvfp, "%d", &tvlen) != 1)) csound->Message(csound, Str("Read failure\n")); if(tvlen <= 0) { strncpy(err_msg, Str("srconv: tvlen <= 0 "), 256); goto err_rtn_msg; } fxval = (MYFLT*) csound->Malloc(csound, tvlen * sizeof(MYFLT)); fyval = (MYFLT*) csound->Malloc(csound, tvlen * sizeof(MYFLT)); i0 = fxval; i1 = fyval; for (i = 0; i < tvlen; i++, i0++, i1++) { #ifdef USE_DOUBLE if ((fscanf(tvfp, "%lf %lf", i0, i1)) != 2) #else if ((fscanf(tvfp, "%f %f", i0, i1)) != 2) #endif { strncpy(err_msg, Str("srconv: too few x-y pairs " "in time-vary function file"), 256); goto err_rtn_msg; } if (*i1 > P) P = *i1; } Rout = Rin / P; /* this is min Rout */ tvx0 = fxval[0]; tvx1 = fxval[1]; tvy0 = fyval[0]; tvy1 = fyval[1]; tvdx = tvx1 - tvx0; if (tvx0 != FL(0.0)) { strncpy(err_msg, Str("srconv: first x value " "in time-vary function must be 0"), 256); goto err_rtn_msg; } if (tvy0 <= FL(0.0)) { strncpy(err_msg, Str("srconv: invalid initial y value " "in time-vary function"),256); goto err_rtn_msg; } if (tvdx <= FL(0.0)) { strncpy(err_msg, Str("srconv: invalid x values in time-vary function"), 256); goto err_rtn_msg; } tvdy = tvy1 - tvy0; tvslope = tvdy / tvdx; tvnxt = 1; } /* This is not right ********* */ if (P != FL(0.0)) { csound->SetUtilSr(csound,Rin); } if (P == FL(0.0)) { csound->SetUtilSr(csound,Rout); } if (O.outformat == 0) O.outformat = AE_SHORT;//p->format; O.sfsampsize = csound->sfsampsize(FORMAT2SF(O.outformat)); if (O.filetyp == TYP_RAW) { O.sfheader = 0; O.rewrt_hdr = 0; } else O.sfheader = 1; #ifdef NeXT if (O.outfilename == NULL && !O.filetyp) O.outfilename = "test.snd"; else if (O.outfilename == NULL) O.outfilename = "test"; #else if (O.outfilename == NULL) { if (O.filetyp == TYP_WAV) O.outfilename = "test.wav"; else if (O.filetyp == TYP_AIFF) O.outfilename = "test.aif"; else O.outfilename = "test"; } #endif { SF_INFO sfinfo; char *name; memset(&sfinfo, 0, sizeof(SF_INFO)); sfinfo.samplerate = (int) ((double) Rout + 0.5); sfinfo.channels = (int) p->nchanls; //printf("filetyp=%x outformat=%x\n", O.filetyp, O.outformat); sfinfo.format = TYPE2SF(O.filetyp) | FORMAT2SF(O.outformat); if (strcmp(O.outfilename, "stdout") != 0) { name = csound->FindOutputFile(csound, O.outfilename, "SFDIR"); if (name == NULL) { snprintf(err_msg, 256, Str("cannot open %s."), O.outfilename); goto err_rtn_msg; } outfd = sf_open(name, SFM_WRITE, &sfinfo); if (outfd != NULL) csound->NotifyFileOpened(csound, name, csound->type2csfiletype(O.filetyp, O.outformat), 1, 0); else { snprintf(err_msg, 256, Str("libsndfile error: %s\n"), sf_strerror(NULL)); goto err_rtn_msg; } csound->Free(csound, name); } else outfd = sf_open_fd(1, SFM_WRITE, &sfinfo, 1); if (outfd == NULL) { snprintf(err_msg, 256, Str("cannot open %s."), O.outfilename); goto err_rtn_msg; } /* register file to be closed by csoundReset() */ (void) csound->CreateFileHandle(csound, &outfd, CSFILE_SND_W, O.outfilename); sf_command(outfd, SFC_SET_CLIPPING, NULL, SF_TRUE); } csound->SetUtilSr(csound, (MYFLT)p->sr); csound->SetUtilNchnls(csound, Chans = p->nchanls); outbufsiz = OBUF * O.sfsampsize; /* calc outbuf size */ csound->Message(csound, Str("writing %d-byte blks of %s to %s"), outbufsiz, csound->getstrformat(O.outformat), O.outfilename); csound->Message(csound, " (%s)\n", csound->type2string(O.filetyp)); /* this program performs arbitrary sample-rate conversion with high fidelity. the method is to step through the input at the desired sampling increment, and to compute the output points as appropriately weighted averages of the surrounding input points. there are two cases to consider: 1) sample rates are in a small-integer ratio - weights are obtained from table, 2) sample rates are in a large-integer ratio - weights are linearly interpolated from table. */ /* calculate increment: if decimating, then window is impulse response of low- pass filter with cutoff frequency at half of Rout; if interpolating, then window is ipulse response of lowpass filter with cutoff frequency at half of Rin. */ fdel = ((MYFLT) (L * Rin) / Rout); del = (int) ((double) fdel + 0.5); idel = (MYFLT) del; if (del > L) N = del; if ((Q >= 1) && (Q <= 8)) M = Q * N * 10 + 1; if (tvflg) fdel = tvy0 * L; invRin = FL(1.0) / Rin; /* make window: the window is the product of a kaiser and a sin(x)/x */ window = (float*) csound->Calloc(csound, (size_t) (M + 2) * sizeof(float)); WinLen = (M-1)/2; window += WinLen; wLen = (M/2 - L) / L; kaiser(M, window, WinLen, 1, (double) beta); for (i = 1; i <= WinLen; i++) { double tmp = (double) N; tmp = tmp * sin(PI * (double) i / tmp) / (PI * (double) i); window[i] = (float) ((double) window[i] * tmp); } if (Rout < Rin) { #if 0 sum = (MYFLT) window[0]; for (i = L-1; i <= WinLen; i += L) sum += (MYFLT) window[i]; sum = FL(2.0) / sum; #else sum = Rout / (Rin * (MYFLT) window[0]); #endif } else sum = FL(1.0) / (MYFLT) window[0]; window[0] = (float) ((double) window[0] * (double) sum); for (i = 1; i <= WinLen; i++) { window[i] = (float) ((double) window[i] * (double) sum); *(window - i) = window[i]; } window[WinLen + 1] = 0.0f; /* set up input buffer: nextIn always points to the next empty word in the input buffer. If the buffer is full, then nextIn jumps back to the beginning, and the old values are written over. */ input = (MYFLT*) csound->Calloc(csound, (size_t) IBUF * sizeof(MYFLT)); /* set up output buffer: nextOut always points to the next empty word in the output buffer. If the buffer is full, then it is flushed, and nextOut jumps back to the beginning. */ output = (MYFLT*) csound->Calloc(csound, (size_t) OBUF * sizeof(MYFLT)); nextOut = output; /* initialization: */ nread = csound->getsndin(csound, inf, input, IBUF2, p); for(i=0; i < nread; i++) input[i] *= 1.0/csound->Get0dBFS(csound); nMax = (long)(input_dur * p->sr); nextIn = input + nread; for (i = nread; i < IBUF2; i++) *(nextIn++) = FL(0.0); jMin = -(wLen + 1) * L; mMax = IBUF2; o = n = m = 0; fo = FL(0.0); /* main loop: If nMax is not specified it is assumed to be very large and then readjusted when read detects the end of input. */ while (n < nMax) { time = n * invRin; /* case 1: (Rin / Rout) * 120 = integer */ if ((tvflg == 0) && (idel == fdel)) { /* apply window (window is sampled at L * Rin) */ for (chan = 0; chan < Chans; chan++) { *nextOut = FL(0.0); k = Chans * (m - wLen) + chan - Chans; if (k < 0) k += IBUF; wj = window + jMin - o; for (i = -wLen; i <= wLen+1; i++){ wj += L; k += Chans; if (k >= IBUF) k -= IBUF; *nextOut += (MYFLT) *wj * *(input + k); } nextOut++; if (nextOut >= (output + OBUF)) { nextOut = output; writebuffer(csound, output, &block, outfd, OBUF, &O); } } /* move window (window advances by del samples at L*Rin sample rate) */ o += del; while (o >= L) { o -= L; n++; m++; if ((Chans * (m + wLen + 1)) >= mMax) { if (!csound->CheckEvents(csound)) csound->LongJmp(csound, 1); mMax += IBUF2; if (nextIn >= (input + IBUF)) nextIn = input; nread = csound->getsndin(csound, inf, nextIn, IBUF2, p); for(i=0; i < nread; i++) input[i] *= 1.0/csound->Get0dBFS(csound); nextIn += nread; if (nread < IBUF2) nMax = n + wLen + (nread / Chans) + 1; for (i = nread; i < IBUF2; i++) *(nextIn++) = FL(0.0); } if ((Chans * m) >= IBUF) { m = 0; mMax = IBUF2; } } } /* case 2: (Rin / Rout) * 120 = non-integer constant */ else { /* apply window (window values are linearly interpolated) */ for (chan = 0; chan < Chans; chan++) { *nextOut = FL(0.0); o = (int)fo; of = fo - o; wj = window + jMin - o; wj1 = wj + 1; k = Chans * (m - wLen) + chan - Chans; if (k < 0) k += IBUF; for (i = -wLen; i <= wLen+1; i++) { wj += L; wj1 += L; k += Chans; if (k >= IBUF) k -= IBUF; iw = (MYFLT) *wj + of * ((MYFLT) *wj1 - (MYFLT) *wj); *nextOut += iw * *(input + k); } nextOut++; if (nextOut >= (output + OBUF)) { nextOut = output; writebuffer(csound, output, &block, outfd, OBUF, &O); } } /* move window */ fo += fdel; while (fo >= fL) { fo -= fL; n++; m++; if ((Chans * (m + wLen + 1)) >= mMax) { if (!csound->CheckEvents(csound)) csound->LongJmp(csound, 1); mMax += IBUF2; if (nextIn >= (input + IBUF)) nextIn = input; nread = csound->getsndin(csound, inf, nextIn, IBUF2, p); for(i=0; i < nread; i++) input[i] *= 1.0/csound->Get0dBFS(csound); nextIn += nread; if (nread < IBUF2) nMax = n + wLen + (nread / Chans) + 1; for (i = nread; i < IBUF2; i++) *(nextIn++) = FL(0.0); } if ((Chans * m) >= IBUF) { m = 0; mMax = IBUF2; } } if (tvflg && (time > FL(0.0))) { while (tvflg && (time >= tvx1)) { if (++tvnxt >= tvlen) tvflg = 0; else { tvx0 = tvx1; tvx1 = fxval[tvnxt]; tvy0 = tvy1; tvy1 = fyval[tvnxt]; tvdx = tvx1 - tvx0; if (tvdx <= FL(0.0)) { strncpy(err_msg, Str("srconv: invalid x values " "in time-vary function"), 256); goto err_rtn_msg; } tvdy = tvy1 - tvy0; tvslope = tvdy / tvdx; } } P = tvy0 + tvslope * (time - tvx0); fdel = (MYFLT) L * P; } } } nread = nextOut - output; writebuffer(csound, output, &block, outfd, nread, &O); csound->Message(csound, "\n\n"); if (O.ringbell) csound->MessageS(csound, CSOUNDMSG_REALTIME, "\a"); return 0; err_rtn_msg: csound->ErrorMsg(csound, err_msg); return -1; }
void FIRFilter::wdfir ( filter_type type, Real atten, Real fl, Real fh) { size_t ieo, nh; Real c, c1, c3, xn, beta, x; ieo = _filtCoeff.size() % 2; if (!(ieo == 1 || type == lowpass || type == bandpass)) { // // Some filter types must have an odd number of taps // _filtCoeff.resize(_filtCoeff.size() - 1); ieo = 1; } // // Window coefficients // const size_t sz = _filtCoeff.size(); RealArray winCoef(sz); // // Compute the ideal (unwindowed) impulse response // if (type == hilbert) { _filtCoeff = Real(0); nh = (1 + sz) / 2; for (size_t ii = nh; ii < sz; ii += 2) { x = M_PI * (ii + 1 - nh) * 0.5; _filtCoeff[ii] = -sin (x) * sin (x) / x; size_t jj = nh - (ii + 2 - nh); _filtCoeff[jj] = -_filtCoeff[ii]; } } else { c1 = fl; if (type == bandpass || type == bandstop) c1 = fh - fl; nh = (1 + sz) / 2; if (ieo == 1) _filtCoeff[nh - 1] = 2.0 * c1; for (size_t ii = ieo; ii < nh; ii++) { xn = ii; if (ieo == 0) xn += 0.5; c = M_PI * xn; c3 = c * c1; if (type == lowpass || type == highpass) c3 *= 2.0; size_t jj = nh + ii - ieo; _filtCoeff[jj] = sin (c3) / c; if (type == bandpass || type == bandstop) _filtCoeff[jj] *= 2.0 * cos (c * (fl + fh)); _filtCoeff[nh - ii - 1] = _filtCoeff[jj]; } } // // Apply a Kaiser-Bessel window // if (atten > 50.0) { beta = 0.1102 * (atten - 8.7); } else if (atten >= 20.96 && atten <= 50.0) { Real tmp = atten - 20.96; beta = 0.58417 * pow (tmp, Real(0.4)) + 0.07886 * tmp; } else // if (atten < 20.96) { beta = Real(0); } kaiser (winCoef, beta); _filtCoeff *= winCoef; if (type == lowpass || type == bandpass) { return; } else if (type == hilbert) { Real kk = 1; Real sum = Real(0); for (size_t ii = nh; ii < sz; ii += 2) { sum += kk * _filtCoeff[ii]; kk = -kk; } _filtCoeff *= (-0.5 / sum); return; } _filtCoeff *= -1; _filtCoeff[nh - 1] += 1; } // end wdfir
int main(int argc, char*argv[]) { // options float r = 1.1f; // resampling rate (output/input) unsigned int m = 13; // resampling filter semi-length (filter delay) float As = 60.0f; // resampling filter stop-band attenuation [dB] float bw = 0.45f; // resampling filter bandwidth unsigned int npfb = 64; // number of filters in bank (timing resolution) unsigned int n = 400; // number of input samples float fc = 0.044f; // complex sinusoid frequency int dopt; while ((dopt = getopt(argc,argv,"hr:m:b:s:p:n:f:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'r': r = atof(optarg); break; case 'm': m = atoi(optarg); break; case 'b': bw = atof(optarg); break; case 's': As = atof(optarg); break; case 'p': npfb = atoi(optarg); break; case 'n': n = atoi(optarg); break; case 'f': fc = atof(optarg); break; default: exit(1); } } // validate input if (r <= 0.0f) { fprintf(stderr,"error: %s, resampling rate must be greater than zero\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 (bw == 0.0f || bw >= 0.5f) { fprintf(stderr,"error: %s, filter bandwidth must be in (0,0.5)\n", argv[0]); exit(1); } else if (As < 0.0f) { fprintf(stderr,"error: %s, filter stop-band attenuation must be greater than zero\n", argv[0]); exit(1); } else if (npfb == 0) { fprintf(stderr,"error: %s, filter bank size must be greater than zero\n", argv[0]); exit(1); } else if (n == 0) { fprintf(stderr,"error: %s, number of input samples must be greater than zero\n", argv[0]); exit(1); } unsigned int i; // number of input samples (zero-padded) unsigned int nx = n + m; // output buffer with extra padding for good measure unsigned int y_len = (unsigned int) ceilf(1.1 * nx * r) + 4; // arrays float complex x[nx]; float complex y[y_len]; // create resampler resamp_crcf q = resamp_crcf_create(r,m,bw,As,npfb); // generate input signal float wsum = 0.0f; for (i=0; i<nx; i++) { // compute window float w = i < n ? kaiser(i, n, 10.0f, 0.0f) : 0.0f; // apply window to complex sinusoid x[i] = cexpf(_Complex_I*2*M_PI*fc*i) * w; // accumulate window wsum += w; } // resample unsigned int ny=0; #if 0 // execute one sample at a time unsigned int nw; for (i=0; i<nx; i++) { // execute resampler, storing in output buffer resamp_crcf_execute(q, x[i], &y[ny], &nw); // increment output size ny += nw; } #else // execute on block of samples resamp_crcf_execute_block(q, x, nx, y, &ny); #endif // clean up allocated objects resamp_crcf_destroy(q); // // analyze resulting signal // // check that the actual resampling rate is close to the target float r_actual = (float)ny / (float)nx; float fy = fc / r; // expected output frequency // run FFT and ensure that carrier has moved and that image // frequencies and distortion have been adequately suppressed unsigned int nfft = 1 << liquid_nextpow2(ny); float complex yfft[nfft]; // fft input float complex Yfft[nfft]; // fft output for (i=0; i<nfft; i++) yfft[i] = i < ny ? y[i] : 0.0f; fft_run(nfft, yfft, Yfft, LIQUID_FFT_FORWARD, 0); fft_shift(Yfft, nfft); // run FFT shift // find peak frequency float Ypeak = 0.0f; float fpeak = 0.0f; float max_sidelobe = -1e9f; // maximum side-lobe [dB] float main_lobe_width = 0.07f; // TODO: figure this out from Kaiser's equations for (i=0; i<nfft; i++) { // normalized output frequency float f = (float)i/(float)nfft - 0.5f; // scale FFT output appropriately float Ymag = 20*log10f( cabsf(Yfft[i] / (r * wsum)) ); // find frequency location of maximum magnitude if (Ymag > Ypeak || i==0) { Ypeak = Ymag; fpeak = f; } // find peak side-lobe value, ignoring frequencies // within a certain range of signal frequency if ( fabsf(f-fy) > main_lobe_width ) max_sidelobe = Ymag > max_sidelobe ? Ymag : max_sidelobe; } // print results and check frequency location printf(" desired resampling rate : %12.8f\n", r); printf(" measured resampling rate : %12.8f (%u/%u)\n", r_actual, ny, nx); printf(" peak spectrum : %12.8f dB (expected 0.0 dB)\n", Ypeak); printf(" peak frequency : %12.8f (expected %-12.8f)\n", fpeak, fy); printf(" max sidelobe : %12.8f dB (expected at least %.2f dB)\n", max_sidelobe, -As); // // export results // 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,"m=%u;\n", m); fprintf(fid,"npfb=%u;\n", npfb); fprintf(fid,"r=%12.8f;\n", r); fprintf(fid,"nx = %u;\n", nx); fprintf(fid,"x = zeros(1,nx);\n"); for (i=0; i<nx; i++) fprintf(fid,"x(%3u) = %12.4e + j*%12.4e;\n", i+1, crealf(x[i]), cimagf(x[i])); fprintf(fid,"ny = %u;\n", ny); fprintf(fid,"y = zeros(1,ny);\n"); for (i=0; i<ny; i++) fprintf(fid,"y(%3u) = %12.4e + j*%12.4e;\n", i+1, crealf(y[i]), cimagf(y[i])); fprintf(fid,"\n\n"); fprintf(fid,"%% plot frequency-domain result\n"); fprintf(fid,"nfft=2^nextpow2(max(nx,ny));\n"); fprintf(fid,"%% estimate PSD, normalize by array length\n"); fprintf(fid,"X=20*log10(abs(fftshift(fft(x,nfft)/length(x))));\n"); fprintf(fid,"Y=20*log10(abs(fftshift(fft(y,nfft)/length(y))));\n"); fprintf(fid,"G=max(X);\n"); fprintf(fid,"X=X-G;\n"); fprintf(fid,"Y=Y-G;\n"); fprintf(fid,"f=[0:(nfft-1)]/nfft-0.5;\n"); fprintf(fid,"figure;\n"); fprintf(fid,"if r>1, fx = f/r; fy = f; %% interpolated\n"); fprintf(fid,"else, fx = f; fy = f*r; %% decimated\n"); fprintf(fid,"end;\n"); fprintf(fid,"plot(fx,X,'Color',[0.5 0.5 0.5],fy,Y,'LineWidth',2);\n"); fprintf(fid,"grid on;\n"); fprintf(fid,"xlabel('normalized frequency');\n"); fprintf(fid,"ylabel('PSD [dB]');\n"); fprintf(fid,"legend('original','resampled','location','northeast');"); fprintf(fid,"axis([-0.5 0.5 -120 20]);\n"); fprintf(fid,"\n\n"); fprintf(fid,"%% plot time-domain result\n"); fprintf(fid,"tx=[0:(length(x)-1)];\n"); fprintf(fid,"ty=[0:(length(y)-1)]/r-m;\n"); fprintf(fid,"figure;\n"); fprintf(fid,"subplot(2,1,1);\n"); fprintf(fid," plot(tx,real(x),'-s','Color',[0.5 0.5 0.5],'MarkerSize',1,...\n"); fprintf(fid," ty,real(y),'-s','Color',[0.5 0 0], 'MarkerSize',1);\n"); fprintf(fid," legend('original','resampled','location','northeast');"); fprintf(fid," xlabel('time');\n"); fprintf(fid," ylabel('real');\n"); fprintf(fid,"subplot(2,1,2);\n"); fprintf(fid," plot(tx,imag(x),'-s','Color',[0.5 0.5 0.5],'MarkerSize',1,...\n"); fprintf(fid," ty,imag(y),'-s','Color',[0 0.5 0], 'MarkerSize',1);\n"); fprintf(fid," legend('original','resampled','location','northeast');"); fprintf(fid," xlabel('time');\n"); fprintf(fid," ylabel('imag');\n"); fclose(fid); printf("results written to %s\n",OUTPUT_FILENAME); printf("done.\n"); return 0; }
int main(int argc, char** argv) { // nc is the number of bits to store the coefficients const int nc = 32; bool polyphase = false; unsigned int polyM = 160; unsigned int polyN = 147; bool debug = false; double Fs = 48000; double Fc = 20478; double atten = 1; int format = 0; // in order to keep the errors associated with the linear // interpolation of the coefficients below the quantization error // we must satisfy: // 2^nz >= 2^(nc/2) // // for 16 bit coefficients that would be 256 // // note that increasing nz only increases memory requirements, // but doesn't increase the amount of computation to do. // // // see: // Smith, J.O. Digital Audio Resampling Home Page // https://ccrma.stanford.edu/~jos/resample/, 2011-03-29 // int nz = 4; // | 0.1102*(A - 8.7) A > 50 // beta = | 0.5842*(A - 21)^0.4 + 0.07886*(A - 21) 21 <= A <= 50 // | 0 A < 21 // with A is the desired stop-band attenuation in dBFS // // for eg: // // 30 dB 2.210 // 40 dB 3.384 // 50 dB 4.538 // 60 dB 5.658 // 70 dB 6.764 // 80 dB 7.865 // 90 dB 8.960 // 100 dB 10.056 double beta = 7.865; // 2*nzc = (A - 8) / (2.285 * dw) // with dw the transition width = 2*pi*dF/Fs // int nzc = 8; // // Example: // 44.1 KHz to 48 KHz resampling // 100 dB rejection above 28 KHz // (the spectrum will fold around 24 KHz and we want 100 dB rejection // at the point where the folding reaches 20 KHz) // ...___|_____ // | \| // | ____/|\____ // |/alias| \ // ------/------+------\---------> KHz // 20 24 28 // Transition band 8 KHz, or dw = 1.0472 // // beta = 10.056 // nzc = 20 // int ch; while ((ch = getopt(argc, argv, ":hds:c:n:f:l:b:p:v:")) != -1) { switch (ch) { case 'd': debug = true; break; case 'p': if (sscanf(optarg, "%u/%u", &polyM, &polyN) != 2) { usage(argv[0]); } polyphase = true; break; case 's': Fs = atof(optarg); break; case 'c': Fc = atof(optarg); break; case 'n': nzc = atoi(optarg); break; case 'l': nz = atoi(optarg); break; case 'f': if (!strcmp(optarg,"fixed")) format = 0; else if (!strcmp(optarg,"float")) format = 1; else usage(argv[0]); break; case 'b': beta = atof(optarg); break; case 'v': atten = pow(10, -fabs(atof(optarg))*0.05 ); break; case 'h': default: usage(argv[0]); break; } } // cut off frequency ratio Fc/Fs double Fcr = Fc / Fs; // total number of coefficients (one side) const int M = (1 << nz); const int N = M * nzc; // generate the right half of the filter if (!debug) { printf("// cmd-line: "); for (int i=1 ; i<argc ; i++) { printf("%s ", argv[i]); } printf("\n"); if (!polyphase) { printf("const int32_t RESAMPLE_FIR_SIZE = %d;\n", N); printf("const int32_t RESAMPLE_FIR_LERP_INT_BITS = %d;\n", nz); printf("const int32_t RESAMPLE_FIR_NUM_COEF = %d;\n", nzc); } else { printf("const int32_t RESAMPLE_FIR_SIZE = %d;\n", 2*nzc*polyN); printf("const int32_t RESAMPLE_FIR_NUM_COEF = %d;\n", 2*nzc); } if (!format) { printf("const int32_t RESAMPLE_FIR_COEF_BITS = %d;\n", nc); } printf("\n"); printf("static %s resampleFIR[] = {", !format ? "int32_t" : "float"); } if (!polyphase) { for (int i=0 ; i<=M ; i++) { // an extra set of coefs for interpolation for (int j=0 ; j<nzc ; j++) { int ix = j*M + i; double x = (2.0 * M_PI * ix * Fcr) / (1 << nz); double y = kaiser(ix+N, 2*N, beta) * sinc(x) * 2.0 * Fcr; y *= atten; if (!debug) { if (j == 0) printf("\n "); } if (!format) { int64_t yi = floor(y * ((1ULL<<(nc-1))) + 0.5); if (yi >= (1LL<<(nc-1))) yi = (1LL<<(nc-1))-1; printf("0x%08x, ", int32_t(yi)); } else { printf("%.9g%s ", y, debug ? "," : "f,"); } } } } else { for (int j=0 ; j<polyN ; j++) { // calculate the phase double p = ((polyM*j) % polyN) / double(polyN); if (!debug) printf("\n "); else printf("\n"); // generate a FIR per phase for (int i=-nzc ; i<nzc ; i++) { double x = 2.0 * M_PI * Fcr * (i + p); double y = kaiser(i+N, 2*N, beta) * sinc(x) * 2.0 * Fcr;; y *= atten; if (!format) { int64_t yi = floor(y * ((1ULL<<(nc-1))) + 0.5); if (yi >= (1LL<<(nc-1))) yi = (1LL<<(nc-1))-1; printf("0x%08x", int32_t(yi)); } else { printf("%.9g%s", y, debug ? "" : "f"); } if (debug && (i==nzc-1)) { } else { printf(", "); } } } } if (!debug) { printf("\n};"); } printf("\n"); return 0; }
// // AUTOTEST : test multi-stage arbitrary resampler // void autotest_msresamp_crcf() { // options unsigned int m = 13; // filter semi-length (filter delay) float r=0.127115323f; // resampling rate (output/input) float As=60.0f; // resampling filter stop-band attenuation [dB] unsigned int n=1200; // number of input samples float fx=0.0254230646f; // complex input sinusoid frequency (0.2*r) //float bw=0.45f; // resampling filter bandwidth //unsigned int npfb=64; // number of filters in bank (timing resolution) unsigned int i; // number of input samples (zero-padded) unsigned int nx = n + m; // output buffer with extra padding for good measure unsigned int y_len = (unsigned int) ceilf(1.1 * nx * r) + 4; // arrays float complex x[nx]; float complex y[y_len]; // create resampler msresamp_crcf q = msresamp_crcf_create(r,As); // generate input signal float wsum = 0.0f; for (i=0; i<nx; i++) { // compute window float w = i < n ? kaiser(i, n, 10.0f, 0.0f) : 0.0f; // apply window to complex sinusoid x[i] = cexpf(_Complex_I*2*M_PI*fx*i) * w; // accumulate window wsum += w; } // resample unsigned int ny=0; unsigned int nw; for (i=0; i<nx; i++) { // execute resampler, storing in output buffer msresamp_crcf_execute(q, &x[i], 1, &y[ny], &nw); // increment output size ny += nw; } // clean up allocated objects msresamp_crcf_destroy(q); // // analyze resulting signal // // check that the actual resampling rate is close to the target float r_actual = (float)ny / (float)nx; float fy = fx / r; // expected output frequency // run FFT and ensure that carrier has moved and that image // frequencies and distortion have been adequately suppressed unsigned int nfft = 1 << liquid_nextpow2(ny); float complex yfft[nfft]; // fft input float complex Yfft[nfft]; // fft output for (i=0; i<nfft; i++) yfft[i] = i < ny ? y[i] : 0.0f; fft_run(nfft, yfft, Yfft, LIQUID_FFT_FORWARD, 0); fft_shift(Yfft, nfft); // run FFT shift // find peak frequency float Ypeak = 0.0f; float fpeak = 0.0f; float max_sidelobe = -1e9f; // maximum side-lobe [dB] float main_lobe_width = 0.07f; // TODO: figure this out from Kaiser's equations for (i=0; i<nfft; i++) { // normalized output frequency float f = (float)i/(float)nfft - 0.5f; // scale FFT output appropriately Yfft[i] /= (r * wsum); float Ymag = 20*log10f( cabsf(Yfft[i]) ); // find frequency location of maximum magnitude if (Ymag > Ypeak || i==0) { Ypeak = Ymag; fpeak = f; } // find peak side-lobe value, ignoring frequencies // within a certain range of signal frequency if ( fabsf(f-fy) > main_lobe_width ) max_sidelobe = Ymag > max_sidelobe ? Ymag : max_sidelobe; } if (liquid_autotest_verbose) { // print results printf(" desired resampling rate : %12.8f\n", r); printf(" measured resampling rate : %12.8f (%u/%u)\n", r_actual, ny, nx); printf(" peak spectrum : %12.8f dB (expected 0.0 dB)\n", Ypeak); printf(" peak frequency : %12.8f (expected %-12.8f)\n", fpeak, fy); printf(" max sidelobe : %12.8f dB (expected at least %.2f dB)\n", max_sidelobe, -As); } CONTEND_DELTA( r_actual, r, 0.01f ); // check actual output sample rate CONTEND_DELTA( Ypeak, 0.0f, 0.25f ); // peak should be about 0 dB CONTEND_DELTA( fpeak, fy, 0.01f ); // peak frequency should be nearly 0.2 CONTEND_LESS_THAN( max_sidelobe, -As ); // maximum side-lobe should be sufficiently low #if 0 // export results for debugging char filename[] = "msresamp_crcf_autotest.m"; FILE*fid = fopen(filename,"w"); fprintf(fid,"%% %s: auto-generated file\n",filename); fprintf(fid,"clear all;\n"); fprintf(fid,"close all;\n"); fprintf(fid,"r = %12.8f;\n", r); fprintf(fid,"nx = %u;\n", nx); fprintf(fid,"ny = %u;\n", ny); fprintf(fid,"nfft = %u;\n", nfft); fprintf(fid,"Y = zeros(1,nfft);\n"); for (i=0; i<nfft; i++) fprintf(fid,"Y(%3u) = %12.4e + j*%12.4e;\n", i+1, crealf(Yfft[i]), cimagf(Yfft[i])); fprintf(fid,"\n\n"); fprintf(fid,"%% plot frequency-domain result\n"); fprintf(fid,"f=[0:(nfft-1)]/nfft-0.5;\n"); fprintf(fid,"figure;\n"); fprintf(fid,"plot(f,20*log10(abs(Y)),'Color',[0.25 0.5 0.0],'LineWidth',2);\n"); fprintf(fid,"grid on;\n"); fprintf(fid,"xlabel('normalized frequency');\n"); fprintf(fid,"ylabel('PSD [dB]');\n"); fprintf(fid,"axis([-0.5 0.5 -120 20]);\n"); fclose(fid); printf("results written to %s\n",filename); #endif }
int main() { unsigned int h_len=20; // filter length float beta = 0.3f; // stop-band attenuation unsigned int num_samples=64; // number of samples // derived values unsigned int n = num_samples + h_len; // extend length of analysis to // incorporate filter delay // create filterbank qmfb_crcf q = qmfb_crcf_create(h_len, beta, LIQUID_QMFB_ANALYZER); qmfb_crcf_print(q); FILE*fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s : auto-generated file\n", OUTPUT_FILENAME); fprintf(fid,"clear all;\nclose all;\n\n"); fprintf(fid,"n=%u;\n", n); fprintf(fid,"x = zeros(1,%u);\n", 2*n); fprintf(fid,"y = zeros(2,%u);\n", n); unsigned int i; float complex x[2*n], y[2][n]; // generate time-domain signal (windowed sinusoidal pulses) nco_crcf nco_0 = nco_crcf_create(LIQUID_VCO); nco_crcf nco_1 = nco_crcf_create(LIQUID_VCO); nco_crcf_set_frequency(nco_0, 0.122*M_PI); nco_crcf_set_frequency(nco_1, 0.779*M_PI); float complex x0,x1; for (i=0; i<2*num_samples; i++) { nco_crcf_cexpf(nco_0, &x0); nco_crcf_cexpf(nco_1, &x1); x[i] = (x0 + x1) * kaiser(i,2*num_samples,10.0f,0.0f); nco_crcf_step(nco_0); nco_crcf_step(nco_1); } // pad end with zeros for (i=2*num_samples; i<2*n; i++) x[i] = 0.0f; // compute QMF sub-channel output for (i=0; i<n; i++) { qmfb_crcf_execute(q, x[2*i+0], x[2*i+1], y[0]+i, y[1]+i); } // write results to output file for (i=0; i<n; i++) { fprintf(fid,"x(%3u) = %8.4f + j*%8.4f;\n", 2*i+1, crealf(x[2*i+0]), cimagf(x[2*i+0])); fprintf(fid,"x(%3u) = %8.4f + j*%8.4f;\n", 2*i+2, crealf(x[2*i+1]), cimagf(x[2*i+1])); fprintf(fid,"y(1,%3u) = %8.4f + j*%8.4f;\n", i+1, crealf(y[0][i]), cimagf(y[0][i])); fprintf(fid,"y(2,%3u) = %8.4f + j*%8.4f;\n", i+1, crealf(y[1][i]), cimagf(y[1][i])); } // plot time-domain results fprintf(fid,"t0=0:(2*n-1);\n"); fprintf(fid,"t1=0:(n-1);\n"); fprintf(fid,"figure;\n"); fprintf(fid,"subplot(3,1,1); plot(t0,real(x),t0,imag(x)); ylabel('x(t)');\n"); fprintf(fid,"subplot(3,1,2); plot(t1,real(y(1,:)),t1,imag(y(1,:))); ylabel('y_0(t)');\n"); fprintf(fid,"subplot(3,1,3); plot(t1,real(y(2,:)),t1,imag(y(2,:))); ylabel('y_1(t)');\n"); // plot freq-domain results fprintf(fid,"nfft=512; %% must be even number\n"); fprintf(fid,"X=20*log10(abs(fftshift(fft(x/n,nfft))));\n"); fprintf(fid,"Y0=20*log10(abs(fftshift(fft(y(1,:)/n,nfft))));\n"); fprintf(fid,"Y1=20*log10(abs(fftshift(fft(y(2,:)/n,nfft))));\n"); // Y1 needs to be split into two regions fprintf(fid,"f=[0:(nfft-1)]/nfft - 0.5;\n"); fprintf(fid,"t0 = [1]:[nfft/2];\n"); fprintf(fid,"t1 = [nfft/2+1]:[nfft];\n"); fprintf(fid,"figure;\n"); fprintf(fid,"hold on;\n"); fprintf(fid," plot(f,X,'Color',[0.5 0.5 0.5]);\n"); fprintf(fid," plot(f/2,Y0,'LineWidth',2,'Color',[0 0.5 0]);\n"); fprintf(fid," plot(f(t0)/2+0.5,Y1(t0),'LineWidth',2,'Color',[0.5 0 0]);\n"); fprintf(fid," plot(f(t1)/2-0.5,Y1(t1),'LineWidth',2,'Color',[0.5 0 0]);\n"); fprintf(fid,"hold off;\n"); fprintf(fid,"grid on;\nxlabel('normalized frequency');\nylabel('PSD [dB]');\n"); fprintf(fid,"legend('original','Y_0','Y_1',1);"); fprintf(fid,"axis([-0.5 0.5 -140 20]);\n"); fclose(fid); printf("results written to %s\n", OUTPUT_FILENAME); qmfb_crcf_destroy(q); nco_crcf_destroy(nco_0); nco_crcf_destroy(nco_1); printf("done.\n"); return 0; }