// // AUTOTEST: // void autotest_firinterp_rrrf_generic() { float h[9] = { -0.2762293319046737, 1.4757679031218007, 0.1432569489572376, -0.2142368750177835, 1.3471241294836864, 0.1166010284926269, 0.0536534505390281, 0.1412672462812405, -0.0991854372394269}; unsigned int M = 4; // firinterp factor firinterp_rrrf q = firinterp_rrrf_create(M,h,9); float x[] = {1.0, -1.0, 1.0, 1.0}; float y[16]; float test[16] = { -0.2762293319046737, 1.4757679031218007, 0.1432569489572376, -0.2142368750177835, 1.6233534613883602, -1.3591668746291738, -0.0896034984182095, 0.3555041212990241, -1.7225388986277870, 1.3591668746291738, 0.0896034984182095, -0.3555041212990241, 1.1700802348184398, 1.5923689316144276, 0.1969103994962658, -0.0729696287365430}; float tol = 1e-6; unsigned int i; for (i=0; i<4; i++) firinterp_rrrf_execute(q, x[i], &y[i*M]); for (i=0; i<16; i++) { CONTEND_DELTA(y[i], test[i], tol); if (liquid_autotest_verbose) printf(" y(%u) = %8.4f;\n", i+1, y[i]); } if (liquid_autotest_verbose) firinterp_rrrf_print(q); // destroy interpolator object firinterp_rrrf_destroy(q); }
int main(int argc, char*argv[]) { // options unsigned int k=2; // samples/symbol unsigned int m=3; // symbol delay float beta=0.7f; // excess bandwidth factor unsigned int num_symbols=16; int ftype_tx = LIQUID_FIRFILT_RRC; int ftype_rx = LIQUID_FIRFILT_RRC; int dopt; while ((dopt = getopt(argc,argv,"uht:k:m:b:n:")) != EOF) { switch (dopt) { case 'u': case 'h': usage(); return 0; case 't': if (strcmp(optarg,"gmsk")==0) { ftype_tx = LIQUID_FIRFILT_GMSKTX; ftype_rx = LIQUID_FIRFILT_GMSKRX; } else { ftype_tx = liquid_getopt_str2firfilt(optarg); ftype_rx = liquid_getopt_str2firfilt(optarg); } if (ftype_tx == LIQUID_FIRFILT_UNKNOWN) { fprintf(stderr,"error: %s, unknown filter type '%s'\n", argv[0], optarg); exit(1); } break; case 'k': k = atoi(optarg); break; case 'm': m = atoi(optarg); break; case 'b': beta = atof(optarg); break; case 'n': num_symbols = atoi(optarg); break; default: exit(1); } } if (k < 2) { fprintf(stderr,"error: %s, k must be at least 2\n", argv[0]); exit(1); } else if (m < 1) { fprintf(stderr,"error: %s, m must be at least 1\n", argv[0]); exit(1); } else if (beta <= 0.0f || beta >= 1.0f) { fprintf(stderr,"error: %s, beta must be in (0,1)\n", argv[0]); exit(1); } unsigned int i; // derived values unsigned int num_samples = num_symbols*k; unsigned int h_len = 2*k*m+1; // transmit/receive filter length unsigned int hc_len = 4*k*m+1; // composite filter length // arrays float ht[h_len]; // transmit filter float hr[h_len]; // receive filter float hc[hc_len]; // composite filter // design the filter(s) liquid_firdes_rnyquist(ftype_tx, k, m, beta, 0, ht); liquid_firdes_rnyquist(ftype_rx, k, m, beta, 0, hr); for (i=0; i<h_len; i++) printf("ht(%3u) = %12.8f;\n", i+1, ht[i]); for (i=0; i<h_len; i++) printf("hr(%3u) = %12.8f;\n", i+1, hr[i]); #if 0 // generate receive filter coefficients (reverse of transmit) float hr[h_len]; for (i=0; i<h_len; i++) hr[i] = ht[h_len-i-1]; #endif // compute composite filter response for (i=0; i<4*k*m+1; i++) { int lag = (int)i - (int)(2*k*m); hc[i] = liquid_filter_crosscorr(ht,h_len, hr,h_len, lag); } // compute filter inter-symbol interference float rxy0 = liquid_filter_crosscorr(ht,h_len, hr,h_len, 0); float isi_rms=0; for (i=1; i<2*m; i++) { float e = liquid_filter_crosscorr(ht,h_len, hr,h_len, i*k) / rxy0; isi_rms += e*e; } isi_rms = sqrtf( isi_rms / (float)(2*m-1) ); printf(" isi (rms) : %12.8f dB\n", 20*log10f(isi_rms)); // compute relative stop-band energy unsigned int nfft = 2048; float As = liquid_filter_energy(ht, h_len, 0.5f*(1.0f + beta)/(float)k, nfft); printf(" As : %12.8f dB\n", 20*log10f(As)); // generate signal float sym_in[num_symbols]; float y[num_samples]; float sym_out[num_symbols]; // create interpolator and decimator firinterp_rrrf interp = firinterp_rrrf_create(k, ht, h_len); firdecim_rrrf decim = firdecim_rrrf_create( k, hr, h_len); for (i=0; i<num_symbols; i++) { // generate random symbol sym_in[i] = (rand() % 2) ? 1.0f : -1.0f; // interpolate firinterp_rrrf_execute(interp, sym_in[i], &y[i*k]); // decimate firdecim_rrrf_execute(decim, &y[i*k], &sym_out[i]); // normalize output sym_out[i] /= k; printf(" %3u : %8.5f", i, sym_out[i]); if (i>=2*m) printf(" *\n"); else printf("\n"); } // clean up objects firinterp_rrrf_destroy(interp); firdecim_rrrf_destroy(decim); // // export results // FILE * fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s : auto-generated file\n\n", OUTPUT_FILENAME); fprintf(fid,"clear all;\n"); fprintf(fid,"close all;\n"); fprintf(fid,"k = %u;\n", k); fprintf(fid,"m = %u;\n", m); fprintf(fid,"beta = %12.8f;\n", beta); fprintf(fid,"num_symbols = %u;\n", num_symbols); fprintf(fid,"num_samples = k*num_symbols;\n"); fprintf(fid,"y = zeros(1,num_samples);\n"); for (i=0; i<num_samples; i++) fprintf(fid," y(%3u) = %12.8f;\n", i+1, y[i]); for (i=0; i<h_len; i++) fprintf(fid,"ht(%3u) = %20.8e;\n", i+1, ht[i]); for (i=0; i<h_len; i++) fprintf(fid,"hr(%3u) = %20.8e;\n", i+1, hr[i]); for (i=0; i<hc_len; i++) fprintf(fid,"hc(%3u) = %20.8e;\n", i+1, hc[i]); fprintf(fid,"nfft=1024;\n"); fprintf(fid,"f = [0:(nfft-1)]/nfft - 0.5;\n"); fprintf(fid,"Ht = 20*log10(abs(fftshift(fft(ht/k, nfft))));\n"); fprintf(fid,"Hr = 20*log10(abs(fftshift(fft(hr/k, nfft))));\n"); fprintf(fid,"Hc = 20*log10(abs(fftshift(fft(hc/k^2, nfft))));\n"); fprintf(fid,"figure;\n"); fprintf(fid,"plot(f,Hc,'-','LineWidth',2,...\n"); fprintf(fid," [0.5/k],[-6],'or',...\n"); fprintf(fid," [0.5/k*(1-beta) 0.5/k*(1-beta)],[-100 10],'-r',...\n"); fprintf(fid," [0.5/k*(1+beta) 0.5/k*(1+beta)],[-100 10],'-r');\n"); fprintf(fid,"xlabel('normalized frequency');\n"); fprintf(fid,"ylabel('PSD');\n"); fprintf(fid,"axis([-0.5 0.5 -100 10]);\n"); fprintf(fid,"grid on;\n"); // compute composite filter fprintf(fid,"figure;\n"); fprintf(fid,"hc = conv(ht,hr)/k;\n"); fprintf(fid,"t = [(-2*k*m):(2*k*m)]/k;\n"); fprintf(fid,"i0 = [0:k:4*k*m]+1;\n"); fprintf(fid,"plot(t, hc, '-s',...\n"); fprintf(fid," t(i0),hc(i0),'or');\n"); fprintf(fid,"xlabel('symbol index');\n"); fprintf(fid,"ylabel('matched filter response');\n"); fprintf(fid,"grid on;\n"); fclose(fid); printf("results written to %s.\n", OUTPUT_FILENAME); printf("done.\n"); return 0; }
int main(int argc, char*argv[]) { // options unsigned int k = 8; // filter samples/symbol unsigned int bps= 1; // number of bits/symbol float h = 0.5f; // modulation index (h=1/2 for MSK) unsigned int num_data_symbols = 20; // number of data symbols float SNRdB = 80.0f; // signal-to-noise ratio [dB] float cfo = 0.0f; // carrier frequency offset float cpo = 0.0f; // carrier phase offset float tau = 0.0f; // fractional symbol offset enum { TXFILT_SQUARE=0, TXFILT_RCOS_FULL, TXFILT_RCOS_HALF, TXFILT_GMSK, } tx_filter_type = TXFILT_SQUARE; float gmsk_bt = 0.35f; // GMSK bandwidth-time factor int dopt; while ((dopt = getopt(argc,argv,"ht:k:b:H:B:n:s:F:P:T:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 't': if (strcmp(optarg,"square")==0) { tx_filter_type = TXFILT_SQUARE; } else if (strcmp(optarg,"rcos-full")==0) { tx_filter_type = TXFILT_RCOS_FULL; } else if (strcmp(optarg,"rcos-half")==0) { tx_filter_type = TXFILT_RCOS_HALF; } else if (strcmp(optarg,"gmsk")==0) { tx_filter_type = TXFILT_GMSK; } else { fprintf(stderr,"error: %s, unknown filter type '%s'\n", argv[0], optarg); exit(1); } break; case 'k': k = atoi(optarg); break; case 'b': bps = atoi(optarg); break; case 'H': h = atof(optarg); break; case 'B': gmsk_bt = atof(optarg); break; case 'n': num_data_symbols = atoi(optarg); break; case 's': SNRdB = atof(optarg); break; case 'F': cfo = atof(optarg); break; case 'P': cpo = atof(optarg); break; case 'T': tau = atof(optarg); break; default: exit(1); } } unsigned int i; // derived values unsigned int num_symbols = num_data_symbols; unsigned int num_samples = k*num_symbols; unsigned int M = 1 << bps; // constellation size float nstd = powf(10.0f, -SNRdB/20.0f); // arrays unsigned char sym_in[num_symbols]; // input symbols float phi[num_samples]; // transmitted phase float complex x[num_samples]; // transmitted signal float complex y[num_samples]; // received signal float complex z[num_samples]; // output... //unsigned char sym_out[num_symbols]; // output symbols unsigned int ht_len = 0; unsigned int tx_delay = 0; float * ht = NULL; switch (tx_filter_type) { case TXFILT_SQUARE: // regular MSK ht_len = k; tx_delay = 1; ht = (float*) malloc(ht_len *sizeof(float)); for (i=0; i<ht_len; i++) ht[i] = h * M_PI / (float)k; break; case TXFILT_RCOS_FULL: // full-response raised-cosine pulse ht_len = k; tx_delay = 1; ht = (float*) malloc(ht_len *sizeof(float)); for (i=0; i<ht_len; i++) ht[i] = h * M_PI / (float)k * (1.0f - cosf(2.0f*M_PI*i/(float)ht_len)); break; case TXFILT_RCOS_HALF: // partial-response raised-cosine pulse ht_len = 3*k; tx_delay = 2; ht = (float*) malloc(ht_len *sizeof(float)); for (i=0; i<ht_len; i++) ht[i] = 0.0f; for (i=0; i<2*k; i++) ht[i+k/2] = h * 0.5f * M_PI / (float)k * (1.0f - cosf(2.0f*M_PI*i/(float)(2*k))); break; case TXFILT_GMSK: ht_len = 2*k*3+1+k; tx_delay = 4; ht = (float*) malloc(ht_len *sizeof(float)); for (i=0; i<ht_len; i++) ht[i] = 0.0f; liquid_firdes_gmsktx(k,3,gmsk_bt,0.0f,&ht[k/2]); for (i=0; i<ht_len; i++) ht[i] *= h * 2.0f / (float)k; break; default: fprintf(stderr,"error: %s, invalid tx filter type\n", argv[0]); exit(1); } for (i=0; i<ht_len; i++) printf("ht(%3u) = %12.8f;\n", i+1, ht[i]); firinterp_rrrf interp_tx = firinterp_rrrf_create(k, ht, ht_len); // generate symbols and interpolate // phase-accumulating filter (trapezoidal integrator) float b[2] = {0.5f, 0.5f}; if (tx_filter_type == TXFILT_SQUARE) { // square filter: rectangular integration with one sample of delay b[0] = 0.0f; b[1] = 1.0f; } float a[2] = {1.0f, -1.0f}; iirfilt_rrrf integrator = iirfilt_rrrf_create(b,2,a,2); float theta = 0.0f; for (i=0; i<num_symbols; i++) { sym_in[i] = rand() % M; float v = 2.0f*sym_in[i] - (float)(M-1); // +/-1, +/-3, ... +/-(M-1) firinterp_rrrf_execute(interp_tx, v, &phi[k*i]); // accumulate phase unsigned int j; for (j=0; j<k; j++) { iirfilt_rrrf_execute(integrator, phi[i*k+j], &theta); x[i*k+j] = cexpf(_Complex_I*theta); } } iirfilt_rrrf_destroy(integrator); // push through channel for (i=0; i<num_samples; i++) { // add carrier frequency/phase offset y[i] = x[i]*cexpf(_Complex_I*(cfo*i + cpo)); // add noise y[i] += nstd*(randnf() + _Complex_I*randnf())*M_SQRT1_2; } // create decimator unsigned int m = 3; float bw = 0.0f; float beta = 0.0f; firfilt_crcf decim_rx = NULL; switch (tx_filter_type) { case TXFILT_SQUARE: //bw = 0.9f / (float)k; bw = 0.4f; decim_rx = firfilt_crcf_create_kaiser(2*k*m+1, bw, 60.0f, 0.0f); firfilt_crcf_set_scale(decim_rx, 2.0f * bw); break; case TXFILT_RCOS_FULL: if (M==2) { decim_rx = firfilt_crcf_create_rnyquist(LIQUID_FIRFILT_GMSKRX,k,m,0.5f,0); firfilt_crcf_set_scale(decim_rx, 1.33f / (float)k); } else { decim_rx = firfilt_crcf_create_rnyquist(LIQUID_FIRFILT_GMSKRX,k/2,2*m,0.9f,0); firfilt_crcf_set_scale(decim_rx, 3.25f / (float)k); } break; case TXFILT_RCOS_HALF: if (M==2) { decim_rx = firfilt_crcf_create_rnyquist(LIQUID_FIRFILT_GMSKRX,k,m,0.3f,0); firfilt_crcf_set_scale(decim_rx, 1.10f / (float)k); } else { decim_rx = firfilt_crcf_create_rnyquist(LIQUID_FIRFILT_GMSKRX,k/2,2*m,0.27f,0); firfilt_crcf_set_scale(decim_rx, 2.90f / (float)k); } break; case TXFILT_GMSK: bw = 0.5f / (float)k; // TODO: figure out beta value here beta = (M == 2) ? 0.8*gmsk_bt : 1.0*gmsk_bt; decim_rx = firfilt_crcf_create_rnyquist(LIQUID_FIRFILT_GMSKRX,k,m,beta,0); firfilt_crcf_set_scale(decim_rx, 2.0f * bw); break; default: fprintf(stderr,"error: %s, invalid tx filter type\n", argv[0]); exit(1); } printf("bw = %f\n", bw); // run receiver unsigned int n=0; unsigned int num_errors = 0; unsigned int num_symbols_checked = 0; float complex z_prime = 0.0f; for (i=0; i<num_samples; i++) { // push through filter firfilt_crcf_push(decim_rx, y[i]); firfilt_crcf_execute(decim_rx, &z[i]); // decimate output if ( (i%k)==0 ) { // compute instantaneous frequency scaled by modulation index float phi_hat = cargf(conjf(z_prime) * z[i]) / (h * M_PI); // estimate transmitted symbol float v = (phi_hat + (M-1.0))*0.5f; unsigned int sym_out = ((int) roundf(v)) % M; // save current point z_prime = z[i]; // print result to screen printf("%3u : %12.8f + j%12.8f, <f=%8.4f : %8.4f> (%1u)", n, crealf(z[i]), cimagf(z[i]), phi_hat, v, sym_out); if (n >= m+tx_delay) { num_errors += (sym_out == sym_in[n-m-tx_delay]) ? 0 : 1; num_symbols_checked++; printf(" (%1u)\n", sym_in[n-m-tx_delay]); } else { printf("\n"); } n++; } } // print number of errors printf("errors : %3u / %3u\n", num_errors, num_symbols_checked); // destroy objects firinterp_rrrf_destroy(interp_tx); firfilt_crcf_destroy(decim_rx); // compute power spectral density of transmitted signal unsigned int nfft = 1024; float psd[nfft]; spgramcf periodogram = spgramcf_create_kaiser(nfft, nfft/2, 8.0f); spgramcf_estimate_psd(periodogram, y, num_samples, psd); spgramcf_destroy(periodogram); // // 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,"k = %u;\n", k); fprintf(fid,"h = %f;\n", h); fprintf(fid,"num_symbols = %u;\n", num_symbols); fprintf(fid,"num_samples = %u;\n", num_samples); fprintf(fid,"nfft = %u;\n", nfft); fprintf(fid,"delay = %u; %% receive filter delay\n", tx_delay); fprintf(fid,"x = zeros(1,num_samples);\n"); fprintf(fid,"y = zeros(1,num_samples);\n"); fprintf(fid,"z = zeros(1,num_samples);\n"); fprintf(fid,"phi = zeros(1,num_samples);\n"); for (i=0; i<num_samples; i++) { fprintf(fid,"x(%4u) = %12.8f + j*%12.8f;\n", i+1, crealf(x[i]), cimagf(x[i])); fprintf(fid,"y(%4u) = %12.8f + j*%12.8f;\n", i+1, crealf(y[i]), cimagf(y[i])); fprintf(fid,"z(%4u) = %12.8f + j*%12.8f;\n", i+1, crealf(z[i]), cimagf(z[i])); fprintf(fid,"phi(%4u) = %12.8f;\n", i+1, phi[i]); } // save PSD fprintf(fid,"psd = zeros(1,nfft);\n"); for (i=0; i<nfft; i++) fprintf(fid,"psd(%4u) = %12.8f;\n", i+1, psd[i]); fprintf(fid,"t=[0:(num_samples-1)]/k;\n"); fprintf(fid,"i = 1:k:num_samples;\n"); fprintf(fid,"figure;\n"); fprintf(fid,"subplot(3,4,1:3);\n"); fprintf(fid," plot(t,real(x),'-', t(i),real(x(i)),'bs','MarkerSize',4,...\n"); fprintf(fid," t,imag(x),'-', t(i),imag(x(i)),'gs','MarkerSize',4);\n"); fprintf(fid," axis([0 num_symbols -1.2 1.2]);\n"); fprintf(fid," xlabel('time');\n"); fprintf(fid," ylabel('x(t)');\n"); fprintf(fid," grid on;\n"); fprintf(fid,"subplot(3,4,5:7);\n"); fprintf(fid," plot(t-delay,real(z),'-', t(i)-delay,real(z(i)),'bs','MarkerSize',4,...\n"); fprintf(fid," t-delay,imag(z),'-', t(i)-delay,imag(z(i)),'gs','MarkerSize',4);\n"); fprintf(fid," axis([0 num_symbols -1.2 1.2]);\n"); fprintf(fid," xlabel('time');\n"); fprintf(fid," ylabel('\"matched\" filter output');\n"); fprintf(fid," grid on;\n"); // plot I/Q constellations fprintf(fid,"subplot(3,4,4);\n"); fprintf(fid," plot(real(y),imag(y),'-',real(y(i)),imag(y(i)),'rs','MarkerSize',3);\n"); fprintf(fid," xlabel('I');\n"); fprintf(fid," ylabel('Q');\n"); fprintf(fid," axis([-1 1 -1 1]*1.2);\n"); fprintf(fid," axis square;\n"); fprintf(fid," grid on;\n"); fprintf(fid,"subplot(3,4,8);\n"); fprintf(fid," plot(real(z),imag(z),'-',real(z(i)),imag(z(i)),'rs','MarkerSize',3);\n"); fprintf(fid," xlabel('I');\n"); fprintf(fid," ylabel('Q');\n"); fprintf(fid," axis([-1 1 -1 1]*1.2);\n"); fprintf(fid," axis square;\n"); fprintf(fid," grid on;\n"); // plot PSD fprintf(fid,"f = [0:(nfft-1)]/nfft - 0.5;\n"); fprintf(fid,"subplot(3,4,9:12);\n"); fprintf(fid," plot(f,psd,'LineWidth',1.5);\n"); fprintf(fid," axis([-0.5 0.5 -40 20]);\n"); fprintf(fid," xlabel('Normalized Frequency [f/F_s]');\n"); fprintf(fid," ylabel('PSD [dB]');\n"); fprintf(fid," grid on;\n"); #if 0 fprintf(fid,"figure;\n"); fprintf(fid," %% compute instantaneous received frequency\n"); fprintf(fid," freq_rx = arg( conj(z(:)) .* circshift(z(:),-1) )';\n"); fprintf(fid," freq_rx(1:(k*delay)) = 0;\n"); fprintf(fid," freq_rx(end) = 0;\n"); fprintf(fid," %% compute instantaneous tx/rx phase\n"); if (tx_filter_type == TXFILT_SQUARE) { fprintf(fid," theta_tx = filter([0 1],[1 -1],phi)/(h*pi);\n"); fprintf(fid," theta_rx = filter([0 1],[1 -1],freq_rx)/(h*pi);\n"); } else { fprintf(fid," theta_tx = filter([0.5 0.5],[1 -1],phi)/(h*pi);\n"); fprintf(fid," theta_rx = filter([0.5 0.5],[1 -1],freq_rx)/(h*pi);\n"); } fprintf(fid," %% plot instantaneous tx/rx phase\n"); fprintf(fid," plot(t, theta_tx,'-b', t(i), theta_tx(i),'sb',...\n"); fprintf(fid," t-delay,theta_rx,'-r', t(i)-delay,theta_rx(i),'sr');\n"); fprintf(fid," xlabel('time');\n"); fprintf(fid," ylabel('instantaneous phase/(h \\pi)');\n"); fprintf(fid," legend('transmitted','syms','received/filtered','syms','location','northwest');\n"); fprintf(fid," grid on;\n"); #else // plot filter response fprintf(fid,"ht_len = %u;\n", ht_len); fprintf(fid,"ht = zeros(1,ht_len);\n"); for (i=0; i<ht_len; i++) fprintf(fid,"ht(%4u) = %12.8f;\n", i+1, ht[i]); fprintf(fid,"gt1 = filter([0.5 0.5],[1 -1],ht) / (pi*h);\n"); fprintf(fid,"gt2 = filter([0.0 1.0],[1 -1],ht) / (pi*h);\n"); fprintf(fid,"tfilt = [0:(ht_len-1)]/k - delay + 0.5;\n"); fprintf(fid,"figure;\n"); fprintf(fid,"plot(tfilt,ht, '-x','MarkerSize',4,...\n"); fprintf(fid," tfilt,gt1,'-x','MarkerSize',4,...\n"); fprintf(fid," tfilt,gt2,'-x','MarkerSize',4);\n"); fprintf(fid,"axis([tfilt(1) tfilt(end) -0.1 1.1]);\n"); fprintf(fid,"legend('pulse','trap. int.','rect. int.','location','northwest');\n"); fprintf(fid,"grid on;\n"); #endif fclose(fid); printf("results written to '%s'\n", OUTPUT_FILENAME); // free allocated filter memory free(ht); return 0; }
// create cpfskmod object (frequency modulator) // _bps : bits per symbol, _bps > 0 // _h : modulation index, _h > 0 // _k : samples/symbol, _k > 1, _k even // _m : filter delay (symbols), _m > 0 // _beta : filter bandwidth parameter, _beta > 0 // _type : filter type (e.g. LIQUID_CPFSK_SQUARE) cpfskmod cpfskmod_create(unsigned int _bps, float _h, unsigned int _k, unsigned int _m, float _beta, int _type) { // validate input if (_bps == 0) { fprintf(stderr,"error: cpfskmod_create(), bits/symbol must be greater than 0\n"); exit(1); } else if (_k < 2 || (_k%2)) { fprintf(stderr,"error: cpfskmod_create(), samples/symbol must be greater than 2 and even\n"); exit(1); } else if (_m == 0) { fprintf(stderr,"error: cpfskmod_create(), filter delay must be greater than 0\n"); exit(1); } else if (_beta <= 0.0f || _beta > 1.0f) { fprintf(stderr,"error: cpfskmod_create(), filter roll-off must be in (0,1]\n"); exit(1); } else if (_h <= 0.0f) { fprintf(stderr,"error: cpfskmod_create(), modulation index must be greater than 0\n"); exit(1); } // create main object memory cpfskmod q = (cpfskmod) malloc(sizeof(struct cpfskmod_s)); // set basic internal properties q->bps = _bps; // bits per symbol q->h = _h; // modulation index q->k = _k; // samples per symbol q->m = _m; // filter delay (symbols) q->beta = _beta; // filter roll-off factor (only for certain filters) q->type = _type; // filter type // derived values q->M = 1 << q->bps; // constellation size // create object depending upon input type float b[2] = {0.5f, 0.5f}; // integrator feed-forward coefficients float a[2] = {1.0f, -1.0f}; // integrator feed-back coefficients q->ht_len = 0; q->ht = NULL; unsigned int i; switch(q->type) { case LIQUID_CPFSK_SQUARE: q->ht_len = q->k; q->symbol_delay = 1; // modify integrator b[0] = 0.0f; b[1] = 1.0f; break; case LIQUID_CPFSK_RCOS_FULL: q->ht_len = q->k; q->symbol_delay = 1; break; case LIQUID_CPFSK_RCOS_PARTIAL: // TODO: adjust reponse based on 'm' q->ht_len = 3*q->k; q->symbol_delay = 2; break; case LIQUID_CPFSK_GMSK: q->symbol_delay = q->m + 1; q->ht_len = 2*(q->k)*(q->m) + (q->k) + 1; break; default: fprintf(stderr,"error: cpfskmodem_create(), invalid filter type '%d'\n", q->type); exit(1); } // create pulse-shaping filter and scale by modulation index q->ht = (float*) malloc(q->ht_len *sizeof(float)); cpfskmod_firdes(q->k, q->m, q->beta, q->type, q->ht, q->ht_len); for (i=0; i<q->ht_len; i++) q->ht[i] *= M_PI * q->h; q->interp = firinterp_rrrf_create(q->k, q->ht, q->ht_len); // create phase integrator q->phase_interp = (float*) malloc(q->k*sizeof(float)); q->integrator = iirfilt_rrrf_create(b,2,a,2); // reset modem object cpfskmod_reset(q); return q; }