void benchmark_gmskmodem_modulate(struct rusage *_start, struct rusage *_finish, unsigned long int *_num_iterations) { // options unsigned int k=2; // filter samples/symbol unsigned int m=3; // filter delay (symbols) float BT=0.3f; // bandwidth-time product // create modem object gmskmod mod = gmskmod_create(k, m, BT); float complex x[k]; unsigned int symbol_in = 0; unsigned long int i; // start trials getrusage(RUSAGE_SELF, _start); for (i=0; i<(*_num_iterations); i++) { gmskmod_modulate(mod, symbol_in, x); gmskmod_modulate(mod, symbol_in, x); gmskmod_modulate(mod, symbol_in, x); gmskmod_modulate(mod, symbol_in, x); } getrusage(RUSAGE_SELF, _finish); *_num_iterations *= 4; // destroy modem objects gmskmod_destroy(mod); }
// destroy gmskframegen object void gmskframegen_destroy(gmskframegen _q) { // destroy gmsk modulator gmskmod_destroy(_q->mod); // destroy/free preamble objects/arrays msequence_destroy(_q->ms_preamble); // destroy/free header objects/arrays free(_q->header_dec); free(_q->header_enc); packetizer_destroy(_q->p_header); // destroy/free payload objects/arrays free(_q->payload_enc); packetizer_destroy(_q->p_payload); // free main object memory free(_q); }
int main(int argc, char*argv[]) { // options unsigned int k=4; // filter samples/symbol unsigned int m=3; // filter delay (symbols) float BT=0.3f; // bandwidth-time product unsigned int num_data_symbols=200; // number of data symbols float SNRdB = 30.0f; // signal-to-noise ratio [dB] float phi = 0.0f; // carrier phase offset float dphi = 0.0f; // carrier frequency offset int dopt; while ((dopt = getopt(argc,argv,"uhk:m:n:b:s:")) != EOF) { switch (dopt) { case 'u': case 'h': usage(); return 0; case 'k': k = atoi(optarg); break; case 'm': m = atoi(optarg); break; case 'n': num_data_symbols = atoi(optarg); break; case 'b': BT = atof(optarg); break; case 's': SNRdB = atof(optarg); break; default: exit(1); } } // validate input if (BT <= 0.0f || BT >= 1.0f) { fprintf(stderr,"error: %s, bandwidth-time product must be in (0,1)\n", argv[0]); exit(1); } // derived values unsigned int num_symbols = num_data_symbols + 2*m; unsigned int num_samples = k*num_symbols; float nstd = powf(10.0f,-SNRdB/20.0f); // noise standard deviation // create modulator gmskmod mod = gmskmod_create(k, m, BT); gmskmod_print(mod); // create demodulator gmskdem demod = gmskdem_create(k, m, BT); gmskdem_set_eq_bw(demod, 0.01f); gmskdem_print(demod); unsigned int i; unsigned int s[num_symbols]; float complex x[num_samples]; float complex y[num_samples]; unsigned int sym_out[num_symbols]; // generate random data sequence for (i=0; i<num_symbols; i++) s[i] = rand() % 2; // modulate signal for (i=0; i<num_symbols; i++) gmskmod_modulate(mod, s[i], &x[k*i]); // add channel impairments for (i=0; i<num_samples; i++) { y[i] = x[i]*cexpf(_Complex_I*(phi + i*dphi)); y[i] += nstd*(randnf() + _Complex_I*randnf())*M_SQRT1_2; } // demodulate signal for (i=0; i<num_symbols; i++) gmskdem_demodulate(demod, &y[k*i], &sym_out[i]); // destroy modem objects gmskmod_destroy(mod); gmskdem_destroy(demod); // print results to screen unsigned int delay = 2*m; unsigned int num_errors=0; for (i=delay; i<num_symbols; i++) { //printf(" %4u : %2u (%2u)\n", i, s[i-delay], sym_out[i]); num_errors += (s[i-delay] == sym_out[i]) ? 0 : 1; } printf("symbol errors : %4u / %4u\n", num_errors, num_data_symbols); // write results to output file FILE * fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s : auto-generated file\n", OUTPUT_FILENAME); fprintf(fid,"clear all\n"); fprintf(fid,"close all\n"); fprintf(fid,"k = %u;\n", k); fprintf(fid,"m = %u;\n", m); fprintf(fid,"BT = %f;\n", BT); fprintf(fid,"num_symbols = %u;\n", num_symbols); fprintf(fid,"num_samples = %u;\n", num_samples); fprintf(fid,"x = zeros(1,num_samples);\n"); fprintf(fid,"y = zeros(1,num_samples);\n"); for (i=0; i<num_samples; i++) { fprintf(fid,"x(%4u) = %12.8f + j*%12.8f;\n", i+1, crealf(x[i]), cimagf(x[i])); fprintf(fid,"y(%4u) = %12.8f + j*%12.8f;\n", i+1, crealf(y[i]), cimagf(y[i])); } fprintf(fid,"t=[0:(num_samples-1)]/k;\n"); fprintf(fid,"figure;\n"); fprintf(fid,"plot(t,real(y),t,imag(y));\n"); // artificially demodulate (generate receive filter, etc.) float hr[2*k*m+1]; liquid_firdes_gmskrx(k,m,BT,0,hr); for (i=0; i<2*k*m+1; i++) fprintf(fid,"hr(%3u) = %12.8f;\n", i+1, hr[i]); fprintf(fid,"z = filter(hr,1,arg( ([y(2:end) 0]).*conj(y) ))/k;\n"); fprintf(fid,"figure;\n"); fprintf(fid,"plot(t,z,t(k:k:end),z(k:k:end),'or');\n"); fprintf(fid,"grid on;\n"); fclose(fid); printf("results written to '%s'\n", OUTPUT_FILENAME); return 0; }
// create GMSK frame synchronizer // _callback : callback function // _userdata : user data pointer passed to callback function gmskframesync gmskframesync_create(framesync_callback _callback, void * _userdata) { gmskframesync q = (gmskframesync) malloc(sizeof(struct gmskframesync_s)); q->callback = _callback; q->userdata = _userdata; q->k = 2; // samples/symbol q->m = 3; // filter delay (symbols) q->BT = 0.5f; // filter bandwidth-time product #if GMSKFRAMESYNC_PREFILTER // create default low-pass Butterworth filter q->prefilter = iirfilt_crcf_create_lowpass(3, 0.5f*(1 + q->BT) / (float)(q->k)); #endif unsigned int i; // frame detector q->preamble_len = 63; q->preamble_pn = (float*)malloc(q->preamble_len*sizeof(float)); q->preamble_rx = (float*)malloc(q->preamble_len*sizeof(float)); float complex preamble_samples[q->preamble_len*q->k]; msequence ms = msequence_create(6, 0x6d, 1); gmskmod mod = gmskmod_create(q->k, q->m, q->BT); for (i=0; i<q->preamble_len + q->m; i++) { unsigned char bit = msequence_advance(ms); // save p/n sequence if (i < q->preamble_len) q->preamble_pn[i] = bit ? 1.0f : -1.0f; // modulate/interpolate if (i < q->m) gmskmod_modulate(mod, bit, &preamble_samples[0]); else gmskmod_modulate(mod, bit, &preamble_samples[(i-q->m)*q->k]); } gmskmod_destroy(mod); msequence_destroy(ms); #if 0 // print sequence for (i=0; i<q->preamble_len*q->k; i++) printf("preamble(%3u) = %12.8f + j*%12.8f;\n", i+1, crealf(preamble_samples[i]), cimagf(preamble_samples[i])); #endif // create frame detector float threshold = 0.5f; // detection threshold float dphi_max = 0.05f; // maximum carrier offset allowable q->frame_detector = detector_cccf_create(preamble_samples, q->preamble_len*q->k, threshold, dphi_max); q->buffer = windowcf_create(q->k*(q->preamble_len+q->m)); // create symbol timing recovery filters q->npfb = 32; // number of filters in the bank q->mf = firpfb_rrrf_create_rnyquist( LIQUID_FIRFILT_GMSKRX,q->npfb,q->k,q->m,q->BT); q->dmf = firpfb_rrrf_create_drnyquist(LIQUID_FIRFILT_GMSKRX,q->npfb,q->k,q->m,q->BT); // create down-coverters for carrier phase tracking q->nco_coarse = nco_crcf_create(LIQUID_NCO); // create/allocate header objects/arrays q->header_mod = (unsigned char*)malloc(GMSKFRAME_H_SYM*sizeof(unsigned char)); q->header_enc = (unsigned char*)malloc(GMSKFRAME_H_ENC*sizeof(unsigned char)); q->header_dec = (unsigned char*)malloc(GMSKFRAME_H_DEC*sizeof(unsigned char)); q->p_header = packetizer_create(GMSKFRAME_H_DEC, GMSKFRAME_H_CRC, GMSKFRAME_H_FEC, LIQUID_FEC_NONE); // create/allocate payload objects/arrays q->payload_dec_len = 1; q->check = LIQUID_CRC_32; q->fec0 = LIQUID_FEC_NONE; q->fec1 = LIQUID_FEC_NONE; q->p_payload = packetizer_create(q->payload_dec_len, q->check, q->fec0, q->fec1); q->payload_enc_len = packetizer_get_enc_msg_len(q->p_payload); q->payload_dec = (unsigned char*) malloc(q->payload_dec_len*sizeof(unsigned char)); q->payload_enc = (unsigned char*) malloc(q->payload_enc_len*sizeof(unsigned char)); #if DEBUG_GMSKFRAMESYNC // debugging structures q->debug_enabled = 0; q->debug_objects_created = 0; q->debug_x = NULL; q->debug_fi = NULL; q->debug_mf = NULL; q->debug_framesyms = NULL; #endif // reset synchronizer gmskframesync_reset(q); // return synchronizer object return q; }