int main() { // options unsigned int num_channels=6; // for now, must be even number unsigned int num_symbols=32; // num symbols unsigned int m=2; // ofdm/oqam symbol delay float beta = 0.99f; // excess bandwidth factor float dt = 0.0f; // timing offset (fractional sample) modulation_scheme ms = LIQUID_MODEM_QAM4; // modulation scheme // number of frames (compensate for filter delay) unsigned int num_frames = num_symbols + 2*m; unsigned int num_samples = num_channels * num_frames; // create synthesizer/analyzer objects ofdmoqam cs = ofdmoqam_create(num_channels, m, beta, dt, LIQUID_SYNTHESIZER,0); ofdmoqam ca = ofdmoqam_create(num_channels, m, beta, dt, LIQUID_ANALYZER,0); // modem modem mod = modem_create(ms); FILE*fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s: auto-generated file\n\n", OUTPUT_FILENAME); fprintf(fid,"clear all;\nclose all;\n\n"); fprintf(fid,"num_channels=%u;\n", num_channels); fprintf(fid,"num_symbols=%u;\n", num_symbols); fprintf(fid,"num_frames = %u;\n", num_frames); fprintf(fid,"num_samples = num_frames*num_channels;\n"); fprintf(fid,"X = zeros(%u,%u);\n", num_channels, num_frames); fprintf(fid,"y = zeros(1,%u);\n", num_samples); fprintf(fid,"Y = zeros(%u,%u);\n", num_channels, num_frames); unsigned int i, j, n=0; unsigned int s[num_symbols][num_channels]; float complex X[num_channels]; // channelized symbols float complex y[num_channels]; // interpolated time-domain samples float complex Y[num_channels]; // received symbols // generate random symbols for (i=0; i<num_symbols; i++) { for (j=0; j<num_channels; j++) { s[i][j] = modem_gen_rand_sym(mod); } } for (i=0; i<num_frames; i++) { // generate frame data for (j=0; j<num_channels; j++) { if (i<num_symbols) { modem_modulate(mod,s[i][j],&X[j]); } else { X[j] = 0.0f; } } // execute synthesyzer ofdmoqam_execute(cs, X, y); // channel // execute analyzer ofdmoqam_execute(ca, y, Y); // write output to file for (j=0; j<num_channels; j++) { // frequency data fprintf(fid,"X(%4u,%4u) = %12.4e + j*%12.4e;\n", j+1, i+1, crealf(X[j]), cimagf(X[j])); // time data fprintf(fid,"y(%4u) = %12.4e + j*%12.4e;\n", n+1, crealf(y[j]), cimag(y[j])); // received data fprintf(fid,"Y(%4u,%4u) = %12.4e + j*%12.4e;\n", j+1, i+1, crealf(Y[j]), cimagf(Y[j])); n++; } } // print results fprintf(fid,"\n\n"); fprintf(fid,"X0 = X(:,1:%u);\n", num_symbols); fprintf(fid,"Y0 = Y(:,%u:%u);\n", 2*m+1, num_symbols + 2*m); fprintf(fid,"for i=1:num_channels,\n"); fprintf(fid," figure;\n"); fprintf(fid," subplot(2,1,1);\n"); fprintf(fid," plot(1:num_symbols,real(X0(i,:)),'-x',1:num_symbols,real(Y0(i,:)),'-x');\n"); fprintf(fid," ylabel('Re');\n"); fprintf(fid," title(['channel ' num2str(i-1)]);\n"); fprintf(fid," subplot(2,1,2);\n"); fprintf(fid," plot(1:num_symbols,imag(X0(i,:)),'-x',1:num_symbols,imag(Y0(i,:)),'-x');\n"); fprintf(fid," ylabel('Im');\n"); fprintf(fid," pause(0.2);\n"); fprintf(fid,"end;\n"); // print results fprintf(fid,"\n\n"); fprintf(fid,"t = 0:(num_samples-1);\n"); fprintf(fid," figure;\n"); fprintf(fid," plot(t,real(y),'-', t,imag(y),'-');\n"); fprintf(fid," xlabel('time');\n"); fprintf(fid," ylabel('signal');\n"); fclose(fid); printf("results written to %s\n", OUTPUT_FILENAME); // destroy objects ofdmoqam_destroy(cs); ofdmoqam_destroy(ca); modem_destroy(mod); printf("done.\n"); return 0; }
int main() { // options unsigned int num_channels=64; // must be even number unsigned int num_symbols=16; // number of symbols unsigned int m=3; // filter delay (symbols) float beta = 0.9f; // filter excess bandwidth factor float phi = 0.0f; // carrier phase offset; float dphi = 0.04f; // carrier frequency offset // number of frames (compensate for filter delay) unsigned int num_frames = num_symbols + 2*m; unsigned int num_samples = num_channels * num_frames; unsigned int i; unsigned int j; // create filter prototype unsigned int h_len = 2*num_channels*m + 1; float h[h_len]; float complex hc[h_len]; float complex gc[h_len]; liquid_firdes_rkaiser(num_channels, m, beta, 0.0f, h); unsigned int g_len = 2*num_channels*m; for (i=0; i<g_len; i++) { hc[i] = h[i]; gc[i] = h[g_len-i-1] * cexpf(_Complex_I*dphi*i); } // data arrays float complex s[num_channels]; // input symbols float complex y[num_samples]; // time-domain samples float complex Y0[num_frames][num_channels]; // channelized output float complex Y1[num_frames][num_channels]; // channelized output // create ofdm/oqam generator object and generate data ofdmoqam qs = ofdmoqam_create(num_channels, m, beta, 0.0f, LIQUID_SYNTHESIZER, 0); for (i=0; i<num_frames; i++) { for (j=0; j<num_channels; j++) { if (i<num_symbols) { #if 0 // QPSK on all subcarriers s[j] = (rand() % 2 ? 1.0f : -1.0f) + (rand() % 2 ? 1.0f : -1.0f) * _Complex_I; s[j] *= 1.0f / sqrtf(2.0f); #else // BPSK on even subcarriers s[j] = rand() % 2 ? 1.0f : -1.0f; s[j] *= (j%2)==0 ? 1.0f : 0.0f; #endif } else { s[j] = 0.0f; } } // run synthesizer ofdmoqam_execute(qs, s, &y[i*num_channels]); } ofdmoqam_destroy(qs); // channel for (i=0; i<num_samples; i++) y[i] *= cexpf(_Complex_I*(phi + dphi*i)); // // analysis filterbank (receiver) // // create filterbank manually dotprod_cccf dp[num_channels]; // vector dot products windowcf w[num_channels]; // window buffers #if DEBUG // print coefficients printf("h_prototype:\n"); for (i=0; i<h_len; i++) printf(" h[%3u] = %12.8f\n", i, h[i]); #endif // create objects unsigned int gc_sub_len = 2*m; float complex gc_sub[gc_sub_len]; for (i=0; i<num_channels; i++) { // sub-sample prototype filter, loading coefficients in // reverse order #if 0 for (j=0; j<gc_sub_len; j++) gc_sub[j] = h[j*num_channels+i]; #else for (j=0; j<gc_sub_len; j++) gc_sub[gc_sub_len-j-1] = gc[j*num_channels+i]; #endif // create window buffer and dotprod objects dp[i] = dotprod_cccf_create(gc_sub, gc_sub_len); w[i] = windowcf_create(gc_sub_len); #if DEBUG printf("gc_sub[%u] : \n", i); for (j=0; j<gc_sub_len; j++) printf(" g[%3u] = %12.8f + %12.8f\n", j, crealf(gc_sub[j]), cimagf(gc_sub[j])); #endif } // generate DFT object float complex x[num_channels]; // time-domain buffer float complex X[num_channels]; // freq-domain buffer #if 0 fftplan fft = fft_create_plan(num_channels, X, x, FFT_REVERSE, 0); #else fftplan fft = fft_create_plan(num_channels, X, x, FFT_FORWARD, 0); #endif // // run analysis filter bank // #if 0 unsigned int filter_index = 0; #else unsigned int filter_index = num_channels-1; #endif float complex y_hat; // input sample float complex * r; // read pointer for (i=0; i<num_frames; i++) { // load buffers for (j=0; j<num_channels; j++) { // grab sample y_hat = y[i*num_channels + j]; // push sample into buffer at filter index windowcf_push(w[filter_index], y_hat); // decrement filter index filter_index = (filter_index + num_channels - 1) % num_channels; //filter_index = (filter_index + 1) % num_channels; } // execute filter outputs, reversing order of output (not // sure why this is necessary) for (j=0; j<num_channels; j++) { windowcf_read(w[j], &r); dotprod_cccf_execute(dp[j], r, &X[num_channels-j-1]); } #if 1 // compensate for carrier frequency offset (before transform) for (j=0; j<num_channels; j++) { X[j] *= cexpf(-_Complex_I*(dphi*i*num_channels)); } #endif // execute DFT, store result in buffer 'x' fft_execute(fft); #if 0 // compensate for carrier frequency offset (after transform) for (j=0; j<num_channels; j++) { x[j] *= cexpf(-_Complex_I*(dphi*i*num_channels)); } #endif // move to output array for (j=0; j<num_channels; j++) Y0[i][j] = x[j]; } // destroy objects for (i=0; i<num_channels; i++) { dotprod_cccf_destroy(dp[i]); windowcf_destroy(w[i]); } fft_destroy_plan(fft); #if 0 // print filterbank channelizer printf("\n"); printf("filterbank channelizer:\n"); for (i=0; i<num_symbols; i++) { printf("%3u: ", i); for (j=0; j<num_channels; j++) { printf(" %8.5f+j%8.5f, ", crealf(Y0[i][j]), cimagf(Y0[i][j])); } printf("\n"); } #endif // // export data // FILE*fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s: auto-generated file\n\n", OUTPUT_FILENAME); fprintf(fid,"clear all;\nclose all;\n\n"); fprintf(fid,"num_channels=%u;\n", num_channels); fprintf(fid,"num_symbols=%u;\n", num_symbols); fprintf(fid,"num_frames = %u;\n", num_frames); fprintf(fid,"num_samples = num_frames*num_channels;\n"); fprintf(fid,"y = zeros(1,%u);\n", num_samples); fprintf(fid,"Y0 = zeros(%u,%u);\n", num_frames, num_channels); fprintf(fid,"Y1 = zeros(%u,%u);\n", num_frames, num_channels); for (i=0; i<num_frames; i++) { for (j=0; j<num_channels; j++) { fprintf(fid,"Y0(%4u,%4u) = %12.4e + j*%12.4e;\n", i+1, j+1, crealf(Y0[i][j]), cimagf(Y0[i][j])); fprintf(fid,"Y1(%4u,%4u) = %12.4e + j*%12.4e;\n", i+1, j+1, crealf(Y1[i][j]), cimagf(Y1[i][j])); } } // plot BPSK results fprintf(fid,"figure;\n"); fprintf(fid,"plot(Y0(:,1:2:end),'x');\n"); fprintf(fid,"axis([-1 1 -1 1]*1.2*sqrt(num_channels));\n"); fprintf(fid,"axis square;\n"); fprintf(fid,"grid on;\n"); fclose(fid); printf("results written to '%s'\n", OUTPUT_FILENAME); printf("done.\n"); return 0; }
ofdmoqamframe64sync ofdmoqamframe64sync_create(unsigned int _m, float _beta, ofdmoqamframe64sync_callback _callback, void * _userdata) { ofdmoqamframe64sync q = (ofdmoqamframe64sync) malloc(sizeof(struct ofdmoqamframe64sync_s)); q->num_subcarriers = 64; // validate input if (_m < 1) { fprintf(stderr,"error: ofdmoqamframe64sync_create(), filter delay must be > 0\n"); exit(1); } else if (_beta < 0.0f) { fprintf(stderr,"error: ofdmoqamframe64sync_create(), filter excess bandwidth must be > 0\n"); exit(1); } q->m = _m; q->beta = _beta; // synchronizer parameters q->rxx_thresh = 0.60f; // auto-correlation threshold q->rxy_thresh = 0.60f; // cross-correlation threshold q->zeta = 64.0f/sqrtf(52.0f); // scaling factor // create analysis filter banks q->ca0 = firpfbch_create(q->num_subcarriers, q->m, q->beta, 0.0f /*dt*/,FIRPFBCH_ROOTNYQUIST,0/*gradient*/); q->ca1 = firpfbch_create(q->num_subcarriers, q->m, q->beta, 0.0f /*dt*/,FIRPFBCH_ROOTNYQUIST,0/*gradient*/); q->X0 = (float complex*) malloc((q->num_subcarriers)*sizeof(float complex)); q->X1 = (float complex*) malloc((q->num_subcarriers)*sizeof(float complex)); q->Y0 = (float complex*) malloc((q->num_subcarriers)*sizeof(float complex)); q->Y1 = (float complex*) malloc((q->num_subcarriers)*sizeof(float complex)); // allocate memory for PLCP arrays q->S0 = (float complex*) malloc((q->num_subcarriers)*sizeof(float complex)); q->S1 = (float complex*) malloc((q->num_subcarriers)*sizeof(float complex)); q->S2 = (float complex*) malloc((q->num_subcarriers)*sizeof(float complex)); ofdmoqamframe64_init_S0(q->S0); ofdmoqamframe64_init_S1(q->S1); ofdmoqamframe64_init_S2(q->S2); unsigned int i; for (i=0; i<q->num_subcarriers; i++) { q->S0[i] *= q->zeta; q->S1[i] *= q->zeta; q->S2[i] *= q->zeta; } q->S1a = (float complex*) malloc((q->num_subcarriers)*sizeof(float complex)); q->S1b = (float complex*) malloc((q->num_subcarriers)*sizeof(float complex)); // set pilot sequence q->ms_pilot = msequence_create_default(8); q->x_phase[0] = -21.0f; q->x_phase[1] = -7.0f; q->x_phase[2] = 7.0f; q->x_phase[3] = 21.0f; // create NCO for pilots q->nco_pilot = nco_crcf_create(LIQUID_VCO); q->pll_pilot = pll_create(); pll_set_bandwidth(q->pll_pilot,0.01f); pll_set_damping_factor(q->pll_pilot,4.0f); // create agc | signal detection object q->sigdet = agc_crcf_create(); agc_crcf_set_bandwidth(q->sigdet,0.1f); // create NCO for CFO compensation q->nco_rx = nco_crcf_create(LIQUID_VCO); // create auto-correlator objects q->autocorr_length = OFDMOQAMFRAME64SYNC_AUTOCORR_LEN; q->autocorr_delay = q->num_subcarriers / 4; q->autocorr = autocorr_cccf_create(q->autocorr_length, q->autocorr_delay); // create cross-correlator object q->hxy = (float complex*) malloc((q->num_subcarriers)*sizeof(float complex)); ofdmoqam cs = ofdmoqam_create(q->num_subcarriers,q->m,q->beta, 0.0f, // dt OFDMOQAM_SYNTHESIZER, 0); // gradient for (i=0; i<2*(q->m); i++) ofdmoqam_execute(cs,q->S1,q->hxy); // time reverse, complex conjugate (same as fftshift for // this particular sequence) memmove(q->X0, q->hxy, 64*sizeof(float complex)); for (i=0; i<64; i++) q->hxy[i] = conjf(q->X0[64-i-1]); // fftshift //fft_shift(q->hxy,64); q->crosscorr = firfilt_cccf_create(q->hxy, q->num_subcarriers); ofdmoqam_destroy(cs); // input buffer q->input_buffer = windowcf_create((q->num_subcarriers)); // gain q->g = 1.0f; q->G0 = (float complex*) malloc((q->num_subcarriers)*sizeof(float complex)); q->G1 = (float complex*) malloc((q->num_subcarriers)*sizeof(float complex)); q->G = (float complex*) malloc((q->num_subcarriers)*sizeof(float complex)); q->data = (float complex*) malloc((q->num_subcarriers)*sizeof(float complex)); // reset object ofdmoqamframe64sync_reset(q); #if DEBUG_OFDMOQAMFRAME64SYNC q->debug_x = windowcf_create(DEBUG_OFDMOQAMFRAME64SYNC_BUFFER_LEN); q->debug_rxx= windowcf_create(DEBUG_OFDMOQAMFRAME64SYNC_BUFFER_LEN); q->debug_rxy= windowcf_create(DEBUG_OFDMOQAMFRAME64SYNC_BUFFER_LEN); q->debug_framesyms= windowcf_create(DEBUG_OFDMOQAMFRAME64SYNC_BUFFER_LEN); q->debug_pilotphase= windowf_create(DEBUG_OFDMOQAMFRAME64SYNC_BUFFER_LEN); q->debug_pilotphase_hat= windowf_create(DEBUG_OFDMOQAMFRAME64SYNC_BUFFER_LEN); q->debug_rssi= windowf_create(DEBUG_OFDMOQAMFRAME64SYNC_BUFFER_LEN); #endif q->callback = _callback; q->userdata = _userdata; return q; }