diff --git a/matlab/tests/mimo_test.m b/matlab/tests/mimo_test.m new file mode 100644 index 000000000..1ee00d652 --- /dev/null +++ b/matlab/tests/mimo_test.m @@ -0,0 +1,84 @@ +clear + +addpath('../../debug/srslte/lib/mimo/test') + +Nt=1; +Nr=1; +Nl=1; +Ncw=1; +txscheme='Port0'; +codebook=0; +enb.NDLRB=6; + +Ns=enb.NDLRB*12*14; +enb.CyclicPrefix='Normal'; +enb.CellRefP=Nt; +enb.TotSubframes=1; + +cfg.Seed = 1; % Random channel seed +cfg.NRxAnts = Nr; % 1 receive antenna +cfg.DelayProfile = 'ETU'; % EVA delay spread +cfg.DopplerFreq = 100; % 120Hz Doppler frequency +cfg.MIMOCorrelation = 'Low'; % Low (no) MIMO correlation +cfg.InitTime = 0; % Initialize at time zero +cfg.NTerms = 16; % Oscillators used in fading model +cfg.ModelType = 'GMEDS'; % Rayleigh fading model type +cfg.InitPhase = 'Random'; % Random initial phases +cfg.NormalizePathGains = 'On'; % Normalize delay profile power +cfg.NormalizeTxAnts = 'On'; % Normalize for transmit antennas + +cec = struct('FreqWindow',9,'TimeWindow',9,'InterpType','cubic'); +cec.PilotAverage = 'UserDefined'; +cec.InterpWinSize = 1; +cec.InterpWindow = 'Causal'; + +sym = 2*rand(Ns*Nl,1)-1; + +layermap = lteLayerMap(sym, Nl, txscheme); +tx = lteDLPrecode(layermap, Nt, txscheme, codebook); + +tx_srs = srslte_precoder(sym, Nl, Nt, txscheme); + +err_tx=mean(abs(tx_srs-tx).^2) + +[txwaveform, info] = lteOFDMModulate(enb, reshape(tx,enb.NDLRB*12,[],Nt)); +cfg.SamplingRate = info.SamplingRate; + +rxwaveform = lteFadingChannel(cfg, txwaveform); + +rxGrid = lteOFDMDemodulate(enb, rxwaveform); +h=lteDLPerfectChannelEstimate(enb, cfg); + +hp=reshape(h,Ns,Nr,Nt); +rx=reshape(rxGrid,Ns,Nr); + +if (Nt > 1) + if (strcmp(txscheme,'TxDiversity')==1) + output_mat = lteTransmitDiversityDecode(rx, hp); + elseif (strcmp(txscheme,'CDD')==1 || strcmp(txscheme,'SpatialMux')==1) + pdsch.NLayers=Nl; + pdsch.RNTI=0; + pdsch.TxScheme=txscheme; + pdsch.PMISet=codebook; + pdsch.NCodewords=Ncw; + deprecoded = lteEqualizeMIMO(enb,pdsch,rx,hp,0); + out_cw = lteLayerDemap(pdsch,deprecoded); + output_mat = []; + for i=1:Ncw + output_mat = [output_mat out_cw{i}]; + end + else + error('Unsupported txscheme') + end +else + output_mat = lteEqualizeMMSE(rx, hp, 0); +end + +output_srs = srslte_predecoder(rx, hp, 0, txscheme); + +plot(abs(output_mat(:)-output_srs(:))) +mean(abs(output_mat(:)-output_srs(:)).^2) + +t=1:100; +plot(t,real(output_mat(t)),t,real(output_srs(t))) + diff --git a/srslte/examples/cell_measurement.c b/srslte/examples/cell_measurement.c index de9962513..8c9d95fe3 100644 --- a/srslte/examples/cell_measurement.c +++ b/srslte/examples/cell_measurement.c @@ -129,9 +129,10 @@ void sig_int_handler(int signo) } } -int srslte_rf_recv_wrapper(void *h, void *data, uint32_t nsamples, srslte_timestamp_t *q) { +int srslte_rf_recv_wrapper(void *h, cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *q) { DEBUG(" ---- Receive %d samples ---- \n", nsamples); - return srslte_rf_recv(h, data, nsamples, 1); + + return srslte_rf_recv(h, data[0], nsamples, 1); } enum receiver_state { DECODE_MIB, DECODE_SIB, MEASURE} state; @@ -141,7 +142,7 @@ enum receiver_state { DECODE_MIB, DECODE_SIB, MEASURE} state; int main(int argc, char **argv) { int ret; - cf_t *sf_buffer; + cf_t *sf_buffer[SRSLTE_MAX_PORTS] = {NULL, NULL}; prog_args_t prog_args; srslte_cell_t cell; int64_t sf_cnt; @@ -180,6 +181,8 @@ int main(int argc, char **argv) { } srslte_rf_set_rx_gain(&rf, 50); } + + sf_buffer[0] = srslte_vec_malloc(3*sizeof(cf_t)*SRSLTE_SF_LEN_PRB(100)); sigset_t sigset; sigemptyset(&sigset); @@ -198,7 +201,7 @@ int main(int argc, char **argv) { uint32_t ntrial=0; do { - ret = rf_search_and_decode_mib(&rf, &cell_detect_config, prog_args.force_N_id_2, &cell, &cfo); + ret = rf_search_and_decode_mib(&rf, 1, &cell_detect_config, prog_args.force_N_id_2, &cell, &cfo); if (ret < 0) { fprintf(stderr, "Error searching for cell\n"); exit(-1); @@ -234,11 +237,11 @@ int main(int argc, char **argv) { srslte_rf_stop_rx_stream(&rf); srslte_rf_flush_buffer(&rf); - if (srslte_ue_sync_init(&ue_sync, cell, srslte_rf_recv_wrapper, (void*) &rf)) { + if (srslte_ue_sync_init_multi(&ue_sync, cell, srslte_rf_recv_wrapper, 1, (void*) &rf)) { fprintf(stderr, "Error initiating ue_sync\n"); return -1; } - if (srslte_ue_dl_init(&ue_dl, cell)) { + if (srslte_ue_dl_init_multi(&ue_dl, cell, 1)) { fprintf(stderr, "Error initiating UE downlink processing module\n"); return -1; } @@ -280,7 +283,7 @@ int main(int argc, char **argv) { /* Main loop */ while ((sf_cnt < prog_args.nof_subframes || prog_args.nof_subframes == -1) && !go_exit) { - ret = srslte_ue_sync_get_buffer(&ue_sync, &sf_buffer); + ret = srslte_ue_sync_zerocopy_multi(&ue_sync, sf_buffer); if (ret < 0) { fprintf(stderr, "Error calling srslte_ue_sync_work()\n"); } @@ -292,7 +295,7 @@ int main(int argc, char **argv) { case DECODE_MIB: if (srslte_ue_sync_get_sfidx(&ue_sync) == 0) { srslte_pbch_decode_reset(&ue_mib.pbch); - n = srslte_ue_mib_decode(&ue_mib, sf_buffer, bch_payload, NULL, &sfn_offset); + n = srslte_ue_mib_decode(&ue_mib, sf_buffer[0], bch_payload, NULL, &sfn_offset); if (n < 0) { fprintf(stderr, "Error decoding UE MIB\n"); return -1; @@ -307,7 +310,7 @@ int main(int argc, char **argv) { case DECODE_SIB: /* We are looking for SI Blocks, search only in appropiate places */ if ((srslte_ue_sync_get_sfidx(&ue_sync) == 5 && (sfn%2)==0)) { - n = srslte_ue_dl_decode(&ue_dl, sf_buffer, data, sfn*10+srslte_ue_sync_get_sfidx(&ue_sync)); + n = srslte_ue_dl_decode_multi(&ue_dl, sf_buffer, data, sfn*10+srslte_ue_sync_get_sfidx(&ue_sync)); if (n < 0) { fprintf(stderr, "Error decoding UE DL\n");fflush(stdout); return -1; @@ -329,11 +332,11 @@ int main(int argc, char **argv) { if (srslte_ue_sync_get_sfidx(&ue_sync) == 5) { /* Run FFT for all subframe data */ - srslte_ofdm_rx_sf(&fft, sf_buffer, sf_symbols); + srslte_ofdm_rx_sf(&fft, sf_buffer[0], sf_symbols); srslte_chest_dl_estimate(&chest, sf_symbols, ce, srslte_ue_sync_get_sfidx(&ue_sync)); - rssi = SRSLTE_VEC_EMA(srslte_vec_avg_power_cf(sf_buffer,SRSLTE_SF_LEN(srslte_symbol_sz(cell.nof_prb))),rssi,0.05); + rssi = SRSLTE_VEC_EMA(srslte_vec_avg_power_cf(sf_buffer[0],SRSLTE_SF_LEN(srslte_symbol_sz(cell.nof_prb))),rssi,0.05); rssi_utra = SRSLTE_VEC_EMA(srslte_chest_dl_get_rssi(&chest),rssi_utra,0.05); rsrq = SRSLTE_VEC_EMA(srslte_chest_dl_get_rsrq(&chest),rsrq,0.05); rsrp = SRSLTE_VEC_EMA(srslte_chest_dl_get_rsrp(&chest),rsrp,0.05); diff --git a/srslte/examples/cell_search.c b/srslte/examples/cell_search.c index 02c3d8ada..fc684578a 100644 --- a/srslte/examples/cell_search.c +++ b/srslte/examples/cell_search.c @@ -120,9 +120,13 @@ void parse_args(int argc, char **argv) { } } -int srslte_rf_recv_wrapper(void *h, void *data, uint32_t nsamples, srslte_timestamp_t *t) { +int srslte_rf_recv_wrapper(void *h, cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *t) { DEBUG(" ---- Receive %d samples ---- \n", nsamples); - return srslte_rf_recv((srslte_rf_t*) h, data, nsamples, 1); + void *ptr[SRSLTE_MAX_PORTS]; + for (int i=0;ifile_offset_freq = 0; args->rf_args = ""; args->rf_freq = -1.0; + args->rf_nof_rx_ant = 1; #ifdef ENABLE_AGC_DEFAULT args->rf_gain = -1.0; #else @@ -128,6 +130,7 @@ void usage(prog_args_t *args, char *prog) { printf("Usage: %s [agpPoOcildDnruv] -f rx_frequency (in Hz) | -i input_file\n", prog); #ifndef DISABLE_RF printf("\t-a RF args [Default %s]\n", args->rf_args); + printf("\t-A Number of RX antennas [Default %d]\n", args->rf_nof_rx_ant); #ifdef ENABLE_AGC_DEFAULT printf("\t-g RF fix RX gain [Default AGC]\n"); #else @@ -163,7 +166,7 @@ void usage(prog_args_t *args, char *prog) { void parse_args(prog_args_t *args, int argc, char **argv) { int opt; args_default(args); - while ((opt = getopt(argc, argv, "aoglipPcOCtdDnvrfuUsS")) != -1) { + while ((opt = getopt(argc, argv, "aAoglipPcOCtdDnvrfuUsS")) != -1) { switch (opt) { case 'i': args->input_file_name = argv[optind]; @@ -186,6 +189,9 @@ void parse_args(prog_args_t *args, int argc, char **argv) { case 'a': args->rf_args = argv[optind]; break; + case 'A': + args->rf_nof_rx_ant = atoi(argv[optind]); + break; case 'g': args->rf_gain = atof(argv[optind]); break; @@ -252,10 +258,16 @@ void sig_int_handler(int signo) } } +cf_t *sf_buffer[2] = {NULL, NULL}; + #ifndef DISABLE_RF -int srslte_rf_recv_wrapper(void *h, void *data, uint32_t nsamples, srslte_timestamp_t *t) { +int srslte_rf_recv_wrapper(void *h, cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *t) { DEBUG(" ---- Receive %d samples ---- \n", nsamples); - return srslte_rf_recv(h, data, nsamples, 1); + void *ptr[SRSLTE_MAX_PORTS]; + for (int i=0;icell, port_id, input, q->pilot_recv_signal); @@ -331,41 +331,61 @@ int srslte_chest_dl_estimate_port(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, u /* Estimate noise power */ if (q->noise_alg == SRSLTE_NOISE_ALG_REFS && q->smooth_filter_len > 0) { - q->noise_estimate[port_id] = estimate_noise_pilots(q, port_id); + q->noise_estimate[rxant_id][port_id] = estimate_noise_pilots(q, port_id); } else if (q->noise_alg == SRSLTE_NOISE_ALG_PSS) { if (sf_idx == 0 || sf_idx == 5) { - q->noise_estimate[port_id] = estimate_noise_pss(q, input, ce); + q->noise_estimate[rxant_id][port_id] = estimate_noise_pss(q, input, ce); } } else { if (sf_idx == 0 || sf_idx == 5) { - q->noise_estimate[port_id] = estimate_noise_empty_sc(q, input); + q->noise_estimate[rxant_id][port_id] = estimate_noise_empty_sc(q, input); } } } /* Compute RSRP for the channel estimates in this port */ - q->rsrp[port_id] = srslte_vec_avg_power_cf(q->pilot_recv_signal, SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id)); + q->rsrp[rxant_id][port_id] = srslte_vec_avg_power_cf(q->pilot_recv_signal, SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id)); if (port_id == 0) { /* compute rssi only for port 0 */ - q->rssi[port_id] = srslte_chest_dl_rssi(q, input, port_id); + q->rssi[rxant_id][port_id] = srslte_chest_dl_rssi(q, input, port_id); } return 0; } +int srslte_chest_dl_estimate_multi(srslte_chest_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], uint32_t sf_idx, uint32_t nof_rx_antennas) +{ + for (uint32_t rxant_id=0;rxant_idcell.nof_ports;port_id++) { + if (srslte_chest_dl_estimate_port(q, input[rxant_id], ce[port_id][rxant_id], sf_idx, port_id, rxant_id)) { + return SRSLTE_ERROR; + } + } + } + q->last_nof_antennas = nof_rx_antennas; + return SRSLTE_SUCCESS; +} + int srslte_chest_dl_estimate(srslte_chest_dl_t *q, cf_t *input, cf_t *ce[SRSLTE_MAX_PORTS], uint32_t sf_idx) { uint32_t port_id; for (port_id=0;port_idcell.nof_ports;port_id++) { - srslte_chest_dl_estimate_port(q, input, ce[port_id], sf_idx, port_id); + if (srslte_chest_dl_estimate_port(q, input, ce[port_id], sf_idx, port_id, 0)) { + return SRSLTE_ERROR; + } } + q->last_nof_antennas = 1; return SRSLTE_SUCCESS; } float srslte_chest_dl_get_noise_estimate(srslte_chest_dl_t *q) { - return srslte_vec_acc_ff(q->noise_estimate, q->cell.nof_ports)/q->cell.nof_ports; + float n = 0; + for (int i=0;ilast_nof_antennas;i++) { + n += srslte_vec_acc_ff(q->noise_estimate[i], q->cell.nof_ports)/q->cell.nof_ports; + } + return n/q->last_nof_antennas; } float srslte_chest_dl_get_snr(srslte_chest_dl_t *q) { @@ -378,20 +398,31 @@ float srslte_chest_dl_get_snr(srslte_chest_dl_t *q) { } float srslte_chest_dl_get_rssi(srslte_chest_dl_t *q) { - return 4*q->rssi[0]/q->cell.nof_prb/SRSLTE_NRE; + float n = 0; + for (int i=0;ilast_nof_antennas;i++) { + n += 4*q->rssi[i][0]/q->cell.nof_prb/SRSLTE_NRE; + } + return n/q->last_nof_antennas; } /* q->rssi[0] is the average power in all RE in all symbol containing references for port 0 . q->rssi[0]/q->cell.nof_prb is the average power per PRB * q->rsrp[0] is the average power of RE containing references only (for port 0). */ float srslte_chest_dl_get_rsrq(srslte_chest_dl_t *q) { - return q->cell.nof_prb*q->rsrp[0] / q->rssi[0]; + float n = 0; + for (int i=0;ilast_nof_antennas;i++) { + n += q->cell.nof_prb*q->rsrp[i][0] / q->rssi[i][0]; + } + return n/q->last_nof_antennas; } -float srslte_chest_dl_get_rsrp(srslte_chest_dl_t *q) { - +float srslte_chest_dl_get_rsrp(srslte_chest_dl_t *q) { // return sum of power received from all tx ports - return srslte_vec_acc_ff(q->rsrp, q->cell.nof_ports); + float n = 0; + for (int i=0;ilast_nof_antennas;i++) { + n += srslte_vec_acc_ff(q->rsrp[i], q->cell.nof_ports)/q->cell.nof_ports; + } + return n/q->last_nof_antennas; } diff --git a/srslte/lib/ch_estimation/test/chest_test_dl.c b/srslte/lib/ch_estimation/test/chest_test_dl.c index d296ccc18..c60e94d96 100644 --- a/srslte/lib/ch_estimation/test/chest_test_dl.c +++ b/srslte/lib/ch_estimation/test/chest_test_dl.c @@ -161,7 +161,7 @@ int main(int argc, char **argv) { struct timeval t[3]; gettimeofday(&t[1], NULL); for (int j=0;j<100;j++) { - srslte_chest_dl_estimate_port(&est, input, ce, sf_idx, n_port); + srslte_chest_dl_estimate_port(&est, input, ce, sf_idx, n_port, 0); } gettimeofday(&t[2], NULL); get_time_interval(t); diff --git a/srslte/lib/mimo/layermap.c b/srslte/lib/mimo/layermap.c index d4bbd5787..1a9058658 100644 --- a/srslte/lib/mimo/layermap.c +++ b/srslte/lib/mimo/layermap.c @@ -117,6 +117,9 @@ int srslte_layermap_type(cf_t *d[SRSLTE_MAX_CODEWORDS], cf_t *x[SRSLTE_MAX_LAYER case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX: return srslte_layermap_multiplex(d, x, nof_cw, nof_layers, nof_symbols); break; + case SRSLTE_MIMO_TYPE_CDD: + fprintf(stderr, "CDD Not implemented\n"); + return -1; } return 0; } @@ -208,6 +211,9 @@ int srslte_layerdemap_type(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *d[SRSLTE_MAX_CODEWO case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX: return srslte_layerdemap_multiplex(x, d, nof_layers, nof_cw, nof_layer_symbols, nof_symbols); break; + case SRSLTE_MIMO_TYPE_CDD: + fprintf(stderr, "CDD Not implemented\n"); + return -1; } return 0; } diff --git a/srslte/lib/mimo/precoding.c b/srslte/lib/mimo/precoding.c index 6a6dab7ff..61f6d367a 100644 --- a/srslte/lib/mimo/precoding.c +++ b/srslte/lib/mimo/precoding.c @@ -37,13 +37,13 @@ #ifdef LV_HAVE_SSE #include #include -int srslte_predecoding_single_sse(cf_t *y, cf_t *h, cf_t *x, int nof_symbols, float noise_estimate); -int srslte_predecoding_diversity2_sse(cf_t *y, cf_t *h[SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS], int nof_symbols); +int srslte_predecoding_single_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS], cf_t *x, int nof_rxant, int nof_symbols, float noise_estimate); +int srslte_predecoding_diversity2_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS], int nof_rxant, int nof_symbols); #endif #ifdef LV_HAVE_AVX #include -int srslte_predecoding_single_avx(cf_t *y, cf_t *h, cf_t *x, int nof_symbols, float noise_estimate); +int srslte_predecoding_single_avx(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS], cf_t *x, int nof_rxant, int nof_symbols, float noise_estimate); #endif @@ -58,46 +58,82 @@ int srslte_predecoding_single_avx(cf_t *y, cf_t *h, cf_t *x, int nof_symbols, fl #define PROD(a,b) _mm_addsub_ps(_mm_mul_ps(a,_mm_moveldup_ps(b)),_mm_mul_ps(_mm_shuffle_ps(a,a,0xB1),_mm_movehdup_ps(b))) -int srslte_predecoding_single_sse(cf_t *y, cf_t *h, cf_t *x, int nof_symbols, float noise_estimate) { +int srslte_predecoding_single_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS], cf_t *x, int nof_rxant, int nof_symbols, float noise_estimate) { float *xPtr = (float*) x; - const float *hPtr = (const float*) h; - const float *yPtr = (const float*) y; + const float *hPtr1 = (const float*) h[0]; + const float *yPtr1 = (const float*) y[0]; + const float *hPtr2 = (const float*) h[1]; + const float *yPtr2 = (const float*) y[1]; __m128 conjugator = _mm_setr_ps(0, -0.f, 0, -0.f); __m128 noise = _mm_set1_ps(noise_estimate); - __m128 h1Val, h2Val, y1Val, y2Val, h12square, h1square, h2square, h1conj, h2conj, x1Val, x2Val; + __m128 h1Val1, h2Val1, y1Val1, y2Val1; + __m128 h1Val2, h2Val2, y1Val2, y2Val2; + __m128 hsquare, h1square, h2square, h1conj1, h2conj1, x1Val1, x2Val1; + __m128 hsquare2, h1conj2, h2conj2, x1Val2, x2Val2; + for (int i=0;i 0) { - h12square = _mm_add_ps(h12square, noise); + y1Val1 = _mm_load_ps(yPtr1); yPtr1+=4; + y2Val1 = _mm_load_ps(yPtr1); yPtr1+=4; + h1Val1 = _mm_load_ps(hPtr1); hPtr1+=4; + h2Val1 = _mm_load_ps(hPtr1); hPtr1+=4; + + if (nof_rxant == 2) { + y1Val2 = _mm_load_ps(yPtr2); yPtr2+=4; + y2Val2 = _mm_load_ps(yPtr2); yPtr2+=4; + h1Val2 = _mm_load_ps(hPtr2); hPtr2+=4; + h2Val2 = _mm_load_ps(hPtr2); hPtr2+=4; } - h1square = _mm_shuffle_ps(h12square, h12square, _MM_SHUFFLE(1, 1, 0, 0)); - h2square = _mm_shuffle_ps(h12square, h12square, _MM_SHUFFLE(3, 3, 2, 2)); + hsquare = _mm_hadd_ps(_mm_mul_ps(h1Val1, h1Val1), _mm_mul_ps(h2Val1, h2Val1)); + if (nof_rxant == 2) { + hsquare2 = _mm_hadd_ps(_mm_mul_ps(h1Val2, h1Val2), _mm_mul_ps(h2Val2, h2Val2)); + hsquare = _mm_add_ps(hsquare, hsquare2); + } + if (noise_estimate > 0) { + hsquare = _mm_add_ps(hsquare, noise); + } + + h1square = _mm_shuffle_ps(hsquare, hsquare, _MM_SHUFFLE(1, 1, 0, 0)); + h2square = _mm_shuffle_ps(hsquare, hsquare, _MM_SHUFFLE(3, 3, 2, 2)); /* Conjugate channel */ - h1conj = _mm_xor_ps(h1Val, conjugator); - h2conj = _mm_xor_ps(h2Val, conjugator); + h1conj1 = _mm_xor_ps(h1Val1, conjugator); + h2conj1 = _mm_xor_ps(h2Val1, conjugator); - /* Complex product */ - x1Val = PROD(y1Val, h1conj); - x2Val = PROD(y2Val, h2conj); - - x1Val = _mm_div_ps(x1Val, h1square); - x2Val = _mm_div_ps(x2Val, h2square); + if (nof_rxant == 2) { + h1conj2 = _mm_xor_ps(h1Val2, conjugator); + h2conj2 = _mm_xor_ps(h2Val2, conjugator); + } + + /* Complex product */ + x1Val1 = PROD(y1Val1, h1conj1); + x2Val1 = PROD(y2Val1, h2conj1); + + if (nof_rxant == 2) { + x1Val2 = PROD(y1Val2, h1conj2); + x2Val2 = PROD(y2Val2, h2conj2); + x1Val1 = _mm_add_ps(x1Val1, x1Val2); + x2Val1 = _mm_add_ps(x2Val1, x2Val2); + } + + x1Val1 = _mm_div_ps(x1Val1, h1square); + x2Val1 = _mm_div_ps(x2Val1, h2square); + + _mm_store_ps(xPtr, x1Val1); xPtr+=4; + _mm_store_ps(xPtr, x2Val1); xPtr+=4; - _mm_store_ps(xPtr, x1Val); xPtr+=4; - _mm_store_ps(xPtr, x2Val); xPtr+=4; } for (int i=8*(nof_symbols/8);i 0) { h12square = _mm256_add_ps(h12square, noise); } + h1_p = _mm256_permute_ps(h12square, _MM_SHUFFLE(1, 1, 0, 0)); h2_p = _mm256_permute_ps(h12square, _MM_SHUFFLE(3, 3, 2, 2)); h1square = _mm256_permute2f128_ps(h1_p, h2_p, 2<<4); h2square = _mm256_permute2f128_ps(h1_p, h2_p, 3<<4 | 1); /* Conjugate channel */ - h1conj = _mm256_xor_ps(h1Val, conjugator); - h2conj = _mm256_xor_ps(h2Val, conjugator); + h1conj1 = _mm256_xor_ps(h1Val1, conjugator); + h2conj1 = _mm256_xor_ps(h2Val1, conjugator); + if (nof_rxant == 2) { + h1conj2 = _mm256_xor_ps(h1Val2, conjugator); + h2conj2 = _mm256_xor_ps(h2Val2, conjugator); + } + /* Complex product */ - x1Val = PROD_AVX(y1Val, h1conj); - x2Val = PROD_AVX(y2Val, h2conj); + x1Val = PROD_AVX(y1Val1, h1conj1); + x2Val = PROD_AVX(y2Val1, h2conj1); + if (nof_rxant == 2) { + x1Val = _mm256_add_ps(x1Val, PROD_AVX(y1Val2, h1conj2)); + x2Val = _mm256_add_ps(x2Val, PROD_AVX(y2Val2, h2conj2)); + } + x1Val = _mm256_div_ps(x1Val, h1square); x2Val = _mm256_div_ps(x2Val, h2square); @@ -153,90 +217,143 @@ int srslte_predecoding_single_avx(cf_t *y, cf_t *h, cf_t *x, int nof_symbols, fl _mm256_store_ps(xPtr, x2Val); xPtr+=8; } for (int i=16*(nof_symbols/16);i 32 && nof_rxant <= 2) { + return srslte_predecoding_single_avx(y, h, x, nof_rxant, nof_symbols, noise_estimate); + } else { + return srslte_predecoding_single_gen(y, h, x, nof_rxant, nof_symbols, noise_estimate); + } +#else + #ifdef LV_HAVE_SSE + if (nof_symbols > 32 && nof_rxant <= 2) { + return srslte_predecoding_single_sse(y, h, x, nof_rxant, nof_symbols, noise_estimate); + } else { + return srslte_predecoding_single_gen(y, h, x, nof_rxant, nof_symbols, noise_estimate); + } + #else + return srslte_predecoding_single_gen(y, h, x, nof_rxant, nof_symbols, noise_estimate); + #endif +#endif +} + +/* ZF/MMSE SISO equalizer x=y(h'h+no)^(-1)h' (ZF if n0=0.0)*/ +int srslte_predecoding_single_multi(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS], cf_t *x, int nof_rxant, int nof_symbols, float noise_estimate) { #ifdef LV_HAVE_AVX if (nof_symbols > 32) { - return srslte_predecoding_single_avx(y, h, x, nof_symbols, noise_estimate); + return srslte_predecoding_single_avx(y, h, x, nof_rxant, nof_symbols, noise_estimate); } else { - return srslte_predecoding_single_gen(y, h, x, nof_symbols, noise_estimate); + return srslte_predecoding_single_gen(y, h, x, nof_rxant, nof_symbols, noise_estimate); } #else #ifdef LV_HAVE_SSE if (nof_symbols > 32) { - return srslte_predecoding_single_sse(y, h, x, nof_symbols, noise_estimate); + return srslte_predecoding_single_sse(y, h, x, nof_rxant, nof_symbols, noise_estimate); } else { - return srslte_predecoding_single_gen(y, h, x, nof_symbols, noise_estimate); + return srslte_predecoding_single_gen(y, h, x, nof_rxant, nof_symbols, noise_estimate); } #else - return srslte_predecoding_single_gen(y, h, x, nof_symbols, noise_estimate); + return srslte_predecoding_single_gen(y, h, x, nof_rxant, nof_symbols, noise_estimate); #endif #endif } /* C implementatino of the SFBC equalizer */ -int srslte_predecoding_diversity_gen_(cf_t *y, cf_t *h[SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS], - int nof_ports, int nof_symbols, int symbol_start) +int srslte_predecoding_diversity_gen_(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], + cf_t *x[SRSLTE_MAX_LAYERS], + int nof_rxant, int nof_ports, int nof_symbols, int symbol_start) { int i; if (nof_ports == 2) { cf_t h00, h01, h10, h11, r0, r1; - float hh; for (i = symbol_start/2; i < nof_symbols / 2; i++) { - h00 = h[0][2 * i]; - h01 = h[0][2 * i+1]; - h10 = h[1][2 * i]; - h11 = h[1][2 * i+1]; - hh = crealf(h00) * crealf(h00) + cimagf(h00) * cimagf(h00) - + crealf(h11) * crealf(h11) + cimagf(h11) * cimagf(h11); - r0 = y[2 * i]; - r1 = y[2 * i + 1]; - if (hh == 0) { - hh = 1e-4; + float hh = 0; + cf_t x0 = 0; + cf_t x1 = 0; + for (int p=0;p 32 && nof_ports == 2) { + return srslte_predecoding_diversity2_sse(y, h, x, nof_rxant, nof_symbols); + } else { + return srslte_predecoding_diversity_gen(y, h, x, nof_rxant, nof_ports, nof_symbols); + } +#else + return srslte_predecoding_diversity_gen(y, h, x, nof_rxant, nof_ports, nof_symbols); +#endif +} + +int srslte_predecoding_diversity_multi(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS], + int nof_rxant, int nof_ports, int nof_symbols) { #ifdef LV_HAVE_SSE if (nof_symbols > 32 && nof_ports == 2) { - return srslte_predecoding_diversity2_sse(y, h, x, nof_symbols); + return srslte_predecoding_diversity2_sse(y, h, x, nof_rxant, nof_symbols); } else { - return srslte_predecoding_diversity_gen(y, h, x, nof_ports, nof_symbols); + return srslte_predecoding_diversity_gen(y, h, x, nof_rxant, nof_ports, nof_symbols); } #else - return srslte_predecoding_diversity_gen(y, h, x, nof_ports, nof_symbols); + return srslte_predecoding_diversity_gen(y, h, x, nof_rxant, nof_ports, nof_symbols); #endif } + /* 36.211 v10.3.0 Section 6.3.4 */ int srslte_predecoding_type(cf_t *y, cf_t *h[SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS], int nof_ports, int nof_layers, int nof_symbols, srslte_mimo_type_t type, float noise_estimate) { @@ -341,6 +532,9 @@ int srslte_predecoding_type(cf_t *y, cf_t *h[SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_M } switch (type) { + case SRSLTE_MIMO_TYPE_CDD: + fprintf(stderr, "CCD not supported\n"); + return -1; case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA: if (nof_ports == 1 && nof_layers == 1) { return srslte_predecoding_single(y, h[0], x[0], nof_symbols, noise_estimate); @@ -442,6 +636,9 @@ int srslte_precoding_type(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], } switch (type) { + case SRSLTE_MIMO_TYPE_CDD: + fprintf(stderr, "CCD not supported\n"); + return -1; case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA: if (nof_ports == 1 && nof_layers == 1) { return srslte_precoding_single(x[0], y[0], nof_symbols); diff --git a/srslte/lib/mimo/test/CMakeLists.txt b/srslte/lib/mimo/test/CMakeLists.txt index ad2120a88..c7925bff2 100644 --- a/srslte/lib/mimo/test/CMakeLists.txt +++ b/srslte/lib/mimo/test/CMakeLists.txt @@ -53,13 +53,12 @@ add_test(layermap_multiplex_28 layermap_test -n 1000 -m multiplex -c 2 -l 8) # LAYER MAPPING TEST ######################################################################## -add_executable(precoding_test precoding_test.c) +add_executable(precoding_test precoder_test.c) target_link_libraries(precoding_test srslte) add_test(precoding_single precoding_test -n 1000 -m single) add_test(precoding_diversity2 precoding_test -n 1000 -m diversity -l 2 -p 2) add_test(precoding_diversity4 precoding_test -n 1024 -m diversity -l 4 -p 4) - diff --git a/srslte/lib/mimo/test/precoder_mex.c b/srslte/lib/mimo/test/precoder_mex.c new file mode 100644 index 000000000..958f06262 --- /dev/null +++ b/srslte/lib/mimo/test/precoder_mex.c @@ -0,0 +1,128 @@ +/** + * + * \section COPYRIGHT + * +* Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsLTE library. + * + * srsLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#include +#include "srslte/srslte.h" +#include "srslte/mex/mexutils.h" + +/** MEX function to be called from MATLAB to test the predecoder + */ + +#define INPUT prhs[0] +#define NLAYERS prhs[1] +#define NPORTS prhs[2] +#define TXSCHEME prhs[3] +#define NOF_INPUTS 3 + + +void help() +{ + mexErrMsgTxt + ("[output] = srslte_decoder(input, NLayers, NCellRefP, TxScheme)\n\n"); +} + +/* the gateway function */ +void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) +{ + cf_t *input = NULL; + cf_t *output = NULL; + + if (nrhs < NOF_INPUTS) { + help(); + return; + } + + // Read input symbols + int nof_symbols = mexutils_read_cf(INPUT, &input); + if (nof_symbols < 0) { + mexErrMsgTxt("Error reading input\n"); + return; + } + uint32_t nof_layers = mxGetScalar(NLAYERS); + uint32_t nof_tx_ports = mxGetScalar(NPORTS); + uint32_t nof_codewords = 1; + + mexPrintf("nof_tx_ports=%d, nof_layers=%d, nof_symbols=%d\n", nof_tx_ports, nof_layers, nof_symbols); + + cf_t *y[SRSLTE_MAX_PORTS]; + cf_t *x[SRSLTE_MAX_LAYERS]; + cf_t *d[SRSLTE_MAX_CODEWORDS]; + + d[0] = input; // Single codeword supported only + + /* Allocate memory */ + for (int i = 0; i < nof_layers; i++) { + x[i] = srslte_vec_malloc(sizeof(cf_t)*nof_symbols/nof_layers); + } + + output = srslte_vec_malloc(sizeof(cf_t)*nof_symbols*nof_tx_ports/nof_layers); + for (int i=0;i= NOF_INPUTS) { + txscheme = mxArrayToString(TXSCHEME); + } + srslte_mimo_type_t type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA; + if (!strcmp(txscheme, "Port0")) { + type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA; + } else if (!strcmp(txscheme, "TxDiversity")) { + type = SRSLTE_MIMO_TYPE_TX_DIVERSITY; + } else if (!strcmp(txscheme, "CDD")) { + type = SRSLTE_MIMO_TYPE_CDD; + } else if (!strcmp(txscheme, "SpatialMux")) { + type = SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX; + } else { + mexPrintf("Unsupported TxScheme=%s\n", txscheme); + return; + } + int symbols_layers[SRSLTE_MAX_LAYERS]; + for (int i=0;i= 1) { + mexutils_write_cf(output, &plhs[0], nof_symbols/nof_layers, nof_tx_ports); + } + + if (input) { + free(input); + } + if (output) { + free(output); + } + for (int i=0;i= 2) { + nof_rx_ants = dims[1]; + } + // Read channel estimates - uint32_t nof_symbols2 = mexutils_read_cf(HEST, &hest); - if (nof_symbols < 0) { + if (mexutils_read_cf(HEST, &hest) < 0) { mexErrMsgTxt("Error reading hest\n"); return; } - if ((nof_symbols2 % nof_symbols) != 0) { - mexErrMsgTxt("Hest size must be multiple of input size\n"); - return; + dims = mxGetDimensions(HEST); + ndims = mxGetNumberOfDimensions(HEST); + + if (ndims == 3) { + nof_tx_ports = dims[2]; } - // Calculate number of ports - uint32_t nof_ports = nof_symbols2/nof_symbols; - cf_t *x[8]; - cf_t *h[4]; + mexPrintf("nof_tx_ports=%d, nof_rx_ants=%d, nof_symbols=%d\n", nof_tx_ports, nof_rx_ants, nof_symbols); + + // Read noise estimate + float noise_estimate = 0; + if (nrhs >= NOF_INPUTS) { + noise_estimate = mxGetScalar(NEST); + } + + cf_t *x[SRSLTE_MAX_LAYERS]; + cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; + cf_t *y[SRSLTE_MAX_PORTS]; + + for (int i=0;i 1) { + srslte_predecoding_diversity_multi(y, h, x, nof_rx_ants, nof_tx_ports, nof_symbols); + srslte_layerdemap_diversity(x, output, nof_tx_ports, nof_symbols / nof_tx_ports); + } else { + srslte_predecoding_single_multi(y, h[0], output, nof_rx_ants, nof_symbols, noise_estimate); } - srslte_predecoding_diversity(input, h, x, nof_ports, nof_symbols); - srslte_layerdemap_diversity(x, output, nof_ports, nof_symbols / nof_ports); - if (nlhs >= 1) { mexutils_write_cf(output, &plhs[0], nof_symbols, 1); @@ -105,7 +135,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) if (output) { free(output); } - for (i=0;i<8;i++) { + for (int i=0;icell = cell; q->regs = regs; q->nof_symbols = PCFICH_RE; + q->nof_rx_antennas = nof_rx_antennas; if (srslte_modem_table_lte(&q->mod, SRSLTE_MOD_QPSK)) { goto clean; @@ -145,21 +150,33 @@ int srslte_pcfich_cfi_encode(uint32_t cfi, uint8_t bits[PCFICH_CFI_LEN]) { } } +int srslte_pcfich_decode(srslte_pcfich_t *q, cf_t *sf_symbols, cf_t *ce[SRSLTE_MAX_PORTS], float noise_estimate, + uint32_t nsubframe, uint32_t *cfi, float *corr_result) +{ + cf_t *_sf_symbols[SRSLTE_MAX_PORTS]; + cf_t *_ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; + + _sf_symbols[0] = sf_symbols; + for (int i=0;icell.nof_ports;i++) { + _ce[i][0] = ce[i]; + } + return srslte_pcfich_decode_multi(q, _sf_symbols, _ce, noise_estimate, nsubframe, cfi, corr_result); +} + /* Decodes the PCFICH channel and saves the CFI in the cfi pointer. * * Returns 1 if successfully decoded the CFI, 0 if not and -1 on error */ -int srslte_pcfich_decode(srslte_pcfich_t *q, cf_t *slot_symbols, cf_t *ce[SRSLTE_MAX_PORTS], float noise_estimate, - uint32_t nsubframe, uint32_t *cfi, float *corr_result) +int srslte_pcfich_decode_multi(srslte_pcfich_t *q, cf_t *sf_symbols[SRSLTE_MAX_PORTS], cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], float noise_estimate, + uint32_t nsubframe, uint32_t *cfi, float *corr_result) { /* Set pointers for layermapping & precoding */ int i; cf_t *x[SRSLTE_MAX_LAYERS]; - cf_t *ce_precoding[SRSLTE_MAX_PORTS]; - + if (q != NULL && - slot_symbols != NULL && + sf_symbols != NULL && nsubframe < SRSLTE_NSUBFRAMES_X_FRAME) { @@ -167,34 +184,37 @@ int srslte_pcfich_decode(srslte_pcfich_t *q, cf_t *slot_symbols, cf_t *ce[SRSLTE for (i = 0; i < SRSLTE_MAX_PORTS; i++) { x[i] = q->x[i]; } - for (i = 0; i < SRSLTE_MAX_PORTS; i++) { - ce_precoding[i] = q->ce[i]; - } - + + cf_t *q_symbols[SRSLTE_MAX_PORTS]; + cf_t *q_ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; + /* extract symbols */ - if (q->nof_symbols - != srslte_regs_pcfich_get(q->regs, slot_symbols, q->symbols[0])) { - fprintf(stderr, "There was an error getting the PCFICH symbols\n"); - return SRSLTE_ERROR; - } - - /* extract channel estimates */ - for (i = 0; i < q->cell.nof_ports; i++) { - if (q->nof_symbols != srslte_regs_pcfich_get(q->regs, ce[i], q->ce[i])) { + for (int j=0;jnof_rx_antennas;j++) { + if (q->nof_symbols + != srslte_regs_pcfich_get(q->regs, sf_symbols[j], q->symbols[j])) { fprintf(stderr, "There was an error getting the PCFICH symbols\n"); return SRSLTE_ERROR; } - } + q_symbols[j] = q->symbols[j]; + + /* extract channel estimates */ + for (i = 0; i < q->cell.nof_ports; i++) { + if (q->nof_symbols != srslte_regs_pcfich_get(q->regs, ce[i][j], q->ce[i][j])) { + fprintf(stderr, "There was an error getting the PCFICH symbols\n"); + return SRSLTE_ERROR; + } + q_ce[i][j] = q->ce[i][j]; + } + } + /* in control channels, only diversity is supported */ if (q->cell.nof_ports == 1) { /* no need for layer demapping */ - srslte_predecoding_single(q->symbols[0], q->ce[0], q->d, q->nof_symbols, noise_estimate); + srslte_predecoding_single_multi(q_symbols, q_ce[0], q->d, q->nof_rx_antennas, q->nof_symbols, noise_estimate); } else { - srslte_predecoding_diversity(q->symbols[0], ce_precoding, x, - q->cell.nof_ports, q->nof_symbols); - srslte_layerdemap_diversity(x, q->d, q->cell.nof_ports, - q->nof_symbols / q->cell.nof_ports); + srslte_predecoding_diversity_multi(q_symbols, q_ce, x, q->nof_rx_antennas, q->cell.nof_ports, q->nof_symbols); + srslte_layerdemap_diversity(x, q->d, q->cell.nof_ports, q->nof_symbols / q->cell.nof_ports); } /* demodulate symbols */ @@ -229,14 +249,14 @@ int srslte_pcfich_encode(srslte_pcfich_t *q, uint32_t cfi, cf_t *slot_symbols[SR /* Set pointers for layermapping & precoding */ cf_t *x[SRSLTE_MAX_LAYERS]; - cf_t *symbols_precoding[SRSLTE_MAX_PORTS]; + cf_t *q_symbols[SRSLTE_MAX_PORTS]; /* number of layers equals number of ports */ for (i = 0; i < q->cell.nof_ports; i++) { x[i] = q->x[i]; } for (i = 0; i < SRSLTE_MAX_PORTS; i++) { - symbols_precoding[i] = q->symbols[i]; + q_symbols[i] = q->symbols[i]; } /* pack CFI */ @@ -250,8 +270,7 @@ int srslte_pcfich_encode(srslte_pcfich_t *q, uint32_t cfi, cf_t *slot_symbols[SR /* layer mapping & precoding */ if (q->cell.nof_ports > 1) { srslte_layermap_diversity(q->d, x, q->cell.nof_ports, q->nof_symbols); - srslte_precoding_diversity(x, symbols_precoding, q->cell.nof_ports, - q->nof_symbols / q->cell.nof_ports); + srslte_precoding_diversity(x, q_symbols, q->cell.nof_ports, q->nof_symbols / q->cell.nof_ports); } else { memcpy(q->symbols[0], q->d, q->nof_symbols * sizeof(cf_t)); } diff --git a/srslte/lib/phch/pdcch.c b/srslte/lib/phch/pdcch.c index 9cf610c01..702a5440f 100644 --- a/srslte/lib/phch/pdcch.c +++ b/srslte/lib/phch/pdcch.c @@ -62,8 +62,12 @@ float srslte_pdcch_coderate(uint32_t nof_bits, uint32_t l) { /** Initializes the PDCCH transmitter and receiver */ int srslte_pdcch_init(srslte_pdcch_t *q, srslte_regs_t *regs, srslte_cell_t cell) { + return srslte_pdcch_init_multi(q, regs, cell, 1); +} + +int srslte_pdcch_init_multi(srslte_pdcch_t *q, srslte_regs_t *regs, srslte_cell_t cell, uint32_t nof_rx_antennas) +{ int ret = SRSLTE_ERROR_INVALID_INPUTS; - uint32_t i; if (q != NULL && regs != NULL && @@ -73,6 +77,7 @@ int srslte_pdcch_init(srslte_pdcch_t *q, srslte_regs_t *regs, srslte_cell_t cell bzero(q, sizeof(srslte_pdcch_t)); q->cell = cell; q->regs = regs; + q->nof_rx_antennas = nof_rx_antennas; /* Allocate memory for the maximum number of PDCCH bits (CFI=3) */ q->max_bits = (srslte_regs_pdcch_nregs(q->regs, 3) / 9) * 72; @@ -87,7 +92,7 @@ int srslte_pdcch_init(srslte_pdcch_t *q, srslte_regs_t *regs, srslte_cell_t cell goto clean; } - for (i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) { + for (int i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) { // we need to pregenerate the sequence for the maximum number of bits, which is 8 times // the maximum number of REGs (for CFI=3) if (srslte_sequence_pdcch(&q->seq[i], 2 * i, q->cell.id, 8*srslte_regs_pdcch_nregs(q->regs, 3))) { @@ -117,17 +122,21 @@ int srslte_pdcch_init(srslte_pdcch_t *q, srslte_regs_t *regs, srslte_cell_t cell goto clean; } - for (i = 0; i < SRSLTE_MAX_PORTS; i++) { - q->ce[i] = srslte_vec_malloc(sizeof(cf_t) * q->max_bits / 2); - if (!q->ce[i]) { - goto clean; + for (int i = 0; i < SRSLTE_MAX_PORTS; i++) { + for (int j=0;jnof_rx_antennas;j++) { + q->ce[i][j] = srslte_vec_malloc(sizeof(cf_t) * q->max_bits / 2); + if (!q->ce[i][j]) { + goto clean; + } } q->x[i] = srslte_vec_malloc(sizeof(cf_t) * q->max_bits / 2); if (!q->x[i]) { goto clean; } - q->symbols[i] = srslte_vec_malloc(sizeof(cf_t) * q->max_bits / 2); - if (!q->symbols[i]) { + } + for (int j=0;jnof_rx_antennas;j++) { + q->symbols[j] = srslte_vec_malloc(sizeof(cf_t) * q->max_bits / 2); + if (!q->symbols[j]) { goto clean; } } @@ -142,7 +151,6 @@ int srslte_pdcch_init(srslte_pdcch_t *q, srslte_regs_t *regs, srslte_cell_t cell } void srslte_pdcch_free(srslte_pdcch_t *q) { - int i; if (q->e) { free(q->e); @@ -153,19 +161,22 @@ void srslte_pdcch_free(srslte_pdcch_t *q) { if (q->d) { free(q->d); } - for (i = 0; i < SRSLTE_MAX_PORTS; i++) { - if (q->ce[i]) { - free(q->ce[i]); + for (int i = 0; i < SRSLTE_MAX_PORTS; i++) { + for (int j=0;jnof_rx_antennas;j++) { + if (q->ce[i][j]) { + free(q->ce[i][j]); + } } if (q->x[i]) { free(q->x[i]); } - if (q->symbols[i]) { - free(q->symbols[i]); + } + for (int j=0;jnof_rx_antennas;j++) { + if (q->symbols[j]) { + free(q->symbols[j]); } } - - for (i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) { + for (int i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) { srslte_sequence_free(&q->seq[i]); } @@ -379,13 +390,27 @@ int srslte_pdcch_decode_msg(srslte_pdcch_t *q, int cnt=0; +int srslte_pdcch_extract_llr(srslte_pdcch_t *q, cf_t *sf_symbols, cf_t *ce[SRSLTE_MAX_PORTS], float noise_estimate, + uint32_t nsubframe, uint32_t cfi) +{ + cf_t *_sf_symbols[SRSLTE_MAX_PORTS]; + cf_t *_ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; + + _sf_symbols[0] = sf_symbols; + for (int i=0;icell.nof_ports;i++) { + _ce[i][0] = ce[i]; + } + return srslte_pdcch_extract_llr_multi(q, _sf_symbols, _ce, noise_estimate, nsubframe, cfi); +} + /** Extracts the LLRs from srslte_dci_location_t location of the subframe and stores them in the srslte_pdcch_t structure. * DCI messages can be extracted from this location calling the function srslte_pdcch_decode_msg(). * Every time this function is called (with a different location), the last demodulated symbols are overwritten and * new messages from other locations can be decoded */ -int srslte_pdcch_extract_llr(srslte_pdcch_t *q, cf_t *sf_symbols, cf_t *ce[SRSLTE_MAX_PORTS], float noise_estimate, - uint32_t nsubframe, uint32_t cfi) { +int srslte_pdcch_extract_llr_multi(srslte_pdcch_t *q, cf_t *sf_symbols[SRSLTE_MAX_PORTS], cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], float noise_estimate, + uint32_t nsubframe, uint32_t cfi) +{ int ret = SRSLTE_ERROR_INVALID_INPUTS; @@ -415,27 +440,29 @@ int srslte_pdcch_extract_llr(srslte_pdcch_t *q, cf_t *sf_symbols, cf_t *ce[SRSLT memset(&x[q->cell.nof_ports], 0, sizeof(cf_t*) * (SRSLTE_MAX_LAYERS - q->cell.nof_ports)); /* extract symbols */ - int n = srslte_regs_pdcch_get(q->regs, sf_symbols, q->symbols[0]); - if (nof_symbols != n) { - fprintf(stderr, "Expected %d PDCCH symbols but got %d symbols\n", nof_symbols, n); - return ret; - } - - /* extract channel estimates */ - for (i = 0; i < q->cell.nof_ports; i++) { - n = srslte_regs_pdcch_get(q->regs, ce[i], q->ce[i]); + for (int j=0;jnof_rx_antennas;j++) { + int n = srslte_regs_pdcch_get(q->regs, sf_symbols[j], q->symbols[j]); if (nof_symbols != n) { fprintf(stderr, "Expected %d PDCCH symbols but got %d symbols\n", nof_symbols, n); return ret; } - } + /* extract channel estimates */ + for (i = 0; i < q->cell.nof_ports; i++) { + n = srslte_regs_pdcch_get(q->regs, ce[i][j], q->ce[i][j]); + if (nof_symbols != n) { + fprintf(stderr, "Expected %d PDCCH symbols but got %d symbols\n", nof_symbols, n); + return ret; + } + } + } + /* in control channels, only diversity is supported */ if (q->cell.nof_ports == 1) { /* no need for layer demapping */ - srslte_predecoding_single(q->symbols[0], q->ce[0], q->d, nof_symbols, noise_estimate/2); + srslte_predecoding_single_multi(q->symbols, q->ce[0], q->d, q->nof_rx_antennas, nof_symbols, noise_estimate/2); } else { - srslte_predecoding_diversity(q->symbols[0], q->ce, x, q->cell.nof_ports, nof_symbols); + srslte_predecoding_diversity_multi(q->symbols, q->ce, x, q->nof_rx_antennas, q->cell.nof_ports, nof_symbols); srslte_layerdemap_diversity(x, q->d, q->cell.nof_ports, nof_symbols / q->cell.nof_ports); } diff --git a/srslte/lib/phch/pdsch.c b/srslte/lib/phch/pdsch.c index b4ae7621f..9a2281753 100644 --- a/srslte/lib/phch/pdsch.c +++ b/srslte/lib/phch/pdsch.c @@ -202,13 +202,20 @@ int srslte_pdsch_get(srslte_pdsch_t *q, cf_t *sf_symbols, cf_t *symbols, return srslte_pdsch_cp(q, sf_symbols, symbols, grant, lstart, subframe, false); } +int srslte_pdsch_init(srslte_pdsch_t *q, srslte_cell_t cell) +{ + return srslte_pdsch_init_multi(q, cell, 1); +} + /** Initializes the PDCCH transmitter and receiver */ -int srslte_pdsch_init(srslte_pdsch_t *q, srslte_cell_t cell) { +int srslte_pdsch_init_multi(srslte_pdsch_t *q, srslte_cell_t cell, uint32_t nof_rx_antennas) +{ int ret = SRSLTE_ERROR_INVALID_INPUTS; int i; - if (q != NULL && - srslte_cell_isvalid(&cell)) + if (q != NULL && + srslte_cell_isvalid(&cell) && + nof_rx_antennas <= SRSLTE_MAX_PORTS) { bzero(q, sizeof(srslte_pdsch_t)); @@ -216,7 +223,8 @@ int srslte_pdsch_init(srslte_pdsch_t *q, srslte_cell_t cell) { q->cell = cell; q->max_re = q->cell.nof_prb * MAX_PDSCH_RE(q->cell.cp); - + q->nof_rx_antennas = nof_rx_antennas; + INFO("Init PDSCH: %d ports %d PRBs, max_symbols: %d\n", q->cell.nof_ports, q->cell.nof_prb, q->max_re); @@ -241,19 +249,23 @@ int srslte_pdsch_init(srslte_pdsch_t *q, srslte_cell_t cell) { } for (i = 0; i < q->cell.nof_ports; i++) { - q->ce[i] = srslte_vec_malloc(sizeof(cf_t) * q->max_re); - if (!q->ce[i]) { - goto clean; - } q->x[i] = srslte_vec_malloc(sizeof(cf_t) * q->max_re); if (!q->x[i]) { goto clean; } - q->symbols[i] = srslte_vec_malloc(sizeof(cf_t) * q->max_re); - if (!q->symbols[i]) { - goto clean; + for (int j=0;jnof_rx_antennas;j++) { + q->ce[i][j] = srslte_vec_malloc(sizeof(cf_t) * q->max_re); + if (!q->ce[i][j]) { + goto clean; + } } } + for (int j=0;jnof_rx_antennas;j++) { + q->symbols[j] = srslte_vec_malloc(sizeof(cf_t) * q->max_re); + if (!q->symbols[j]) { + goto clean; + } + } q->users = calloc(sizeof(srslte_pdsch_user_t*), 1+SRSLTE_SIRNTI); if (!q->users) { @@ -280,17 +292,20 @@ void srslte_pdsch_free(srslte_pdsch_t *q) { free(q->d); } for (i = 0; i < q->cell.nof_ports; i++) { - if (q->ce[i]) { - free(q->ce[i]); - } if (q->x[i]) { free(q->x[i]); } - if (q->symbols[i]) { - free(q->symbols[i]); + for (int j=0;jnof_rx_antennas;j++) { + if (q->ce[i][j]) { + free(q->ce[i][j]); + } } } - + for (int j=0;jnof_rx_antennas;j++) { + if (q->symbols[j]) { + free(q->symbols[j]); + } + } if (q->users) { for (uint16_t u=0;uusers[u]) { @@ -363,13 +378,28 @@ void srslte_pdsch_free_rnti(srslte_pdsch_t* q, uint16_t rnti) } } -/** Decodes the PDSCH from the received symbols - */ int srslte_pdsch_decode(srslte_pdsch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffer, cf_t *sf_symbols, cf_t *ce[SRSLTE_MAX_PORTS], float noise_estimate, uint16_t rnti, uint8_t *data) { + cf_t *_sf_symbols[SRSLTE_MAX_PORTS]; + cf_t *_ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; + + _sf_symbols[0] = sf_symbols; + for (int i=0;icell.nof_ports;i++) { + _ce[i][0] = ce[i]; + } + return srslte_pdsch_decode_multi(q, cfg, softbuffer, _sf_symbols, _ce, noise_estimate, rnti, data); +} + +/** Decodes the PDSCH from the received symbols + */ +int srslte_pdsch_decode_multi(srslte_pdsch_t *q, + srslte_pdsch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffer, + cf_t *sf_symbols[SRSLTE_MAX_PORTS], cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], float noise_estimate, + uint16_t rnti, uint8_t *data) +{ /* Set pointers for layermapping & precoding */ uint32_t i, n; @@ -391,31 +421,31 @@ int srslte_pdsch_decode(srslte_pdsch_t *q, } memset(&x[q->cell.nof_ports], 0, sizeof(cf_t*) * (SRSLTE_MAX_LAYERS - q->cell.nof_ports)); - /* extract symbols */ - n = srslte_pdsch_get(q, sf_symbols, q->symbols[0], &cfg->grant, cfg->nbits.lstart, cfg->sf_idx); - if (n != cfg->nbits.nof_re) { - fprintf(stderr, "Error expecting %d symbols but got %d\n", cfg->nbits.nof_re, n); - return SRSLTE_ERROR; - } - - /* extract channel estimates */ - for (i = 0; i < q->cell.nof_ports; i++) { - n = srslte_pdsch_get(q, ce[i], q->ce[i], &cfg->grant, cfg->nbits.lstart, cfg->sf_idx); + for (int j=0;jnof_rx_antennas;j++) { + /* extract symbols */ + n = srslte_pdsch_get(q, sf_symbols[j], q->symbols[j], &cfg->grant, cfg->nbits.lstart, cfg->sf_idx); if (n != cfg->nbits.nof_re) { fprintf(stderr, "Error expecting %d symbols but got %d\n", cfg->nbits.nof_re, n); return SRSLTE_ERROR; } + + /* extract channel estimates */ + for (i = 0; i < q->cell.nof_ports; i++) { + n = srslte_pdsch_get(q, ce[i][j], q->ce[i][j], &cfg->grant, cfg->nbits.lstart, cfg->sf_idx); + if (n != cfg->nbits.nof_re) { + fprintf(stderr, "Error expecting %d symbols but got %d\n", cfg->nbits.nof_re, n); + return SRSLTE_ERROR; + } + } } /* TODO: only diversity is supported */ if (q->cell.nof_ports == 1) { /* no need for layer demapping */ - srslte_predecoding_single(q->symbols[0], q->ce[0], q->d, cfg->nbits.nof_re, noise_estimate); + srslte_predecoding_single_multi(q->symbols, q->ce[0], q->d, q->nof_rx_antennas, cfg->nbits.nof_re, noise_estimate); } else { - srslte_predecoding_diversity(q->symbols[0], q->ce, x, q->cell.nof_ports, - cfg->nbits.nof_re); - srslte_layerdemap_diversity(x, q->d, q->cell.nof_ports, - cfg->nbits.nof_re / q->cell.nof_ports); + srslte_predecoding_diversity_multi(q->symbols, q->ce, x, q->nof_rx_antennas, q->cell.nof_ports, cfg->nbits.nof_re); + srslte_layerdemap_diversity(x, q->d, q->cell.nof_ports, cfg->nbits.nof_re / q->cell.nof_ports); } if (SRSLTE_VERBOSE_ISDEBUG()) { diff --git a/srslte/lib/phch/phich.c b/srslte/lib/phch/phich.c index ae5b6aa67..f7e6d7d29 100644 --- a/srslte/lib/phch/phich.c +++ b/srslte/lib/phch/phich.c @@ -67,8 +67,14 @@ void srslte_phich_reset(srslte_phich_t *q, cf_t *slot_symbols[SRSLTE_MAX_PORTS]) } } +int srslte_phich_init(srslte_phich_t *q, srslte_regs_t *regs, srslte_cell_t cell) +{ + return srslte_phich_init_multi(q, regs, cell, 1); +} + /** Initializes the phich channel receiver */ -int srslte_phich_init(srslte_phich_t *q, srslte_regs_t *regs, srslte_cell_t cell) { +int srslte_phich_init_multi(srslte_phich_t *q, srslte_regs_t *regs, srslte_cell_t cell, uint32_t nof_rx_antennas) +{ int ret = SRSLTE_ERROR_INVALID_INPUTS; if (q != NULL && @@ -81,6 +87,7 @@ int srslte_phich_init(srslte_phich_t *q, srslte_regs_t *regs, srslte_cell_t cell q->cell = cell; q->regs = regs; + q->nof_rx_antennas = nof_rx_antennas; if (srslte_modem_table_lte(&q->mod, SRSLTE_MOD_BPSK)) { goto clean; @@ -155,19 +162,32 @@ void srslte_phich_ack_encode(uint8_t ack, uint8_t bits[SRSLTE_PHICH_NBITS]) { memset(bits, ack, 3 * sizeof(uint8_t)); } +int srslte_phich_decode(srslte_phich_t *q, cf_t *sf_symbols, cf_t *ce[SRSLTE_MAX_PORTS], float noise_estimate, + uint32_t ngroup, uint32_t nseq, uint32_t subframe, uint8_t *ack, float *distance) +{ + cf_t *_sf_symbols[SRSLTE_MAX_PORTS]; + cf_t *_ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; + + _sf_symbols[0] = sf_symbols; + for (int i=0;icell.nof_ports;i++) { + _ce[i][0] = ce[i]; + } + + return srslte_phich_decode_multi(q, _sf_symbols, _ce, noise_estimate, ngroup, nseq, subframe, ack, distance); +} /* Decodes the phich channel and saves the CFI in the cfi pointer. * * Returns 1 if successfully decoded the CFI, 0 if not and -1 on error */ -int srslte_phich_decode(srslte_phich_t *q, cf_t *slot_symbols, cf_t *ce[SRSLTE_MAX_PORTS], float noise_estimate, - uint32_t ngroup, uint32_t nseq, uint32_t subframe, uint8_t *ack, float *distance) { +int srslte_phich_decode_multi(srslte_phich_t *q, cf_t *sf_symbols[SRSLTE_MAX_PORTS], cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], float noise_estimate, + uint32_t ngroup, uint32_t nseq, uint32_t subframe, uint8_t *ack, float *distance) +{ /* Set pointers for layermapping & precoding */ int i, j; cf_t *x[SRSLTE_MAX_LAYERS]; - cf_t *ce_precoding[SRSLTE_MAX_PORTS]; - if (q == NULL || slot_symbols == NULL) { + if (q == NULL || sf_symbols == NULL) { return SRSLTE_ERROR_INVALID_INPUTS; } @@ -198,34 +218,37 @@ int srslte_phich_decode(srslte_phich_t *q, cf_t *slot_symbols, cf_t *ce[SRSLTE_M for (i = 0; i < SRSLTE_MAX_PORTS; i++) { x[i] = q->x[i]; } - for (i = 0; i < SRSLTE_MAX_PORTS; i++) { - ce_precoding[i] = q->ce[i]; - } + cf_t *q_ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; + cf_t *q_sf_symbols[SRSLTE_MAX_PORTS]; + /* extract symbols */ - if (SRSLTE_PHICH_MAX_NSYMB - != srslte_regs_phich_get(q->regs, slot_symbols, q->symbols[0], ngroup)) { - fprintf(stderr, "There was an error getting the phich symbols\n"); - return SRSLTE_ERROR; - } - - /* extract channel estimates */ - for (i = 0; i < q->cell.nof_ports; i++) { - if (SRSLTE_PHICH_MAX_NSYMB != srslte_regs_phich_get(q->regs, ce[i], q->ce[i], ngroup)) { + for (int j=0;jnof_rx_antennas;j++) { + if (SRSLTE_PHICH_MAX_NSYMB + != srslte_regs_phich_get(q->regs, sf_symbols[j], q->sf_symbols[j], ngroup)) { fprintf(stderr, "There was an error getting the phich symbols\n"); return SRSLTE_ERROR; + } + q_sf_symbols[j] = q->sf_symbols[j]; + + /* extract channel estimates */ + for (i = 0; i < q->cell.nof_ports; i++) { + if (SRSLTE_PHICH_MAX_NSYMB != srslte_regs_phich_get(q->regs, ce[i][j], q->ce[i][j], ngroup)) { + fprintf(stderr, "There was an error getting the phich symbols\n"); + return SRSLTE_ERROR; + } + q_ce[i][j] = q->ce[i][j]; } + } /* in control channels, only diversity is supported */ if (q->cell.nof_ports == 1) { /* no need for layer demapping */ - srslte_predecoding_single(q->symbols[0], q->ce[0], q->d0, SRSLTE_PHICH_MAX_NSYMB, noise_estimate); + srslte_predecoding_single_multi(q_sf_symbols, q_ce[0], q->d0, q->nof_rx_antennas, SRSLTE_PHICH_MAX_NSYMB, noise_estimate); } else { - srslte_predecoding_diversity(q->symbols[0], ce_precoding, x, - q->cell.nof_ports, SRSLTE_PHICH_MAX_NSYMB); - srslte_layerdemap_diversity(x, q->d0, q->cell.nof_ports, - SRSLTE_PHICH_MAX_NSYMB / q->cell.nof_ports); + srslte_predecoding_diversity_multi(q_sf_symbols, q_ce, x, q->nof_rx_antennas, q->cell.nof_ports, SRSLTE_PHICH_MAX_NSYMB); + srslte_layerdemap_diversity(x, q->d0, q->cell.nof_ports, SRSLTE_PHICH_MAX_NSYMB / q->cell.nof_ports); } DEBUG("Recv!!: \n", 0); DEBUG("d0: ", 0); @@ -328,7 +351,7 @@ int srslte_phich_encode(srslte_phich_t *q, uint8_t ack, uint32_t ngroup, uint32_ x[i] = q->x[i]; } for (i = 0; i < SRSLTE_MAX_PORTS; i++) { - symbols_precoding[i] = q->symbols[i]; + symbols_precoding[i] = q->sf_symbols[i]; } /* encode ACK/NACK bit */ @@ -391,12 +414,12 @@ int srslte_phich_encode(srslte_phich_t *q, uint8_t ack, uint32_t ngroup, uint32_ SRSLTE_PHICH_MAX_NSYMB / q->cell.nof_ports); /**FIXME: According to 6.9.2, Precoding for 4 tx ports is different! */ } else { - memcpy(q->symbols[0], q->d0, SRSLTE_PHICH_MAX_NSYMB * sizeof(cf_t)); + memcpy(q->sf_symbols[0], q->d0, SRSLTE_PHICH_MAX_NSYMB * sizeof(cf_t)); } /* mapping to resource elements */ for (i = 0; i < q->cell.nof_ports; i++) { - if (srslte_regs_phich_add(q->regs, q->symbols[i], ngroup, slot_symbols[i]) + if (srslte_regs_phich_add(q->regs, q->sf_symbols[i], ngroup, slot_symbols[i]) < 0) { fprintf(stderr, "Error putting PCHICH resource elements\n"); return SRSLTE_ERROR; diff --git a/srslte/lib/phch/test/pdsch_pdcch_file_test.c b/srslte/lib/phch/test/pdsch_pdcch_file_test.c index 33ad2c58d..0d19d689e 100644 --- a/srslte/lib/phch/test/pdsch_pdcch_file_test.c +++ b/srslte/lib/phch/test/pdsch_pdcch_file_test.c @@ -137,7 +137,7 @@ int base_init() { exit(-1); } - if (srslte_ue_dl_init(&ue_dl, cell)) { + if (srslte_ue_dl_init_multi(&ue_dl, cell, 1)) { fprintf(stderr, "Error initializing UE DL\n"); return -1; } diff --git a/srslte/lib/phch/test/pdsch_test_mex.c b/srslte/lib/phch/test/pdsch_test_mex.c index 45bd1ae09..c2273916a 100644 --- a/srslte/lib/phch/test/pdsch_test_mex.c +++ b/srslte/lib/phch/test/pdsch_test_mex.c @@ -55,7 +55,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) srslte_ofdm_t ofdm_rx; srslte_pdsch_t pdsch; srslte_chest_dl_t chest; - cf_t *input_fft; + cf_t *input_fft[SRSLTE_MAX_PORTS]; srslte_pdsch_cfg_t cfg; srslte_softbuffer_rx_t softbuffer; uint32_t rnti32; @@ -92,8 +92,16 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) fprintf(stderr, "Error initializing FFT\n"); return; } - - if (srslte_pdsch_init(&pdsch, cell)) { + + + const size_t ndims = mxGetNumberOfDimensions(INPUT); + uint32_t nof_antennas = 1; + if (ndims >= 3) { + const mwSize *dims = mxGetDimensions(INPUT); + nof_antennas = dims[2]; + } + + if (srslte_pdsch_init_multi(&pdsch, cell, nof_antennas)) { mexErrMsgTxt("Error initiating PDSCH\n"); return; } @@ -188,18 +196,19 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) nof_retx = mexutils_getLength(INPUT); } - cf_t *ce[SRSLTE_MAX_PORTS]; - for (i=0;i= 6) { - mexutils_write_cf(ce[0], &plhs[5], SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp), 1); + uint32_t len = nof_antennas*cell.nof_ports*SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp); + cf_t *cearray_ptr = srslte_vec_malloc(len*sizeof(cf_t)); + int n=0; + for (i=0;irx_rate, meta.timestamp, secs, frac_secs); } + +int rf_blade_recv_with_time_multi(void *h, + void **data, + uint32_t nsamples, + bool blocking, + time_t *secs, + double *frac_secs) +{ + return rf_blade_recv_with_time(h, *data, nsamples, blocking, secs, frac_secs); +} + int rf_blade_recv_with_time(void *h, void *data, uint32_t nsamples, diff --git a/srslte/lib/rf/rf_blade_imp.h b/srslte/lib/rf/rf_blade_imp.h index 552564620..f40ee374e 100644 --- a/srslte/lib/rf/rf_blade_imp.h +++ b/srslte/lib/rf/rf_blade_imp.h @@ -33,6 +33,8 @@ SRSLTE_API int rf_blade_open(char *args, void **handler); +SRSLTE_API int rf_blade_open_multi(char *args, + void **handler, uint32_t nof_rx_antennas); SRSLTE_API char* rf_blade_devname(void *h); @@ -82,6 +84,13 @@ SRSLTE_API void rf_blade_register_error_handler(void *h, SRSLTE_API double rf_blade_set_rx_freq(void *h, double freq); +SRSLTE_API int rf_blade_recv_with_time_multi(void *h, + void **data, + uint32_t nsamples, + bool blocking, + time_t *secs, + double *frac_secs); + SRSLTE_API int rf_blade_recv_with_time(void *h, void *data, uint32_t nsamples, diff --git a/srslte/lib/rf/rf_dev.h b/srslte/lib/rf/rf_dev.h index 2dd65552c..293f158b1 100644 --- a/srslte/lib/rf/rf_dev.h +++ b/srslte/lib/rf/rf_dev.h @@ -38,6 +38,7 @@ typedef struct { void (*srslte_rf_suppress_stdout)(void *h); void (*srslte_rf_register_error_handler)(void *h, srslte_rf_error_handler_t error_handler); int (*srslte_rf_open)(char *args, void **h); + int (*srslte_rf_open_multi)(char *args, void **h, uint32_t nof_rx_antennas); int (*srslte_rf_close)(void *h); void (*srslte_rf_set_master_clock_rate)(void *h, double rate); bool (*srslte_rf_is_master_clock_dynamic)(void *h); @@ -52,6 +53,8 @@ typedef struct { void (*srslte_rf_get_time)(void *h, time_t *secs, double *frac_secs); int (*srslte_rf_recv_with_time)(void *h, void *data, uint32_t nsamples, bool blocking, time_t *secs,double *frac_secs); + int (*srslte_rf_recv_with_time_multi)(void *h, void **data, uint32_t nsamples, + bool blocking, time_t *secs,double *frac_secs); int (*srslte_rf_send_timed)(void *h, void *data, int nsamples, time_t secs, double frac_secs, bool has_time_spec, bool blocking, bool is_start_of_burst, bool is_end_of_burst); @@ -78,6 +81,7 @@ static rf_dev_t dev_uhd = { rf_uhd_suppress_stdout, rf_uhd_register_error_handler, rf_uhd_open, + rf_uhd_open_multi, rf_uhd_close, rf_uhd_set_master_clock_rate, rf_uhd_is_master_clock_dynamic, @@ -91,6 +95,7 @@ static rf_dev_t dev_uhd = { rf_uhd_set_tx_freq, rf_uhd_get_time, rf_uhd_recv_with_time, + rf_uhd_recv_with_time_multi, rf_uhd_send_timed, rf_uhd_set_tx_cal, rf_uhd_set_rx_cal @@ -114,6 +119,7 @@ static rf_dev_t dev_blade = { rf_blade_suppress_stdout, rf_blade_register_error_handler, rf_blade_open, + rf_blade_open_multi, rf_blade_close, rf_blade_set_master_clock_rate, rf_blade_is_master_clock_dynamic, @@ -127,6 +133,7 @@ static rf_dev_t dev_blade = { rf_blade_set_tx_freq, rf_blade_get_time, rf_blade_recv_with_time, + rf_blade_recv_with_time_multi, rf_blade_send_timed, rf_blade_set_tx_cal, rf_blade_set_rx_cal diff --git a/srslte/lib/rf/rf_imp.c b/srslte/lib/rf/rf_imp.c index fe93d0e93..eca353ffa 100644 --- a/srslte/lib/rf/rf_imp.c +++ b/srslte/lib/rf/rf_imp.c @@ -99,6 +99,10 @@ const char* srslte_rf_get_devname(srslte_rf_t *rf) { } int srslte_rf_open_devname(srslte_rf_t *rf, char *devname, char *args) { + return srslte_rf_open_devname_multi(rf, devname, args, 1); +} + +int srslte_rf_open_devname_multi(srslte_rf_t *rf, char *devname, char *args, uint32_t nof_rx_antennas) { /* Try to open the device if name is provided */ if (devname) { if (devname[0] != '\0') { @@ -106,7 +110,7 @@ int srslte_rf_open_devname(srslte_rf_t *rf, char *devname, char *args) { while(available_devices[i] != NULL) { if (!strcmp(available_devices[i]->name, devname)) { rf->dev = available_devices[i]; - return available_devices[i]->srslte_rf_open(args, &rf->handler); + return available_devices[i]->srslte_rf_open_multi(args, &rf->handler, nof_rx_antennas); } i++; } @@ -117,7 +121,7 @@ int srslte_rf_open_devname(srslte_rf_t *rf, char *devname, char *args) { /* If in auto mode or provided device not found, try to open in order of apperance in available_devices[] array */ int i=0; while(available_devices[i] != NULL) { - if (!available_devices[i]->srslte_rf_open(args, &rf->handler)) { + if (!available_devices[i]->srslte_rf_open_multi(args, &rf->handler, nof_rx_antennas)) { rf->dev = available_devices[i]; return 0; } @@ -182,7 +186,12 @@ void srslte_rf_register_error_handler(srslte_rf_t *rf, srslte_rf_error_handler_t int srslte_rf_open(srslte_rf_t *h, char *args) { - return srslte_rf_open_devname(h, NULL, args); + return srslte_rf_open_devname_multi(h, NULL, args, 1); +} + +int srslte_rf_open_multi(srslte_rf_t *h, char *args, uint32_t nof_rx_antennas) +{ + return srslte_rf_open_devname_multi(h, NULL, args, nof_rx_antennas); } int srslte_rf_close(srslte_rf_t *rf) @@ -231,6 +240,11 @@ int srslte_rf_recv(srslte_rf_t *rf, void *data, uint32_t nsamples, bool blocking return srslte_rf_recv_with_time(rf, data, nsamples, blocking, NULL, NULL); } +int srslte_rf_recv_multi(srslte_rf_t *rf, void **data, uint32_t nsamples, bool blocking) +{ + return srslte_rf_recv_with_time_multi(rf, data, nsamples, blocking, NULL, NULL); +} + int srslte_rf_recv_with_time(srslte_rf_t *rf, void *data, uint32_t nsamples, @@ -241,6 +255,16 @@ int srslte_rf_recv_with_time(srslte_rf_t *rf, return ((rf_dev_t*) rf->dev)->srslte_rf_recv_with_time(rf->handler, data, nsamples, blocking, secs, frac_secs); } +int srslte_rf_recv_with_time_multi(srslte_rf_t *rf, + void **data, + uint32_t nsamples, + bool blocking, + time_t *secs, + double *frac_secs) +{ + return ((rf_dev_t*) rf->dev)->srslte_rf_recv_with_time_multi(rf->handler, data, nsamples, blocking, secs, frac_secs); +} + double srslte_rf_set_tx_gain(srslte_rf_t *rf, double gain) { return ((rf_dev_t*) rf->dev)->srslte_rf_set_tx_gain(rf->handler, gain); diff --git a/srslte/lib/rf/rf_uhd_imp.c b/srslte/lib/rf/rf_uhd_imp.c index d936f4d18..f4e8671f8 100644 --- a/srslte/lib/rf/rf_uhd_imp.c +++ b/srslte/lib/rf/rf_uhd_imp.c @@ -51,6 +51,8 @@ typedef struct { bool dynamic_rate; bool has_rssi; uhd_sensor_value_handle rssi_value; + uint32_t nof_rx_channels; + int nof_tx_channels; } rf_uhd_handler_t; void suppress_handler(const char *x) @@ -204,9 +206,11 @@ int rf_uhd_stop_rx_stream(void *h) void rf_uhd_flush_buffer(void *h) { int n; - cf_t tmp[1024]; + cf_t tmp1[1024]; + cf_t tmp2[1024]; + void *data[2] = {tmp1, tmp2}; do { - n = rf_uhd_recv_with_time(h, tmp, 1024, 0, NULL, NULL); + n = rf_uhd_recv_with_time_multi(h, data, 1024, 0, NULL, NULL); } while (n > 0); } @@ -238,6 +242,11 @@ float rf_uhd_get_rssi(void *h) { } int rf_uhd_open(char *args, void **h) +{ + return rf_uhd_open_multi(args, h, 1); +} + +int rf_uhd_open_multi(char *args, void **h, uint32_t nof_rx_antennas) { if (h) { *h = NULL; @@ -318,14 +327,17 @@ int rf_uhd_open(char *args, void **h) if (!handler->devname) { handler->devname = "uhd_unknown"; } - size_t channel = 0; + size_t channel[4] = {0, 1, 2, 3}; uhd_stream_args_t stream_args = { .cpu_format = "fc32", .otw_format = "sc16", .args = "", - .channel_list = &channel, - .n_channels = 1 + .channel_list = channel, + .n_channels = nof_rx_antennas }; + + handler->nof_rx_channels = nof_rx_antennas; + handler->nof_tx_channels = 1; // Set external clock reference if (strstr(args, "clock=external")) { @@ -405,7 +417,9 @@ bool rf_uhd_is_master_clock_dynamic(void *h) { double rf_uhd_set_rx_srate(void *h, double freq) { rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h; - uhd_usrp_set_rx_rate(handler->usrp, freq, 0); + for (int i=0;inof_rx_channels;i++) { + uhd_usrp_set_rx_rate(handler->usrp, freq, i); + } uhd_usrp_get_rx_rate(handler->usrp, 0, &freq); return freq; } @@ -413,7 +427,9 @@ double rf_uhd_set_rx_srate(void *h, double freq) double rf_uhd_set_tx_srate(void *h, double freq) { rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h; - uhd_usrp_set_tx_rate(handler->usrp, freq, 0); + for (int i=0;inof_tx_channels;i++) { + uhd_usrp_set_tx_rate(handler->usrp, freq, i); + } uhd_usrp_get_tx_rate(handler->usrp, 0, &freq); handler->tx_rate = freq; return freq; @@ -422,7 +438,9 @@ double rf_uhd_set_tx_srate(void *h, double freq) double rf_uhd_set_rx_gain(void *h, double gain) { rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h; - uhd_usrp_set_rx_gain(handler->usrp, gain, 0, ""); + for (int i=0;inof_rx_channels;i++) { + uhd_usrp_set_rx_gain(handler->usrp, gain, i, ""); + } uhd_usrp_get_rx_gain(handler->usrp, 0, "", &gain); return gain; } @@ -430,7 +448,9 @@ double rf_uhd_set_rx_gain(void *h, double gain) double rf_uhd_set_tx_gain(void *h, double gain) { rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h; - uhd_usrp_set_tx_gain(handler->usrp, gain, 0, ""); + for (int i=0;inof_tx_channels;i++) { + uhd_usrp_set_tx_gain(handler->usrp, gain, i, ""); + } uhd_usrp_get_tx_gain(handler->usrp, 0, "", &gain); return gain; } @@ -460,7 +480,9 @@ double rf_uhd_set_rx_freq(void *h, double freq) }; uhd_tune_result_t tune_result; rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h; - uhd_usrp_set_rx_freq(handler->usrp, &tune_request, 0, &tune_result); + for (int i=0;inof_rx_channels;i++) { + uhd_usrp_set_rx_freq(handler->usrp, &tune_request, i, &tune_result); + } uhd_usrp_get_rx_freq(handler->usrp, 0, &freq); return freq; } @@ -474,7 +496,9 @@ double rf_uhd_set_tx_freq(void *h, double freq) }; uhd_tune_result_t tune_result; rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h; - uhd_usrp_set_tx_freq(handler->usrp, &tune_request, 0, &tune_result); + for (int i=0;inof_tx_channels;i++) { + uhd_usrp_set_tx_freq(handler->usrp, &tune_request, i, &tune_result); + } uhd_usrp_get_tx_freq(handler->usrp, 0, &freq); return freq; } @@ -492,6 +516,19 @@ int rf_uhd_recv_with_time(void *h, time_t *secs, double *frac_secs) { + return rf_uhd_recv_with_time_multi(h, &data, nsamples, blocking, secs, frac_secs); +} + +cf_t data1[1024*100]; +cf_t data2[1024*100]; + +int rf_uhd_recv_with_time_multi(void *h, + void **data, + uint32_t nsamples, + bool blocking, + time_t *secs, + double *frac_secs) +{ rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h; size_t rxd_samples; @@ -499,18 +536,20 @@ int rf_uhd_recv_with_time(void *h, int trials = 0; if (blocking) { int n = 0; - cf_t *data_c = (cf_t*) data; do { - size_t rx_samples = handler->rx_nof_samples; + size_t rx_samples = nsamples; if (rx_samples > nsamples - n) { rx_samples = nsamples - n; } - void *buff = (void*) &data_c[n]; - void **buffs_ptr = (void**) &buff; + void *buffs_ptr[4]; + for (int i=0;inof_rx_channels;i++) { + cf_t *data_c = (cf_t*) data[i]; + buffs_ptr[i] = &data_c[n]; + } + uhd_error error = uhd_rx_streamer_recv(handler->rx_stream, buffs_ptr, - rx_samples, md, 5.0, false, &rxd_samples); - + rx_samples, md, 1.0, false, &rxd_samples); if (error) { fprintf(stderr, "Error receiving from UHD: %d\n", error); return -1; @@ -520,9 +559,8 @@ int rf_uhd_recv_with_time(void *h, trials++; } while (n < nsamples && trials < 100); } else { - void **buffs_ptr = (void**) &data; - return uhd_rx_streamer_recv(handler->rx_stream, buffs_ptr, - nsamples, md, 0.0, false, &rxd_samples); + return uhd_rx_streamer_recv(handler->rx_stream, data, + nsamples, md, 0.0, false, &rxd_samples); } if (secs && frac_secs) { uhd_rx_metadata_time_spec(handler->rx_md_first, secs, frac_secs); diff --git a/srslte/lib/rf/rf_uhd_imp.h b/srslte/lib/rf/rf_uhd_imp.h index ee13ea36e..edab6ea51 100644 --- a/srslte/lib/rf/rf_uhd_imp.h +++ b/srslte/lib/rf/rf_uhd_imp.h @@ -37,6 +37,10 @@ SRSLTE_API int rf_uhd_open(char *args, void **handler); +SRSLTE_API int rf_uhd_open_multi(char *args, + void **handler, + uint32_t nof_rx_antennas); + SRSLTE_API char* rf_uhd_devname(void *h); SRSLTE_API int rf_uhd_close(void *h); @@ -89,6 +93,13 @@ SRSLTE_API int rf_uhd_recv_with_time(void *h, time_t *secs, double *frac_secs); +SRSLTE_API int rf_uhd_recv_with_time_multi(void *h, + void **data, + uint32_t nsamples, + bool blocking, + time_t *secs, + double *frac_secs); + SRSLTE_API double rf_uhd_set_tx_srate(void *h, double freq); diff --git a/srslte/lib/rf/rf_utils.c b/srslte/lib/rf/rf_utils.c index 066b9a2b3..10c6b53df 100644 --- a/srslte/lib/rf/rf_utils.c +++ b/srslte/lib/rf/rf_utils.c @@ -82,10 +82,13 @@ free_and_exit: return ret; } - -int srslte_rf_recv_wrapper_cs(void *h, void *data, uint32_t nsamples, srslte_timestamp_t *t) { +int srslte_rf_recv_wrapper_cs(void *h, cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *t) { DEBUG(" ---- Receive %d samples ---- \n", nsamples); - return srslte_rf_recv(h, data, nsamples, 1); + void *ptr[SRSLTE_MAX_PORTS]; + for (int i=0;iid, cell->cp, srslte_rf_recv_wrapper_cs, (void*) rf)) { + if (srslte_ue_mib_sync_init_multi(&ue_mib, cell->id, cell->cp, srslte_rf_recv_wrapper_cs, nof_rx_antennas, (void*) rf)) { fprintf(stderr, "Error initiating srslte_ue_mib_sync\n"); goto clean_exit; } @@ -151,8 +154,9 @@ clean_exit: /** This function is simply a wrapper to the ue_cell_search module for rf devices */ -int rf_cell_search(srslte_rf_t *rf, cell_search_cfg_t *config, - int force_N_id_2, srslte_cell_t *cell, float *cfo) +int rf_cell_search(srslte_rf_t *rf, uint32_t nof_rx_antennas, + cell_search_cfg_t *config, + int force_N_id_2, srslte_cell_t *cell, float *cfo) { int ret = SRSLTE_ERROR; srslte_ue_cellsearch_t cs; @@ -160,7 +164,7 @@ int rf_cell_search(srslte_rf_t *rf, cell_search_cfg_t *config, bzero(found_cells, 3*sizeof(srslte_ue_cellsearch_result_t)); - if (srslte_ue_cellsearch_init(&cs, config->max_frames_pss, srslte_rf_recv_wrapper_cs, (void*) rf)) { + if (srslte_ue_cellsearch_init_multi(&cs, config->max_frames_pss, srslte_rf_recv_wrapper_cs, nof_rx_antennas, (void*) rf)) { fprintf(stderr, "Error initiating UE cell detect\n"); return SRSLTE_ERROR; } @@ -234,15 +238,15 @@ int rf_cell_search(srslte_rf_t *rf, cell_search_cfg_t *config, * 0 if no cell was found or MIB could not be decoded, * -1 on error */ -int rf_search_and_decode_mib(srslte_rf_t *rf, cell_search_cfg_t *config, int force_N_id_2, srslte_cell_t *cell, float *cfo) +int rf_search_and_decode_mib(srslte_rf_t *rf, uint32_t nof_rx_antennas, cell_search_cfg_t *config, int force_N_id_2, srslte_cell_t *cell, float *cfo) { int ret = SRSLTE_ERROR; printf("Searching for cell...\n"); - ret = rf_cell_search(rf, config, force_N_id_2, cell, cfo); + ret = rf_cell_search(rf, nof_rx_antennas, config, force_N_id_2, cell, cfo); if (ret > 0) { printf("Decoding PBCH for cell %d (N_id_2=%d)\n", cell->id, cell->id%3); - ret = rf_mib_decoder(rf, config, cell, cfo); + ret = rf_mib_decoder(rf, nof_rx_antennas, config, cell, cfo); if (ret < 0) { fprintf(stderr, "Could not decode PBCH from CELL ID %d\n", cell->id); return SRSLTE_ERROR; diff --git a/srslte/lib/ue/ue_cell_search.c b/srslte/lib/ue/ue_cell_search.c index 018f20a8a..868af36b9 100644 --- a/srslte/lib/ue/ue_cell_search.c +++ b/srslte/lib/ue/ue_cell_search.c @@ -36,7 +36,8 @@ #include "srslte/utils/vector.h" int srslte_ue_cellsearch_init(srslte_ue_cellsearch_t * q, uint32_t max_frames, - int (recv_callback)(void*, void*, uint32_t,srslte_timestamp_t*), void *stream_handler) + int (recv_callback)(void*, void*, uint32_t,srslte_timestamp_t*), + void *stream_handler) { int ret = SRSLTE_ERROR_INVALID_INPUTS; @@ -55,6 +56,65 @@ int srslte_ue_cellsearch_init(srslte_ue_cellsearch_t * q, uint32_t max_frames, goto clean_exit; } + q->sf_buffer[0] = srslte_vec_malloc(3*sizeof(cf_t)*SRSLTE_SF_LEN_PRB(100)); + q->nof_rx_antennas = 1; + + q->candidates = calloc(sizeof(srslte_ue_cellsearch_result_t), max_frames); + if (!q->candidates) { + perror("malloc"); + goto clean_exit; + } + q->mode_ntimes = calloc(sizeof(uint32_t), max_frames); + if (!q->mode_ntimes) { + perror("malloc"); + goto clean_exit; + } + q->mode_counted = calloc(sizeof(uint8_t), max_frames); + if (!q->mode_counted) { + perror("malloc"); + goto clean_exit; + } + + q->max_frames = max_frames; + q->nof_valid_frames = max_frames; + + ret = SRSLTE_SUCCESS; + } + +clean_exit: + if (ret == SRSLTE_ERROR) { + srslte_ue_cellsearch_free(q); + } + return ret; +} + +int srslte_ue_cellsearch_init_multi(srslte_ue_cellsearch_t * q, uint32_t max_frames, + int (recv_callback)(void*, cf_t*[SRSLTE_MAX_PORTS], uint32_t,srslte_timestamp_t*), + uint32_t nof_rx_antennas, + void *stream_handler) +{ + int ret = SRSLTE_ERROR_INVALID_INPUTS; + + if (q != NULL) { + ret = SRSLTE_ERROR; + srslte_cell_t cell; + + bzero(q, sizeof(srslte_ue_cellsearch_t)); + + bzero(&cell, sizeof(srslte_cell_t)); + cell.id = SRSLTE_CELL_ID_UNKNOWN; + cell.nof_prb = SRSLTE_CS_NOF_PRB; + + if (srslte_ue_sync_init_multi(&q->ue_sync, cell, recv_callback, nof_rx_antennas, stream_handler)) { + fprintf(stderr, "Error initiating ue_sync\n"); + goto clean_exit; + } + + for (int i=0;isf_buffer[i] = srslte_vec_malloc(3*sizeof(cf_t)*SRSLTE_SF_LEN_PRB(100)); + } + q->nof_rx_antennas = nof_rx_antennas; + q->candidates = calloc(sizeof(srslte_ue_cellsearch_result_t), max_frames); if (!q->candidates) { perror("malloc"); @@ -86,6 +146,11 @@ clean_exit: void srslte_ue_cellsearch_free(srslte_ue_cellsearch_t * q) { + for (int i=0;inof_rx_antennas;i++) { + if (q->sf_buffer[i]) { + free(q->sf_buffer[i]); + } + } if (q->candidates) { free(q->candidates); } @@ -203,7 +268,6 @@ int srslte_ue_cellsearch_scan_N_id_2(srslte_ue_cellsearch_t * q, srslte_ue_cellsearch_result_t *found_cell) { int ret = SRSLTE_ERROR_INVALID_INPUTS; - cf_t *sf_buffer = NULL; uint32_t nof_detected_frames = 0; uint32_t nof_scanned_frames = 0; @@ -215,7 +279,7 @@ int srslte_ue_cellsearch_scan_N_id_2(srslte_ue_cellsearch_t * q, srslte_ue_sync_reset(&q->ue_sync); do { - ret = srslte_ue_sync_get_buffer(&q->ue_sync, &sf_buffer); + ret = srslte_ue_sync_zerocopy_multi(&q->ue_sync, q->sf_buffer); if (ret < 0) { fprintf(stderr, "Error calling srslte_ue_sync_work()\n"); break; diff --git a/srslte/lib/ue/ue_dl.c b/srslte/lib/ue/ue_dl.c index d1a19620a..bd98802c0 100644 --- a/srslte/lib/ue/ue_dl.c +++ b/srslte/lib/ue/ue_dl.c @@ -44,13 +44,20 @@ const uint32_t nof_ue_formats = 2; static srslte_dci_format_t common_formats[] = {SRSLTE_DCI_FORMAT1A,SRSLTE_DCI_FORMAT1C}; const uint32_t nof_common_formats = 2; - int srslte_ue_dl_init(srslte_ue_dl_t *q, - srslte_cell_t cell) + srslte_cell_t cell) +{ + return srslte_ue_dl_init_multi(q, cell, 1); +} + +int srslte_ue_dl_init_multi(srslte_ue_dl_t *q, + srslte_cell_t cell, + uint32_t nof_rx_antennas) { int ret = SRSLTE_ERROR_INVALID_INPUTS; - if (q != NULL && + if (q != NULL && + nof_rx_antennas <= SRSLTE_MAX_PORTS && srslte_cell_isvalid(&cell)) { ret = SRSLTE_ERROR; @@ -62,6 +69,7 @@ int srslte_ue_dl_init(srslte_ue_dl_t *q, q->pkts_total = 0; q->pending_ul_dci_rnti = 0; q->sample_offset = 0; + q->nof_rx_antennas = nof_rx_antennas; if (srslte_ofdm_rx_init(&q->fft, q->cell.cp, q->cell.nof_prb)) { fprintf(stderr, "Error initiating FFT\n"); @@ -75,7 +83,7 @@ int srslte_ue_dl_init(srslte_ue_dl_t *q, fprintf(stderr, "Error initiating REGs\n"); goto clean_exit; } - if (srslte_pcfich_init(&q->pcfich, &q->regs, q->cell)) { + if (srslte_pcfich_init_multi(&q->pcfich, &q->regs, q->cell, nof_rx_antennas)) { fprintf(stderr, "Error creating PCFICH object\n"); goto clean_exit; } @@ -84,12 +92,12 @@ int srslte_ue_dl_init(srslte_ue_dl_t *q, goto clean_exit; } - if (srslte_pdcch_init(&q->pdcch, &q->regs, q->cell)) { + if (srslte_pdcch_init_multi(&q->pdcch, &q->regs, q->cell, nof_rx_antennas)) { fprintf(stderr, "Error creating PDCCH object\n"); goto clean_exit; } - if (srslte_pdsch_init(&q->pdsch, q->cell)) { + if (srslte_pdsch_init_multi(&q->pdsch, q->cell, nof_rx_antennas)) { fprintf(stderr, "Error creating PDSCH object\n"); goto clean_exit; } @@ -103,17 +111,24 @@ int srslte_ue_dl_init(srslte_ue_dl_t *q, } srslte_cfo_set_tol(&q->sfo_correct, 1e-5/q->fft.symbol_sz); - q->sf_symbols = srslte_vec_malloc(CURRENT_SFLEN_RE * sizeof(cf_t)); - if (!q->sf_symbols) { - perror("malloc"); - goto clean_exit; - } - for (uint32_t i=0;icell.nof_ports;i++) { - q->ce[i] = srslte_vec_malloc(CURRENT_SFLEN_RE * sizeof(cf_t)); - if (!q->ce[i]) { + for (int j=0;jsf_symbols_m[j] = srslte_vec_malloc(CURRENT_SFLEN_RE * sizeof(cf_t)); + if (!q->sf_symbols_m[j]) { perror("malloc"); goto clean_exit; } + for (uint32_t i=0;icell.nof_ports;i++) { + q->ce_m[i][j] = srslte_vec_malloc(CURRENT_SFLEN_RE * sizeof(cf_t)); + if (!q->ce_m[i][j]) { + perror("malloc"); + goto clean_exit; + } + } + } + + q->sf_symbols = q->sf_symbols_m[0]; + for (int i=0;icell.nof_ports;i++) { + q->ce[i] = q->ce_m[i][0]; } ret = SRSLTE_SUCCESS; @@ -140,12 +155,14 @@ void srslte_ue_dl_free(srslte_ue_dl_t *q) { srslte_pdsch_free(&q->pdsch); srslte_cfo_free(&q->sfo_correct); srslte_softbuffer_rx_free(&q->softbuffer); - if (q->sf_symbols) { - free(q->sf_symbols); - } - for (uint32_t i=0;icell.nof_ports;i++) { - if (q->ce[i]) { - free(q->ce[i]); + for (int j=0;jnof_rx_antennas;j++) { + if (q->sf_symbols_m[j]) { + free(q->sf_symbols_m[j]); + } + for (uint32_t i=0;icell.nof_ports;i++) { + if (q->ce_m[i][j]) { + free(q->ce_m[i][j]); + } } } bzero(q, sizeof(srslte_ue_dl_t)); @@ -187,22 +204,38 @@ void srslte_ue_dl_set_sample_offset(srslte_ue_dl_t * q, float sample_offset) { * - PDSCH decoding: Decode TB scrambling with RNTI given by srslte_ue_dl_set_rnti() */ int srslte_ue_dl_decode(srslte_ue_dl_t *q, cf_t *input, uint8_t *data, uint32_t tti) { - return srslte_ue_dl_decode_rnti(q, input, data, tti, q->current_rnti); + cf_t *_input[SRSLTE_MAX_PORTS]; + _input[0] = input; + return srslte_ue_dl_decode_rnti_multi(q, _input, data, tti, q->current_rnti); } -int srslte_ue_dl_decode_fft_estimate(srslte_ue_dl_t *q, cf_t *input, uint32_t sf_idx, uint32_t *cfi) { +int srslte_ue_dl_decode_multi(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint8_t *data, uint32_t tti) { + return srslte_ue_dl_decode_rnti_multi(q, input, data, tti, q->current_rnti); +} + +int srslte_ue_dl_decode_fft_estimate(srslte_ue_dl_t *q, cf_t *input, uint32_t sf_idx, uint32_t *cfi) +{ + cf_t *_input[SRSLTE_MAX_PORTS]; + _input[0] = input; + return srslte_ue_dl_decode_fft_estimate_multi(q, _input, sf_idx, cfi); +} + +int srslte_ue_dl_decode_fft_estimate_multi(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint32_t sf_idx, uint32_t *cfi) +{ if (input && q && cfi && sf_idx < SRSLTE_NSUBFRAMES_X_FRAME) { /* Run FFT for all subframe data */ - srslte_ofdm_rx_sf(&q->fft, input, q->sf_symbols); - - /* Correct SFO multiplying by complex exponential in the time domain */ - if (q->sample_offset) { - for (int i=0;i<2*SRSLTE_CP_NSYMB(q->cell.cp);i++) { - srslte_cfo_correct(&q->sfo_correct, - &q->sf_symbols[i*q->cell.nof_prb*SRSLTE_NRE], - &q->sf_symbols[i*q->cell.nof_prb*SRSLTE_NRE], - q->sample_offset / q->fft.symbol_sz); + for (int j=0;jnof_rx_antennas;j++) { + srslte_ofdm_rx_sf(&q->fft, input[j], q->sf_symbols_m[j]); + + /* Correct SFO multiplying by complex exponential in the time domain */ + if (q->sample_offset) { + for (int i=0;i<2*SRSLTE_CP_NSYMB(q->cell.cp);i++) { + srslte_cfo_correct(&q->sfo_correct, + &q->sf_symbols_m[j][i*q->cell.nof_prb*SRSLTE_NRE], + &q->sf_symbols_m[j][i*q->cell.nof_prb*SRSLTE_NRE], + q->sample_offset / q->fft.symbol_sz); + } } } return srslte_ue_dl_decode_estimate(q, sf_idx, cfi); @@ -216,10 +249,10 @@ int srslte_ue_dl_decode_estimate(srslte_ue_dl_t *q, uint32_t sf_idx, uint32_t *c if (q && cfi && sf_idx < SRSLTE_NSUBFRAMES_X_FRAME) { /* Get channel estimates for each port */ - srslte_chest_dl_estimate(&q->chest, q->sf_symbols, q->ce, sf_idx); + srslte_chest_dl_estimate_multi(&q->chest, q->sf_symbols_m, q->ce_m, sf_idx, q->nof_rx_antennas); /* First decode PCFICH and obtain CFI */ - if (srslte_pcfich_decode(&q->pcfich, q->sf_symbols, q->ce, + if (srslte_pcfich_decode_multi(&q->pcfich, q->sf_symbols_m, q->ce_m, srslte_chest_dl_get_noise_estimate(&q->chest), sf_idx, cfi, &cfi_corr)<0) { fprintf(stderr, "Error decoding PCFICH\n"); @@ -246,6 +279,13 @@ int srslte_ue_dl_cfg_grant(srslte_ue_dl_t *q, srslte_ra_dl_grant_t *grant, uint3 } int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, cf_t *input, uint8_t *data, uint32_t tti, uint16_t rnti) +{ + cf_t *_input[SRSLTE_MAX_PORTS]; + _input[0] = input; + return srslte_ue_dl_decode_rnti_multi(q, _input, data, tti, rnti); +} + +int srslte_ue_dl_decode_rnti_multi(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint8_t *data, uint32_t tti, uint16_t rnti) { srslte_dci_msg_t dci_msg; srslte_ra_dl_dci_t dci_unpacked; @@ -255,11 +295,15 @@ int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, cf_t *input, uint8_t *data, uint uint32_t sf_idx = tti%10; - if ((ret = srslte_ue_dl_decode_fft_estimate(q, input, sf_idx, &cfi)) < 0) { + if ((ret = srslte_ue_dl_decode_fft_estimate_multi(q, input, sf_idx, &cfi)) < 0) { return ret; } - if (srslte_pdcch_extract_llr(&q->pdcch, q->sf_symbols, q->ce, srslte_chest_dl_get_noise_estimate(&q->chest), sf_idx, cfi)) { + float noise_estimate = srslte_chest_dl_get_noise_estimate(&q->chest); + // Uncoment next line to do ZF by default in pdsch_ue example + //float noise_estimate = 0; + + if (srslte_pdcch_extract_llr_multi(&q->pdcch, q->sf_symbols_m, q->ce_m, noise_estimate, sf_idx, cfi)) { fprintf(stderr, "Error extracting LLRs\n"); return SRSLTE_ERROR; } @@ -294,13 +338,10 @@ int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, cf_t *input, uint8_t *data, uint q->nof_detected++; - // Uncoment next line to do ZF by default in pdsch_ue example - //float noise_estimate = 0; - float noise_estimate = srslte_chest_dl_get_noise_estimate(&q->chest); if (q->pdsch_cfg.grant.mcs.mod > 0 && q->pdsch_cfg.grant.mcs.tbs >= 0) { - ret = srslte_pdsch_decode(&q->pdsch, &q->pdsch_cfg, &q->softbuffer, - q->sf_symbols, q->ce, + ret = srslte_pdsch_decode_multi(&q->pdsch, &q->pdsch_cfg, &q->softbuffer, + q->sf_symbols_m, q->ce_m, noise_estimate, rnti, data); @@ -502,7 +543,14 @@ bool srslte_ue_dl_decode_phich(srslte_ue_dl_t *q, uint32_t sf_idx, uint32_t n_pr INFO("Decoding PHICH sf_idx=%d, n_prb_lowest=%d, n_dmrs=%d, n_group=%d, n_seq=%d, Ngroups=%d, Nsf=%d\n", sf_idx, n_prb_lowest, n_dmrs, ngroup, nseq, srslte_phich_ngroups(&q->phich), srslte_phich_nsf(&q->phich)); - if (!srslte_phich_decode(&q->phich, q->sf_symbols, q->ce, 0, ngroup, nseq, sf_idx, &ack_bit, &distance)) { + + cf_t *ce0[SRSLTE_MAX_PORTS]; + for (int i=0;ice_m[i][0]; + } + + + if (!srslte_phich_decode(&q->phich, q->sf_symbols_m[0], ce0, 0, ngroup, nseq, sf_idx, &ack_bit, &distance)) { INFO("Decoded PHICH %d with distance %f\n", ack_bit, distance); } else { fprintf(stderr, "Error decoding PHICH\n"); @@ -516,11 +564,11 @@ bool srslte_ue_dl_decode_phich(srslte_ue_dl_t *q, uint32_t sf_idx, uint32_t n_pr } void srslte_ue_dl_save_signal(srslte_ue_dl_t *q, srslte_softbuffer_rx_t *softbuffer, uint32_t tti, uint32_t rv_idx, uint16_t rnti, uint32_t cfi) { - srslte_vec_save_file("sf_symbols", q->sf_symbols, SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t)); + srslte_vec_save_file("sf_symbols", q->sf_symbols_m, SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t)); printf("%d samples\n", SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)); - srslte_vec_save_file("ce0", q->ce[0], SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t)); + srslte_vec_save_file("ce0", q->ce_m[0], SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t)); if (q->cell.nof_ports > 1) { - srslte_vec_save_file("ce1", q->ce[1], SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t)); + srslte_vec_save_file("ce1", q->ce_m[1], SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t)); } srslte_vec_save_file("pcfich_ce0", q->pcfich.ce[0], q->pcfich.nof_symbols*sizeof(cf_t)); srslte_vec_save_file("pcfich_ce1", q->pcfich.ce[1], q->pcfich.nof_symbols*sizeof(cf_t)); diff --git a/srslte/lib/ue/ue_mib.c b/srslte/lib/ue/ue_mib.c index 5cfeaaadd..9b5b4e9ef 100644 --- a/srslte/lib/ue/ue_mib.c +++ b/srslte/lib/ue/ue_mib.c @@ -161,13 +161,11 @@ int srslte_ue_mib_decode(srslte_ue_mib_t * q, cf_t *input, return ret; } - - int srslte_ue_mib_sync_init(srslte_ue_mib_sync_t *q, - uint32_t cell_id, - srslte_cp_t cp, - int (recv_callback)(void*, void*, uint32_t, srslte_timestamp_t*), - void *stream_handler) + uint32_t cell_id, + srslte_cp_t cp, + int (recv_callback)(void*, void*, uint32_t, srslte_timestamp_t*), + void *stream_handler) { srslte_cell_t cell; // If the ports are set to 0, ue_mib goes through 1, 2 and 4 ports to blindly detect nof_ports @@ -176,6 +174,9 @@ int srslte_ue_mib_sync_init(srslte_ue_mib_sync_t *q, cell.cp = cp; cell.nof_prb = SRSLTE_UE_MIB_NOF_PRB; + q->sf_buffer[0] = srslte_vec_malloc(3*sizeof(cf_t)*SRSLTE_SF_LEN_PRB(cell.nof_prb)); + q->nof_rx_antennas = 1; + if (srslte_ue_mib_init(&q->ue_mib, cell)) { fprintf(stderr, "Error initiating ue_mib\n"); return SRSLTE_ERROR; @@ -189,7 +190,44 @@ int srslte_ue_mib_sync_init(srslte_ue_mib_sync_t *q, return SRSLTE_SUCCESS; } +int srslte_ue_mib_sync_init_multi(srslte_ue_mib_sync_t *q, + uint32_t cell_id, + srslte_cp_t cp, + int (recv_callback)(void*, cf_t*[SRSLTE_MAX_PORTS], uint32_t, srslte_timestamp_t*), + uint32_t nof_rx_antennas, + void *stream_handler) +{ + srslte_cell_t cell; + // If the ports are set to 0, ue_mib goes through 1, 2 and 4 ports to blindly detect nof_ports + cell.nof_ports = 0; + cell.id = cell_id; + cell.cp = cp; + cell.nof_prb = SRSLTE_UE_MIB_NOF_PRB; + + for (int i=0;isf_buffer[i] = srslte_vec_malloc(3*sizeof(cf_t)*SRSLTE_SF_LEN_PRB(cell.nof_prb)); + } + q->nof_rx_antennas = nof_rx_antennas; + + if (srslte_ue_mib_init(&q->ue_mib, cell)) { + fprintf(stderr, "Error initiating ue_mib\n"); + return SRSLTE_ERROR; + } + if (srslte_ue_sync_init_multi(&q->ue_sync, cell, recv_callback, nof_rx_antennas, stream_handler)) { + fprintf(stderr, "Error initiating ue_sync\n"); + srslte_ue_mib_free(&q->ue_mib); + return SRSLTE_ERROR; + } + srslte_ue_sync_decode_sss_on_track(&q->ue_sync, true); + return SRSLTE_SUCCESS; +} + void srslte_ue_mib_sync_free(srslte_ue_mib_sync_t *q) { + for (int i=0;inof_rx_antennas;i++) { + if (q->sf_buffer[i]) { + free(q->sf_buffer[i]); + } + } srslte_ue_mib_free(&q->ue_mib); srslte_ue_sync_free(&q->ue_sync); } @@ -207,7 +245,6 @@ int srslte_ue_mib_sync_decode(srslte_ue_mib_sync_t * q, { int ret = SRSLTE_ERROR_INVALID_INPUTS; - cf_t *sf_buffer = NULL; uint32_t nof_frames = 0; int mib_ret = SRSLTE_UE_MIB_NOTFOUND; @@ -216,13 +253,13 @@ int srslte_ue_mib_sync_decode(srslte_ue_mib_sync_t * q, ret = SRSLTE_SUCCESS; do { mib_ret = SRSLTE_UE_MIB_NOTFOUND; - ret = srslte_ue_sync_get_buffer(&q->ue_sync, &sf_buffer); + ret = srslte_ue_sync_zerocopy_multi(&q->ue_sync, q->sf_buffer); if (ret < 0) { fprintf(stderr, "Error calling srslte_ue_sync_work()\n"); break; } else if (srslte_ue_sync_get_sfidx(&q->ue_sync) == 0) { if (ret == 1) { - mib_ret = srslte_ue_mib_decode(&q->ue_mib, sf_buffer, bch_payload, nof_tx_ports, sfn_offset); + mib_ret = srslte_ue_mib_decode(&q->ue_mib, q->sf_buffer[0], bch_payload, nof_tx_ports, sfn_offset); } else { DEBUG("Resetting PBCH decoder after %d frames\n", q->ue_mib.frame_cnt); srslte_ue_mib_reset(&q->ue_mib); diff --git a/srslte/lib/ue/ue_sync.c b/srslte/lib/ue/ue_sync.c index 6ef05daff..4cf61bbb3 100644 --- a/srslte/lib/ue/ue_sync.c +++ b/srslte/lib/ue/ue_sync.c @@ -39,7 +39,6 @@ #define MAX_TIME_OFFSET 128 -cf_t dummy[MAX_TIME_OFFSET]; #define TRACK_MAX_LOST 4 #define TRACK_FRAME_SIZE 32 @@ -47,7 +46,11 @@ cf_t dummy[MAX_TIME_OFFSET]; #define DEFAULT_SAMPLE_OFFSET_CORRECT_PERIOD 0 #define DEFAULT_SFO_EMA_COEFF 0.1 -cf_t dummy_offset_buffer[1024*1024]; +cf_t dummy_buffer0[15*2048/2]; +cf_t dummy_buffer1[15*2048/2]; + +// FIXME: this will break for 4 antennas!! +cf_t *dummy_offset_buffer[SRSLTE_MAX_PORTS] = {dummy_buffer0, dummy_buffer1}; int srslte_ue_sync_init_file(srslte_ue_sync_t *q, uint32_t nof_prb, char *file_name, int offset_time, float offset_freq) { int ret = SRSLTE_ERROR_INVALID_INPUTS; @@ -74,12 +77,6 @@ int srslte_ue_sync_init_file(srslte_ue_sync_t *q, uint32_t nof_prb, char *file_n goto clean_exit; } - q->input_buffer = srslte_vec_malloc(2 * q->sf_len * sizeof(cf_t)); - if (!q->input_buffer) { - perror("malloc"); - goto clean_exit; - } - INFO("Offseting input file by %d samples and %.1f kHz\n", offset_time, offset_freq/1000); srslte_filesource_read(&q->file_source, dummy_offset_buffer, offset_time); @@ -109,16 +106,33 @@ int srslte_ue_sync_start_agc(srslte_ue_sync_t *q, double (set_gain_callback)(voi return n; } +int recv_callback_multi_to_single(void *h, cf_t *x[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t*t) +{ + srslte_ue_sync_t *q = (srslte_ue_sync_t*) h; + return q->recv_callback_single(q->stream, (void*) x[0], nsamples, t); +} + int srslte_ue_sync_init(srslte_ue_sync_t *q, srslte_cell_t cell, - int (recv_callback)(void*, void*, uint32_t,srslte_timestamp_t*), + int (recv_callback)(void*, void*, uint32_t,srslte_timestamp_t*), void *stream_handler) +{ + q->recv_callback_single = recv_callback; + return srslte_ue_sync_init_multi(q, cell, recv_callback_multi_to_single, 1, q); +} + +int srslte_ue_sync_init_multi(srslte_ue_sync_t *q, + srslte_cell_t cell, + int (recv_callback)(void*, cf_t*[SRSLTE_MAX_PORTS], uint32_t,srslte_timestamp_t*), + uint32_t nof_rx_antennas, + void *stream_handler) { int ret = SRSLTE_ERROR_INVALID_INPUTS; if (q != NULL && stream_handler != NULL && - srslte_nofprb_isvalid(cell.nof_prb) && + srslte_nofprb_isvalid(cell.nof_prb) && + nof_rx_antennas <= SRSLTE_MAX_PORTS && recv_callback != NULL) { ret = SRSLTE_ERROR; @@ -127,6 +141,7 @@ int srslte_ue_sync_init(srslte_ue_sync_t *q, q->stream = stream_handler; q->recv_callback = recv_callback; + q->nof_rx_antennas = nof_rx_antennas; q->cell = cell; q->fft_size = srslte_symbol_sz(q->cell.nof_prb); q->sf_len = SRSLTE_SF_LEN(q->fft_size); @@ -209,13 +224,6 @@ int srslte_ue_sync_init(srslte_ue_sync_t *q, } - /* FIXME: Go for zerocopy only and eliminate this allocation */ - q->input_buffer = srslte_vec_malloc(2*q->frame_len * sizeof(cf_t)); - if (!q->input_buffer) { - perror("malloc"); - goto clean_exit; - } - srslte_ue_sync_reset(q); ret = SRSLTE_SUCCESS; @@ -233,9 +241,6 @@ uint32_t srslte_ue_sync_sf_len(srslte_ue_sync_t *q) { } void srslte_ue_sync_free(srslte_ue_sync_t *q) { - if (q->input_buffer) { - free(q->input_buffer); - } if (q->do_agc) { srslte_agc_free(&q->agc); } @@ -309,7 +314,7 @@ void srslte_ue_sync_set_agc_period(srslte_ue_sync_t *q, uint32_t period) { q->agc_period = period; } -static int find_peak_ok(srslte_ue_sync_t *q, cf_t *input_buffer) { +static int find_peak_ok(srslte_ue_sync_t *q, cf_t *input_buffer[SRSLTE_MAX_PORTS]) { if (srslte_sync_sss_detected(&q->sfind)) { @@ -408,7 +413,7 @@ static int track_peak_ok(srslte_ue_sync_t *q, uint32_t track_idx) { discard the offseted samples to align next frame */ if (q->next_rf_sample_offset > 0 && q->next_rf_sample_offset < MAX_TIME_OFFSET) { DEBUG("Positive time offset %d samples.\n", q->next_rf_sample_offset); - if (q->recv_callback(q->stream, dummy, (uint32_t) q->next_rf_sample_offset, &q->last_timestamp) < 0) { + if (q->recv_callback(q->stream, dummy_offset_buffer, (uint32_t) q->next_rf_sample_offset, &q->last_timestamp) < 0) { fprintf(stderr, "Error receiving from USRP\n"); return SRSLTE_ERROR; } @@ -443,7 +448,7 @@ static int track_peak_no(srslte_ue_sync_t *q) { } -static int receive_samples(srslte_ue_sync_t *q, cf_t *input_buffer) { +static int receive_samples(srslte_ue_sync_t *q, cf_t *input_buffer[SRSLTE_MAX_PORTS]) { /* A negative time offset means there are samples in our buffer for the next subframe, because we are sampling too fast. @@ -453,7 +458,11 @@ static int receive_samples(srslte_ue_sync_t *q, cf_t *input_buffer) { } /* Get N subframes from the USRP getting more samples and keeping the previous samples, if any */ - if (q->recv_callback(q->stream, &input_buffer[q->next_rf_sample_offset], q->frame_len - q->next_rf_sample_offset, &q->last_timestamp) < 0) { + cf_t *ptr[SRSLTE_MAX_PORTS]; + for (int i=0;inext_rf_sample_offset]; + } + if (q->recv_callback(q->stream, ptr, q->frame_len - q->next_rf_sample_offset, &q->last_timestamp) < 0) { return SRSLTE_ERROR; } @@ -465,17 +474,14 @@ static int receive_samples(srslte_ue_sync_t *q, cf_t *input_buffer) { bool first_track = true; -int srslte_ue_sync_get_buffer(srslte_ue_sync_t *q, cf_t **sf_symbols) { - int ret = srslte_ue_sync_zerocopy(q, q->input_buffer); - if (sf_symbols) { - *sf_symbols = q->input_buffer; - } - return ret; - +int srslte_ue_sync_zerocopy(srslte_ue_sync_t *q, cf_t *input_buffer) { + cf_t *_input_buffer[SRSLTE_MAX_PORTS]; + _input_buffer[0] = input_buffer; + return srslte_ue_sync_zerocopy_multi(q, _input_buffer); } /* Returns 1 if the subframe is synchronized in time, 0 otherwise */ -int srslte_ue_sync_zerocopy(srslte_ue_sync_t *q, cf_t *input_buffer) { +int srslte_ue_sync_zerocopy_multi(srslte_ue_sync_t *q, cf_t *input_buffer[SRSLTE_MAX_PORTS]) { int ret = SRSLTE_ERROR_INVALID_INPUTS; uint32_t track_idx; @@ -484,7 +490,7 @@ int srslte_ue_sync_zerocopy(srslte_ue_sync_t *q, cf_t *input_buffer) { { if (q->file_mode) { - int n = srslte_filesource_read(&q->file_source, input_buffer, q->sf_len); + int n = srslte_filesource_read(&q->file_source, input_buffer[0], q->sf_len); if (n < 0) { fprintf(stderr, "Error reading input file\n"); return SRSLTE_ERROR; @@ -492,7 +498,7 @@ int srslte_ue_sync_zerocopy(srslte_ue_sync_t *q, cf_t *input_buffer) { if (n == 0) { srslte_filesource_seek(&q->file_source, 0); q->sf_idx = 9; - int n = srslte_filesource_read(&q->file_source, input_buffer, q->sf_len); + int n = srslte_filesource_read(&q->file_source, input_buffer[0], q->sf_len); if (n < 0) { fprintf(stderr, "Error reading input file\n"); return SRSLTE_ERROR; @@ -500,8 +506,8 @@ int srslte_ue_sync_zerocopy(srslte_ue_sync_t *q, cf_t *input_buffer) { } if (q->correct_cfo) { srslte_cfo_correct(&q->file_cfo_correct, - input_buffer, - input_buffer, + input_buffer[0], + input_buffer[0], q->file_cfo / 15000 / q->fft_size); } @@ -519,7 +525,7 @@ int srslte_ue_sync_zerocopy(srslte_ue_sync_t *q, cf_t *input_buffer) { switch (q->state) { case SF_FIND: - switch(srslte_sync_find(&q->sfind, input_buffer, 0, &q->peak_idx)) { + switch(srslte_sync_find(&q->sfind, input_buffer[0], 0, &q->peak_idx)) { case SRSLTE_SYNC_ERROR: ret = SRSLTE_ERROR; fprintf(stderr, "Error finding correlation peak (%d)\n", ret); @@ -539,7 +545,7 @@ int srslte_ue_sync_zerocopy(srslte_ue_sync_t *q, cf_t *input_buffer) { break; } if (q->do_agc) { - srslte_agc_process(&q->agc, input_buffer, q->sf_len); + srslte_agc_process(&q->agc, input_buffer[0], q->sf_len); } break; @@ -557,7 +563,7 @@ int srslte_ue_sync_zerocopy(srslte_ue_sync_t *q, cf_t *input_buffer) { if (q->do_agc && (q->agc_period == 0 || (q->agc_period && (q->frame_total_cnt%q->agc_period) == 0))) { - srslte_agc_process(&q->agc, input_buffer, q->sf_len); + srslte_agc_process(&q->agc, input_buffer[0], q->sf_len); } #ifdef MEASURE_EXEC_TIME @@ -570,7 +576,7 @@ int srslte_ue_sync_zerocopy(srslte_ue_sync_t *q, cf_t *input_buffer) { /* Track PSS/SSS around the expected PSS position * In tracking phase, the subframe carrying the PSS is always the last one of the frame */ - switch(srslte_sync_find(&q->strack, input_buffer, + switch(srslte_sync_find(&q->strack, input_buffer[0], q->frame_len - q->sf_len/2 - q->fft_size - q->strack.max_offset/2, &track_idx)) { @@ -607,10 +613,12 @@ int srslte_ue_sync_zerocopy(srslte_ue_sync_t *q, cf_t *input_buffer) { q->frame_total_cnt++; } if (q->correct_cfo) { - srslte_cfo_correct(&q->sfind.cfocorr, - input_buffer, - input_buffer, + for (int i=0;inof_rx_antennas;i++) { + srslte_cfo_correct(&q->sfind.cfocorr, + input_buffer[i], + input_buffer[i], -srslte_sync_get_cfo(&q->strack) / q->fft_size); + } } break; }