From fa741f24e705eee752735704fdc36725c7e507a2 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Tue, 25 Jul 2017 10:43:20 +0200 Subject: [PATCH 01/60] Added .gitignore --- .gitignore | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..694c93182 --- /dev/null +++ b/.gitignore @@ -0,0 +1,21 @@ +# Ignore build directories +build +debug +cmake-build-debug + +# Ignore CLion IDE project files +.idea + +# Generated data files +*.dat + +# Temporal files +*~ + +# Internal development +matlab +mex +cmake/modules/BuildMex.cmake +cmake/modules/FindMATLAB.cmake +cmake/modules/FindOCTAVE.cmake + From 6142a5f9e50ae522dff3a2bc669ab08adbae1ab5 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Tue, 25 Jul 2017 13:17:36 +0200 Subject: [PATCH 02/60] Merge to next_with_matlab --- lib/examples/cell_measurement.c | 13 +- lib/examples/pdsch_enodeb.c | 202 +++++++--- lib/examples/pdsch_ue.c | 73 +++- lib/examples/usrp_capture.c | 36 +- lib/examples/usrp_capture_sync.c | 25 +- .../srslte/phy/ch_estimation/chest_dl.h | 3 + lib/include/srslte/phy/common/phy_common.h | 2 + lib/include/srslte/phy/io/filesink.h | 5 + lib/include/srslte/phy/io/filesource.h | 5 + lib/include/srslte/phy/phch/pdcch.h | 15 + lib/include/srslte/phy/phch/pdsch.h | 39 +- lib/include/srslte/phy/phch/pdsch_cfg.h | 5 + lib/include/srslte/phy/phch/ra.h | 7 + lib/include/srslte/phy/phch/sch.h | 12 + lib/include/srslte/phy/rf/rf.h | 18 + lib/include/srslte/phy/ue/ue_dl.h | 13 +- lib/include/srslte/phy/ue/ue_sync.h | 7 + lib/include/srslte/phy/utils/debug.h | 1 + lib/src/phy/ch_estimation/chest_dl.c | 15 +- lib/src/phy/ch_estimation/test/CMakeLists.txt | 1 - lib/src/phy/common/phy_common.c | 19 +- lib/src/phy/io/filesink.c | 57 +++ lib/src/phy/io/filesource.c | 26 ++ lib/src/phy/mimo/precoding.c | 156 +++++++- lib/src/phy/mimo/test/CMakeLists.txt | 3 +- lib/src/phy/mimo/test/layermap_test.c | 2 +- lib/src/phy/mimo/test/precoder_mex.c | 25 +- lib/src/phy/mimo/test/precoder_test.c | 187 ++++++--- lib/src/phy/mimo/test/predecoder_mex.c | 137 ++++--- lib/src/phy/phch/dci.c | 10 + lib/src/phy/phch/pdcch.c | 34 +- lib/src/phy/phch/pdsch.c | 297 +++++++++++++-- lib/src/phy/phch/pucch.c | 2 +- lib/src/phy/phch/ra.c | 48 ++- lib/src/phy/phch/sch.c | 55 +++ lib/src/phy/phch/test/CMakeLists.txt | 21 + lib/src/phy/phch/test/dlsch_encode_test_mex.c | 32 +- lib/src/phy/phch/test/pdcch_test.c | 224 ++++++++--- lib/src/phy/phch/test/pdcch_test_mex.c | 14 +- lib/src/phy/phch/test/pdsch_test.c | 359 +++++++++++++----- lib/src/phy/phch/test/pdsch_test_mex.c | 2 +- lib/src/phy/phch/test/prach_detect_test_mex.c | 2 + lib/src/phy/phch/test/pucch_encode_test_mex.c | 2 +- lib/src/phy/phch/test/pucch_test_mex.c | 6 +- lib/src/phy/rf/rf_blade_imp.c | 16 +- lib/src/phy/rf/rf_blade_imp.h | 12 +- lib/src/phy/rf/rf_dev.h | 12 +- lib/src/phy/rf/rf_imp.c | 25 +- lib/src/phy/rf/rf_uhd_imp.c | 48 ++- lib/src/phy/rf/rf_uhd_imp.h | 11 + lib/src/phy/ue/ue_dl.c | 63 ++- lib/src/phy/ue/ue_sync.c | 31 +- srsue/hdr/phy/phch_worker.h | 1 + srsue/src/phy/phch_worker.cc | 10 +- 54 files changed, 1945 insertions(+), 501 deletions(-) diff --git a/lib/examples/cell_measurement.c b/lib/examples/cell_measurement.c index bc8262b29..9c7856daa 100644 --- a/lib/examples/cell_measurement.c +++ b/lib/examples/cell_measurement.c @@ -118,7 +118,7 @@ int parse_args(prog_args_t *args, int argc, char **argv) { /**********************************************************************/ /* TODO: Do something with the output data */ -uint8_t data[1000000]; +uint8_t *data[SRSLTE_MAX_CODEWORDS]; bool go_exit = false; void sig_int_handler(int signo) @@ -183,6 +183,9 @@ int main(int argc, char **argv) { } sf_buffer[0] = srslte_vec_malloc(3*sizeof(cf_t)*SRSLTE_SF_LEN_PRB(100)); + for (int i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { + data[i] = srslte_vec_malloc(sizeof(uint8_t) * 1500*8); + } sigset_t sigset; sigemptyset(&sigset); @@ -322,7 +325,7 @@ int main(int argc, char **argv) { nof_trials++; } else { printf("Decoded SIB1. Payload: "); - srslte_vec_fprint_byte(stdout, data, n/8);; + srslte_vec_fprint_byte(stdout, data[0], n/8);; state = MEASURE; } } @@ -386,6 +389,12 @@ int main(int argc, char **argv) { sf_cnt++; } // Main loop + for (int i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { + if (data[i]) { + free(data[i]); + } + } + srslte_ue_sync_free(&ue_sync); srslte_rf_close(&rf); printf("\nBye\n"); diff --git a/lib/examples/pdsch_enodeb.c b/lib/examples/pdsch_enodeb.c index 800e04de9..01e06c4c3 100644 --- a/lib/examples/pdsch_enodeb.c +++ b/lib/examples/pdsch_enodeb.c @@ -27,12 +27,12 @@ #include #include #include -#include #include -#include #include #include #include +#include +#include #include "srslte/srslte.h" @@ -55,19 +55,21 @@ char *output_file_name = NULL; #define DOWN_KEY 66 srslte_cell_t cell = { - 25, // nof_prb - 1, // nof_ports - 0, // cell_id - SRSLTE_CP_NORM, // cyclic prefix - SRSLTE_PHICH_R_1, // PHICH resources - SRSLTE_PHICH_NORM // PHICH length + 25, // nof_prb + 1, // nof_ports + 0, // cell_id + SRSLTE_CP_NORM, // cyclic prefix + SRSLTE_PHICH_NORM, // PHICH length + SRSLTE_PHICH_R_1 // PHICH resources }; - + int net_port = -1; // -1 generates random dataThat means there is some problem sending samples to the device uint32_t cfi=3; uint32_t mcs_idx = 1, last_mcs_idx = 1; int nof_frames = -1; +char mimo_type_str[32] = "single"; +uint32_t nof_tb = 1; char *rf_args = ""; float rf_amp = 0.8, rf_gain = 70.0, rf_freq = 2400000000; @@ -80,14 +82,14 @@ srslte_pcfich_t pcfich; srslte_pdcch_t pdcch; srslte_pdsch_t pdsch; srslte_pdsch_cfg_t pdsch_cfg; -srslte_softbuffer_tx_t softbuffer; +srslte_softbuffer_tx_t softbuffers[SRSLTE_MAX_CODEWORDS]; srslte_regs_t regs; srslte_ra_dl_dci_t ra_dl; -cf_t *sf_buffer = NULL, *output_buffer = NULL; +cf_t *sf_buffer[SRSLTE_MAX_PORTS] = {NULL}, *output_buffer [SRSLTE_MAX_PORTS] = {NULL}; int sf_n_re, sf_n_samples; -pthread_t net_thread; +pthread_t net_thread; void *net_thread_fnc(void *arg); sem_t net_sem; bool net_packet_ready = false; @@ -99,7 +101,7 @@ int prbset_orig = 0; void usage(char *prog) { - printf("Usage: %s [agmfoncvpu]\n", prog); + printf("Usage: %s [agmfoncvpuM]\n", prog); #ifndef DISABLE_RF printf("\t-a RF args [Default %s]\n", rf_args); printf("\t-l RF amplitude [Default %.2f]\n", rf_amp); @@ -113,13 +115,14 @@ void usage(char *prog) { printf("\t-n number of frames [Default %d]\n", nof_frames); printf("\t-c cell id [Default %d]\n", cell.id); printf("\t-p nof_prb [Default %d]\n", cell.nof_prb); + printf("\t-M Transmission mode[single|diversity|cdd] [Default %s]\n", mimo_type_str); printf("\t-u listen TCP port for input data (-1 is random) [Default %d]\n", net_port); printf("\t-v [set srslte_verbose to debug, default none]\n"); } void parse_args(int argc, char **argv) { int opt; - while ((opt = getopt(argc, argv, "aglfmoncpvu")) != -1) { + while ((opt = getopt(argc, argv, "aglfmoncpvutM")) != -1) { switch (opt) { case 'a': rf_args = argv[optind]; @@ -151,6 +154,9 @@ void parse_args(int argc, char **argv) { case 'c': cell.id = atoi(argv[optind]); break; + case 'M': + strncpy(mimo_type_str, argv[optind], 32); + break; case 'v': srslte_verbose++; break; @@ -168,18 +174,54 @@ void parse_args(int argc, char **argv) { } void base_init() { - - /* init memory */ - sf_buffer = srslte_vec_malloc(sizeof(cf_t) * sf_n_re); - if (!sf_buffer) { - perror("malloc"); + int i; + + /* Select transmission mode */ + if (srslte_str2mimotype(mimo_type_str, &pdsch_cfg.mimo_type)) { + ERROR("Wrong transmission mode! Allowed modes: single, diversity, cdd"); exit(-1); } - output_buffer = srslte_vec_malloc(sizeof(cf_t) * sf_n_samples); - if (!output_buffer) { - perror("malloc"); - exit(-1); + + /* Configure cell and PDSCH in function of the transmission mode */ + switch(pdsch_cfg.mimo_type) { + case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA: + cell.nof_ports = 1; + pdsch_cfg.nof_layers = 1; + nof_tb = 1; + break; + case SRSLTE_MIMO_TYPE_TX_DIVERSITY: + cell.nof_ports = 2; + pdsch_cfg.nof_layers = 2; + nof_tb = 1; + break; + case SRSLTE_MIMO_TYPE_CDD: + cell.nof_ports = 2; + pdsch_cfg.nof_layers = 2; + nof_tb = 2; + break; + default: + ERROR("Transmission mode not implemented."); + exit(-1); } + + /* init memory */ + for (i = 0; i < cell.nof_ports; i++) { + sf_buffer[i] = srslte_vec_malloc(sizeof(cf_t) * sf_n_re); + if (!sf_buffer[i]) { + perror("malloc"); + exit(-1); + } + } + + for (i = 0; i < SRSLTE_MAX_PORTS; i++) { + output_buffer[i] = srslte_vec_malloc(sizeof(cf_t) * sf_n_samples); + if (!output_buffer[i]) { + perror("malloc"); + exit(-1); + } + bzero(output_buffer[i], sizeof(cf_t) * sf_n_samples); + } + /* open file or USRP */ if (output_file_name) { if (strcmp(output_file_name, "NULL")) { @@ -194,7 +236,7 @@ void base_init() { } else { #ifndef DISABLE_RF printf("Opening RF device...\n"); - if (srslte_rf_open(&rf, rf_args)) { + if (srslte_rf_open_multi2(&rf, rf_args, cell.nof_ports, 1)) { fprintf(stderr, "Error opening rf\n"); exit(-1); } @@ -247,27 +289,32 @@ void base_init() { exit(-1); } - if (srslte_pdcch_init(&pdcch, ®s, cell)) { + if (srslte_pdcch_init_tx(&pdcch, ®s, cell)) { fprintf(stderr, "Error creating PDCCH object\n"); exit(-1); } - if (srslte_pdsch_init(&pdsch, cell)) { + bzero(&pdsch, sizeof(srslte_pdsch_t)); + if (srslte_pdsch_init_tx_multi(&pdsch, cell)) { fprintf(stderr, "Error creating PDSCH object\n"); exit(-1); } - + srslte_pdsch_set_rnti(&pdsch, UE_CRNTI); - - if (srslte_softbuffer_tx_init(&softbuffer, cell.nof_prb)) { - fprintf(stderr, "Error initiating soft buffer\n"); - exit(-1); + + for (i = 0; i < nof_tb; i++) { + if (srslte_softbuffer_tx_init(&softbuffers[i], cell.nof_prb)) { + fprintf(stderr, "Error initiating soft buffer\n"); + exit(-1); + } } } void base_free() { - - srslte_softbuffer_tx_free(&softbuffer); + int i; + for (i = 0; i < nof_tb; i++) { + srslte_softbuffer_tx_free(&softbuffers[i]); + } srslte_pdsch_free(&pdsch); srslte_pdcch_free(&pdcch); srslte_regs_free(®s); @@ -275,11 +322,14 @@ void base_free() { srslte_ofdm_tx_free(&ifft); - if (sf_buffer) { - free(sf_buffer); - } - if (output_buffer) { - free(output_buffer); + for (i = 0; i < SRSLTE_MAX_PORTS; i++) { + if (sf_buffer[i]) { + free(sf_buffer[i]); + } + + if (output_buffer[i]) { + free(output_buffer[i]); + } } if (output_file_name) { if (!null_file_sink) { @@ -340,7 +390,14 @@ int update_radl() { ra_dl.rv_idx = 0; ra_dl.alloc_type = SRSLTE_RA_ALLOC_TYPE0; ra_dl.type0_alloc.rbg_bitmask = prbset_to_bitmask(); - ra_dl.tb_en[0] = 1; + ra_dl.tb_en[0] = 1; + + if (nof_tb > 1) { + ra_dl.mcs_idx_1 = mcs_idx; + ra_dl.ndi_1 = 0; + ra_dl.rv_idx_1 = 0; + ra_dl.tb_en[1] = 1; + } srslte_ra_pdsch_fprint(stdout, &ra_dl, cell.nof_prb); srslte_ra_dl_grant_t dummy_grant; @@ -497,9 +554,9 @@ int main(int argc, char **argv) { exit(-1); } - for (i = 0; i < SRSLTE_MAX_PORTS; i++) { // now there's only 1 port - sf_symbols[i] = sf_buffer; - slot1_symbols[i] = &sf_buffer[SRSLTE_SLOT_LEN_RE(cell.nof_prb, cell.cp)]; + for (i = 0; i < SRSLTE_MAX_PORTS; i++) { + sf_symbols[i] = sf_buffer[i%cell.nof_ports]; + slot1_symbols[i] = &sf_buffer[i%cell.nof_ports][SRSLTE_SLOT_LEN_RE(cell.nof_prb, cell.cp)]; } #ifndef DISABLE_RF @@ -556,7 +613,9 @@ int main(int argc, char **argv) { nf = 0; bool send_data = false; - srslte_softbuffer_tx_reset(&softbuffer); + for (i = 0; i < nof_tb; i++) { + srslte_softbuffer_tx_reset(&softbuffers[i]); + } #ifndef DISABLE_RF bool start_of_burst = true; @@ -564,15 +623,25 @@ int main(int argc, char **argv) { while ((nf < nof_frames || nof_frames == -1) && !go_exit) { for (sf_idx = 0; sf_idx < SRSLTE_NSUBFRAMES_X_FRAME && (nf < nof_frames || nof_frames == -1); sf_idx++) { - bzero(sf_buffer, sizeof(cf_t) * sf_n_re); + /* Set Antenna port resource elements to zero */ + bzero(sf_symbols[0], sizeof(cf_t) * sf_n_re); + /* Populate Synchronization signals if required */ if (sf_idx == 0 || sf_idx == 5) { - srslte_pss_put_slot(pss_signal, sf_buffer, cell.nof_prb, SRSLTE_CP_NORM); - srslte_sss_put_slot(sf_idx ? sss_signal5 : sss_signal0, sf_buffer, cell.nof_prb, + srslte_pss_put_slot(pss_signal, sf_symbols[0], cell.nof_prb, SRSLTE_CP_NORM); + srslte_sss_put_slot(sf_idx ? sss_signal5 : sss_signal0, sf_symbols[0], cell.nof_prb, SRSLTE_CP_NORM); } - srslte_refsignal_cs_put_sf(cell, 0, est.csr_signal.pilots[0][sf_idx], sf_buffer); + /* Copy zeros, SSS, PSS into the rest of antenna ports */ + for (i = 1; i < cell.nof_ports; i++) { + memcpy(sf_symbols[i], sf_symbols[0], sizeof(cf_t) * sf_n_re); + } + + /* Put reference signals */ + for (i = 0; i < cell.nof_ports; i++) { + srslte_refsignal_cs_put_sf(cell, (uint32_t) i, est.csr_signal.pilots[i / 2][sf_idx], sf_symbols[i]); + } srslte_pbch_mib_pack(&cell, sfn, bch_payload); if (sf_idx == 0) { @@ -606,10 +675,23 @@ int main(int argc, char **argv) { } if (send_data) { - + srslte_dci_format_t dci_format = SRSLTE_DCI_FORMAT1; + switch(pdsch_cfg.mimo_type) { + case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA: + dci_format = SRSLTE_DCI_FORMAT1; + break; + case SRSLTE_MIMO_TYPE_TX_DIVERSITY: + case SRSLTE_MIMO_TYPE_CDD: + dci_format = SRSLTE_DCI_FORMAT2A; + break; + case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX: + default: + fprintf(stderr, "Wrong MIMO configuration\n"); + exit(SRSLTE_ERROR); + } /* Encode PDCCH */ INFO("Putting DCI to location: n=%d, L=%d\n", locations[sf_idx][0].ncce, locations[sf_idx][0].L); - srslte_dci_msg_pack_pdsch(&ra_dl, SRSLTE_DCI_FORMAT1, &dci_msg, cell.nof_prb, cell.nof_ports, false); + srslte_dci_msg_pack_pdsch(&ra_dl, dci_format, &dci_msg, cell.nof_prb, cell.nof_ports, false); if (srslte_pdcch_encode(&pdcch, &dci_msg, locations[sf_idx][0], UE_CRNTI, sf_symbols, sf_idx, cfi)) { fprintf(stderr, "Error encoding DCI message\n"); exit(-1); @@ -618,13 +700,14 @@ int main(int argc, char **argv) { /* Configure pdsch_cfg parameters */ srslte_ra_dl_grant_t grant; srslte_ra_dl_dci_to_grant(&ra_dl, cell.nof_prb, UE_CRNTI, &grant); - if (srslte_pdsch_cfg(&pdsch_cfg, cell, &grant, cfi, sf_idx, 0)) { + if (srslte_pdsch_cfg_multi(&pdsch_cfg, cell, &grant, cfi, sf_idx, 0, 0)) { fprintf(stderr, "Error configuring PDSCH\n"); exit(-1); } /* Encode PDSCH */ - if (srslte_pdsch_encode(&pdsch, &pdsch_cfg, &softbuffer, data, UE_CRNTI, sf_symbols)) { + if (srslte_pdsch_encode_multi(&pdsch, &pdsch_cfg, softbuffers, (uint8_t*[2]){data, data}, UE_CRNTI, + sf_symbols)) { fprintf(stderr, "Error encoding PDSCH\n"); exit(-1); } @@ -641,21 +724,24 @@ int main(int argc, char **argv) { } /* Transform to OFDM symbols */ - srslte_ofdm_tx_sf(&ifft, sf_buffer, output_buffer); - + for (i = 0; i < cell.nof_ports; i++) { + srslte_ofdm_tx_sf(&ifft, sf_buffer[i], output_buffer[i]); + } + /* send to file or usrp */ if (output_file_name) { if (!null_file_sink) { - srslte_filesink_write(&fsink, output_buffer, sf_n_samples); + srslte_filesink_write_multi(&fsink, (void**) output_buffer, sf_n_samples, cell.nof_ports); } usleep(1000); } else { #ifndef DISABLE_RF - // FIXME float norm_factor = (float) cell.nof_prb/15/sqrtf(pdsch_cfg.grant.nof_prb); - srslte_vec_sc_prod_cfc(output_buffer, rf_amp*norm_factor, output_buffer, SRSLTE_SF_LEN_PRB(cell.nof_prb)); - srslte_rf_send2(&rf, output_buffer, sf_n_samples, true, start_of_burst, false); - start_of_burst=false; + for (i = 0; i < cell.nof_ports; i++) { + srslte_vec_sc_prod_cfc(output_buffer[i], rf_amp * norm_factor, output_buffer[i], SRSLTE_SF_LEN_PRB(cell.nof_prb)); + } + srslte_rf_send_multi(&rf, (void**) output_buffer, sf_n_samples, true, start_of_burst, false); + start_of_burst=false; #endif } } diff --git a/lib/examples/pdsch_ue.c b/lib/examples/pdsch_ue.c index 72dc36731..bab9d7219 100644 --- a/lib/examples/pdsch_ue.c +++ b/lib/examples/pdsch_ue.c @@ -258,7 +258,7 @@ void parse_args(prog_args_t *args, int argc, char **argv) { /**********************************************************************/ /* TODO: Do something with the output data */ -uint8_t data[20000]; +uint8_t *data[SRSLTE_MAX_CODEWORDS]; bool go_exit = false; void sig_int_handler(int signo) @@ -266,10 +266,12 @@ void sig_int_handler(int signo) printf("SIGINT received. Exiting...\n"); if (signo == SIGINT) { go_exit = true; + } else if (signo == SIGSEGV) { + exit(1); } } -cf_t *sf_buffer[2] = {NULL, NULL}; +cf_t *sf_buffer[SRSLTE_MAX_PORTS] = {NULL}; #ifndef DISABLE_RF int srslte_rf_recv_wrapper(void *h, cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *t) { @@ -315,6 +317,14 @@ int main(int argc, char **argv) { parse_args(&prog_args, argc, argv); + for (int i = 0; i< SRSLTE_MAX_CODEWORDS; i++) { + data[i] = srslte_vec_malloc(sizeof(uint8_t)*1500*8); + if (!data[i]) { + ERROR("Allocating data"); + go_exit = true; + } + } + if(prog_args.cpu_affinity > -1) { cpu_set_t cpuset; @@ -435,8 +445,8 @@ int main(int argc, char **argv) { cell.nof_ports = prog_args.file_nof_ports; cell.nof_prb = prog_args.file_nof_prb; - if (srslte_ue_sync_init_file(&ue_sync, prog_args.file_nof_prb, - prog_args.input_file_name, prog_args.file_offset_time, prog_args.file_offset_freq)) { + if (srslte_ue_sync_init_file_multi(&ue_sync, prog_args.file_nof_prb, + prog_args.input_file_name, prog_args.file_offset_time, prog_args.file_offset_freq, prog_args.rf_nof_rx_ant)) { fprintf(stderr, "Error initiating ue_sync\n"); exit(-1); } @@ -498,7 +508,7 @@ int main(int argc, char **argv) { // Variables for measurements uint32_t nframes=0; - float rsrp=0.0, rsrq=0.0, noise=0.0; + float rsrp0=0.0, rsrp1=0.0, rsrq=0.0, noise=0.0; bool decode_pdsch = false; #ifndef DISABLE_RF @@ -596,8 +606,9 @@ int main(int argc, char **argv) { nof_trials++; rsrq = SRSLTE_VEC_EMA(srslte_chest_dl_get_rsrq(&ue_dl.chest), rsrq, 0.1); - rsrp = SRSLTE_VEC_EMA(srslte_chest_dl_get_rsrp(&ue_dl.chest), rsrp, 0.05); - noise = SRSLTE_VEC_EMA(srslte_chest_dl_get_noise_estimate(&ue_dl.chest), noise, 0.05); + rsrp0 = SRSLTE_VEC_EMA(srslte_chest_dl_get_rsrp_port(&ue_dl.chest, 0), rsrp0, 0.05); + rsrp1 = SRSLTE_VEC_EMA(srslte_chest_dl_get_rsrp_port(&ue_dl.chest, 1), rsrp1, 0.05); + noise = SRSLTE_VEC_EMA(srslte_chest_dl_get_noise_estimate(&ue_dl.chest), noise, 0.05); nframes++; if (isnan(rsrq)) { rsrq = 0; @@ -605,9 +616,12 @@ int main(int argc, char **argv) { if (isnan(noise)) { noise = 0; } - if (isnan(rsrp)) { - rsrp = 0; - } + if (isnan(rsrp0)) { + rsrp1 = 0; + } + if (isnan(rsrp0)) { + rsrp1 = 0; + } } // Plot and Printf @@ -616,14 +630,27 @@ int main(int argc, char **argv) { if (gain < 0) { gain = 10*log10(srslte_agc_get_gain(&ue_sync.agc)); } - printf("CFO: %+6.2f kHz, " - "SNR: %4.1f dB, " - "PDCCH-Miss: %5.2f%%, PDSCH-BLER: %5.2f%%\r", - - srslte_ue_sync_get_cfo(&ue_sync)/1000, - 10*log10(rsrp/noise), - 100*(1-(float) ue_dl.nof_detected/nof_trials), - (float) 100*ue_dl.pkt_errors/ue_dl.pkts_total); + if (cell.nof_ports == 1) { + printf("CFO: %+6.2f kHz, " + "SNR: %4.1f dB, " + "PDCCH-Miss: %5.2f%%, PDSCH-BLER: %5.2f%%\r", + + srslte_ue_sync_get_cfo(&ue_sync) / 1000, + 10 * log10(rsrp0 / noise), + 100 * (1 - (float) ue_dl.nof_detected / nof_trials), + (float) 100 * ue_dl.pkt_errors / ue_dl.pkts_total); + } else { + printf("CFO: %+6.2f kHz, " + "SNR port 0: %4.1f dB, " + "SNR port 1: %4.1f dB, " + "PDCCH-Miss: %5.2f%%, PDSCH-BLER: %5.2f%%\r", + + srslte_ue_sync_get_cfo(&ue_sync) / 1000, + 10 * log10(rsrp0 / noise), + 10 * log10(rsrp1 / noise), + 100 * (1 - (float) ue_dl.nof_detected / nof_trials), + (float) 100 * ue_dl.pkt_errors / ue_dl.pkts_total); + } } break; } @@ -674,6 +701,16 @@ int main(int argc, char **argv) { #endif srslte_ue_dl_free(&ue_dl); srslte_ue_sync_free(&ue_sync); + for (int i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { + if (data[i]) { + free(data[i]); + } + } + for (int i = 0; i < prog_args.rf_nof_rx_ant; i++) { + if (sf_buffer[i]) { + free(sf_buffer[i]); + } + } #ifndef DISABLE_RF if (!prog_args.input_file_name) { diff --git a/lib/examples/usrp_capture.c b/lib/examples/usrp_capture.c index 2692deb0d..02b543c0e 100644 --- a/lib/examples/usrp_capture.c +++ b/lib/examples/usrp_capture.c @@ -44,6 +44,7 @@ char *output_file_name; char *rf_args=""; float rf_gain=40.0, rf_freq=-1.0, rf_rate=0.96e6; int nof_samples = -1; +int nof_rx_antennas = 1; void int_handler(int dummy) { keep_running = false; @@ -55,12 +56,13 @@ void usage(char *prog) { printf("\t-g RF Gain [Default %.2f dB]\n", rf_gain); printf("\t-r RF Rate [Default %.6f Hz]\n", rf_rate); printf("\t-n nof_samples [Default %d]\n", nof_samples); + printf("\t-A nof_rx_antennas [Default %d]\n", nof_rx_antennas); printf("\t-v srslte_verbose\n"); } void parse_args(int argc, char **argv) { int opt; - while ((opt = getopt(argc, argv, "agrnvfo")) != -1) { + while ((opt = getopt(argc, argv, "agrnvfoA")) != -1) { switch (opt) { case 'o': output_file_name = argv[optind]; @@ -80,6 +82,9 @@ void parse_args(int argc, char **argv) { case 'n': nof_samples = atoi(argv[optind]); break; + case 'A': + nof_rx_antennas = atoi(argv[optind]); + break; case 'v': srslte_verbose++; break; @@ -95,11 +100,11 @@ void parse_args(int argc, char **argv) { } int main(int argc, char **argv) { - cf_t *buffer; + cf_t *buffer[SRSLTE_MAX_PORTS]; int sample_count, n; srslte_rf_t rf; srslte_filesink_t sink; - int32_t buflen; + uint32_t buflen; signal(SIGINT, int_handler); @@ -107,17 +112,19 @@ int main(int argc, char **argv) { buflen = 4800; sample_count = 0; - - buffer = malloc(sizeof(cf_t) * buflen); - if (!buffer) { - perror("malloc"); - exit(-1); + + for (int i = 0; i < nof_rx_antennas; i++) { + buffer[i] = malloc(sizeof(cf_t) * buflen); + if (!buffer[i]) { + perror("malloc"); + exit(-1); + } } srslte_filesink_init(&sink, output_file_name, SRSLTE_COMPLEX_FLOAT_BIN); printf("Opening RF device...\n"); - if (srslte_rf_open(&rf, rf_args)) { + if (srslte_rf_open_multi(&rf, rf_args, nof_rx_antennas)) { fprintf(stderr, "Error opening rf\n"); exit(-1); } @@ -151,18 +158,23 @@ int main(int argc, char **argv) { while((sample_count < nof_samples || nof_samples == -1) && keep_running){ - n = srslte_rf_recv(&rf, buffer, buflen, 1); + n = srslte_rf_recv_with_time_multi(&rf, (void**) buffer, buflen, true, NULL, NULL); if (n < 0) { fprintf(stderr, "Error receiving samples\n"); exit(-1); } - srslte_filesink_write(&sink, buffer, buflen); + srslte_filesink_write_multi(&sink, (void**) buffer, buflen, nof_rx_antennas); sample_count += buflen; } + for (int i = 0; i < nof_rx_antennas; i++) { + if (buffer[i]) { + free(buffer[i]); + } + } + srslte_filesink_free(&sink); - free(buffer); srslte_rf_close(&rf); printf("Ok - wrote %d samples\n", sample_count); diff --git a/lib/examples/usrp_capture_sync.c b/lib/examples/usrp_capture_sync.c index 6d2ec18dc..41c233be7 100644 --- a/lib/examples/usrp_capture_sync.c +++ b/lib/examples/usrp_capture_sync.c @@ -45,6 +45,7 @@ float rf_gain=60.0, rf_freq=-1.0; int nof_prb = 6; int nof_subframes = -1; int N_id_2 = -1; +uint32_t nof_rx_antennas = 1; void int_handler(int dummy) { keep_running = false; @@ -56,12 +57,13 @@ void usage(char *prog) { printf("\t-g RF Gain [Default %.2f dB]\n", rf_gain); printf("\t-p nof_prb [Default %d]\n", nof_prb); printf("\t-n nof_subframes [Default %d]\n", nof_subframes); + printf("\t-A nof_rx_antennas [Default %d]\n", nof_rx_antennas); printf("\t-v verbose\n"); } void parse_args(int argc, char **argv) { int opt; - while ((opt = getopt(argc, argv, "agpnvfol")) != -1) { + while ((opt = getopt(argc, argv, "agpnvfolA")) != -1) { switch (opt) { case 'o': output_file_name = argv[optind]; @@ -84,6 +86,9 @@ void parse_args(int argc, char **argv) { case 'l': N_id_2 = atoi(argv[optind]); break; + case 'A': + nof_rx_antennas = (uint32_t) atoi(argv[optind]); + break; case 'v': srslte_verbose++; break; @@ -100,7 +105,7 @@ void parse_args(int argc, char **argv) { 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[0], nsamples, 1); + return srslte_rf_recv_with_time_multi(h, (void**) data, nsamples, true, NULL, NULL); } int main(int argc, char **argv) { @@ -118,13 +123,15 @@ int main(int argc, char **argv) { srslte_filesink_init(&sink, output_file_name, SRSLTE_COMPLEX_FLOAT_BIN); printf("Opening RF device...\n"); - if (srslte_rf_open(&rf, rf_args)) { + if (srslte_rf_open_multi(&rf, rf_args, nof_rx_antennas)) { fprintf(stderr, "Error opening rf\n"); exit(-1); } srslte_rf_set_master_clock_rate(&rf, 30.72e6); - buffer[0] = srslte_vec_malloc(3*sizeof(cf_t)*SRSLTE_SF_LEN_PRB(100)); + for (int i = 0; i< SRSLTE_MAX_PORTS; i++) { + buffer[i] = srslte_vec_malloc(3 * sizeof(cf_t) * SRSLTE_SF_LEN_PRB(100)); + } sigset_t sigset; sigemptyset(&sigset); @@ -158,7 +165,7 @@ int main(int argc, char **argv) { cell.nof_prb = nof_prb; cell.nof_ports = 1; - if (srslte_ue_sync_init_multi(&ue_sync, cell, srslte_rf_recv_wrapper, 1, (void*) &rf)) { + if (srslte_ue_sync_init_multi(&ue_sync, cell, srslte_rf_recv_wrapper, nof_rx_antennas, (void*) &rf)) { fprintf(stderr, "Error initiating ue_sync\n"); exit(-1); } @@ -181,7 +188,7 @@ int main(int argc, char **argv) { } } else { printf("Writing to file %6d subframes...\r", subframe_count); - srslte_filesink_write(&sink, buffer[0], SRSLTE_SF_LEN_PRB(nof_prb)); + srslte_filesink_write_multi(&sink, (void**) buffer, SRSLTE_SF_LEN_PRB(nof_prb),nof_rx_antennas); subframe_count++; } } @@ -196,6 +203,12 @@ int main(int argc, char **argv) { srslte_rf_close(&rf); srslte_ue_sync_free(&ue_sync); + for (int i = 0; i < SRSLTE_MAX_PORTS; i++) { + if (buffer[i]) { + free(buffer[i]); + } + } + printf("Ok - wrote %d subframes\n", subframe_count); exit(0); } diff --git a/lib/include/srslte/phy/ch_estimation/chest_dl.h b/lib/include/srslte/phy/ch_estimation/chest_dl.h index a454f939c..5d0820aa4 100644 --- a/lib/include/srslte/phy/ch_estimation/chest_dl.h +++ b/lib/include/srslte/phy/ch_estimation/chest_dl.h @@ -132,6 +132,9 @@ SRSLTE_API float srslte_chest_dl_get_rssi(srslte_chest_dl_t *q); SRSLTE_API float srslte_chest_dl_get_rsrq(srslte_chest_dl_t *q); +SRSLTE_API float srslte_chest_dl_get_rsrp_port(srslte_chest_dl_t *q, + uint32_t port); + SRSLTE_API float srslte_chest_dl_get_rsrp(srslte_chest_dl_t *q); #endif diff --git a/lib/include/srslte/phy/common/phy_common.h b/lib/include/srslte/phy/common/phy_common.h index efd498c86..b891b7330 100644 --- a/lib/include/srslte/phy/common/phy_common.h +++ b/lib/include/srslte/phy/common/phy_common.h @@ -244,6 +244,8 @@ SRSLTE_API uint32_t srslte_N_ta_new(uint32_t N_ta_old, SRSLTE_API char *srslte_cp_string(srslte_cp_t cp); +SRSLTE_API srslte_mod_t srslte_str2mod (char * mod_str); + SRSLTE_API char *srslte_mod_string(srslte_mod_t mod); SRSLTE_API uint32_t srslte_mod_bits_x_symbol(srslte_mod_t mod); diff --git a/lib/include/srslte/phy/io/filesink.h b/lib/include/srslte/phy/io/filesink.h index b8ca8db51..921f1e440 100644 --- a/lib/include/srslte/phy/io/filesink.h +++ b/lib/include/srslte/phy/io/filesink.h @@ -59,4 +59,9 @@ SRSLTE_API int srslte_filesink_write(srslte_filesink_t *q, void *buffer, int nsamples); +SRSLTE_API int srslte_filesink_write_multi(srslte_filesink_t *q, + void **buffer, + int nsamples, + int nchannels); + #endif // FILESINK_ diff --git a/lib/include/srslte/phy/io/filesource.h b/lib/include/srslte/phy/io/filesource.h index ee8bc080d..f515d7034 100644 --- a/lib/include/srslte/phy/io/filesource.h +++ b/lib/include/srslte/phy/io/filesource.h @@ -62,4 +62,9 @@ SRSLTE_API int srslte_filesource_read(srslte_filesource_t *q, void *buffer, int nsamples); +SRSLTE_API int srslte_filesource_read_multi(srslte_filesource_t *q, + void **buffer, + int nsamples, + int nof_channels); + #endif // FILESOURCE_ diff --git a/lib/include/srslte/phy/phch/pdcch.h b/lib/include/srslte/phy/phch/pdcch.h index 8d4aba790..f67d29dcb 100644 --- a/lib/include/srslte/phy/phch/pdcch.h +++ b/lib/include/srslte/phy/phch/pdcch.h @@ -88,11 +88,26 @@ SRSLTE_API int srslte_pdcch_init(srslte_pdcch_t *q, srslte_regs_t *regs, srslte_cell_t cell); +SRSLTE_API int srslte_pdcch_init_tx(srslte_pdcch_t *q, + srslte_regs_t *regs, + srslte_cell_t cell); + +SRSLTE_API int srslte_pdcch_init_rx(srslte_pdcch_t *q, + srslte_regs_t *regs, + srslte_cell_t cell, + uint32_t nof_rx_antennas); + SRSLTE_API int srslte_pdcch_init_multi(srslte_pdcch_t *q, srslte_regs_t *regs, srslte_cell_t cell, uint32_t nof_rx_antennas); +SRSLTE_API int srslte_pdcch_init_txrx(srslte_pdcch_t *q, + srslte_regs_t *regs, + srslte_cell_t cell, + uint32_t nof_rx_antennas, + bool isReceiver); + SRSLTE_API void srslte_pdcch_free(srslte_pdcch_t *q); diff --git a/lib/include/srslte/phy/phch/pdsch.h b/lib/include/srslte/phy/phch/pdsch.h index ad01c4ef8..7bdaaef9c 100644 --- a/lib/include/srslte/phy/phch/pdsch.h +++ b/lib/include/srslte/phy/phch/pdsch.h @@ -49,6 +49,7 @@ typedef struct { srslte_sequence_t seq[SRSLTE_NSUBFRAMES_X_FRAME]; + srslte_sequence_t seq2[SRSLTE_NSUBFRAMES_X_FRAME]; bool sequence_generated; } srslte_pdsch_user_t; @@ -62,11 +63,13 @@ typedef struct SRSLTE_API { /* buffers */ // void buffers are shared for tx and rx - cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; - cf_t *symbols[SRSLTE_MAX_PORTS]; - cf_t *x[SRSLTE_MAX_PORTS]; - cf_t *d; + cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; /* Channel estimation (Rx only) */ + cf_t *symbols[SRSLTE_MAX_PORTS]; /* PDSCH Encoded/Decoded Symbols */ + cf_t *x[SRSLTE_MAX_LAYERS]; /* Layer mapped */ + cf_t *d; /* Modulated/Demodulated codeword 1 */ + cf_t *d2; /* Modulated/Demodulated codeword 2 */ void *e; + void *e2; /* tx & rx objects */ srslte_modem_table_t mod[4]; @@ -81,9 +84,12 @@ typedef struct SRSLTE_API { SRSLTE_API int srslte_pdsch_init(srslte_pdsch_t *q, srslte_cell_t cell); -SRSLTE_API int srslte_pdsch_init_multi(srslte_pdsch_t *q, - srslte_cell_t cell, - uint32_t nof_rx_antennas); +SRSLTE_API int srslte_pdsch_init_tx_multi(srslte_pdsch_t *q, + srslte_cell_t cell); + +SRSLTE_API int srslte_pdsch_init_rx_multi(srslte_pdsch_t *q, + srslte_cell_t cell, + uint32_t nof_antennas); SRSLTE_API void srslte_pdsch_free(srslte_pdsch_t *q); @@ -103,6 +109,14 @@ SRSLTE_API int srslte_pdsch_cfg(srslte_pdsch_cfg_t *cfg, uint32_t sf_idx, uint32_t rvidx); +SRSLTE_API int srslte_pdsch_cfg_multi(srslte_pdsch_cfg_t *cfg, + srslte_cell_t cell, + srslte_ra_dl_grant_t *grant, + uint32_t cfi, + uint32_t sf_idx, + uint32_t rvidx, + uint32_t rvidx2); + SRSLTE_API int srslte_pdsch_encode(srslte_pdsch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbuffer_tx_t *softbuffer, @@ -110,6 +124,13 @@ SRSLTE_API int srslte_pdsch_encode(srslte_pdsch_t *q, uint16_t rnti, cf_t *sf_symbols[SRSLTE_MAX_PORTS]); +SRSLTE_API int srslte_pdsch_encode_multi(srslte_pdsch_t *q, + srslte_pdsch_cfg_t *cfg, + srslte_softbuffer_tx_t softbuffers[SRSLTE_MAX_CODEWORDS], + uint8_t *data[SRSLTE_MAX_CODEWORDS], + uint16_t rnti, + cf_t *sf_symbols[SRSLTE_MAX_PORTS]); + SRSLTE_API int srslte_pdsch_decode(srslte_pdsch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffer, @@ -121,12 +142,12 @@ SRSLTE_API int srslte_pdsch_decode(srslte_pdsch_t *q, SRSLTE_API int srslte_pdsch_decode_multi(srslte_pdsch_t *q, srslte_pdsch_cfg_t *cfg, - srslte_softbuffer_rx_t *softbuffer, + srslte_softbuffer_rx_t softbuffers[SRSLTE_MAX_CODEWORDS], 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); + uint8_t *data[SRSLTE_MAX_CODEWORDS]); SRSLTE_API float srslte_pdsch_average_noi(srslte_pdsch_t *q); diff --git a/lib/include/srslte/phy/phch/pdsch_cfg.h b/lib/include/srslte/phy/phch/pdsch_cfg.h index 2745470f8..bec326338 100644 --- a/lib/include/srslte/phy/phch/pdsch_cfg.h +++ b/lib/include/srslte/phy/phch/pdsch_cfg.h @@ -41,10 +41,15 @@ typedef struct SRSLTE_API { srslte_cbsegm_t cb_segm; + srslte_cbsegm_t cb_segm2; srslte_ra_dl_grant_t grant; srslte_ra_nbits_t nbits; + srslte_ra_nbits_t nbits2; uint32_t rv; + uint32_t rv2; uint32_t sf_idx; + uint32_t nof_layers; + srslte_mimo_type_t mimo_type; } srslte_pdsch_cfg_t; #endif diff --git a/lib/include/srslte/phy/phch/ra.h b/lib/include/srslte/phy/phch/ra.h index cec2e6087..3c7c3d93c 100644 --- a/lib/include/srslte/phy/phch/ra.h +++ b/lib/include/srslte/phy/phch/ra.h @@ -209,6 +209,13 @@ SRSLTE_API void srslte_ra_dl_grant_to_nbits(srslte_ra_dl_grant_t *grant, uint32_t sf_idx, srslte_ra_nbits_t *nbits); +SRSLTE_API void srslte_ra_dl_grant_to_nbits_multi(srslte_ra_dl_grant_t *grant, + uint32_t cfi, + srslte_cell_t cell, + uint32_t sf_idx, + srslte_ra_nbits_t *nbits, + srslte_ra_nbits_t *nbits2); + SRSLTE_API uint32_t srslte_ra_dl_approx_nof_re(srslte_cell_t cell, uint32_t nof_prb, uint32_t nof_ctrl_symbols); diff --git a/lib/include/srslte/phy/phch/sch.h b/lib/include/srslte/phy/phch/sch.h index 4ef0b3070..0e59ecbc9 100644 --- a/lib/include/srslte/phy/phch/sch.h +++ b/lib/include/srslte/phy/phch/sch.h @@ -96,12 +96,24 @@ SRSLTE_API int srslte_dlsch_encode(srslte_sch_t *q, uint8_t *data, uint8_t *e_bits); +SRSLTE_API int srslte_dlsch_encode_multi(srslte_sch_t *q, + srslte_pdsch_cfg_t *cfg, + srslte_softbuffer_tx_t softbuffers[SRSLTE_MAX_CODEWORDS], + uint8_t *data[SRSLTE_MAX_CODEWORDS], + uint8_t *e_bits[SRSLTE_MAX_CODEWORDS]); + SRSLTE_API int srslte_dlsch_decode(srslte_sch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffer, int16_t *e_bits, uint8_t *data); +SRSLTE_API int srslte_dlsch_decode_multi(srslte_sch_t *q, + srslte_pdsch_cfg_t *cfg, + srslte_softbuffer_rx_t softbuffers[SRSLTE_MAX_CODEWORDS], + int16_t *e_bits[SRSLTE_MAX_CODEWORDS], + uint8_t *data[SRSLTE_MAX_CODEWORDS]); + SRSLTE_API int srslte_ulsch_encode(srslte_sch_t *q, srslte_pusch_cfg_t *cfg, srslte_softbuffer_tx_t *softbuffer, diff --git a/lib/include/srslte/phy/rf/rf.h b/lib/include/srslte/phy/rf/rf.h index 907a5a008..d37750749 100644 --- a/lib/include/srslte/phy/rf/rf.h +++ b/lib/include/srslte/phy/rf/rf.h @@ -75,6 +75,11 @@ SRSLTE_API int srslte_rf_open_multi(srslte_rf_t *h, char *args, uint32_t nof_rx_antennas); +SRSLTE_API int srslte_rf_open_multi2(srslte_rf_t *h, + char *args, + uint32_t nof_tx_antennas, + uint32_t nof_rx_antennas); + SRSLTE_API int srslte_rf_open_devname(srslte_rf_t *h, char *devname, char *args); @@ -84,6 +89,12 @@ SRSLTE_API int srslte_rf_open_devname_multi(srslte_rf_t *h, char *args, uint32_t nof_rx_antennas); +SRSLTE_API int srslte_rf_open_devname_multi2(srslte_rf_t *rf, + char *devname, + char *args, + uint32_t nof_tx_antennas, + uint32_t nof_rx_antennas); + SRSLTE_API const char *srslte_rf_name(srslte_rf_t *h); SRSLTE_API int srslte_rf_start_gain_thread(srslte_rf_t *rf, @@ -200,5 +211,12 @@ SRSLTE_API int srslte_rf_send_timed2(srslte_rf_t *h, bool is_start_of_burst, bool is_end_of_burst); +SRSLTE_API int srslte_rf_send_multi(srslte_rf_t *rf, + void *data[4], + int nsamples, + bool blocking, + bool is_start_of_burst, + bool is_end_of_burst); + #endif diff --git a/lib/include/srslte/phy/ue/ue_dl.h b/lib/include/srslte/phy/ue/ue_dl.h index 7c3f83320..408ba0c65 100644 --- a/lib/include/srslte/phy/ue/ue_dl.h +++ b/lib/include/srslte/phy/ue/ue_dl.h @@ -84,7 +84,7 @@ typedef struct SRSLTE_API { srslte_cfo_t sfo_correct; srslte_pdsch_cfg_t pdsch_cfg; - srslte_softbuffer_rx_t softbuffer; + srslte_softbuffer_rx_t softbuffers[SRSLTE_MAX_CODEWORDS]; srslte_ra_dl_dci_t dl_dci; srslte_cell_t cell; @@ -142,6 +142,13 @@ SRSLTE_API int srslte_ue_dl_cfg_grant(srslte_ue_dl_t *q, uint32_t sf_idx, uint32_t rvidx); +SRSLTE_API int srslte_ue_dl_cfg_grant_multi(srslte_ue_dl_t *q, + srslte_ra_dl_grant_t *grant, + uint32_t cfi, + uint32_t sf_idx, + uint32_t rvidx, + uint32_t rvidx2); + SRSLTE_API int srslte_ue_dl_find_ul_dci(srslte_ue_dl_t *q, uint32_t cfi, uint32_t sf_idx, @@ -173,7 +180,7 @@ SRSLTE_API int srslte_ue_dl_decode(srslte_ue_dl_t * q, SRSLTE_API int srslte_ue_dl_decode_multi(srslte_ue_dl_t * q, cf_t *input[SRSLTE_MAX_PORTS], - uint8_t *data, + uint8_t *data[SRSLTE_MAX_CODEWORDS], uint32_t tti); SRSLTE_API int srslte_ue_dl_decode_rnti(srslte_ue_dl_t * q, @@ -184,7 +191,7 @@ SRSLTE_API int srslte_ue_dl_decode_rnti(srslte_ue_dl_t * q, SRSLTE_API int srslte_ue_dl_decode_rnti_multi(srslte_ue_dl_t * q, cf_t *input[SRSLTE_MAX_PORTS], - uint8_t *data, + uint8_t *data[SRSLTE_MAX_CODEWORDS], uint32_t tti, uint16_t rnti); diff --git a/lib/include/srslte/phy/ue/ue_sync.h b/lib/include/srslte/phy/ue/ue_sync.h index 94d4f9136..3570e5a30 100644 --- a/lib/include/srslte/phy/ue/ue_sync.h +++ b/lib/include/srslte/phy/ue/ue_sync.h @@ -148,6 +148,13 @@ SRSLTE_API int srslte_ue_sync_init_file(srslte_ue_sync_t *q, int offset_time, float offset_freq); +SRSLTE_API int srslte_ue_sync_init_file_multi(srslte_ue_sync_t *q, + uint32_t nof_prb, + char *file_name, + int offset_time, + float offset_freq, + uint32_t nof_rx_ant); + SRSLTE_API void srslte_ue_sync_free(srslte_ue_sync_t *q); SRSLTE_API int srslte_ue_sync_start_agc(srslte_ue_sync_t *q, diff --git a/lib/include/srslte/phy/utils/debug.h b/lib/include/srslte/phy/utils/debug.h index 9233d9c61..e1021bc2a 100644 --- a/lib/include/srslte/phy/utils/debug.h +++ b/lib/include/srslte/phy/utils/debug.h @@ -63,5 +63,6 @@ SRSLTE_API extern int srslte_verbose; #define INFO(_fmt, ...) if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO) \ fprintf(stdout, "[INFO]: " _fmt, __VA_ARGS__) +#define ERROR(_fmt) fprintf(stderr, "%s.%d: " _fmt "\n", __FILE__, __LINE__) #endif // DEBUG_H diff --git a/lib/src/phy/ch_estimation/chest_dl.c b/lib/src/phy/ch_estimation/chest_dl.c index 690721b3c..3c2f4210c 100644 --- a/lib/src/phy/ch_estimation/chest_dl.c +++ b/lib/src/phy/ch_estimation/chest_dl.c @@ -417,12 +417,15 @@ float srslte_chest_dl_get_rsrq(srslte_chest_dl_t *q) { } -float srslte_chest_dl_get_rsrp(srslte_chest_dl_t *q) { - // Note: use only port 0 but average across antennas - float n = 0; - for (int i=0;ilast_nof_antennas;i++) { - n += q->rsrp[i][0]; +float srslte_chest_dl_get_rsrp_port(srslte_chest_dl_t *q, uint32_t port) { + float n = 0; + for (int i = 0; i < q->last_nof_antennas; i++) { + n += q->rsrp[i][port]; } - return n/q->last_nof_antennas; + return n / q->last_nof_antennas; } +float srslte_chest_dl_get_rsrp(srslte_chest_dl_t *q) { + // Note: use only port 0 but average across antennas + return srslte_chest_dl_get_rsrp_port(q, 0); +} diff --git a/lib/src/phy/ch_estimation/test/CMakeLists.txt b/lib/src/phy/ch_estimation/test/CMakeLists.txt index fd293c273..8e1208ef5 100644 --- a/lib/src/phy/ch_estimation/test/CMakeLists.txt +++ b/lib/src/phy/ch_estimation/test/CMakeLists.txt @@ -52,4 +52,3 @@ add_test(chest_test_ul_cellid1 chest_test_ul -c 2 -r 50) - diff --git a/lib/src/phy/common/phy_common.c b/lib/src/phy/common/phy_common.c index 8386ae18b..69e39b49a 100644 --- a/lib/src/phy/common/phy_common.c +++ b/lib/src/phy/common/phy_common.c @@ -124,6 +124,19 @@ bool srslte_N_id_1_isvalid(uint32_t N_id_1) { } } +srslte_mod_t srslte_str2mod (char * mod_str) { + if (!strcmp(mod_str, "QPSK")) { + return SRSLTE_MOD_QPSK; + } else if (!strcmp(mod_str, "16QAM")) { + return SRSLTE_MOD_16QAM; + } else if (!strcmp(mod_str, "64QAM")) { + return SRSLTE_MOD_64QAM; + } else { + return (srslte_mod_t) SRSLTE_ERROR_INVALID_INPUTS; + } +}; + + char *srslte_mod_string(srslte_mod_t mod) { switch (mod) { case SRSLTE_MOD_BPSK: @@ -419,12 +432,14 @@ struct lte_band lte_bands[SRSLTE_NOF_LTE_BANDS] = { int srslte_str2mimotype(char *mimo_type_str, srslte_mimo_type_t *type) { - if (!strcmp(mimo_type_str, "single")) { + if (!strcmp(mimo_type_str, "single") || !strcmp(mimo_type_str, "Port0")) { *type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA; - } else if (!strcmp(mimo_type_str, "diversity")) { + } else if (!strcmp(mimo_type_str, "diversity") || !strcmp(mimo_type_str, "TxDiversity")) { *type = SRSLTE_MIMO_TYPE_TX_DIVERSITY; } else if (!strcmp(mimo_type_str, "multiplex")) { *type = SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX; + } else if (!strcmp(mimo_type_str, "cdd") || !strcmp(mimo_type_str, "CDD")) { + *type = SRSLTE_MIMO_TYPE_CDD; } else { return SRSLTE_ERROR; } diff --git a/lib/src/phy/io/filesink.c b/lib/src/phy/io/filesink.c index 60a8c386e..a61c417fd 100644 --- a/lib/src/phy/io/filesink.c +++ b/lib/src/phy/io/filesink.c @@ -99,3 +99,60 @@ int srslte_filesink_write(srslte_filesink_t *q, void *buffer, int nsamples) { return i; } +int srslte_filesink_write_multi(srslte_filesink_t *q, void **buffer, int nsamples, int nchannels) { + int i, j; + float **fbuf = (float**) buffer; + _Complex float **cbuf = (_Complex float**) buffer; + _Complex short **sbuf = (_Complex short**) buffer; + int size; + + switch(q->type) { + case SRSLTE_FLOAT: + for (i=0;if, "%g%c", fbuf[j][i], (j!=(nchannels-1))?'\t':'\n'); + } + } + break; + case SRSLTE_COMPLEX_FLOAT: + for (i=0;if, "%g%+gi%c", __real__ cbuf[j][i], __imag__ cbuf[j][i], (j!=(nchannels-1))?'\t':'\n'); + } + } + break; + case SRSLTE_COMPLEX_SHORT: + for (i=0;if, "%hd%+hdi%c", __real__ sbuf[j][i], __imag__ sbuf[j][i], (j!=(nchannels-1))?'\t':'\n'); + } + } + break; + case SRSLTE_FLOAT_BIN: + case SRSLTE_COMPLEX_FLOAT_BIN: + case SRSLTE_COMPLEX_SHORT_BIN: + if (q->type == SRSLTE_FLOAT_BIN) { + size = sizeof(float); + } else if (q->type == SRSLTE_COMPLEX_FLOAT_BIN) { + size = sizeof(_Complex float); + } else if (q->type == SRSLTE_COMPLEX_SHORT_BIN) { + size = sizeof(_Complex short); + } + if (nchannels > 1) { + uint32_t count = 0; + for (i = 0; i < nsamples; i++) { + for (j = 0; j < nchannels; j++) { + count += fwrite(&cbuf[j][i], size, 1, q->f); + } + } + return count; + } else { + return fwrite(buffer[0], size, nsamples, q->f); + } + break; + default: + i = -1; + break; + } + return i; +} \ No newline at end of file diff --git a/lib/src/phy/io/filesource.c b/lib/src/phy/io/filesource.c index 4010f8da4..048ecb584 100644 --- a/lib/src/phy/io/filesource.c +++ b/lib/src/phy/io/filesource.c @@ -116,3 +116,29 @@ int srslte_filesource_read(srslte_filesource_t *q, void *buffer, int nsamples) { return i; } +int srslte_filesource_read_multi(srslte_filesource_t *q, void **buffer, int nsamples, int nof_channels) { + int i, j, count = 0; + _Complex float **cbuf = (_Complex float **) buffer; + + switch (q->type) { + case SRSLTE_FLOAT: + case SRSLTE_COMPLEX_FLOAT: + case SRSLTE_COMPLEX_SHORT: + case SRSLTE_FLOAT_BIN: + case SRSLTE_COMPLEX_SHORT_BIN: + fprintf(stderr, "%s.%d:Read Mode not implemented\n", __FILE__, __LINE__); + count = SRSLTE_ERROR; + break; + case SRSLTE_COMPLEX_FLOAT_BIN: + for (i = 0; i < nsamples; i++) { + for (j = 0; j < nof_channels; j++) { + count += fread(&cbuf[j][i], sizeof(cf_t), (size_t) 1, q->f); + } + } + break; + default: + count = SRSLTE_ERROR; + break; + } + return count; +} \ No newline at end of file diff --git a/lib/src/phy/mimo/precoding.c b/lib/src/phy/mimo/precoding.c index 8781dbad2..f93c63479 100644 --- a/lib/src/phy/mimo/precoding.c +++ b/lib/src/phy/mimo/precoding.c @@ -530,6 +530,154 @@ int srslte_predecoding_type(cf_t *y_, cf_t *h_[SRSLTE_MAX_PORTS], cf_t *x[SRSLTE return srslte_predecoding_type_multi(y, h, x, nof_rxant, nof_ports, nof_layers, nof_symbols, type, noise_estimate); } + +int srslte_precoding_mimo_2x2_gen(cf_t W[2][2], cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS], + int nof_symbols, float noise_estimate) +{ + + cf_t G[2][2], Gx[2][2]; + + for (int i=0; i= 2 && nof_layers <= 4) { + return srslte_predecoding_ccd_zf(y, h, x, nof_rxant, nof_ports, nof_layers, nof_symbols); + } else { + fprintf(stderr, + "Invalid number of layers %d\n", nof_layers); + return -1; + } return -1; case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA: if (nof_ports == 1 && nof_layers == 1) { diff --git a/lib/src/phy/mimo/test/CMakeLists.txt b/lib/src/phy/mimo/test/CMakeLists.txt index e0e5578d5..42e262550 100644 --- a/lib/src/phy/mimo/test/CMakeLists.txt +++ b/lib/src/phy/mimo/test/CMakeLists.txt @@ -42,7 +42,7 @@ add_test(layermap_multiplex_24 layermap_test -n 1000 -m multiplex -c 2 -l 4) ######################################################################## -# LAYER MAPPING TEST +# PRECODING MAPPING TEST ######################################################################## add_executable(precoding_test precoder_test.c) @@ -52,6 +52,7 @@ 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) +add_test(precoding_cdd_2x2 precoding_test -m cdd -l 2 -p 2 -r 2) diff --git a/lib/src/phy/mimo/test/layermap_test.c b/lib/src/phy/mimo/test/layermap_test.c index 209a9ac73..6fcc72682 100644 --- a/lib/src/phy/mimo/test/layermap_test.c +++ b/lib/src/phy/mimo/test/layermap_test.c @@ -40,7 +40,7 @@ int nof_cw = 1, nof_layers = 1; char *mimo_type_name = NULL; void usage(char *prog) { - printf("Usage: %s -m [single|diversity|multiplex] -c [nof_cw] -l [nof_layers]\n", prog); + printf("Usage: %s -m [single|diversity|multiplex|cdd] -c [nof_cw] -l [nof_layers]\n", prog); printf("\t-n num_symbols [Default %d]\n", nof_symbols); } diff --git a/lib/src/phy/mimo/test/precoder_mex.c b/lib/src/phy/mimo/test/precoder_mex.c index 958f06262..b021f422a 100644 --- a/lib/src/phy/mimo/test/precoder_mex.c +++ b/lib/src/phy/mimo/test/precoder_mex.c @@ -78,9 +78,9 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) 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); + output = srslte_vec_malloc(sizeof(cf_t)*nof_symbols*nof_tx_ports); for (int i=0;i= 1) { - mexutils_write_cf(output, &plhs[0], nof_symbols/nof_layers, nof_tx_ports); + switch (type) { + case SRSLTE_MIMO_TYPE_CDD: + mexutils_write_cf(output, &plhs[0], nof_symbols/nof_layers, nof_tx_ports); + break; + case SRSLTE_MIMO_TYPE_TX_DIVERSITY: + case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX: + case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA: + default: + mexutils_write_cf(output, &plhs[0], (uint32_t) nof_symbols, nof_tx_ports); + break; + } + } + + if (nlhs >= 2) { + mexutils_write_cf(x[0], &plhs[1], nof_symbols / nof_layers, 1); + } + if (nlhs >= 3) { + mexutils_write_cf(x[1], &plhs[2], nof_symbols / nof_layers, 1); } if (input) { diff --git a/lib/src/phy/mimo/test/precoder_test.c b/lib/src/phy/mimo/test/precoder_test.c index e935a7067..cf8dac89a 100644 --- a/lib/src/phy/mimo/test/precoder_test.c +++ b/lib/src/phy/mimo/test/precoder_test.c @@ -35,28 +35,31 @@ #include "srslte/srslte.h" -#define MSE_THRESHOLD 0.00001 +#define MSE_THRESHOLD 0.0005 int nof_symbols = 1000; -int nof_layers = 1, nof_ports = 1; +int nof_layers = 1, nof_tx_ports = 1, nof_rx_ports = 1, nof_re = 1; char *mimo_type_name = NULL; void usage(char *prog) { printf( - "Usage: %s -m [single|diversity|multiplex] -l [nof_layers] -p [nof_ports]\n", - prog); + "Usage: %s -m [single|diversity|multiplex|cdd] -l [nof_layers] -p [nof_tx_ports]\n" + " -r [nof_rx_ports]\n", prog); printf("\t-n num_symbols [Default %d]\n", nof_symbols); } void parse_args(int argc, char **argv) { int opt; - while ((opt = getopt(argc, argv, "mpln")) != -1) { + while ((opt = getopt(argc, argv, "mplnr")) != -1) { switch (opt) { case 'n': nof_symbols = atoi(argv[optind]); break; case 'p': - nof_ports = atoi(argv[optind]); + nof_tx_ports = atoi(argv[optind]); + break; + case 'r': + nof_rx_ports = atoi(argv[optind]); break; case 'l': nof_layers = atoi(argv[optind]); @@ -75,102 +78,175 @@ void parse_args(int argc, char **argv) { } } +void populate_channel_cdd(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], uint32_t n) { + int i, j, k; + + for (i = 0; i < nof_tx_ports; i++) { + for (j = 0; j < nof_rx_ports; j++) { + for (k = 0; k < n; k++) { + h[i][j][k] = (float) rand() / RAND_MAX + ((float) rand() / RAND_MAX) * _Complex_I; + } + } + } +} + +void populate_channel_diversity(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], uint32_t n) { + int i, j, k, l; + + for (i = 0; i < nof_tx_ports; i++) { + for (j = 0; j < nof_rx_ports; j++) { + for (k = 0; k < n / nof_layers; k++) { + cf_t hsymb = (float) rand() / RAND_MAX + ((float) rand() / RAND_MAX) * _Complex_I; + for (l = 0; l < nof_layers; l++) { + // assume the channel is the same for all symbols + h[i][j][k * nof_layers + l] = hsymb; + } + } + } + } +} + +void populate_channel_single(cf_t *h) { + int i; + + for (i = 0; i < nof_re; i++) { + h[i] = (float) rand() / RAND_MAX + ((float) rand() / RAND_MAX) * _Complex_I; + } +} + +void populate_channel(srslte_mimo_type_t type, cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]) { + switch (type) { + case SRSLTE_MIMO_TYPE_CDD: + populate_channel_cdd(h, (uint32_t) nof_re); + break; + case SRSLTE_MIMO_TYPE_TX_DIVERSITY: + populate_channel_diversity(h, (uint32_t) nof_re); + break; + case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX: + fprintf(stderr, "Error: not implemented channel emulator\n"); + exit(-1); + //break; + case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA: + default: + populate_channel_single(h[0][0]); + } +} + int main(int argc, char **argv) { - int i, j; + int i, j, k; float mse; - cf_t *x[SRSLTE_MAX_LAYERS], *r[SRSLTE_MAX_PORTS], *y[SRSLTE_MAX_PORTS], *h[SRSLTE_MAX_PORTS], + cf_t *x[SRSLTE_MAX_LAYERS], *r[SRSLTE_MAX_PORTS], *y[SRSLTE_MAX_PORTS], *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], *xr[SRSLTE_MAX_LAYERS]; srslte_mimo_type_t type; parse_args(argc, argv); - if (nof_ports > SRSLTE_MAX_PORTS || nof_layers > SRSLTE_MAX_LAYERS) { + /* Check input ranges */ + if (nof_tx_ports > SRSLTE_MAX_PORTS || nof_rx_ports > SRSLTE_MAX_PORTS || nof_layers > SRSLTE_MAX_LAYERS) { fprintf(stderr, "Invalid number of layers or ports\n"); exit(-1); } + /* Parse MIMO Type */ if (srslte_str2mimotype(mimo_type_name, &type)) { fprintf(stderr, "Invalid MIMO type %s\n", mimo_type_name); exit(-1); } + /* Check scenario conditions are OK */ + switch (type) { + case SRSLTE_MIMO_TYPE_TX_DIVERSITY: + nof_re = nof_layers*nof_symbols; + break; + case SRSLTE_MIMO_TYPE_CDD: + nof_re = nof_symbols*nof_tx_ports/nof_layers; + if (nof_rx_ports != 2 || nof_tx_ports != 2) { + fprintf(stderr, "CDD nof_tx_ports=%d nof_rx_ports=%d is not currently supported\n", nof_tx_ports, nof_rx_ports); + exit(-1); + } + break; + default: + nof_re = nof_symbols*nof_layers; + } + + /* Allocate x and xr (received symbols) in memory for each layer */ for (i = 0; i < nof_layers; i++) { + /* Source data */ x[i] = srslte_vec_malloc(sizeof(cf_t) * nof_symbols); if (!x[i]) { perror("srslte_vec_malloc"); exit(-1); } + + /* Sink data */ xr[i] = srslte_vec_malloc(sizeof(cf_t) * nof_symbols); if (!xr[i]) { perror("srslte_vec_malloc"); exit(-1); } } - for (i = 0; i < nof_ports; i++) { - y[i] = srslte_vec_malloc(sizeof(cf_t) * nof_symbols * nof_layers); - // TODO: The number of symbols per port is different in spatial multiplexing. + + /* Allocate y in memory for tx each port */ + for (i = 0; i < nof_tx_ports; i++) { + y[i] = srslte_vec_malloc(sizeof(cf_t) * nof_re); if (!y[i]) { perror("srslte_vec_malloc"); exit(-1); } - h[i] = srslte_vec_malloc(sizeof(cf_t) * nof_symbols * nof_layers); - if (!h[i]) { - perror("srslte_vec_malloc"); - exit(-1); + } + + /* Allocate h in memory for each cross channel and layer */ + for (i = 0; i < nof_tx_ports; i++) { + for (j = 0; j < nof_rx_ports; j++) { + h[i][j] = srslte_vec_malloc(sizeof(cf_t) * nof_re); + if (!h[i][j]) { + perror("srslte_vec_malloc"); + exit(-1); + } } } - /* only 1 receiver antenna supported now */ - r[0] = srslte_vec_malloc(sizeof(cf_t) * nof_symbols * nof_layers); - if (!r[0]) { - perror("srslte_vec_malloc"); - exit(-1); + /* Allocate r */ + for (i = 0; i < nof_rx_ports; i++) { + r[i] = srslte_vec_malloc(sizeof(cf_t) * nof_re); + if (!r[i]) { + perror("srslte_vec_malloc"); + exit(-1); + } } - /* generate random data */ + /* Generate source random data */ for (i = 0; i < nof_layers; i++) { for (j = 0; j < nof_symbols; j++) { - x[i][j] = (2*(rand()%2)-1+(2*(rand()%2)-1)*_Complex_I)/sqrt(2); + x[i][j] = (2 * (rand() % 2) - 1 + (2 * (rand() % 2) - 1) * _Complex_I) / sqrt(2); } } - - /* precoding */ - if (srslte_precoding_type(x, y, nof_layers, nof_ports, nof_symbols, type) < 0) { + + /* Execute Precoding (Tx) */ + if (srslte_precoding_type(x, y, nof_layers, nof_tx_ports, nof_symbols, type) < 0) { fprintf(stderr, "Error layer mapper encoder\n"); exit(-1); } /* generate channel */ - for (i = 0; i < nof_ports; i++) { - for (j = 0; j < nof_symbols; j++) { - h[i][nof_layers*j] = (float) rand()/RAND_MAX+((float) rand()/RAND_MAX)*_Complex_I; - // assume the channel is time-invariant in nlayer consecutive symbols - for (int k=0;k SRSLTE_MAX_LAYERS) { + mexErrMsgTxt("Too many layers\n"); + return; + } + + /* Read number of symbols and Rx antennas */ + ndims = mxGetNumberOfDimensions(INPUT); + nof_symbols = (uint32_t) dims[0]; + if (ndims >= 2) { - nof_rx_ants = dims[1]; + nof_rx_ants = (uint32_t) dims[1]; } - // Read channel estimates + /* Read channel estimates */ if (mexutils_read_cf(HEST, &hest) < 0) { mexErrMsgTxt("Error reading hest\n"); return; } + + /* Get number of tx ports */ dims = mxGetDimensions(HEST); ndims = mxGetNumberOfDimensions(HEST); if (ndims == 3) { - nof_tx_ports = dims[2]; + nof_tx_ports = (uint32_t) dims[2]; } - + + /* Print parameters trace */ mexPrintf("nof_tx_ports=%d, nof_rx_ants=%d, nof_layers=%d, nof_symbols=%d\n", nof_tx_ports, nof_rx_ants, nof_layers, nof_symbols); - // Read noise estimate - float noise_estimate = 0; + /* Read noise estimate */ if (nrhs >= NOF_INPUTS) { - noise_estimate = mxGetScalar(NEST); + noise_estimate = (float) 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= NOF_INPUTS) { - txscheme = mxArrayToString(TXSCHEME); - } - srslte_mimo_type_t type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA; + mxGetString_700(TXSCHEME, txscheme, 32); + } + 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")) { + } 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, 1); + /* Set output pointer */ + cf_t *d[SRSLTE_MAX_CODEWORDS]; + for (i = 0; i= 1) { + mexutils_write_cf(output, &plhs[0], nof_symbols*nof_layers*nof_rx_ants/nof_tx_ports, 1); + } + + /* Free memory */ if (input) { free(input); } + if (hest) { + free(hest); + } if (output) { free(output); } - for (int i=0;itb_cw_swap; } + + /* Force MCS_idx and RV_idx in function of block enable according to 7.1.7 of 36.213 */ + if (!data->tb_en[0]) { + data->mcs_idx = 0; + data->rv_idx= 1; + } + if (!data->tb_en[1]) { + data->mcs_idx_1 = 0; + data->rv_idx_1 = 1; + } /* pack TB1 */ srslte_bit_unpack(data->mcs_idx, &y, 5); diff --git a/lib/src/phy/phch/pdcch.c b/lib/src/phy/phch/pdcch.c index cfdb19621..f4c59b321 100644 --- a/lib/src/phy/phch/pdcch.c +++ b/lib/src/phy/phch/pdcch.c @@ -65,7 +65,19 @@ 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 srslte_pdcch_init_tx(srslte_pdcch_t *q, srslte_regs_t *regs, srslte_cell_t cell) { + return srslte_pdcch_init_txrx(q, regs, cell, 1, false); +} + +int srslte_pdcch_init_rx(srslte_pdcch_t *q, srslte_regs_t *regs, srslte_cell_t cell, uint32_t nof_rx_antennas) { + return srslte_pdcch_init_txrx(q, regs, cell, nof_rx_antennas, true); +} + +int srslte_pdcch_init_multi(srslte_pdcch_t *q, srslte_regs_t *regs, srslte_cell_t cell, uint32_t nof_rx_antennas) { + return srslte_pdcch_init_txrx(q, regs, cell, nof_rx_antennas, true); +} + +int srslte_pdcch_init_txrx(srslte_pdcch_t *q, srslte_regs_t *regs, srslte_cell_t cell, uint32_t nof_rx_antennas, bool isReceiver) { int ret = SRSLTE_ERROR_INVALID_INPUTS; @@ -122,19 +134,25 @@ int srslte_pdcch_init_multi(srslte_pdcch_t *q, srslte_regs_t *regs, srslte_cell_ 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; - } + if (isReceiver) { + for (int i = 0; i < SRSLTE_MAX_PORTS; i++) { + for (int j = 0; j < q->nof_rx_antennas; j++) { + q->ce[i][j] = srslte_vec_malloc(sizeof(cf_t) * q->max_bits / 2); + if (!q->ce[i][j]) { + goto clean; + } + } } + } + + for (int i = 0; i < SRSLTE_MAX_PORTS; i++) { q->x[i] = srslte_vec_malloc(sizeof(cf_t) * q->max_bits / 2); if (!q->x[i]) { goto clean; } } - for (int j=0;jnof_rx_antennas;j++) { + + for (int j = 0; j < ((isReceiver) ? q->nof_rx_antennas : cell.nof_ports); j++) { q->symbols[j] = srslte_vec_malloc(sizeof(cf_t) * q->max_bits / 2); if (!q->symbols[j]) { goto clean; diff --git a/lib/src/phy/phch/pdsch.c b/lib/src/phy/phch/pdsch.c index 9b6128c64..3d24cf175 100644 --- a/lib/src/phy/phch/pdsch.c +++ b/lib/src/phy/phch/pdsch.c @@ -203,20 +203,15 @@ 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_multi(srslte_pdsch_t *q, srslte_cell_t cell, uint32_t nof_rx_antennas) +/** Initializes the PDCCH transmitter or receiver */ +int srslte_pdsch_init_multi(srslte_pdsch_t *q, srslte_cell_t cell, uint32_t nof_antennas, bool is_receiver) { int ret = SRSLTE_ERROR_INVALID_INPUTS; int i; if (q != NULL && srslte_cell_isvalid(&cell) && - nof_rx_antennas <= SRSLTE_MAX_PORTS) + nof_antennas <= SRSLTE_MAX_PORTS) { bzero(q, sizeof(srslte_pdsch_t)); @@ -224,8 +219,10 @@ int srslte_pdsch_init_multi(srslte_pdsch_t *q, srslte_cell_t cell, uint32_t nof_ q->cell = cell; q->max_re = q->cell.nof_prb * MAX_PDSCH_RE(q->cell.cp); - q->nof_rx_antennas = nof_rx_antennas; - + if (is_receiver) { + q->nof_rx_antennas = nof_antennas; + } + INFO("Init PDSCH: %d ports %d PRBs, max_symbols: %d\n", q->cell.nof_ports, q->cell.nof_prb, q->max_re); @@ -244,20 +241,37 @@ int srslte_pdsch_init_multi(srslte_pdsch_t *q, srslte_cell_t cell, uint32_t nof_ goto clean; } + q->e2 = srslte_vec_malloc(sizeof(int16_t) * q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM)); + if (!q->e) { + goto clean; + } + q->d = srslte_vec_malloc(sizeof(cf_t) * q->max_re); if (!q->d) { goto clean; } + q->d2 = srslte_vec_malloc(sizeof(cf_t) * q->max_re); + if (!q->d) { + goto clean; + } + + /* Layer mapped symbols memory allocation */ for (i = 0; i < q->cell.nof_ports; i++) { q->x[i] = srslte_vec_malloc(sizeof(cf_t) * q->max_re); if (!q->x[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; + } + + /* If it is the receiver side, allocate estimated channel */ + if (is_receiver) { + for (i = 0; i < q->cell.nof_ports; i++) { + for (int j = 0; j < q->nof_rx_antennas; j++) { + q->ce[i][j] = srslte_vec_malloc(sizeof(cf_t) * q->max_re); + if (!q->ce[i][j]) { + goto clean; + } } } } @@ -268,6 +282,7 @@ int srslte_pdsch_init_multi(srslte_pdsch_t *q, srslte_cell_t cell, uint32_t nof_ } } + /* Allocate User memory (all zeros) */ q->users = calloc(sizeof(srslte_pdsch_user_t*), 1+SRSLTE_SIRNTI); if (!q->users) { perror("malloc"); @@ -283,15 +298,33 @@ int srslte_pdsch_init_multi(srslte_pdsch_t *q, srslte_cell_t cell, uint32_t nof_ return ret; } +int srslte_pdsch_init(srslte_pdsch_t *q, srslte_cell_t cell) { + return srslte_pdsch_init_multi(q, cell, 1, true); +} + +int srslte_pdsch_init_tx_multi(srslte_pdsch_t *q, srslte_cell_t cell) { + return srslte_pdsch_init_multi(q, cell, 0, false); +} + +int srslte_pdsch_init_rx_multi(srslte_pdsch_t *q, srslte_cell_t cell, uint32_t nof_antennas) { + return srslte_pdsch_init_multi(q, cell, nof_antennas, true); +} + void srslte_pdsch_free(srslte_pdsch_t *q) { int i; if (q->e) { free(q->e); } + if (q->e2) { + free(q->e2); + } if (q->d) { free(q->d); } + if (q->d2) { + free(q->d2); + } for (i = 0; i < q->cell.nof_ports; i++) { if (q->x[i]) { free(q->x[i]); @@ -302,7 +335,7 @@ void srslte_pdsch_free(srslte_pdsch_t *q) { } } } - for (int j=0;jnof_rx_antennas;j++) { + for (int j=0;jsymbols[j]) { free(q->symbols[j]); } @@ -348,6 +381,50 @@ int srslte_pdsch_cfg(srslte_pdsch_cfg_t *cfg, srslte_cell_t cell, srslte_ra_dl_g } } +/* Configures the structure srslte_pdsch_cfg_t from the DL DCI allocation dci_msg. + * If dci_msg is NULL, the grant is assumed to be already stored in cfg->grant + */ +int srslte_pdsch_cfg_multi(srslte_pdsch_cfg_t *cfg, srslte_cell_t cell, srslte_ra_dl_grant_t *grant, uint32_t cfi, + uint32_t sf_idx, uint32_t rvidx, uint32_t rvidx2) +{ + if (cfg) { + if (grant) { + memcpy(&cfg->grant, grant, sizeof(srslte_ra_dl_grant_t)); + } + if (srslte_cbsegm(&cfg->cb_segm, (uint32_t) cfg->grant.mcs.tbs)) { + fprintf(stderr, "Error computing Codeblock (1) segmentation for TBS=%d\n", cfg->grant.mcs.tbs); + return SRSLTE_ERROR; + } + + if (srslte_cbsegm(&cfg->cb_segm2, (uint32_t) cfg->grant.mcs2.tbs)) { + fprintf(stderr, "Error computing Codeblock (2) segmentation for TBS=%d\n", cfg->grant.mcs.tbs); + return SRSLTE_ERROR; + } + + srslte_ra_dl_grant_to_nbits_multi(&cfg->grant, cfi, cell, sf_idx, &cfg->nbits, &cfg->nbits2); + cfg->sf_idx = sf_idx; + cfg->rv = rvidx; + cfg->rv2 = rvidx2; + + if (cell.nof_ports == 1 && grant->nof_tb == 1) { + cfg->mimo_type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA; + cfg->nof_layers = 1; + } else if (cell.nof_ports == 2 && grant->nof_tb == 1) { + cfg->mimo_type = SRSLTE_MIMO_TYPE_TX_DIVERSITY; + cfg->nof_layers = 2; + } else if (cell.nof_ports == 2 && grant->nof_tb == 2) { + cfg->mimo_type = SRSLTE_MIMO_TYPE_CDD; + cfg->nof_layers = 2; + } else { + INFO("nof_ports=%d, nof_tb=%d are not consistent\n", cell.nof_ports, grant->nof_tb); + return SRSLTE_ERROR; + } + + return SRSLTE_SUCCESS; + } else { + return SRSLTE_ERROR_INVALID_INPUTS; + } +} /* Precalculate the PDSCH scramble sequences for a given RNTI. This function takes a while * to execute, so shall be called once the final C-RNTI has been allocated for the session. @@ -362,6 +439,10 @@ int srslte_pdsch_set_rnti(srslte_pdsch_t *q, uint16_t rnti) { q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM))) { return SRSLTE_ERROR; } + if (srslte_sequence_pdsch(&q->users[rnti]->seq2[i], rnti, 1, 2 * i, q->cell.id, + q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM))) { + return SRSLTE_ERROR; + } } q->users[rnti]->sequence_generated = true; } @@ -374,6 +455,7 @@ void srslte_pdsch_free_rnti(srslte_pdsch_t* q, uint16_t rnti) if (q->users[rnti]) { for (int i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) { srslte_sequence_free(&q->users[rnti]->seq[i]); + srslte_sequence_free(&q->users[rnti]->seq2[i]); } free(q->users[rnti]); q->users[rnti] = NULL; @@ -392,15 +474,15 @@ int srslte_pdsch_decode(srslte_pdsch_t *q, 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); + 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, + srslte_pdsch_cfg_t *cfg, srslte_softbuffer_rx_t softbuffers[SRSLTE_MAX_CODEWORDS], 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) + uint16_t rnti, uint8_t *data[SRSLTE_MAX_CODEWORDS]) { /* Set pointers for layermapping & precoding */ @@ -441,22 +523,38 @@ int srslte_pdsch_decode_multi(srslte_pdsch_t *q, } } - /* TODO: only diversity is supported */ if (q->cell.nof_ports == 1) { /* no need for layer demapping */ 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_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); + int nof_symbols [SRSLTE_MAX_CODEWORDS]; + nof_symbols[0] = cfg->nbits.nof_re * cfg->grant.nof_tb / q->cell.nof_ports; + nof_symbols[1] = cfg->nbits2.nof_re * cfg->grant.nof_tb / q->cell.nof_ports; + + srslte_predecoding_type_multi(q->symbols, q->ce, x, q->nof_rx_antennas, q->cell.nof_ports, cfg->nof_layers, + cfg->nbits.nof_re, cfg->mimo_type, 0.0); + srslte_layerdemap_type(x, (cf_t *[SRSLTE_MAX_CODEWORDS]) {q->d, q->d2}, cfg->nof_layers, cfg->grant.nof_tb, + nof_symbols[0], nof_symbols, cfg->mimo_type); } if (SRSLTE_VERBOSE_ISDEBUG()) { - DEBUG("SAVED FILE subframe.dat: received subframe symbols\n",0); - srslte_vec_save_file("subframe.dat", sf_symbols[0], SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t)); - DEBUG("SAVED FILE hest0.dat and hest1.dat: channel estimates for port 0 and port 1\n",0); - srslte_vec_save_file("hest0.dat", ce[0][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("hest1.dat", ce[1][0], SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t)); + char filename[FILENAME_MAX]; + for (int j = 0; j < q->nof_rx_antennas; j++) { + if (snprintf(filename, FILENAME_MAX, "subframe_p%d.dat", j) < 0) { + ERROR("Generating file name"); + break; + } + DEBUG("SAVED FILE %s: received subframe symbols\n", filename); + srslte_vec_save_file(filename, sf_symbols, SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t)); + + for (i = 0; i < q->cell.nof_ports; i++) { + if (snprintf(filename, FILENAME_MAX, "hest_%d%d.dat", i, j) < 0) { + ERROR("Generating file name"); + break; + } + DEBUG("SAVED FILE %s: channel estimates for Tx %d and Rx %d\n", filename, j, i); + srslte_vec_save_file(filename, ce[i][j], SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t)); + } } DEBUG("SAVED FILE pdsch_symbols.dat: symbols after equalization\n",0); srslte_vec_save_file("pdsch_symbols.dat", q->d, cfg->nbits.nof_re*sizeof(cf_t)); @@ -466,18 +564,40 @@ int srslte_pdsch_decode_multi(srslte_pdsch_t *q, * The MAX-log-MAP algorithm used in turbo decoding is unsensitive to SNR estimation, * thus we don't need tot set it in the LLRs normalization */ - srslte_demod_soft_demodulate_s(cfg->grant.mcs.mod, q->d, q->e, cfg->nbits.nof_re); - + if (cfg->nbits.nof_re) { + srslte_demod_soft_demodulate_s(cfg->grant.mcs.mod, q->d, q->e, cfg->nbits.nof_re); + } + + if (cfg->nbits2.nof_re) { + srslte_demod_soft_demodulate_s(cfg->grant.mcs2.mod, q->d2, q->e2, cfg->nbits2.nof_re); + } + /* descramble */ if (q->users[rnti] && q->users[rnti]->sequence_generated) { - srslte_scrambling_s_offset(&q->users[rnti]->seq[cfg->sf_idx], q->e, 0, cfg->nbits.nof_bits); + if (cfg->nbits.nof_bits) { + srslte_scrambling_s_offset(&q->users[rnti]->seq[cfg->sf_idx], q->e, 0, cfg->nbits.nof_bits); + } + + if (cfg->nbits2.nof_bits) { + srslte_scrambling_s_offset(&q->users[rnti]->seq2[cfg->sf_idx], q->e2, 0, cfg->nbits2.nof_bits); + } } else { srslte_sequence_t seq; - if (srslte_sequence_pdsch(&seq, rnti, 0, 2 * cfg->sf_idx, q->cell.id, cfg->nbits.nof_bits)) { - return SRSLTE_ERROR; + if (cfg->nbits.nof_bits) { + if (srslte_sequence_pdsch(&seq, rnti, 0, 2 * cfg->sf_idx, q->cell.id, cfg->nbits.nof_bits)) { + return SRSLTE_ERROR; + } + srslte_scrambling_s_offset(&seq, q->e, 0, cfg->nbits.nof_bits); + srslte_sequence_free(&seq); + } + + if (cfg->nbits2.nof_bits) { + if (srslte_sequence_pdsch(&seq, rnti, 1, 2 * cfg->sf_idx, q->cell.id, cfg->nbits2.nof_bits)) { + return SRSLTE_ERROR; + } + srslte_scrambling_s_offset(&seq, q->e2, 0, cfg->nbits2.nof_bits); + srslte_sequence_free(&seq); } - srslte_scrambling_s_offset(&seq, q->e, 0, cfg->nbits.nof_bits); - srslte_sequence_free(&seq); } if (SRSLTE_VERBOSE_ISDEBUG()) { @@ -485,7 +605,8 @@ int srslte_pdsch_decode_multi(srslte_pdsch_t *q, srslte_vec_save_file("llr.dat", q->e, cfg->nbits.nof_bits*sizeof(int16_t)); } - return srslte_dlsch_decode(&q->dl_sch, cfg, softbuffer, q->e, data); + return srslte_dlsch_decode_multi(&q->dl_sch, cfg, softbuffers, (int16_t *[SRSLTE_MAX_CODEWORDS]) {q->e, q->e2}, + data); } else { return SRSLTE_ERROR_INVALID_INPUTS; @@ -571,6 +692,112 @@ int srslte_pdsch_encode(srslte_pdsch_t *q, return ret; } +int srslte_pdsch_encode_multi(srslte_pdsch_t *q, + srslte_pdsch_cfg_t *cfg, srslte_softbuffer_tx_t softbuffers[SRSLTE_MAX_CODEWORDS], + uint8_t *data[SRSLTE_MAX_CODEWORDS], uint16_t rnti, cf_t *sf_symbols[SRSLTE_MAX_PORTS]) { + + int i; + /* Set pointers for layermapping & precoding */ + cf_t *x[SRSLTE_MAX_LAYERS]; + int ret = SRSLTE_ERROR_INVALID_INPUTS; + + if (q != NULL && + cfg != NULL) { + + for (i = 0; i < q->cell.nof_ports; i++) { + if (sf_symbols[i] == NULL) { + return SRSLTE_ERROR_INVALID_INPUTS; + } + } + + /* If both transport block sizes are zero return error */ + if (cfg->grant.mcs.tbs == 0 && cfg->grant.mcs2.tbs == 0) { + return SRSLTE_ERROR_INVALID_INPUTS; + } + + if (cfg->nbits.nof_re > q->max_re) { + fprintf(stderr, + "Error too many RE per subframe (%d). PDSCH configured for %d RE (%d PRB)\n", + cfg->nbits.nof_re, q->max_re, q->cell.nof_prb); + return SRSLTE_ERROR_INVALID_INPUTS; + } + + INFO("Encoding PDSCH SF: %d (TB 1), Mod %s, NofBits: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d\n", + cfg->sf_idx, srslte_mod_string(cfg->grant.mcs.mod), cfg->grant.mcs.tbs, + cfg->nbits.nof_re, cfg->nbits.nof_bits, cfg->rv); + if (cfg->grant.nof_tb > 1) { + INFO("Encoding PDSCH SF: %d (TB 2), Mod %s, NofBits: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d\n", + cfg->sf_idx, srslte_mod_string(cfg->grant.mcs2.mod), cfg->grant.mcs2.tbs, + cfg->nbits.nof_re, cfg->nbits.nof_bits, cfg->rv2); + } + + /* number of layers equals number of ports */ + for (i = 0; i < q->cell.nof_ports; i++) { + x[i] = q->x[i]; + } + memset(&x[q->cell.nof_ports], 0, sizeof(cf_t *) * (SRSLTE_MAX_LAYERS - q->cell.nof_ports)); + + if (srslte_dlsch_encode_multi(&q->dl_sch, cfg, softbuffers, data, (uint8_t *[SRSLTE_MAX_CODEWORDS]) {q->e, q->e2})) { + fprintf(stderr, "Error encoding TB\n"); + return SRSLTE_ERROR; + } + + /* scramble */ + if (!q->users[rnti]) { + srslte_sequence_t seq; + + if (cfg->nbits.nof_bits) { + if (srslte_sequence_pdsch(&seq, rnti, 0, 2 * cfg->sf_idx, q->cell.id, cfg->nbits.nof_bits)) { + return SRSLTE_ERROR; + } + srslte_scrambling_bytes(&seq, (uint8_t *) q->e, cfg->nbits.nof_bits); + srslte_sequence_free(&seq); + } + + if (cfg->nbits2.nof_bits) { + if (srslte_sequence_pdsch(&seq, rnti, 1, 2 * cfg->sf_idx, q->cell.id, cfg->nbits2.nof_bits)) { + return SRSLTE_ERROR; + } + srslte_scrambling_bytes(&seq, (uint8_t *) q->e2, cfg->nbits2.nof_bits); + srslte_sequence_free(&seq); + } + } else { + if (cfg->nbits.nof_bits) { + srslte_scrambling_bytes(&q->users[rnti]->seq[cfg->sf_idx], (uint8_t *) q->e, cfg->nbits.nof_bits); + } + + if (cfg->nbits2.nof_bits) { + srslte_scrambling_bytes(&q->users[rnti]->seq2[cfg->sf_idx], (uint8_t *) q->e2, cfg->nbits2.nof_bits); + } + } + + if (cfg->nbits.nof_bits) { + srslte_mod_modulate_bytes(&q->mod[cfg->grant.mcs.mod], (uint8_t *) q->e, q->d, cfg->nbits.nof_bits); + } + + if (cfg->nbits2.nof_bits) { + srslte_mod_modulate_bytes(&q->mod[cfg->grant.mcs2.mod], (uint8_t *) q->e2, q->d2, cfg->nbits2.nof_bits); + } + + if (q->cell.nof_ports > 1) { + int nof_symbols = srslte_layermap_type((cf_t *[SRSLTE_MAX_CODEWORDS]) {q->d, q->d2}, x, cfg->grant.nof_tb, cfg->nof_layers, + (int[SRSLTE_MAX_CODEWORDS]) {cfg->nbits.nof_re, cfg->nbits2.nof_re}, cfg->mimo_type); + srslte_precoding_type(x, q->symbols, q->cell.nof_ports, cfg->nof_layers, + nof_symbols, cfg->mimo_type); + } else { + memcpy(q->symbols[0], q->d, cfg->nbits.nof_re * sizeof(cf_t)); + } + + /* mapping to resource elements */ + for (i = 0; i < q->cell.nof_ports; i++) { + srslte_pdsch_put(q, q->symbols[i], sf_symbols[i], &cfg->grant, cfg->nbits.lstart, cfg->sf_idx); + } + + ret = SRSLTE_SUCCESS; + } + return ret; +} + float srslte_pdsch_average_noi(srslte_pdsch_t *q) { return q->dl_sch.average_nof_iterations; diff --git a/lib/src/phy/phch/pucch.c b/lib/src/phy/phch/pucch.c index 6a889b89c..a61f798fb 100644 --- a/lib/src/phy/phch/pucch.c +++ b/lib/src/phy/phch/pucch.c @@ -826,4 +826,4 @@ int srslte_pucch_decode(srslte_pucch_t* q, srslte_pucch_format_t format, } - \ No newline at end of file + diff --git a/lib/src/phy/phch/ra.c b/lib/src/phy/phch/ra.c index 976a669f4..635172762 100644 --- a/lib/src/phy/phch/ra.c +++ b/lib/src/phy/phch/ra.c @@ -496,7 +496,6 @@ static int dl_dci_to_grant_mcs(srslte_ra_dl_dci_t *dci, srslte_ra_dl_grant_t *gr grant->mcs.tbs = (uint32_t) tbs; } else { n_prb = grant->nof_prb; - grant->nof_tb = 0; if (dci->tb_en[0]) { grant->mcs.idx = dci->mcs_idx; tbs = dl_fill_ra_mcs(&grant->mcs, n_prb); @@ -506,7 +505,6 @@ static int dl_dci_to_grant_mcs(srslte_ra_dl_dci_t *dci, srslte_ra_dl_grant_t *gr // For mcs>=29, set last TBS received for this PID grant->mcs.tbs = last_dl_tbs[dci->harq_process%8]; } - grant->nof_tb++; } else { grant->mcs.tbs = 0; } @@ -519,16 +517,18 @@ static int dl_dci_to_grant_mcs(srslte_ra_dl_dci_t *dci, srslte_ra_dl_grant_t *gr // For mcs>=29, set last TBS received for this PID grant->mcs2.tbs = last_dl_tbs2[dci->harq_process%8]; } - grant->nof_tb++; } else { grant->mcs2.tbs = 0; } - } + } + grant->nof_tb = 0; if (dci->tb_en[0]) { - grant->Qm = srslte_mod_bits_x_symbol(grant->mcs.mod); + grant->Qm = srslte_mod_bits_x_symbol(grant->mcs.mod); + grant->nof_tb++; } if (dci->tb_en[1]) { - grant->Qm2 = srslte_mod_bits_x_symbol(grant->mcs2.mod); + grant->Qm2 = srslte_mod_bits_x_symbol(grant->mcs2.mod); + grant->nof_tb++; } if (tbs < 0) { return SRSLTE_ERROR; @@ -546,6 +546,23 @@ void srslte_ra_dl_grant_to_nbits(srslte_ra_dl_grant_t *grant, uint32_t cfi, srsl nbits->nof_bits = nbits->nof_re * grant->Qm; } +void srslte_ra_dl_grant_to_nbits_multi(srslte_ra_dl_grant_t *grant, uint32_t cfi, srslte_cell_t cell, uint32_t sf_idx, + srslte_ra_nbits_t *nbits, srslte_ra_nbits_t *nbits2) { + /* Compute number of RE for first transport block */ + nbits->nof_re = srslte_ra_dl_grant_nof_re(grant, cell, sf_idx, cell.nof_prb<10?(cfi+1):cfi); + nbits->lstart = cell.nof_prb<10?(cfi+1):cfi; + nbits->nof_symb = 2*SRSLTE_CP_NSYMB(cell.cp)-nbits->lstart; + nbits->nof_bits = nbits->nof_re * grant->Qm; + + /*/ Compute number of RE for second transport block */ + if (grant->nof_tb > 1) { + nbits2->nof_re = nbits->nof_re; + nbits2->lstart = nbits->lstart; + nbits2->nof_symb = 2 * SRSLTE_CP_NSYMB(cell.cp) - nbits2->lstart; + nbits2->nof_bits = nbits2->nof_re * grant->Qm2; + } +} + /** Obtains a DL grant from a DCI grant for PDSCH */ int srslte_ra_dl_dci_to_grant(srslte_ra_dl_dci_t *dci, uint32_t nof_prb, uint16_t msg_rnti, srslte_ra_dl_grant_t *grant) @@ -796,18 +813,31 @@ void srslte_ra_pdsch_fprint(FILE *f, srslte_ra_dl_dci_t *dci, uint32_t nof_prb) } break; } - fprintf(f, " - Modulation and coding scheme index:\t%d\n", dci->mcs_idx); fprintf(f, " - HARQ process:\t\t\t%d\n", dci->harq_process); - fprintf(f, " - New data indicator:\t\t\t%s\n", dci->ndi ? "Yes" : "No"); - fprintf(f, " - Redundancy version:\t\t\t%d\n", dci->rv_idx); fprintf(f, " - TPC command for PUCCH:\t\t--\n"); + fprintf(f, " - Transport blocks swapped:\t\t%s\n", (dci->tb_cw_swap)?"true":"false"); + fprintf(f, " - Transport block 1 enabled:\t\t%s\n", (dci->tb_en[0])?"true":"false"); + if (dci->tb_en[0]) { + fprintf(f, " + Modulation and coding scheme index:\t%d\n", dci->mcs_idx); + fprintf(f, " + New data indicator:\t\t\t%s\n", dci->ndi ? "Yes" : "No"); + fprintf(f, " + Redundancy version:\t\t\t%d\n", dci->rv_idx); + } + fprintf(f, " - Transport block 2 enabled:\t\t%s\n", (dci->tb_en[1])?"true":"false"); + if (dci->tb_en[1]) { + fprintf(f, " + Modulation and coding scheme index:\t%d\n", dci->mcs_idx_1); + fprintf(f, " + New data indicator:\t\t\t%s\n", dci->ndi_1 ? "Yes" : "No"); + fprintf(f, " + Redundancy version:\t\t\t%d\n", dci->rv_idx_1); + } } void srslte_ra_dl_grant_fprint(FILE *f, srslte_ra_dl_grant_t *grant) { srslte_ra_prb_fprint(f, grant); fprintf(f, " - Number of PRBs:\t\t\t%d\n", grant->nof_prb); + fprintf(f, " - Number of TBs:\t\t\t%d\n", grant->nof_tb); fprintf(f, " - Modulation type:\t\t\t%s\n", srslte_mod_string(grant->mcs.mod)); fprintf(f, " - Transport block size:\t\t%d\n", grant->mcs.tbs); + fprintf(f, " - Modulation type (TB2):\t\t%s\n", srslte_mod_string(grant->mcs2.mod)); + fprintf(f, " - Transport block size (TB2):\t\t%d\n", grant->mcs2.tbs); } void srslte_ra_prb_fprint(FILE *f, srslte_ra_dl_grant_t *grant) { diff --git a/lib/src/phy/phch/sch.c b/lib/src/phy/phch/sch.c index dceab2506..f0515227e 100644 --- a/lib/src/phy/phch/sch.c +++ b/lib/src/phy/phch/sch.c @@ -523,6 +523,32 @@ int srslte_dlsch_decode(srslte_sch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbuf e_bits, data); } + +int srslte_dlsch_decode_multi(srslte_sch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbuffer_rx_t softbuffers[SRSLTE_MAX_CODEWORDS], + int16_t *e_bits[SRSLTE_MAX_CODEWORDS], uint8_t *data[SRSLTE_MAX_CODEWORDS]) +{ + int ret = SRSLTE_SUCCESS; + uint32_t Nl = 1; + + if (cfg->nof_layers != cfg->grant.nof_tb) { + Nl = 2; + } + + if (cfg->nbits.nof_bits) { + ret |= decode_tb(q, &softbuffers[0], &cfg->cb_segm, + cfg->grant.Qm*Nl, cfg->rv, cfg->nbits.nof_bits, + e_bits[0], data[0]); + } + + if (cfg->nbits2.nof_bits) { + ret |= decode_tb(q, &softbuffers[1], &cfg->cb_segm2, + cfg->grant.Qm2*Nl, cfg->rv2, cfg->nbits2.nof_bits, + e_bits[1], data[1]); + } + + return ret; +} + /** * Encode transport block. Segments into code blocks, adds channel coding, and does rate matching. * @@ -542,6 +568,35 @@ int srslte_dlsch_encode(srslte_sch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbuf data, e_bits); } +int srslte_dlsch_encode_multi(srslte_sch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbuffer_tx_t softbuffers[SRSLTE_MAX_CODEWORDS], + uint8_t *data[SRSLTE_MAX_CODEWORDS], uint8_t *e_bits[SRSLTE_MAX_CODEWORDS]) +{ + int ret = 0; + uint32_t Nl = 1; + + if (cfg->nof_layers != cfg->grant.nof_tb) { + Nl = 2; + } + + /* Check if codeword 1 shall be encoded */ + if(cfg->nbits.nof_bits) { + ret |= encode_tb(q, + &softbuffers[0], &cfg->cb_segm, + cfg->grant.Qm*Nl, cfg->rv, cfg->nbits.nof_bits, + data[0], e_bits[0]); + } + + /* Check if codeword 2 shall be encoded */ + if(cfg->nbits2.nof_bits) { + ret |= encode_tb(q, + &softbuffers[1], &cfg->cb_segm2, + cfg->grant.Qm2*Nl, cfg->rv2, cfg->nbits2.nof_bits, + data[1], e_bits[1]); + } + + return ret; +} + /* Compute the interleaving function on-the-fly, because it depends on number of RI bits * Profiling show that the computation of this matrix is neglegible. */ diff --git a/lib/src/phy/phch/test/CMakeLists.txt b/lib/src/phy/phch/test/CMakeLists.txt index 6170f82fe..1c9846c76 100644 --- a/lib/src/phy/phch/test/CMakeLists.txt +++ b/lib/src/phy/phch/test/CMakeLists.txt @@ -87,6 +87,27 @@ add_test(pdsch_test_qam16 pdsch_test -m 20 -n 100) add_test(pdsch_test_qam16 pdsch_test -m 20 -n 100 -r 2) add_test(pdsch_test_qam64 pdsch_test -m 28 -n 100) +add_test(pdsch_test_sin_6 pdsch_test -p 1 -a 2 -w 1 -n 6) +add_test(pdsch_test_sin_12 pdsch_test -p 1 -a 2 -w 1 -n 12) +add_test(pdsch_test_sin_25 pdsch_test -p 1 -a 2 -w 1 -n 25) +add_test(pdsch_test_sin_50 pdsch_test -p 1 -a 2 -w 1 -n 50) +add_test(pdsch_test_sin_75 pdsch_test -p 1 -a 2 -w 1 -n 75) +add_test(pdsch_test_sin_100 pdsch_test -p 1 -a 2 -w 1 -n 100 -m 28) + +add_test(pdsch_test_div_6 pdsch_test -p 2 -a 2 -w 1 -n 6) +add_test(pdsch_test_div_12 pdsch_test -p 2 -a 2 -w 1 -n 12) +add_test(pdsch_test_div_25 pdsch_test -p 2 -a 2 -w 1 -n 25) +add_test(pdsch_test_div_50 pdsch_test -p 2 -a 2 -w 1 -n 50) +add_test(pdsch_test_div_75 pdsch_test -p 2 -a 2 -w 1 -n 75) +add_test(pdsch_test_div_100 pdsch_test -p 2 -a 2 -w 1 -n 100 -m 28) + +add_test(pdsch_test_cdd_6 pdsch_test -p 2 -a 2 -w 2 -n 6) +add_test(pdsch_test_cdd_12 pdsch_test -p 2 -a 2 -w 2 -n 12) +add_test(pdsch_test_cdd_25 pdsch_test -p 2 -a 2 -w 2 -n 25) +add_test(pdsch_test_cdd_50 pdsch_test -p 2 -a 2 -w 2 -n 50) +add_test(pdsch_test_cdd_75 pdsch_test -p 2 -a 2 -w 2 -n 75) +add_test(pdsch_test_cdd_100 pdsch_test -p 2 -a 2 -w 2 -n 100 -m 28 -M 28) + ######################################################################## # FILE TEST ######################################################################## diff --git a/lib/src/phy/phch/test/dlsch_encode_test_mex.c b/lib/src/phy/phch/test/dlsch_encode_test_mex.c index 8c2318583..f391ab111 100644 --- a/lib/src/phy/phch/test/dlsch_encode_test_mex.c +++ b/lib/src/phy/phch/test/dlsch_encode_test_mex.c @@ -43,9 +43,14 @@ void help() /* the gateway function */ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { + int i; srslte_sch_t dlsch; srslte_pdsch_cfg_t cfg; - srslte_softbuffer_tx_t softbuffer; + srslte_softbuffer_tx_t *softbuffers[SRSLTE_MAX_CODEWORDS]; + uint32_t nof_codewords = 1; + + memset(&dlsch, 0, sizeof(srslte_sch_t)); + memset(&cfg, 0, sizeof(srslte_pdsch_cfg_t)); if (nrhs < NOF_INPUTS) { help(); @@ -62,6 +67,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) srslte_verbose = SRSLTE_VERBOSE_NONE; uint8_t *trblkin_bits = NULL; + cfg.grant.nof_tb = 1; cfg.grant.mcs.tbs = mexutils_read_uint8(TRBLKIN, &trblkin_bits); if (cfg.grant.mcs.tbs == 0) { mexErrMsgTxt("Error trblklen is zero\n"); @@ -76,6 +82,11 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) return; } + if (mexutils_read_uint32_struct(PUSCHCFG, "NLayers", &cfg.nof_layers)) { + mexErrMsgTxt("Field NLayers not found in dlsch config\n"); + return; + } + char *mod_str = mexutils_get_char_struct(PUSCHCFG, "Modulation"); if (!strcmp(mod_str, "QPSK")) { @@ -94,9 +105,13 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) mxFree(mod_str); - if (srslte_softbuffer_tx_init(&softbuffer, cell.nof_prb)) { - mexErrMsgTxt("Error initiating DL-SCH soft buffer\n"); - return; + /* Initialise buffers */ + for (i = 0; i < nof_codewords; i++) { + softbuffers[i] = srslte_vec_malloc(sizeof(srslte_softbuffer_tx_t)); + if (srslte_softbuffer_tx_init(softbuffers[i], cell.nof_prb)) { + mexErrMsgTxt("Error initiating DL-SCH soft buffer\n"); + return; + } } cfg.nbits.nof_bits = mxGetScalar(OUTLEN); @@ -111,13 +126,13 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) uint32_t tmp_rv=cfg.rv; if (tmp_rv) { cfg.rv = 0; - if (srslte_dlsch_encode(&dlsch, &cfg, &softbuffer, trblkin, e_bits)) { + if (srslte_dlsch_encode_multi(&dlsch, &cfg, softbuffers, &trblkin, &e_bits)) { mexErrMsgTxt("Error encoding TB\n"); return; } cfg.rv = tmp_rv; } - if (srslte_dlsch_encode(&dlsch, &cfg, &softbuffer, trblkin, e_bits)) { + if (srslte_dlsch_encode_multi(&dlsch, &cfg, softbuffers, &trblkin, &e_bits)) { mexErrMsgTxt("Error encoding TB\n"); return; } @@ -135,7 +150,10 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) free(trblkin); free(e_bits); free(e_bits_unpacked); - + for (i = 0; i < nof_codewords; i++) { + srslte_softbuffer_tx_free(softbuffers[i]); + free(softbuffers[i]); + } return; } diff --git a/lib/src/phy/phch/test/pdcch_test.c b/lib/src/phy/phch/test/pdcch_test.c index 5d4fb0a7c..9495c497b 100644 --- a/lib/src/phy/phch/test/pdcch_test.c +++ b/lib/src/phy/phch/test/pdcch_test.c @@ -27,22 +27,26 @@ #include #include #include -#include #include +#include +#include +#include +#include #include "srslte/srslte.h" srslte_cell_t cell = { - 6, // nof_prb - 1, // nof_ports - 1, // cell_id - SRSLTE_CP_NORM, // cyclic prefix - SRSLTE_PHICH_R_1, // PHICH resources - SRSLTE_PHICH_NORM // PHICH length + .nof_prb = 6, + .nof_ports = 1, + .id = 1, + .cp = SRSLTE_CP_NORM, + .phich_resources = SRSLTE_PHICH_R_1, + .phich_length = SRSLTE_PHICH_NORM }; uint32_t cfi = 1; -bool print_dci_table; +uint32_t nof_rx_ant = 1; +bool print_dci_table; void usage(char *prog) { printf("Usage: %s [cfpndv]\n", prog); @@ -50,25 +54,29 @@ void usage(char *prog) { printf("\t-f cfi [Default %d]\n", cfi); printf("\t-p cell.nof_ports [Default %d]\n", cell.nof_ports); printf("\t-n cell.nof_prb [Default %d]\n", cell.nof_prb); + printf("\t-A nof_rx_ant [Default %d]\n", nof_rx_ant); printf("\t-d Print DCI table [Default %s]\n", print_dci_table?"yes":"no"); printf("\t-v [set srslte_verbose to debug, default none]\n"); } void parse_args(int argc, char **argv) { int opt; - while ((opt = getopt(argc, argv, "cfpndv")) != -1) { + while ((opt = getopt(argc, argv, "cfpndvA")) != -1) { switch (opt) { case 'p': - cell.nof_ports = atoi(argv[optind]); + cell.nof_ports = (uint32_t) atoi(argv[optind]); break; case 'f': - cfi = atoi(argv[optind]); + cfi = (uint32_t) atoi(argv[optind]); break; case 'n': - cell.nof_prb = atoi(argv[optind]); + cell.nof_prb = (uint32_t) atoi(argv[optind]); break; case 'c': - cell.id = atoi(argv[optind]); + cell.id = (uint32_t) atoi(argv[optind]); + break; + case 'A': + nof_rx_ant = (uint32_t) atoi(argv[optind]); break; case 'd': print_dci_table = true; @@ -85,25 +93,26 @@ void parse_args(int argc, char **argv) { int test_dci_payload_size() { int i, j; - int x[4]; - const srslte_dci_format_t formats[4] = { SRSLTE_DCI_FORMAT0, SRSLTE_DCI_FORMAT1, SRSLTE_DCI_FORMAT1A, SRSLTE_DCI_FORMAT1C }; + int x[5]; + const srslte_dci_format_t formats[] = { SRSLTE_DCI_FORMAT0, SRSLTE_DCI_FORMAT1, SRSLTE_DCI_FORMAT1A, SRSLTE_DCI_FORMAT1C, SRSLTE_DCI_FORMAT2A }; const int prb[6] = { 6, 15, 25, 50, 75, 100 }; - const int dci_sz[6][5] = { { 21, 19, 21, 8 }, { 22, 23, 22, 10 }, { 25, 27, - 25, 12 }, { 27, 31, 27, 13 }, { 27, 33, 27, 14 }, { 28, 39, 28, 15 } }; + const int dci_sz[6][5] = { { 21, 19, 21, 8, 28 }, { 22, 23, 22, 10 , 31}, { 25, 27, + 25, 12 , 36}, { 27, 31, 27, 13 , 41}, { 27, 33, 27, 14 , 42}, { 28, 39, 28, 15, 48 }}; + printf("Testing DCI payload sizes...\n"); - printf(" PRB\t0\t1\t1A\t1C\n"); + printf(" PRB\t0\t1\t1A\t1C\t2A\n"); for (i = 0; i < 6; i++) { int n = prb[i]; - for (j = 0; j < 4; j++) { - x[j] = srslte_dci_format_sizeof(formats[j], n, 1); + for (j = 0; j < 5; j++) { + x[j] = srslte_dci_format_sizeof(formats[j], (uint32_t) n, 1); if (x[j] != dci_sz[i][j]) { fprintf(stderr, "Invalid DCI payload size for %s\n", srslte_dci_format_string(formats[j])); return -1; } } - printf(" %2d:\t%2d\t%2d\t%2d\t%2d\n", n, x[0], x[1], x[2], x[3]); + printf(" %2d:\t%2d\t%2d\t%2d\t%2d\t%2d\n", n, x[0], x[1], x[2], x[3], x[4]); } printf("Ok\n"); @@ -111,8 +120,8 @@ int test_dci_payload_size() { printf("dci_sz_table[101][4] = {\n"); for (i=0;i<=100;i++) { printf(" {"); - for (int j=0;j<4;j++) { - printf("%d",srslte_dci_format_sizeof(formats[j], i, 1)); + for (j=0;j<4;j++) { + printf("%d",srslte_dci_format_sizeof(formats[j], (uint32_t) i, 1)); if (j<3) { printf(", "); } @@ -128,16 +137,23 @@ int test_dci_payload_size() { return 0; } +typedef struct { + srslte_dci_msg_t dci_tx, dci_rx; + srslte_dci_location_t dci_location; + srslte_dci_format_t dci_format; + srslte_ra_dl_dci_t ra_dl_tx; + srslte_ra_dl_dci_t ra_dl_rx; +} testcase_dci_t; + int main(int argc, char **argv) { - srslte_pdcch_t pdcch; - srslte_dci_msg_t dci_tx[2], dci_rx[2], dci_tmp; - srslte_dci_location_t dci_locations[2]; + srslte_pdcch_t pdcch_tx, pdcch_rx; + testcase_dci_t testcases[10] = {0}; srslte_ra_dl_dci_t ra_dl; srslte_regs_t regs; - int i, j; - cf_t *ce[SRSLTE_MAX_PORTS]; + int i, j, k; + cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; int nof_re; - cf_t *slot_symbols[SRSLTE_MAX_PORTS]; + cf_t *tx_slot_symbols[SRSLTE_MAX_PORTS], *rx_slot_symbols[SRSLTE_MAX_PORTS]; int nof_dcis; int ret = -1; @@ -152,19 +168,30 @@ int main(int argc, char **argv) { /* init memory */ for (i = 0; i < SRSLTE_MAX_PORTS; i++) { - ce[i] = malloc(sizeof(cf_t) * nof_re); - if (!ce[i]) { + for (j = 0; j < SRSLTE_MAX_PORTS; j++) { + ce[i][j] = malloc(sizeof(cf_t) * nof_re); + if (!ce[i][j]) { + perror("malloc"); + exit(-1); + } + for (k = 0; k < nof_re; k++) { + //ce[i][j][k] = (i == j) ? 1 : 0; + ce[i][j][k] = ((float)rand()/(float)RAND_MAX) + _Complex_I*((float)rand()/(float)RAND_MAX); + } + } + tx_slot_symbols[i] = malloc(sizeof(cf_t) * nof_re); + if (!tx_slot_symbols[i]) { perror("malloc"); exit(-1); } - for (j = 0; j < nof_re; j++) { - ce[i][j] = 1; - } - slot_symbols[i] = malloc(sizeof(cf_t) * nof_re); - if (!slot_symbols[i]) { + bzero(tx_slot_symbols[i], sizeof(cf_t) * nof_re); + + rx_slot_symbols[i] = malloc(sizeof(cf_t) * nof_re); + if (!rx_slot_symbols[i]) { perror("malloc"); exit(-1); } + bzero(rx_slot_symbols[i], sizeof(cf_t) * nof_re); } if (srslte_regs_init(®s, cell)) { @@ -177,12 +204,18 @@ int main(int argc, char **argv) { exit(-1); } - if (srslte_pdcch_init(&pdcch, ®s, cell)) { + if (srslte_pdcch_init_tx(&pdcch_tx, ®s, cell)) { + fprintf(stderr, "Error creating PDCCH object\n"); + exit(-1); + } + + if (srslte_pdcch_init_rx(&pdcch_rx, ®s, cell, nof_rx_ant)) { fprintf(stderr, "Error creating PDCCH object\n"); exit(-1); } - nof_dcis = 2; + /* Resource allocate init */ + nof_dcis = 0; bzero(&ra_dl, sizeof(srslte_ra_dl_dci_t)); ra_dl.harq_process = 0; ra_dl.mcs_idx = 5; @@ -190,62 +223,131 @@ int main(int argc, char **argv) { ra_dl.rv_idx = 0; ra_dl.alloc_type = SRSLTE_RA_ALLOC_TYPE0; ra_dl.type0_alloc.rbg_bitmask = 0x5; + ra_dl.tb_en[0] = true; - srslte_dci_msg_pack_pdsch(&ra_dl, SRSLTE_DCI_FORMAT1, &dci_tx[0], cell.nof_prb, cell.nof_ports, false); - srslte_dci_location_set(&dci_locations[0], 0, 0); + /* Format 1 Test case */ + testcases[nof_dcis].dci_format = SRSLTE_DCI_FORMAT1; + testcases[nof_dcis].ra_dl_tx = ra_dl; + nof_dcis++; + /* Format 1 Test case */ ra_dl.mcs_idx = 15; - srslte_dci_msg_pack_pdsch(&ra_dl, SRSLTE_DCI_FORMAT1, &dci_tx[1], cell.nof_prb, cell.nof_ports, false); - srslte_dci_location_set(&dci_locations[1], 0, 1); - + testcases[nof_dcis].dci_format = SRSLTE_DCI_FORMAT1; + testcases[nof_dcis].ra_dl_tx = ra_dl; + nof_dcis++; + + /* Tx Diversity Test case */ + if (cell.nof_ports > 1) { + ra_dl.mcs_idx_1 = 0; + ra_dl.rv_idx_1 = 0; + ra_dl.ndi_1 = false; + ra_dl.tb_en[1] = false; + testcases[nof_dcis].dci_format = SRSLTE_DCI_FORMAT2A; + testcases[nof_dcis].ra_dl_tx = ra_dl; + nof_dcis++; + } + + /* CDD Spatial Multiplexing Test case */ + if (cell.nof_ports > 1) { + ra_dl.mcs_idx_1 = 28; + ra_dl.rv_idx_1 = 1; + ra_dl.ndi_1 = false; + ra_dl.tb_en[1] = true; + testcases[nof_dcis].dci_format = SRSLTE_DCI_FORMAT2A; + testcases[nof_dcis].ra_dl_tx = ra_dl; + nof_dcis++; + } + + /* Execute Rx */ for (i=0;i= 1234 && crc_rem < 1234 + nof_dcis) { crc_rem -= 1234; - memcpy(&dci_rx[crc_rem], &dci_tmp, sizeof(srslte_dci_msg_t)); } else { printf("Received invalid DCI CRC 0x%x\n", crc_rem); goto quit; } } + + /* Compare Tx and Rx */ for (i = 0; i < nof_dcis; i++) { - if (memcmp(dci_tx[i].data, dci_rx[i].data, dci_tx[i].nof_bits)) { + if (memcmp(testcases[i].dci_tx.data, testcases[i].dci_rx.data, testcases[i].dci_tx.nof_bits)) { printf("Error in DCI %d: Received data does not match\n", i); goto quit; } + if (memcmp(&testcases[i].ra_dl_tx, &testcases[i].ra_dl_rx, sizeof(srslte_ra_dl_dci_t))) { + printf("Error in RA %d: Received data does not match\n", i); + printf(" Field | Tx | Rx \n"); + printf("--------------+----------+----------\n"); + printf(" harq_process | %8d | %8d\n", testcases[i].ra_dl_tx.harq_process, testcases[i].ra_dl_rx.harq_process); + printf(" mcs_idx | %8d | %8d\n", testcases[i].ra_dl_tx.mcs_idx, testcases[i].ra_dl_rx.mcs_idx); + printf(" rv_idx | %8d | %8d\n", testcases[i].ra_dl_tx.rv_idx, testcases[i].ra_dl_rx.rv_idx); + printf(" ndi | %8d | %8d\n", testcases[i].ra_dl_tx.ndi, testcases[i].ra_dl_rx.ndi); + printf(" mcs_idx_1 | %8d | %8d\n", testcases[i].ra_dl_tx.mcs_idx_1, testcases[i].ra_dl_rx.mcs_idx_1); + printf(" rv_idx_1 | %8d | %8d\n", testcases[i].ra_dl_tx.rv_idx_1, testcases[i].ra_dl_rx.rv_idx_1); + printf(" ndi_1 | %8d | %8d\n", testcases[i].ra_dl_tx.ndi_1, testcases[i].ra_dl_rx.ndi_1); + printf(" tb_cw_swap | %8d | %8d\n", testcases[i].ra_dl_tx.tb_cw_swap, testcases[i].ra_dl_rx.tb_cw_swap); + printf(" sram_id | %8d | %8d\n", testcases[i].ra_dl_tx.sram_id, testcases[i].ra_dl_rx.sram_id); + printf(" pinfo | %8d | %8d\n", testcases[i].ra_dl_tx.pinfo, testcases[i].ra_dl_rx.pinfo); + printf(" pconf | %8d | %8d\n", testcases[i].ra_dl_tx.pconf, testcases[i].ra_dl_rx.pconf); + printf(" power_offset | %8d | %8d\n", testcases[i].ra_dl_tx.power_offset, testcases[i].ra_dl_rx.power_offset); + printf(" tpc_pucch | %8d | %8d\n", testcases[i].ra_dl_tx.tpc_pucch, testcases[i].ra_dl_rx.tpc_pucch); + printf(" tb_en[0] | %8d | %8d\n", testcases[i].ra_dl_tx.tb_en[0], testcases[i].ra_dl_rx.tb_en[0]); + printf(" tb_en[1] | %8d | %8d\n", testcases[i].ra_dl_tx.tb_en[1], testcases[i].ra_dl_rx.tb_en[1]); + printf(" dci_is_1a | %8d | %8d\n", testcases[i].ra_dl_tx.dci_is_1a, testcases[i].ra_dl_rx.dci_is_1a); + printf(" dci_is_1c | %8d | %8d\n", testcases[i].ra_dl_tx.dci_is_1c, testcases[i].ra_dl_rx.dci_is_1c); + goto quit; + } } ret = 0; quit: - srslte_pdcch_free(&pdcch); + srslte_pdcch_free(&pdcch_tx); + srslte_pdcch_free(&pdcch_rx); srslte_regs_free(®s); for (i = 0; i < SRSLTE_MAX_PORTS; i++) { - free(ce[i]); - free(slot_symbols[i]); + for (j = 0; j < SRSLTE_MAX_PORTS; j++) { + free(ce[i][j]); + } + free(tx_slot_symbols[i]); + free(rx_slot_symbols[i]); } if (ret) { printf("Error\n"); diff --git a/lib/src/phy/phch/test/pdcch_test_mex.c b/lib/src/phy/phch/test/pdcch_test_mex.c index e30ef900f..76b0bb021 100644 --- a/lib/src/phy/phch/test/pdcch_test_mex.c +++ b/lib/src/phy/phch/test/pdcch_test_mex.c @@ -33,13 +33,14 @@ #define ENBCFG prhs[0] #define RNTI prhs[1] -#define INPUT prhs[2] -#define NOF_INPUTS 3 +#define AMP prhs[2] +#define INPUT prhs[3] +#define NOF_INPUTS 4 -srslte_dci_format_t ue_formats[] = {SRSLTE_DCI_FORMAT1A,SRSLTE_DCI_FORMAT1}; // SRSLTE_DCI_FORMAT1B should go here also -const uint32_t nof_ue_formats = 2; +srslte_dci_format_t ue_formats[] = {SRSLTE_DCI_FORMAT1A,SRSLTE_DCI_FORMAT1,SRSLTE_DCI_FORMAT2B}; // SRSLTE_DCI_FORMAT1B should go here also +const uint32_t nof_ue_formats = 3; srslte_dci_format_t common_formats[] = {SRSLTE_DCI_FORMAT1A,SRSLTE_DCI_FORMAT1C}; const uint32_t nof_common_formats = 2; @@ -162,7 +163,10 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) } else { noise_power = srslte_chest_dl_get_noise_estimate(&chest); } - mexPrintf("noise power=%f, RNTI=0x%x, cfi=%d\n", noise_power, rnti, cfi); + + float amplitude = mxGetScalar(AMP); + + srslte_viterbi_set_gain_quant(&pdcch.decoder, amplitude); srslte_pdcch_extract_llr(&pdcch, input_fft, ce, noise_power, sf_idx, cfi); diff --git a/lib/src/phy/phch/test/pdsch_test.c b/lib/src/phy/phch/test/pdsch_test.c index d4e5163d3..2dc21bab4 100644 --- a/lib/src/phy/phch/test/pdsch_test.c +++ b/lib/src/phy/phch/test/pdsch_test.c @@ -30,45 +30,60 @@ #include #include #include +#include #include "srslte/srslte.h" // Enable to measure execution time //#define DO_OFDM +#ifdef DO_OFDM +#define NOF_CE_SYMBOLS SRSLTE_SF_LEN_PRB(cell.nof_prb) +#else +#define NOF_CE_SYMBOLS SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp) +#endif + srslte_cell_t cell = { 6, // nof_prb 1, // nof_ports 0, // cell_id SRSLTE_CP_NORM, // cyclic prefix - SRSLTE_PHICH_R_1_6, // PHICH resources - SRSLTE_PHICH_NORM // PHICH length + SRSLTE_PHICH_NORM, // PHICH length + SRSLTE_PHICH_R_1_6 // PHICH resources }; uint32_t cfi = 2; uint32_t mcs = 0; +uint32_t mcs2 = 0; uint32_t subframe = 1; uint32_t rv_idx = 0; -uint16_t rnti = 1234; +uint32_t rv_idx2 = 0; +uint16_t rnti = 1234; +uint32_t nof_tb = 1; +uint32_t nof_rx_antennas = 1; char *input_file = NULL; void usage(char *prog) { - printf("Usage: %s [fmcsrRFpnv] \n", prog); + printf("Usage: %s [fmMcsrtRFpnwav] \n", prog); printf("\t-f read signal from file [Default generate it with pdsch_encode()]\n"); printf("\t-m MCS [Default %d]\n", mcs); + printf("\t-M MCS2 [Default %d]\n", mcs2); printf("\t-c cell id [Default %d]\n", cell.id); printf("\t-s subframe [Default %d]\n", subframe); printf("\t-r rv_idx [Default %d]\n", rv_idx); + printf("\t-t rv_idx2 [Default %d]\n", rv_idx2); printf("\t-R rnti [Default %d]\n", rnti); printf("\t-F cfi [Default %d]\n", cfi); printf("\t-p cell.nof_ports [Default %d]\n", cell.nof_ports); printf("\t-n cell.nof_prb [Default %d]\n", cell.nof_prb); + printf("\t-w nof_tb [Default %d]\n", nof_tb); + printf("\t-a nof_rx_antennas [Default %d]\n", nof_rx_antennas); printf("\t-v [set srslte_verbose to debug, default none]\n"); } void parse_args(int argc, char **argv) { int opt; - while ((opt = getopt(argc, argv, "fmcsrRFpnv")) != -1) { + while ((opt = getopt(argc, argv, "fmMcsrtRFpnwav")) != -1) { switch(opt) { case 'f': input_file = argv[optind]; @@ -76,12 +91,18 @@ void parse_args(int argc, char **argv) { case 'm': mcs = atoi(argv[optind]); break; + case 'M': + mcs2 = (uint32_t) atoi(argv[optind]); + break; case 's': subframe = atoi(argv[optind]); break; case 'r': rv_idx = atoi(argv[optind]); break; + case 't': + rv_idx2 = (uint32_t) atoi(argv[optind]); + break; case 'R': rnti = atoi(argv[optind]); break; @@ -97,6 +118,12 @@ void parse_args(int argc, char **argv) { case 'c': cell.id = atoi(argv[optind]); break; + case 'w': + nof_tb = (uint32_t) atoi(argv[optind]); + break; + case 'a': + nof_rx_antennas = (uint32_t) atoi(argv[optind]); + break; case 'v': srslte_verbose++; break; @@ -107,30 +134,37 @@ void parse_args(int argc, char **argv) { } } -uint8_t *data = NULL; -cf_t *ce[SRSLTE_MAX_PORTS]; -srslte_softbuffer_rx_t softbuffer_rx; +uint8_t *data[SRSLTE_MAX_CODEWORDS] = {NULL}; +cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; +srslte_softbuffer_rx_t softbuffers_rx[SRSLTE_MAX_CODEWORDS]; srslte_ra_dl_grant_t grant; srslte_pdsch_cfg_t pdsch_cfg; -cf_t *sf_symbols; -cf_t *slot_symbols[SRSLTE_MAX_PORTS]; -srslte_pdsch_t pdsch; +#ifdef DO_OFDM +cf_t *tx_sf_symbols[SRSLTE_MAX_PORTS]; +cf_t *rx_sf_symbols[SRSLTE_MAX_PORTS]; +#endif /* DO_OFDM */ +cf_t *tx_slot_symbols[SRSLTE_MAX_PORTS]; +cf_t *rx_slot_symbols[SRSLTE_MAX_PORTS]; +srslte_pdsch_t pdsch_tx, pdsch_rx; srslte_ofdm_t ofdm_tx, ofdm_rx; int main(int argc, char **argv) { - uint32_t i, j; + uint32_t i, j, k; int ret = -1; struct timeval t[3]; - srslte_softbuffer_tx_t softbuffer_tx; + srslte_softbuffer_tx_t softbuffers_tx[SRSLTE_MAX_CODEWORDS]; parse_args(argc,argv); - bzero(&pdsch, sizeof(srslte_pdsch_t)); + /* Initialise to zeros */ + bzero(&pdsch_tx, sizeof(srslte_pdsch_t)); + bzero(&pdsch_rx, sizeof(srslte_pdsch_t)); bzero(&pdsch_cfg, sizeof(srslte_pdsch_cfg_t)); bzero(ce, sizeof(cf_t*)*SRSLTE_MAX_PORTS); - bzero(slot_symbols, sizeof(cf_t*)*SRSLTE_MAX_PORTS); - bzero(&softbuffer_rx, sizeof(srslte_softbuffer_rx_t)); - bzero(&softbuffer_tx, sizeof(srslte_softbuffer_tx_t)); + bzero(tx_slot_symbols, sizeof(cf_t*)*SRSLTE_MAX_PORTS); + bzero(rx_slot_symbols, sizeof(cf_t*)*SRSLTE_MAX_PORTS); + bzero(softbuffers_tx, sizeof(srslte_softbuffer_tx_t)*SRSLTE_MAX_CODEWORDS); + bzero(softbuffers_rx, sizeof(srslte_softbuffer_rx_t)*SRSLTE_MAX_CODEWORDS); srslte_ra_dl_dci_t dci; bzero(&dci, sizeof(srslte_ra_dl_dci_t)); @@ -138,57 +172,136 @@ int main(int argc, char **argv) { dci.rv_idx = rv_idx; dci.type0_alloc.rbg_bitmask = 0xffffffff; dci.tb_en[0] = true; + if (nof_tb > 1) { + dci.mcs_idx_1 = mcs2; + dci.rv_idx_1 = rv_idx2; + dci.tb_en[1] = true; + } + + /* Generate grant from DCI */ if (srslte_ra_dl_dci_to_grant(&dci, cell.nof_prb, rnti, &grant)) { fprintf(stderr, "Error computing resource allocation\n"); return ret; } +#ifdef DO_OFDM srslte_ofdm_tx_init(&ofdm_tx, cell.cp, cell.nof_prb); srslte_ofdm_rx_init(&ofdm_rx, cell.cp, cell.nof_prb); - sf_symbols=srslte_vec_malloc(sizeof(cf_t)*SRSLTE_SF_LEN_PRB(cell.nof_prb)); - + srslte_ofdm_set_normalize(&ofdm_tx, true); + srslte_ofdm_set_normalize(&ofdm_rx, true); + + for (i = 0; i < cell.nof_ports; i++) { + tx_sf_symbols[i] = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_SF_LEN_PRB(cell.nof_prb)); + } + + for (i = 0; i < nof_rx_antennas; i++) { + rx_sf_symbols[i] = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_SF_LEN_PRB(cell.nof_prb)); + } +#endif /* DO_OFDM */ + /* Configure PDSCH */ - if (srslte_pdsch_cfg(&pdsch_cfg, cell, &grant, cfi, subframe, rv_idx)) { + if (srslte_pdsch_cfg_multi(&pdsch_cfg, cell, &grant, cfi, subframe, rv_idx, rv_idx2)) { fprintf(stderr, "Error configuring PDSCH\n"); exit(-1); } + /* Select MIMO mode */ + if (cell.nof_ports == 1 && nof_tb == 1) { + pdsch_cfg.mimo_type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA; + pdsch_cfg.nof_layers = 1; + } else if (cell.nof_ports == 2 && nof_tb == 1) { + pdsch_cfg.mimo_type = SRSLTE_MIMO_TYPE_TX_DIVERSITY; + pdsch_cfg.nof_layers = 2; + } else if (cell.nof_ports == 2 && nof_tb == 2) { + pdsch_cfg.mimo_type = SRSLTE_MIMO_TYPE_CDD; + pdsch_cfg.nof_layers = 2; + } else { + fprintf(stderr, "nof_ports=%d, nof_tb=%d are not consistent\n", cell.nof_ports, nof_tb); + exit(-1); + } + /* init memory */ for (i=0;i 0) { - slot_symbols[0][j] += slot_symbols[i][j]; + for (j = 0; j < nof_rx_antennas; j++) { + for (k = 0; k < NOF_CE_SYMBOLS; k++) { + rx_sf_symbols[j][k] = 0.0f; + for (i = 0; i < cell.nof_ports; i++) { + rx_sf_symbols[j][k] += tx_sf_symbols[i][k] * ce[i][j][k]; + } + } + } + #else + /* combine outputs */ + for (j = 0; j < nof_rx_antennas; j++) { + for (k = 0; k < SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp); k++) { + rx_slot_symbols[j][k] = 0.0f; + for (i = 0; i < cell.nof_ports; i++) { + rx_slot_symbols[j][k] += tx_slot_symbols[i][k] * ce[i][j][k]; } - ce[i][j] = 1; } } - - #ifdef DO_OFDM - srslte_ofdm_tx_sf(&ofdm_tx, slot_symbols[0], sf_symbols); #endif - } - int M=1; + + + } + int M=10; int r=0; - srslte_sch_set_max_noi(&pdsch.dl_sch, 10); + srslte_sch_set_max_noi(&pdsch_rx.dl_sch, 10); gettimeofday(&t[1], NULL); - for (i=0;iname, devname)) { rf->dev = available_devices[i]; - return available_devices[i]->srslte_rf_open_multi(args, &rf->handler, nof_rx_antennas); + return available_devices[i]->srslte_rf_open_multi(args, &rf->handler, nof_tx_antennas, nof_rx_antennas); } i++; } @@ -121,7 +125,7 @@ int srslte_rf_open_devname_multi(srslte_rf_t *rf, char *devname, char *args, uin /* 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_multi(args, &rf->handler, nof_rx_antennas)) { + if (!available_devices[i]->srslte_rf_open_multi(args, &rf->handler, nof_tx_antennas, nof_rx_antennas)) { rf->dev = available_devices[i]; return 0; } @@ -194,6 +198,11 @@ 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_open_multi2(srslte_rf_t *h, char *args, uint32_t nof_tx_antennas, uint32_t nof_rx_antennas) +{ + return srslte_rf_open_devname_multi2(h, NULL, args, nof_tx_antennas, nof_rx_antennas); +} + int srslte_rf_close(srslte_rf_t *rf) { return ((rf_dev_t*) rf->dev)->srslte_rf_close(rf->handler); @@ -301,6 +310,18 @@ int srslte_rf_send_timed3(srslte_rf_t *rf, has_time_spec, blocking, is_start_of_burst, is_end_of_burst); } +int srslte_rf_send_multi(srslte_rf_t *rf, + void *data[4], + int nsamples, + bool blocking, + bool is_start_of_burst, + bool is_end_of_burst) +{ + + return ((rf_dev_t*) rf->dev)->srslte_rf_send_timed_multi(rf->handler, data, nsamples, 0, 0, + false, blocking, is_start_of_burst, is_end_of_burst); +} + int srslte_rf_send(srslte_rf_t *rf, void *data, uint32_t nsamples, bool blocking) { return srslte_rf_send2(rf, data, nsamples, blocking, true, true); diff --git a/lib/src/phy/rf/rf_uhd_imp.c b/lib/src/phy/rf/rf_uhd_imp.c index 319093994..e0f3ac573 100644 --- a/lib/src/phy/rf/rf_uhd_imp.c +++ b/lib/src/phy/rf/rf_uhd_imp.c @@ -286,10 +286,10 @@ float rf_uhd_get_rssi(void *h) { int rf_uhd_open(char *args, void **h) { - return rf_uhd_open_multi(args, h, 1); + return rf_uhd_open_multi(args, h, 1, 1); } -int rf_uhd_open_multi(char *args, void **h, uint32_t nof_rx_antennas) +int rf_uhd_open_multi(char *args, void **h, uint32_t nof_tx_antennas, uint32_t nof_rx_antennas) { if (h) { *h = NULL; @@ -395,12 +395,11 @@ int rf_uhd_open_multi(char *args, void **h, uint32_t nof_rx_antennas) .otw_format = "sc16", .args = "", .channel_list = channel, - .n_channels = 1 + .n_channels = (nof_tx_antennas > nof_rx_antennas)?nof_tx_antennas:nof_rx_antennas, }; handler->nof_rx_channels = nof_rx_antennas; - handler->nof_tx_channels = 1; - + handler->nof_tx_channels = nof_tx_antennas; /* Initialize rx and tx stremers */ uhd_rx_streamer_make(&handler->rx_stream); error = uhd_usrp_get_rx_stream(handler->usrp, &stream_args, handler->rx_stream); @@ -648,8 +647,28 @@ int rf_uhd_send_timed(void *h, bool is_start_of_burst, bool is_end_of_burst) { + void *_data[SRSLTE_MAX_PORTS]= {data, zero_mem, zero_mem, zero_mem}; + + return rf_uhd_send_timed_multi(h, _data, nsamples, secs, frac_secs, has_time_spec, blocking, is_start_of_burst, is_end_of_burst); +} + +int rf_uhd_send_timed_multi(void *h, + void *data[4], + int nsamples, + time_t secs, + double frac_secs, + bool has_time_spec, + bool blocking, + bool is_start_of_burst, + bool is_end_of_burst) { rf_uhd_handler_t* handler = (rf_uhd_handler_t*) h; + /* Resets the USRP time FIXME: this might cause problems for burst transmissions */ + if (is_start_of_burst && handler->nof_tx_channels > 1) { + uhd_usrp_set_time_now(handler->usrp, 0, 0, 0); + uhd_tx_metadata_set_time_spec(&handler->tx_md, 0, 0.1); + } + size_t txd_samples; if (has_time_spec) { uhd_tx_metadata_set_time_spec(&handler->tx_md, secs, frac_secs); @@ -657,7 +676,10 @@ int rf_uhd_send_timed(void *h, int trials = 0; if (blocking) { int n = 0; - cf_t *data_c = (cf_t*) data; + cf_t *data_c[4]; + for (int i = 0; i < 4; i++) { + data_c[i] = data[i]; + } do { size_t tx_samples = handler->tx_nof_samples; @@ -675,9 +697,12 @@ int rf_uhd_send_timed(void *h, tx_samples = nsamples - n; uhd_tx_metadata_set_end(&handler->tx_md, is_end_of_burst); } - - void *buff = (void*) &data_c[n]; - const void *buffs_ptr[4] = {buff, zero_mem, zero_mem, zero_mem}; + + const void *buffs_ptr[4]; + for (int i = 0; i < 4; i++) { + void *buff = (void*) &data_c[i][n]; + buffs_ptr[i] = buff; + } uhd_error error = uhd_tx_streamer_send(handler->tx_stream, buffs_ptr, tx_samples, &handler->tx_md, 3.0, &txd_samples); if (error) { @@ -691,7 +716,10 @@ int rf_uhd_send_timed(void *h, } while (n < nsamples && trials < 100); return nsamples; } else { - const void *buffs_ptr[4] = {data, zero_mem, zero_mem, zero_mem}; + const void *buffs_ptr[4]; + for (int i = 0; i < 4; i++) { + buffs_ptr[i] = data[i]; + } uhd_tx_metadata_set_start(&handler->tx_md, is_start_of_burst); uhd_tx_metadata_set_end(&handler->tx_md, is_end_of_burst); return uhd_tx_streamer_send(handler->tx_stream, buffs_ptr, nsamples, &handler->tx_md, 0.0, &txd_samples); diff --git a/lib/src/phy/rf/rf_uhd_imp.h b/lib/src/phy/rf/rf_uhd_imp.h index 7c26f015c..6c0ab7dc7 100644 --- a/lib/src/phy/rf/rf_uhd_imp.h +++ b/lib/src/phy/rf/rf_uhd_imp.h @@ -39,6 +39,7 @@ SRSLTE_API int rf_uhd_open(char *args, SRSLTE_API int rf_uhd_open_multi(char *args, void **handler, + uint32_t nof_tx_antennas, uint32_t nof_rx_antennas); SRSLTE_API char* rf_uhd_devname(void *h); @@ -123,3 +124,13 @@ SRSLTE_API int rf_uhd_send_timed(void *h, bool is_start_of_burst, bool is_end_of_burst); +SRSLTE_API int rf_uhd_send_timed_multi(void *h, + void *data[SRSLTE_MAX_PORTS], + int nsamples, + time_t secs, + double frac_secs, + bool has_time_spec, + bool blocking, + bool is_start_of_burst, + bool is_end_of_burst); + diff --git a/lib/src/phy/ue/ue_dl.c b/lib/src/phy/ue/ue_dl.c index 7201f96c2..3b1a83466 100644 --- a/lib/src/phy/ue/ue_dl.c +++ b/lib/src/phy/ue/ue_dl.c @@ -38,8 +38,8 @@ #define CURRENT_SFLEN_RE SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp) -static srslte_dci_format_t ue_formats[] = {SRSLTE_DCI_FORMAT1A, SRSLTE_DCI_FORMAT1}; // Only TM1 and TM2 are currently supported -const uint32_t nof_ue_formats = 2; +static srslte_dci_format_t ue_formats[] = {SRSLTE_DCI_FORMAT1A, SRSLTE_DCI_FORMAT1, SRSLTE_DCI_FORMAT2A}; // Only TM1 and TM2 are currently supported +const uint32_t nof_ue_formats = 3; static srslte_dci_format_t common_formats[] = {SRSLTE_DCI_FORMAT1A,SRSLTE_DCI_FORMAT1C}; const uint32_t nof_common_formats = 2; @@ -97,13 +97,16 @@ int srslte_ue_dl_init_multi(srslte_ue_dl_t *q, goto clean_exit; } - if (srslte_pdsch_init_multi(&q->pdsch, q->cell, nof_rx_antennas)) { + if (srslte_pdsch_init_rx_multi(&q->pdsch, q->cell, nof_rx_antennas)) { fprintf(stderr, "Error creating PDSCH object\n"); goto clean_exit; } - if (srslte_softbuffer_rx_init(&q->softbuffer, q->cell.nof_prb)) { - fprintf(stderr, "Error initiating soft buffer\n"); - goto clean_exit; + + for (int i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { + if (srslte_softbuffer_rx_init(&q->softbuffers[i], q->cell.nof_prb)) { + fprintf(stderr, "Error initiating soft buffer\n"); + goto clean_exit; + } } if (srslte_cfo_init(&q->sfo_correct, q->cell.nof_prb*SRSLTE_NRE)) { fprintf(stderr, "Error initiating SFO correct\n"); @@ -154,7 +157,9 @@ void srslte_ue_dl_free(srslte_ue_dl_t *q) { srslte_pdcch_free(&q->pdcch); srslte_pdsch_free(&q->pdsch); srslte_cfo_free(&q->sfo_correct); - srslte_softbuffer_rx_free(&q->softbuffer); + for (int i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { + srslte_softbuffer_rx_free(&q->softbuffers[i]); + } for (int j=0;jnof_rx_antennas;j++) { if (q->sf_symbols_m[j]) { free(q->sf_symbols_m[j]); @@ -188,7 +193,9 @@ void srslte_ue_dl_set_rnti(srslte_ue_dl_t *q, uint16_t rnti) { } void srslte_ue_dl_reset(srslte_ue_dl_t *q) { - srslte_softbuffer_rx_reset(&q->softbuffer); + for(int i = 0; i < SRSLTE_MAX_CODEWORDS; i++){ + srslte_softbuffer_rx_reset(&q->softbuffers[i]); + } bzero(&q->pdsch_cfg, sizeof(srslte_pdsch_cfg_t)); } @@ -204,12 +211,14 @@ 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) { + uint8_t *_data[SRSLTE_MAX_CODEWORDS]; cf_t *_input[SRSLTE_MAX_PORTS]; + _data[0] = data; _input[0] = input; - return srslte_ue_dl_decode_rnti_multi(q, _input, data, tti, q->current_rnti); + return srslte_ue_dl_decode_rnti_multi(q, _input, _data, tti, q->current_rnti); } -int srslte_ue_dl_decode_multi(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint8_t *data, uint32_t tti) { +int srslte_ue_dl_decode_multi(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint8_t *data[SRSLTE_MAX_CODEWORDS], uint32_t tti) { return srslte_ue_dl_decode_rnti_multi(q, input, data, tti, q->current_rnti); } @@ -275,17 +284,24 @@ int srslte_ue_dl_decode_estimate(srslte_ue_dl_t *q, uint32_t sf_idx, uint32_t *c int srslte_ue_dl_cfg_grant(srslte_ue_dl_t *q, srslte_ra_dl_grant_t *grant, uint32_t cfi, uint32_t sf_idx, uint32_t rvidx) { - return srslte_pdsch_cfg(&q->pdsch_cfg, q->cell, grant, cfi, sf_idx, rvidx); + return srslte_pdsch_cfg_multi(&q->pdsch_cfg, q->cell, grant, cfi, sf_idx, rvidx, 0); } -int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, cf_t *input, uint8_t *data, uint32_t tti, uint16_t rnti) +int srslte_ue_dl_cfg_grant_multi(srslte_ue_dl_t *q, srslte_ra_dl_grant_t *grant, uint32_t cfi, uint32_t sf_idx, uint32_t rvidx, uint32_t rvidx2) { + return srslte_pdsch_cfg_multi(&q->pdsch_cfg, q->cell, grant, cfi, sf_idx, rvidx, rvidx2); +} + +int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, cf_t *input, uint8_t *data, uint32_t tti, uint16_t rnti) +{ + uint8_t *_data[SRSLTE_MAX_CODEWORDS]; cf_t *_input[SRSLTE_MAX_PORTS]; _input[0] = input; - return srslte_ue_dl_decode_rnti_multi(q, _input, data, tti, rnti); + _data[0] = data; + 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) +int srslte_ue_dl_decode_rnti_multi(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint8_t *data[SRSLTE_MAX_CODEWORDS], uint32_t tti, uint16_t rnti) { srslte_dci_msg_t dci_msg; srslte_ra_dl_dci_t dci_unpacked; @@ -320,17 +336,26 @@ int srslte_ue_dl_decode_rnti_multi(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_POR uint32_t rvidx = 0; + uint32_t rvidx2 = 0; if (dci_unpacked.rv_idx < 0) { uint32_t sfn = tti/10; uint32_t k = (sfn/2)%4; rvidx = ((uint32_t) ceilf((float)1.5*k))%4; - srslte_softbuffer_rx_reset_tbs(&q->softbuffer, grant.mcs.tbs); + srslte_softbuffer_rx_reset_tbs(&q->softbuffers[0], (uint32_t) grant.mcs.tbs); + if (grant.nof_tb > 1) { + rvidx2 = ((uint32_t) ceilf((float)1.5*k))%4; + srslte_softbuffer_rx_reset_tbs(&q->softbuffers[1], (uint32_t) grant.mcs2.tbs); + } } else { - rvidx = dci_unpacked.rv_idx; - srslte_softbuffer_rx_reset_tbs(&q->softbuffer, grant.mcs.tbs); + rvidx = (uint32_t) dci_unpacked.rv_idx; + srslte_softbuffer_rx_reset_tbs(&q->softbuffers[0], (uint32_t) grant.mcs.tbs); + if (grant.nof_tb > 1) { + rvidx2 = (uint32_t) dci_unpacked.rv_idx_1; + srslte_softbuffer_rx_reset_tbs(&q->softbuffers[1], (uint32_t) grant.mcs2.tbs); + } } - if (srslte_ue_dl_cfg_grant(q, &grant, cfi, sf_idx, rvidx)) { + if (srslte_ue_dl_cfg_grant_multi(q, &grant, cfi, sf_idx, rvidx, rvidx2)) { return SRSLTE_ERROR; } @@ -340,7 +365,7 @@ int srslte_ue_dl_decode_rnti_multi(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_POR if (q->pdsch_cfg.grant.mcs.mod > 0 && q->pdsch_cfg.grant.mcs.tbs >= 0) { - ret = srslte_pdsch_decode_multi(&q->pdsch, &q->pdsch_cfg, &q->softbuffer, + ret = srslte_pdsch_decode_multi(&q->pdsch, &q->pdsch_cfg, q->softbuffers, q->sf_symbols_m, q->ce_m, noise_estimate, rnti, data); diff --git a/lib/src/phy/ue/ue_sync.c b/lib/src/phy/ue/ue_sync.c index b5b2be3d0..e011789ca 100644 --- a/lib/src/phy/ue/ue_sync.c +++ b/lib/src/phy/ue/ue_sync.c @@ -53,6 +53,11 @@ cf_t dummy_buffer1[15*2048/2]; 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) { + return srslte_ue_sync_init_file_multi(q, nof_prb, file_name, offset_time, offset_freq, 1); +} + +int srslte_ue_sync_init_file_multi(srslte_ue_sync_t *q, uint32_t nof_prb, char *file_name, int offset_time, + float offset_freq, uint32_t nof_rx_ant) { int ret = SRSLTE_ERROR_INVALID_INPUTS; if (q != NULL && @@ -66,6 +71,7 @@ int srslte_ue_sync_init_file(srslte_ue_sync_t *q, uint32_t nof_prb, char *file_n q->file_cfo = -offset_freq; q->correct_cfo = true; q->fft_size = srslte_symbol_sz(nof_prb); + q->nof_rx_antennas = nof_rx_ant; if (srslte_cfo_init(&q->file_cfo_correct, 2*q->sf_len)) { fprintf(stderr, "Error initiating CFO\n"); @@ -80,12 +86,12 @@ int srslte_ue_sync_init_file(srslte_ue_sync_t *q, uint32_t nof_prb, char *file_n INFO("Offseting input file by %d samples and %.1f kHz\n", offset_time, offset_freq/1000); if (offset_time) { - cf_t *file_offset_buffer = srslte_vec_malloc(offset_time * sizeof(cf_t)); + cf_t *file_offset_buffer = srslte_vec_malloc(offset_time * nof_rx_ant * sizeof(cf_t)); if (!file_offset_buffer) { perror("malloc"); goto clean_exit; } - srslte_filesource_read(&q->file_source, file_offset_buffer, offset_time); + srslte_filesource_read(&q->file_source, file_offset_buffer, offset_time * nof_rx_ant); free(file_offset_buffer); } @@ -518,26 +524,27 @@ int srslte_ue_sync_zerocopy_multi(srslte_ue_sync_t *q, cf_t *input_buffer[SRSLTE { if (q->file_mode) { - int n = srslte_filesource_read(&q->file_source, input_buffer[0], q->sf_len); + int n = srslte_filesource_read_multi(&q->file_source, (void **) input_buffer, q->sf_len, q->nof_rx_antennas); if (n < 0) { fprintf(stderr, "Error reading input file\n"); - return SRSLTE_ERROR; + return SRSLTE_ERROR; } if (n == 0) { srslte_filesource_seek(&q->file_source, 0); - q->sf_idx = 9; - int n = srslte_filesource_read(&q->file_source, input_buffer[0], q->sf_len); + q->sf_idx = 9; + n = srslte_filesource_read_multi(&q->file_source, (void **) input_buffer, q->sf_len, q->nof_rx_antennas); if (n < 0) { fprintf(stderr, "Error reading input file\n"); - return SRSLTE_ERROR; + return SRSLTE_ERROR; } } if (q->correct_cfo) { - srslte_cfo_correct(&q->file_cfo_correct, - input_buffer[0], - input_buffer[0], - q->file_cfo / 15000 / q->fft_size); - + for (int i = 0; i < q->nof_rx_antennas; i++) { + srslte_cfo_correct(&q->file_cfo_correct, + input_buffer[i], + input_buffer[i], + q->file_cfo / 15000 / q->fft_size); + } } q->sf_idx++; if (q->sf_idx == 10) { diff --git a/srsue/hdr/phy/phch_worker.h b/srsue/hdr/phy/phch_worker.h index 669422981..8cdec22c2 100644 --- a/srsue/hdr/phy/phch_worker.h +++ b/srsue/hdr/phy/phch_worker.h @@ -78,6 +78,7 @@ private: bool decode_pdcch_dl(mac_interface_phy::mac_grant_t *grant); bool decode_phich(bool *ack); bool decode_pdsch(srslte_ra_dl_grant_t *grant, uint8_t *payload, srslte_softbuffer_rx_t* softbuffer, int rv, uint16_t rnti, uint32_t pid); + bool decode_pdsch_multi(srslte_ra_dl_grant_t *grant, uint8_t *payload[SRSLTE_MAX_CODEWORDS], srslte_softbuffer_rx_t softbuffers[SRSLTE_MAX_CODEWORDS], int rv, uint16_t rnti, uint32_t pid); /* ... for UL */ void encode_pusch(srslte_ra_ul_grant_t *grant, uint8_t *payload, uint32_t current_tx_nb, srslte_softbuffer_tx_t *softbuffer, diff --git a/srsue/src/phy/phch_worker.cc b/srsue/src/phy/phch_worker.cc index c2796e2ad..ef3640a40 100644 --- a/srsue/src/phy/phch_worker.cc +++ b/srsue/src/phy/phch_worker.cc @@ -405,8 +405,14 @@ bool phch_worker::decode_pdcch_dl(srsue::mac_interface_phy::mac_grant_t* grant) } } -bool phch_worker::decode_pdsch(srslte_ra_dl_grant_t *grant, uint8_t *payload, +bool phch_worker::decode_pdsch(srslte_ra_dl_grant_t *grant, uint8_t *payload, srslte_softbuffer_rx_t* softbuffer, int rv, uint16_t rnti, uint32_t harq_pid) +{ + return decode_pdsch_multi(grant, &payload, softbuffer, rv, rnti, harq_pid); +} + +bool phch_worker::decode_pdsch_multi(srslte_ra_dl_grant_t *grant, uint8_t *payload[SRSLTE_MAX_CODEWORDS], + srslte_softbuffer_rx_t softbuffers[SRSLTE_MAX_CODEWORDS], int rv, uint16_t rnti, uint32_t harq_pid) { char timestr[64]; timestr[0]='\0'; @@ -435,7 +441,7 @@ bool phch_worker::decode_pdsch(srslte_ra_dl_grant_t *grant, uint8_t *payload, gettimeofday(&t[1], NULL); #endif - bool ack = srslte_pdsch_decode_multi(&ue_dl.pdsch, &ue_dl.pdsch_cfg, softbuffer, ue_dl.sf_symbols_m, + bool ack = srslte_pdsch_decode_multi(&ue_dl.pdsch, &ue_dl.pdsch_cfg, softbuffers, ue_dl.sf_symbols_m, ue_dl.ce_m, noise_estimate, rnti, payload) == 0; #ifdef LOG_EXECTIME gettimeofday(&t[2], NULL); From 19bc98081a1c505679e3626f807985d023e0a33d Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Tue, 25 Jul 2017 15:35:25 +0200 Subject: [PATCH 03/60] PDSCH decoder multi has been modified for future parallel decoding of codewords. --- lib/include/srslte/phy/phch/sch.h | 9 ++++--- lib/src/phy/phch/pdsch.c | 45 ++++++++++++++++--------------- lib/src/phy/phch/sch.c | 19 +++++++------ 3 files changed, 38 insertions(+), 35 deletions(-) diff --git a/lib/include/srslte/phy/phch/sch.h b/lib/include/srslte/phy/phch/sch.h index 0e59ecbc9..128cfea6f 100644 --- a/lib/include/srslte/phy/phch/sch.h +++ b/lib/include/srslte/phy/phch/sch.h @@ -108,11 +108,12 @@ SRSLTE_API int srslte_dlsch_decode(srslte_sch_t *q, int16_t *e_bits, uint8_t *data); -SRSLTE_API int srslte_dlsch_decode_multi(srslte_sch_t *q, +SRSLTE_API int srslte_dlsch_decode2(srslte_sch_t *q, srslte_pdsch_cfg_t *cfg, - srslte_softbuffer_rx_t softbuffers[SRSLTE_MAX_CODEWORDS], - int16_t *e_bits[SRSLTE_MAX_CODEWORDS], - uint8_t *data[SRSLTE_MAX_CODEWORDS]); + srslte_softbuffer_rx_t *softbuffer, + int16_t *e_bits, + uint8_t *data, + int codeword_idx); SRSLTE_API int srslte_ulsch_encode(srslte_sch_t *q, srslte_pusch_cfg_t *cfg, diff --git a/lib/src/phy/phch/pdsch.c b/lib/src/phy/phch/pdsch.c index 3d24cf175..5d85a3ec2 100644 --- a/lib/src/phy/phch/pdsch.c +++ b/lib/src/phy/phch/pdsch.c @@ -33,6 +33,8 @@ #include #include #include +#include +#include #include "prb_dl.h" #include "srslte/phy/phch/pdsch.h" @@ -488,7 +490,8 @@ int srslte_pdsch_decode_multi(srslte_pdsch_t *q, /* Set pointers for layermapping & precoding */ uint32_t i, n; cf_t *x[SRSLTE_MAX_LAYERS]; - + int ret = 0; + if (q != NULL && sf_symbols != NULL && data != NULL && @@ -564,26 +567,14 @@ int srslte_pdsch_decode_multi(srslte_pdsch_t *q, * The MAX-log-MAP algorithm used in turbo decoding is unsensitive to SNR estimation, * thus we don't need tot set it in the LLRs normalization */ - if (cfg->nbits.nof_re) { + if (cfg->nbits.nof_bits) { + INFO("Decoding CW 0 (%d bits)\n", cfg->nbits.nof_bits); srslte_demod_soft_demodulate_s(cfg->grant.mcs.mod, q->d, q->e, cfg->nbits.nof_re); - } - - if (cfg->nbits2.nof_re) { - srslte_demod_soft_demodulate_s(cfg->grant.mcs2.mod, q->d2, q->e2, cfg->nbits2.nof_re); - } - /* descramble */ - if (q->users[rnti] && q->users[rnti]->sequence_generated) { - if (cfg->nbits.nof_bits) { + if (q->users[rnti] && q->users[rnti]->sequence_generated) { srslte_scrambling_s_offset(&q->users[rnti]->seq[cfg->sf_idx], q->e, 0, cfg->nbits.nof_bits); - } - - if (cfg->nbits2.nof_bits) { - srslte_scrambling_s_offset(&q->users[rnti]->seq2[cfg->sf_idx], q->e2, 0, cfg->nbits2.nof_bits); - } - } else { - srslte_sequence_t seq; - if (cfg->nbits.nof_bits) { + } else { + srslte_sequence_t seq; if (srslte_sequence_pdsch(&seq, rnti, 0, 2 * cfg->sf_idx, q->cell.id, cfg->nbits.nof_bits)) { return SRSLTE_ERROR; } @@ -591,22 +582,34 @@ int srslte_pdsch_decode_multi(srslte_pdsch_t *q, srslte_sequence_free(&seq); } - if (cfg->nbits2.nof_bits) { + ret |= srslte_dlsch_decode2(&q->dl_sch, cfg, &softbuffers[0], q->e, data[0], 0); + } + + if (cfg->nbits2.nof_bits) { + INFO("Decoding CW 1 (%d bits)\n", cfg->nbits2.nof_bits); + srslte_demod_soft_demodulate_s(cfg->grant.mcs2.mod, q->d2, q->e2, cfg->nbits2.nof_re); + + if (q->users[rnti] && q->users[rnti]->sequence_generated) { + srslte_scrambling_s_offset(&q->users[rnti]->seq2[cfg->sf_idx], q->e2, 0, cfg->nbits2.nof_bits); + } else { + srslte_sequence_t seq; if (srslte_sequence_pdsch(&seq, rnti, 1, 2 * cfg->sf_idx, q->cell.id, cfg->nbits2.nof_bits)) { return SRSLTE_ERROR; } srslte_scrambling_s_offset(&seq, q->e2, 0, cfg->nbits2.nof_bits); srslte_sequence_free(&seq); } + + ret |= srslte_dlsch_decode2(&q->dl_sch, cfg, &softbuffers[1], q->e2, data[1], 1); } + if (SRSLTE_VERBOSE_ISDEBUG()) { DEBUG("SAVED FILE llr.dat: LLR estimates after demodulation and descrambling\n",0); srslte_vec_save_file("llr.dat", q->e, cfg->nbits.nof_bits*sizeof(int16_t)); } - return srslte_dlsch_decode_multi(&q->dl_sch, cfg, softbuffers, (int16_t *[SRSLTE_MAX_CODEWORDS]) {q->e, q->e2}, - data); + return ret; } else { return SRSLTE_ERROR_INVALID_INPUTS; diff --git a/lib/src/phy/phch/sch.c b/lib/src/phy/phch/sch.c index f0515227e..1caacacc9 100644 --- a/lib/src/phy/phch/sch.c +++ b/lib/src/phy/phch/sch.c @@ -524,29 +524,28 @@ int srslte_dlsch_decode(srslte_sch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbuf } -int srslte_dlsch_decode_multi(srslte_sch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbuffer_rx_t softbuffers[SRSLTE_MAX_CODEWORDS], - int16_t *e_bits[SRSLTE_MAX_CODEWORDS], uint8_t *data[SRSLTE_MAX_CODEWORDS]) +int srslte_dlsch_decode2(srslte_sch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffer, + int16_t *e_bits, uint8_t *data, int codeword_idx) { - int ret = SRSLTE_SUCCESS; uint32_t Nl = 1; if (cfg->nof_layers != cfg->grant.nof_tb) { Nl = 2; } - if (cfg->nbits.nof_bits) { - ret |= decode_tb(q, &softbuffers[0], &cfg->cb_segm, + if (codeword_idx == 0) { + return decode_tb(q, softbuffer, &cfg->cb_segm, cfg->grant.Qm*Nl, cfg->rv, cfg->nbits.nof_bits, - e_bits[0], data[0]); + e_bits, data); } - if (cfg->nbits2.nof_bits) { - ret |= decode_tb(q, &softbuffers[1], &cfg->cb_segm2, + if (codeword_idx == 1) { + return decode_tb(q, softbuffer, &cfg->cb_segm2, cfg->grant.Qm2*Nl, cfg->rv2, cfg->nbits2.nof_bits, - e_bits[1], data[1]); + e_bits, data); } - return ret; + return SRSLTE_ERROR; } /** From 6a45147f4598b6d2b37a2a196d40c03a27c92cd0 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Wed, 26 Jul 2017 11:31:02 +0200 Subject: [PATCH 04/60] Added different data sources and sinks --- lib/examples/pdsch_enodeb.c | 48 ++++++++++++++++++++++++++++--------- lib/examples/pdsch_ue.c | 22 ++++++++++++----- 2 files changed, 53 insertions(+), 17 deletions(-) diff --git a/lib/examples/pdsch_enodeb.c b/lib/examples/pdsch_enodeb.c index 01e06c4c3..b1304958c 100644 --- a/lib/examples/pdsch_enodeb.c +++ b/lib/examples/pdsch_enodeb.c @@ -99,6 +99,9 @@ srslte_netsink_t net_sink; int prbset_num = 1, last_prbset_num = 1; int prbset_orig = 0; +#define DATA_BUFF_SZ 1024*1024 +uint8_t *data[2], data2[DATA_BUFF_SZ]; +uint8_t data_tmp[DATA_BUFF_SZ]; void usage(char *prog) { printf("Usage: %s [agmfoncvpuM]\n", prog); @@ -204,6 +207,16 @@ void base_init() { exit(-1); } + /* Allocate memory */ + for(i = 0; i < nof_tb; i++) { + data[i] = srslte_vec_malloc(sizeof(uint8_t) * SOFTBUFFER_SIZE); + if (!data[i]) { + perror("malloc"); + exit(-1); + } + bzero(data[i], sizeof(uint8_t) * SOFTBUFFER_SIZE); + } + /* init memory */ for (i = 0; i < cell.nof_ports; i++) { sf_buffer[i] = srslte_vec_malloc(sizeof(cf_t) * sf_n_re); @@ -322,6 +335,12 @@ void base_free() { srslte_ofdm_tx_free(&ifft); + for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { + if (data[i]) { + free(data[i]); + } + } + for (i = 0; i < SRSLTE_MAX_PORTS; i++) { if (sf_buffer[i]) { free(sf_buffer[i]); @@ -468,10 +487,6 @@ int update_control() { } } -#define DATA_BUFF_SZ 1024*128 -uint8_t data[8*DATA_BUFF_SZ], data2[DATA_BUFF_SZ]; -uint8_t data_tmp[DATA_BUFF_SZ]; - /** Function run in a separate thread to receive UDP data */ void *net_thread_fnc(void *arg) { int n; @@ -480,14 +495,16 @@ void *net_thread_fnc(void *arg) { do { n = srslte_netsource_read(&net_source, &data2[rpm], DATA_BUFF_SZ-rpm); if (n > 0) { - int nbytes = 1+(pdsch_cfg.grant.mcs.tbs-1)/8; + // FIXME: I assume that both transport blocks have same size in case of 2 tb are active + int nbytes = 1 + (pdsch_cfg.grant.mcs.tbs + pdsch_cfg.grant.mcs2.tbs - 1) / 8; rpm += n; INFO("received %d bytes. rpm=%d/%d\n",n,rpm,nbytes); wpm = 0; while (rpm >= nbytes) { // wait for packet to be transmitted sem_wait(&net_sem); - memcpy(data, &data2[wpm], nbytes); + memcpy(data[0], &data2[wpm], nbytes / (size_t) 2); + memcpy(data[1], &data2[wpm], nbytes / (size_t) 2); INFO("Sent %d/%d bytes ready\n", nbytes, rpm); rpm -= nbytes; wpm += nbytes; @@ -663,8 +680,11 @@ int main(int argc, char **argv) { } } else { INFO("SF: %d, Generating %d random bits\n", sf_idx, pdsch_cfg.grant.mcs.tbs); - for (i=0;i 0 && net_packet_ready) { if (null_file_sink) { - srslte_bit_pack_vector(data, data_tmp, pdsch_cfg.grant.mcs.tbs); + srslte_bit_pack_vector(data[0], data_tmp, pdsch_cfg.grant.mcs.tbs); if (srslte_netsink_write(&net_sink, data_tmp, 1+(pdsch_cfg.grant.mcs.tbs-1)/8) < 0) { fprintf(stderr, "Error sending data through UDP socket\n"); - } + } + if (nof_tb > 1) { + srslte_bit_pack_vector(data[1], data_tmp, pdsch_cfg.grant.mcs2.tbs); + if (srslte_netsink_write(&net_sink, data_tmp, 1 + (pdsch_cfg.grant.mcs2.tbs - 1) / 8) < 0) { + fprintf(stderr, "Error sending data through UDP socket\n"); + } + } } net_packet_ready = false; sem_post(&net_sem); diff --git a/lib/examples/pdsch_ue.c b/lib/examples/pdsch_ue.c index bab9d7219..80f960508 100644 --- a/lib/examples/pdsch_ue.c +++ b/lib/examples/pdsch_ue.c @@ -36,6 +36,9 @@ #include #include #include +#include +#include +#include #include "srslte/srslte.h" @@ -508,7 +511,7 @@ int main(int argc, char **argv) { // Variables for measurements uint32_t nframes=0; - float rsrp0=0.0, rsrp1=0.0, rsrq=0.0, noise=0.0; + float rsrp0=0.0, rsrp1=0.0, rsrq=0.0, noise=0.0, enodebrate = 0.0, uerate = 0.0; bool decode_pdsch = false; #ifndef DISABLE_RF @@ -584,7 +587,9 @@ int main(int argc, char **argv) { /* Send data if socket active */ if (prog_args.net_port > 0) { - srslte_netsink_write(&net_sink, data, 1+(n-1)/8); + // FIXME: UDP Data transmission does not work + srslte_netsink_write(&net_sink, data[0], 1 + (ue_dl.pdsch_cfg.grant.mcs.tbs - 1) / 8); + srslte_netsink_write(&net_sink, data[1], 1 + (ue_dl.pdsch_cfg.grant.mcs2.tbs - 1) / 8); } #ifdef PRINT_CHANGE_SCHEDULIGN @@ -609,6 +614,8 @@ int main(int argc, char **argv) { rsrp0 = SRSLTE_VEC_EMA(srslte_chest_dl_get_rsrp_port(&ue_dl.chest, 0), rsrp0, 0.05); rsrp1 = SRSLTE_VEC_EMA(srslte_chest_dl_get_rsrp_port(&ue_dl.chest, 1), rsrp1, 0.05); noise = SRSLTE_VEC_EMA(srslte_chest_dl_get_noise_estimate(&ue_dl.chest), noise, 0.05); + enodebrate = SRSLTE_VEC_EMA((ue_dl.pdsch_cfg.grant.mcs.tbs + ue_dl.pdsch_cfg.grant.mcs2.tbs)/1000.0, enodebrate, 0.05); + uerate = SRSLTE_VEC_EMA((n>0)?(ue_dl.pdsch_cfg.grant.mcs.tbs + ue_dl.pdsch_cfg.grant.mcs2.tbs)/1000.0:0.0, uerate, 0.01); nframes++; if (isnan(rsrq)) { rsrq = 0; @@ -640,14 +647,17 @@ int main(int argc, char **argv) { 100 * (1 - (float) ue_dl.nof_detected / nof_trials), (float) 100 * ue_dl.pkt_errors / ue_dl.pkts_total); } else { - printf("CFO: %+6.2f kHz, " - "SNR port 0: %4.1f dB, " - "SNR port 1: %4.1f dB, " - "PDCCH-Miss: %5.2f%%, PDSCH-BLER: %5.2f%%\r", + printf("CFO: %+5.2f kHz, " + "SNR: %+5.1f dB | %+5.1f dB, " + "Rb: %6.2f / %6.2f Mbps, " + "PDCCH-Miss: %5.2f%%, " + "PDSCH-BLER: %5.2f%%\r", srslte_ue_sync_get_cfo(&ue_sync) / 1000, 10 * log10(rsrp0 / noise), 10 * log10(rsrp1 / noise), + uerate, + enodebrate, 100 * (1 - (float) ue_dl.nof_detected / nof_trials), (float) 100 * ue_dl.pkt_errors / ue_dl.pkts_total); } From 1d00e1acaa2168888f3ae250f3c925523b82590f Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Thu, 3 Aug 2017 13:56:57 +0200 Subject: [PATCH 05/60] Merge with next_with_matlab --- lib/examples/pdsch_enodeb.c | 36 +- lib/examples/pdsch_ue.c | 21 +- lib/include/srslte/phy/common/phy_common.h | 2 + lib/include/srslte/phy/mimo/precoding.h | 13 +- lib/include/srslte/phy/phch/pdsch.h | 4 +- lib/include/srslte/phy/phch/pdsch_cfg.h | 1 + lib/include/srslte/phy/phch/ra.h | 7 + lib/include/srslte/phy/rf/rf.h | 5 + lib/include/srslte/phy/ue/ue_dl.h | 4 +- lib/include/srslte/phy/utils/algebra.h | 70 ++ lib/src/phy/common/phy_common.c | 2 +- lib/src/phy/mimo/precoding.c | 710 +++++++++++++++++++-- lib/src/phy/mimo/test/CMakeLists.txt | 11 +- lib/src/phy/mimo/test/precoder_test.c | 19 +- lib/src/phy/phch/pdsch.c | 139 +++- lib/src/phy/phch/test/CMakeLists.txt | 95 ++- lib/src/phy/phch/test/pdsch_test.c | 92 +-- lib/src/phy/phch/test/pdsch_test_mex.c | 19 +- lib/src/phy/ue/ue_dl.c | 78 ++- lib/src/phy/utils/algebra.c | 72 +++ 20 files changed, 1240 insertions(+), 160 deletions(-) create mode 100644 lib/include/srslte/phy/utils/algebra.h create mode 100644 lib/src/phy/utils/algebra.c diff --git a/lib/examples/pdsch_enodeb.c b/lib/examples/pdsch_enodeb.c index b1304958c..1275360a4 100644 --- a/lib/examples/pdsch_enodeb.c +++ b/lib/examples/pdsch_enodeb.c @@ -70,6 +70,8 @@ uint32_t mcs_idx = 1, last_mcs_idx = 1; int nof_frames = -1; char mimo_type_str[32] = "single"; uint32_t nof_tb = 1; +uint32_t multiplex_pmi = 0; +uint32_t multiplex_nof_layers = 1; char *rf_args = ""; float rf_amp = 0.8, rf_gain = 70.0, rf_freq = 2400000000; @@ -104,7 +106,7 @@ uint8_t *data[2], data2[DATA_BUFF_SZ]; uint8_t data_tmp[DATA_BUFF_SZ]; void usage(char *prog) { - printf("Usage: %s [agmfoncvpuM]\n", prog); + printf("Usage: %s [agmfoncvpuxb]\n", prog); #ifndef DISABLE_RF printf("\t-a RF args [Default %s]\n", rf_args); printf("\t-l RF amplitude [Default %.2f]\n", rf_amp); @@ -118,14 +120,18 @@ void usage(char *prog) { printf("\t-n number of frames [Default %d]\n", nof_frames); printf("\t-c cell id [Default %d]\n", cell.id); printf("\t-p nof_prb [Default %d]\n", cell.nof_prb); - printf("\t-M Transmission mode[single|diversity|cdd] [Default %s]\n", mimo_type_str); + printf("\t-x Transmission mode[single|diversity|cdd|multiplex] [Default %s]\n", mimo_type_str); + printf("\t-b Precoding Matrix Index (multiplex mode only)* [Default %d]\n", multiplex_pmi); + printf("\t-w Number of codewords/layers (multiplex mode only)* [Default %d]\n", multiplex_nof_layers); printf("\t-u listen TCP port for input data (-1 is random) [Default %d]\n", net_port); printf("\t-v [set srslte_verbose to debug, default none]\n"); + printf("\n"); + printf("\t*: See 3GPP 36.212 Table 5.3.3.1.5-4 for more information\n"); } void parse_args(int argc, char **argv) { int opt; - while ((opt = getopt(argc, argv, "aglfmoncpvutM")) != -1) { + while ((opt = getopt(argc, argv, "aglfmoncpvutxbw")) != -1) { switch (opt) { case 'a': rf_args = argv[optind]; @@ -157,9 +163,15 @@ void parse_args(int argc, char **argv) { case 'c': cell.id = atoi(argv[optind]); break; - case 'M': + case 'x': strncpy(mimo_type_str, argv[optind], 32); break; + case 'b': + multiplex_pmi = (uint32_t) atoi(argv[optind]); + break; + case 'w': + multiplex_nof_layers = (uint32_t) atoi(argv[optind]); + break; case 'v': srslte_verbose++; break; @@ -202,6 +214,11 @@ void base_init() { pdsch_cfg.nof_layers = 2; nof_tb = 2; break; + case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX: + cell.nof_ports = 2; + pdsch_cfg.nof_layers = multiplex_nof_layers; + nof_tb = multiplex_nof_layers; + break; default: ERROR("Transmission mode not implemented."); exit(-1); @@ -695,7 +712,7 @@ int main(int argc, char **argv) { } if (send_data) { - srslte_dci_format_t dci_format = SRSLTE_DCI_FORMAT1; + srslte_dci_format_t dci_format; switch(pdsch_cfg.mimo_type) { case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA: dci_format = SRSLTE_DCI_FORMAT1; @@ -705,6 +722,13 @@ int main(int argc, char **argv) { dci_format = SRSLTE_DCI_FORMAT2A; break; case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX: + dci_format = SRSLTE_DCI_FORMAT2; + if (multiplex_nof_layers == 1) { + ra_dl.pinfo = (uint8_t) (multiplex_pmi + 1); + } else { + ra_dl.pinfo = (uint8_t) multiplex_pmi; + } + break; default: fprintf(stderr, "Wrong MIMO configuration\n"); exit(SRSLTE_ERROR); @@ -720,7 +744,7 @@ int main(int argc, char **argv) { /* Configure pdsch_cfg parameters */ srslte_ra_dl_grant_t grant; srslte_ra_dl_dci_to_grant(&ra_dl, cell.nof_prb, UE_CRNTI, &grant); - if (srslte_pdsch_cfg_multi(&pdsch_cfg, cell, &grant, cfi, sf_idx, 0, 0)) { + if (srslte_pdsch_cfg_multi(&pdsch_cfg, cell, &grant, cfi, sf_idx, 0, 0, pdsch_cfg.mimo_type, multiplex_pmi)) { fprintf(stderr, "Error configuring PDSCH\n"); exit(-1); } diff --git a/lib/examples/pdsch_ue.c b/lib/examples/pdsch_ue.c index 80f960508..1c6059d9f 100644 --- a/lib/examples/pdsch_ue.c +++ b/lib/examples/pdsch_ue.c @@ -511,7 +511,8 @@ int main(int argc, char **argv) { // Variables for measurements uint32_t nframes=0; - float rsrp0=0.0, rsrp1=0.0, rsrq=0.0, noise=0.0, enodebrate = 0.0, uerate = 0.0; + uint32_t ri = 0, pmi = 0; + float rsrp0=0.0, rsrp1=0.0, rsrq=0.0, noise=0.0, enodebrate = 0.0, uerate = 0.0, sinr = 0.0; bool decode_pdsch = false; #ifndef DISABLE_RF @@ -616,6 +617,16 @@ int main(int argc, char **argv) { noise = SRSLTE_VEC_EMA(srslte_chest_dl_get_noise_estimate(&ue_dl.chest), noise, 0.05); enodebrate = SRSLTE_VEC_EMA((ue_dl.pdsch_cfg.grant.mcs.tbs + ue_dl.pdsch_cfg.grant.mcs2.tbs)/1000.0, enodebrate, 0.05); uerate = SRSLTE_VEC_EMA((n>0)?(ue_dl.pdsch_cfg.grant.mcs.tbs + ue_dl.pdsch_cfg.grant.mcs2.tbs)/1000.0:0.0, uerate, 0.01); + + if (ue_dl.cell.nof_ports == 2 && ue_dl.pdsch.nof_rx_antennas == 2) { + float _sinr; + srslte_ue_dl_ri_pmi_select(&ue_dl, &ri, &pmi, &_sinr); + + if (!isinff(_sinr) && !isnanf(_sinr)) { + sinr = SRSLTE_VEC_EMA(_sinr, sinr, 0.05f); + } + } + nframes++; if (isnan(rsrq)) { rsrq = 0; @@ -651,7 +662,8 @@ int main(int argc, char **argv) { "SNR: %+5.1f dB | %+5.1f dB, " "Rb: %6.2f / %6.2f Mbps, " "PDCCH-Miss: %5.2f%%, " - "PDSCH-BLER: %5.2f%%\r", + "PDSCH-BLER: %5.2f%%, " + "SINR: %3.1f dB RI: %d PMI: %d \r", srslte_ue_sync_get_cfo(&ue_sync) / 1000, 10 * log10(rsrp0 / noise), @@ -659,7 +671,10 @@ int main(int argc, char **argv) { uerate, enodebrate, 100 * (1 - (float) ue_dl.nof_detected / nof_trials), - (float) 100 * ue_dl.pkt_errors / ue_dl.pkts_total); + (float) 100 * ue_dl.pkt_errors / ue_dl.pkts_total, + 10 * log10(sinr), + ri, + pmi); } } break; diff --git a/lib/include/srslte/phy/common/phy_common.h b/lib/include/srslte/phy/common/phy_common.h index b891b7330..e1c6f1b0d 100644 --- a/lib/include/srslte/phy/common/phy_common.h +++ b/lib/include/srslte/phy/common/phy_common.h @@ -55,6 +55,8 @@ #define SRSLTE_MAX_CODEBLOCKS 32 +#define SRSLTE_MAX_CODEBOOKS 4 + #define SRSLTE_LTE_CRC24A 0x1864CFB #define SRSLTE_LTE_CRC24B 0X1800063 #define SRSLTE_LTE_CRC16 0x11021 diff --git a/lib/include/srslte/phy/mimo/precoding.h b/lib/include/srslte/phy/mimo/precoding.h index 62fad08ef..222c085b6 100644 --- a/lib/include/srslte/phy/mimo/precoding.h +++ b/lib/include/srslte/phy/mimo/precoding.h @@ -65,8 +65,9 @@ SRSLTE_API int srslte_precoding_cdd(cf_t *x[SRSLTE_MAX_LAYERS], SRSLTE_API int srslte_precoding_type(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], int nof_layers, - int nof_ports, - int nof_symbols, + int nof_ports, + int codebook_idx, + int nof_symbols, srslte_mimo_type_t type); /* Estimates the vector "x" based on the received signal "y" and the channel estimates "h" @@ -112,8 +113,16 @@ SRSLTE_API int srslte_predecoding_type_multi(cf_t *y[SRSLTE_MAX_PORTS], int nof_rxant, int nof_ports, int nof_layers, + int codebook_idx, int nof_symbols, srslte_mimo_type_t type, float noise_estimate); +int srslte_precoding_pmi_select (cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], + uint32_t nof_symbols, + float noise_estimate, + int nof_layers, + uint32_t *pmi, + float sinr[SRSLTE_MAX_CODEBOOKS]); + #endif /* PRECODING_H_ */ diff --git a/lib/include/srslte/phy/phch/pdsch.h b/lib/include/srslte/phy/phch/pdsch.h index 7bdaaef9c..fc250a7d5 100644 --- a/lib/include/srslte/phy/phch/pdsch.h +++ b/lib/include/srslte/phy/phch/pdsch.h @@ -115,7 +115,9 @@ SRSLTE_API int srslte_pdsch_cfg_multi(srslte_pdsch_cfg_t *cfg, uint32_t cfi, uint32_t sf_idx, uint32_t rvidx, - uint32_t rvidx2); + uint32_t rvidx2, + srslte_mimo_type_t mimo_type, + uint32_t pmi); SRSLTE_API int srslte_pdsch_encode(srslte_pdsch_t *q, srslte_pdsch_cfg_t *cfg, diff --git a/lib/include/srslte/phy/phch/pdsch_cfg.h b/lib/include/srslte/phy/phch/pdsch_cfg.h index bec326338..9664d826d 100644 --- a/lib/include/srslte/phy/phch/pdsch_cfg.h +++ b/lib/include/srslte/phy/phch/pdsch_cfg.h @@ -49,6 +49,7 @@ typedef struct SRSLTE_API { uint32_t rv2; uint32_t sf_idx; uint32_t nof_layers; + uint32_t codebook_idx; srslte_mimo_type_t mimo_type; } srslte_pdsch_cfg_t; diff --git a/lib/include/srslte/phy/phch/ra.h b/lib/include/srslte/phy/phch/ra.h index 3c7c3d93c..5fab0f10b 100644 --- a/lib/include/srslte/phy/phch/ra.h +++ b/lib/include/srslte/phy/phch/ra.h @@ -216,6 +216,13 @@ SRSLTE_API void srslte_ra_dl_grant_to_nbits_multi(srslte_ra_dl_grant_t *grant, srslte_ra_nbits_t *nbits, srslte_ra_nbits_t *nbits2); +SRSLTE_API void srslte_ra_dl_grant_to_nbits_multi(srslte_ra_dl_grant_t *grant, + uint32_t cfi, + srslte_cell_t cell, + uint32_t sf_idx, + srslte_ra_nbits_t *nbits, + srslte_ra_nbits_t *nbits2); + SRSLTE_API uint32_t srslte_ra_dl_approx_nof_re(srslte_cell_t cell, uint32_t nof_prb, uint32_t nof_ctrl_symbols); diff --git a/lib/include/srslte/phy/rf/rf.h b/lib/include/srslte/phy/rf/rf.h index d37750749..bc74d17e7 100644 --- a/lib/include/srslte/phy/rf/rf.h +++ b/lib/include/srslte/phy/rf/rf.h @@ -80,6 +80,11 @@ SRSLTE_API int srslte_rf_open_multi2(srslte_rf_t *h, uint32_t nof_tx_antennas, uint32_t nof_rx_antennas); +SRSLTE_API int srslte_rf_open_multi2(srslte_rf_t *h, + char *args, + uint32_t nof_tx_antennas, + uint32_t nof_rx_antennas); + SRSLTE_API int srslte_rf_open_devname(srslte_rf_t *h, char *devname, char *args); diff --git a/lib/include/srslte/phy/ue/ue_dl.h b/lib/include/srslte/phy/ue/ue_dl.h index 408ba0c65..0c77ba911 100644 --- a/lib/include/srslte/phy/ue/ue_dl.h +++ b/lib/include/srslte/phy/ue/ue_dl.h @@ -147,7 +147,9 @@ SRSLTE_API int srslte_ue_dl_cfg_grant_multi(srslte_ue_dl_t *q, uint32_t cfi, uint32_t sf_idx, uint32_t rvidx, - uint32_t rvidx2); + uint32_t rvidx2, + srslte_mimo_type_t mimo_type, + uint32_t pinfo); SRSLTE_API int srslte_ue_dl_find_ul_dci(srslte_ue_dl_t *q, uint32_t cfi, diff --git a/lib/include/srslte/phy/utils/algebra.h b/lib/include/srslte/phy/utils/algebra.h new file mode 100644 index 000000000..41d5e0025 --- /dev/null +++ b/lib/include/srslte/phy/utils/algebra.h @@ -0,0 +1,70 @@ +/** + * + * \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/. + * + */ + +#ifndef SRSLTE_ALGEBRA_H +#define SRSLTE_ALGEBRA_H + +#include "srslte/config.h" + +#ifdef LV_HAVE_SSE + +#define _MM_MULJ_PS(X) _mm_permute_ps(_MM_CONJ_PS(X), 0b10110001) +#define _MM_CONJ_PS(X) (_mm_xor_ps(X, (__m128){0.0f, -0.0f, 0.0f, -0.0f})) +#define _MM_PROD_PS(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))) + +SRSLTE_API void srslte_algebra_2x2_zf_sse(__m128 y0, + __m128 y1, + __m128 h00, + __m128 h01, + __m128 h10, + __m128 h11, + __m128 *x0, + __m128 *x1, + float norm); + +#endif /* LV_HAVE_SSE */ + +#ifdef LV_HAVE_AVX + +#define _MM256_MULJ_PS(X) _mm256_permute_ps(_MM256_CONJ_PS(X), 0b10110001) +#define _MM256_CONJ_PS(X) (_mm256_xor_ps(X, (__m256){0.0f, -0.0f, 0.0f, -0.0f, 0.0f, -0.0f, 0.0f, -0.0f})) +#define _MM256_PROD_PS(a, b) _mm256_addsub_ps(_mm256_mul_ps(a,_mm256_moveldup_ps(b)),\ + _mm256_mul_ps(_mm256_shuffle_ps(a,a,0xB1),_mm256_movehdup_ps(b))) + +SRSLTE_API void srslte_algebra_2x2_zf_avx(__m256 y0, + __m256 y1, + __m256 h00, + __m256 h01, + __m256 h10, + __m256 h11, + __m256 *x0, + __m256 *x1, + float norm); + +#endif /* LV_HAVE_AVX */ + +#endif //SRSLTE_ALGEBRA_H diff --git a/lib/src/phy/common/phy_common.c b/lib/src/phy/common/phy_common.c index 69e39b49a..7be57c63a 100644 --- a/lib/src/phy/common/phy_common.c +++ b/lib/src/phy/common/phy_common.c @@ -436,7 +436,7 @@ int srslte_str2mimotype(char *mimo_type_str, srslte_mimo_type_t *type) { *type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA; } else if (!strcmp(mimo_type_str, "diversity") || !strcmp(mimo_type_str, "TxDiversity")) { *type = SRSLTE_MIMO_TYPE_TX_DIVERSITY; - } else if (!strcmp(mimo_type_str, "multiplex")) { + } else if (!strcmp(mimo_type_str, "multiplex") || !strcmp(mimo_type_str, "SpatialMux")) { *type = SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX; } else if (!strcmp(mimo_type_str, "cdd") || !strcmp(mimo_type_str, "CDD")) { *type = SRSLTE_MIMO_TYPE_CDD; diff --git a/lib/src/phy/mimo/precoding.c b/lib/src/phy/mimo/precoding.c index f93c63479..ba950f196 100644 --- a/lib/src/phy/mimo/precoding.c +++ b/lib/src/phy/mimo/precoding.c @@ -33,6 +33,7 @@ #include "srslte/phy/common/phy_common.h" #include "srslte/phy/mimo/precoding.h" #include "srslte/phy/utils/vector.h" +#include "srslte/phy/utils/debug.h" #ifdef LV_HAVE_SSE #include @@ -43,6 +44,9 @@ int srslte_predecoding_diversity2_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_ #ifdef LV_HAVE_AVX #include +#include +#include + 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 @@ -527,7 +531,7 @@ int srslte_predecoding_type(cf_t *y_, cf_t *h_[SRSLTE_MAX_PORTS], cf_t *x[SRSLTE h[i][0] = h_[i]; } y[0] = y_; - return srslte_predecoding_type_multi(y, h, x, nof_rxant, nof_ports, nof_layers, nof_symbols, type, noise_estimate); + return srslte_predecoding_type_multi(y, h, x, nof_rxant, nof_ports, nof_layers, 0, nof_symbols, type, noise_estimate); } @@ -565,11 +569,46 @@ int srslte_precoding_mimo_2x2_gen(cf_t W[2][2], cf_t *y[SRSLTE_MAX_PORTS], cf_t return SRSLTE_SUCCESS; } +// SSE implementation of ZF 2x2 CCD equalizer +#ifdef LV_HAVE_AVX +int srslte_predecoding_ccd_2x2_zf_avx(cf_t *y[SRSLTE_MAX_PORTS], + cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], + cf_t *x[SRSLTE_MAX_LAYERS], + uint32_t nof_symbols) { + uint32_t i = 0; + for (i = 0; i < nof_symbols; i += 4) { + /* Load channel */ + __m256 h00i = _mm256_load_ps((float *) &h[0][0][i]); + __m256 h01i = _mm256_load_ps((float *) &h[0][1][i]); + __m256 h10i = _mm256_load_ps((float *) &h[1][0][i]); + __m256 h11i = _mm256_load_ps((float *) &h[1][1][i]); + /* Apply precoding */ + __m256 h00 = _mm256_add_ps(h00i, _mm256_xor_ps(h10i, + (__m256) {+0.0f, +0.0f, -0.0f, -0.0f, +0.0f, +0.0f, -0.0f, -0.0f})); + __m256 h10 = _mm256_add_ps(h01i, _mm256_xor_ps(h11i, + (__m256) {+0.0f, +0.0f, -0.0f, -0.0f, +0.0f, +0.0f, -0.0f, -0.0f})); + __m256 h01 = _mm256_add_ps(h00i, _mm256_xor_ps(h10i, + (__m256) {-0.0f, -0.0f, +0.0f, +0.0f, -0.0f, -0.0f, +0.0f, +0.0f})); + __m256 h11 = _mm256_add_ps(h01i, _mm256_xor_ps(h11i, + (__m256) {-0.0f, -0.0f, +0.0f, +0.0f, -0.0f, -0.0f, +0.0f, +0.0f})); + __m256 y0 = _mm256_load_ps((float *) &y[0][i]); + __m256 y1 = _mm256_load_ps((float *) &y[1][i]); + __m256 x0, x1; + + srslte_algebra_2x2_zf_avx(y0, y1, h00, h01, h10, h11, &x0, &x1, 2.0f); + + _mm256_store_ps((float *) &x[0][i], x0); + _mm256_store_ps((float *) &x[1][i], x1); + } + + return nof_symbols; +} +#endif /* LV_HAVE_AVX */ // SSE implementation of ZF 2x2 CCD equalizer #ifdef LV_HAVE_SSE @@ -580,9 +619,6 @@ int srslte_predecoding_ccd_2x2_zf_sse(cf_t *y[SRSLTE_MAX_PORTS], uint32_t nof_symbols) { uint32_t i = 0; - /* Conjugate mask */ - __m128 conj_mask = (__m128) {+0.0f, -0.0f, +0.0f, -0.0f}; - for (i = 0; i < nof_symbols; i += 2) { /* Load channel */ __m128 h00i = _mm_load_ps((float *) &h[0][0][i]); @@ -596,21 +632,12 @@ int srslte_predecoding_ccd_2x2_zf_sse(cf_t *y[SRSLTE_MAX_PORTS], __m128 h01 = _mm_add_ps(h00i, _mm_xor_ps(h10i, (__m128) {-0.0f, -0.0f, +0.0f, +0.0f})); __m128 h11 = _mm_add_ps(h01i, _mm_xor_ps(h11i, (__m128) {-0.0f, -0.0f, +0.0f, +0.0f})); - __m128 detmult1 = PROD(h00, h11); - __m128 detmult2 = PROD(h01, h10); - - __m128 det = _mm_sub_ps(detmult1, detmult2); - __m128 detconj = _mm_xor_ps(det, conj_mask); - __m128 detabs2 = PROD(det, detconj); - __m128 detabs2rec = _mm_rcp_ps(detabs2); - detabs2rec = _mm_shuffle_ps(detabs2rec, detabs2rec, _MM_SHUFFLE(2, 2, 0, 0)); - __m128 detrec = _mm_mul_ps(_mm_mul_ps(detconj, detabs2rec), (__m128) {2.0f, 2.0f, 2.0f, 2.0f}); - __m128 y0 = _mm_load_ps((float *) &y[0][i]); __m128 y1 = _mm_load_ps((float *) &y[1][i]); - __m128 x0 = PROD(_mm_sub_ps(PROD(h11, y0), PROD(h01, y1)), detrec); - __m128 x1 = PROD(_mm_sub_ps(PROD(h00, y1), PROD(h10, y0)), detrec); + __m128 x0, x1; + + srslte_algebra_2x2_zf_sse(y0, y1, h00, h01, h10, h11, &x0, &x1, 2.0f); _mm_store_ps((float *) &x[0][i], x0); _mm_store_ps((float *) &x[1][i], x1); @@ -659,11 +686,15 @@ int srslte_predecoding_ccd_zf(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORT { if (nof_ports == 2 && nof_rxant == 2) { if (nof_layers == 2) { +#ifdef LV_HAVE_AVX + return srslte_predecoding_ccd_2x2_zf_avx(y, h, x, nof_symbols); +#else #ifdef LV_HAVE_SSE return srslte_predecoding_ccd_2x2_zf_sse(y, h, x, nof_symbols); #else return srslte_predecoding_ccd_2x2_zf_gen(y, h, x, nof_symbols); -#endif +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX */ } else { fprintf(stderr, "Error predecoding CCD: Invalid number of layers %d\n", nof_layers); return -1; @@ -676,11 +707,535 @@ int srslte_predecoding_ccd_zf(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORT return SRSLTE_ERROR; } +/* PMI Select for 1 layer */ +int srslte_precoding_pmi_select_1l (cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], uint32_t nof_symbols, + float noise_estimate, uint32_t *pmi, + float sinr_list[SRSLTE_MAX_CODEBOOKS]) { + +#define SQRT1_2 ((float)M_SQRT1_2); + float max_sinr = 0.0; + uint32_t i, count; + + for (i = 0; i < 4; i++) { + sinr_list[i] = 0; + count = 0; + + for (uint32_t j = 0; j < nof_symbols; j += 100) { + /* 0. Load channel matrix */ + cf_t h00 = h[0][0][j]; + cf_t h01 = h[1][0][j]; + cf_t h10 = h[0][1][j]; + cf_t h11 = h[1][1][j]; + + /* 1. B = W'* H' */ + cf_t a0, a1; + switch(i) { + case 0: + a0 = conjf(h00) + conjf(h01); + a1 = conjf(h10) + conjf(h11); + break; + case 1: + a0 = conjf(h00) - conjf(h01); + a1 = conjf(h10) - conjf(h11); + break; + case 2: + a0 = conjf(h00) - _Complex_I * conjf(h01); + a1 = conjf(h10) - _Complex_I * conjf(h11); + break; + case 3: + a0 = conjf(h00) + _Complex_I * conjf(h01); + a1 = conjf(h10) + _Complex_I * conjf(h11); + break; + } + a0 *= SQRT1_2; + a1 *= SQRT1_2; + + /* 2. B = W' * H' * H = A * H */ + cf_t b0 = a0*h00 + a1*h10; + cf_t b1 = a0*h01 + a1*h11; + + /* 3. C = W' * H' * H * W' = B * W */ + cf_t c; + switch(i) { + case 0: + c = b0 + b1; + break; + case 1: + c = b0 - b1; + break; + case 2: + c = b0 + _Complex_I*b1; + break; + case 3: + c = b0 - _Complex_I*b1; + break; + default: + return SRSLTE_ERROR; + } + c *= SQRT1_2; + + /* Add for averaging */ + sinr_list[i] += crealf(c); + + count ++; + } + + /* Divide average by noise */ + sinr_list[i] /= noise_estimate*count; + + if (sinr_list[i] > max_sinr) { + max_sinr = sinr_list[i]; + *pmi = i; + } + } + + INFO("Precoder PMI Select for 1 layer SINR=[%.1fdB; %.1fdB; %.1fdB; %.1fdB] PMI=%d\n", 10*log10(sinr_list[0]), 10*log10(sinr_list[1]), + 10*log10(sinr_list[2]), 10*log10(sinr_list[3]), *pmi); + + return i; +} + +/* PMI Select for 2 layers */ +int srslte_precoding_pmi_select_2l (cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], uint32_t nof_symbols, + float noise_estimate, uint32_t *pmi, + float sinr_list[SRSLTE_MAX_CODEBOOKS]) { + + float max_sinr = 0.0; + uint32_t i, count; + + for (i = 0; i < 2; i++) { + sinr_list[i] = 0; + count = 0; + + for (uint32_t j = 0; j < nof_symbols; j += 100) { + /* 0. Load channel matrix */ + cf_t h00 = h[0][0][j]; + cf_t h01 = h[1][0][j]; + cf_t h10 = h[0][1][j]; + cf_t h11 = h[1][1][j]; + + /* 1. B = W'* H' */ + cf_t a00, a01, a10, a11; + switch(i) { + case 0: + a00 = conjf(h00) + conjf(h01); + a01 = conjf(h10) + conjf(h11); + a10 = conjf(h00) - conjf(h01); + a11 = conjf(h10) - conjf(h11); + break; + case 1: + a00 = conjf(h00) - _Complex_I*conjf(h01); + a01 = conjf(h10) - _Complex_I*conjf(h11); + a10 = conjf(h00) + _Complex_I*conjf(h01); + a11 = conjf(h10) + _Complex_I*conjf(h11); + break; + default: + return SRSLTE_ERROR; + } + a00 *= 0.5f; + a01 *= 0.5f; + a10 *= 0.5f; + a11 *= 0.5f; + + /* 2. B = W' * H' * H = A * H */ + cf_t b00 = a00*h00 + a01*h10; + cf_t b01 = a00*h01 + a01*h11; + cf_t b10 = a10*h00 + a11*h10; + cf_t b11 = a10*h01 + a11*h11; + + /* 3. C = W' * H' * H * W' = B * W */ + cf_t c00, c01, c10, c11; + switch(i) { + case 0: + c00 = b00 + b01; + c01 = b00 - b01; + c10 = b10 + b11; + c11 = b10 - b11; + break; + case 1: + c00 = b00 + _Complex_I*b01; + c01 = b00 - _Complex_I*b01; + c10 = b10 + _Complex_I*b11; + c11 = b10 - _Complex_I*b11; + break; + default: + return SRSLTE_ERROR; + } + c00 *= 0.5; + c01 *= 0.5; + c10 *= 0.5; + c11 *= 0.5; + + /* 4. C += noise * I */ + c00 += noise_estimate; + c11 += noise_estimate; + + /* 5. detC */ + cf_t detC = c00*c11 - c01*c10; + cf_t inv_detC = conjf(detC)/(crealf(detC)*crealf(detC) + cimagf(detC)*cimagf(detC)); + + cf_t den0 = noise_estimate*c00*inv_detC; + cf_t den1 = noise_estimate*c11*inv_detC; + + float gamma0 = crealf((conjf(den0)/(crealf(den0)*crealf(den0) + cimagf(den0)*cimagf(den0))) - 1); + float gamma1 = crealf((conjf(den1)/(crealf(den1)*crealf(den1) + cimagf(den1)*cimagf(den1))) - 1); + + /* Add for averaging */ + sinr_list[i] += (gamma0 + gamma1); + + count ++; + } + + /* Divide average by noise */ + sinr_list[i] /= (2*count); + + if (sinr_list[i] > max_sinr) { + max_sinr = sinr_list[i]; + *pmi = i; + } + } + + INFO("Precoder PMI Select for 2 layers SINR=[%.1fdB; %.1fdB] PMI=%d\n", 10*log10(sinr_list[0]), 10*log10(sinr_list[1]), *pmi); + + return i; +} + +int srslte_precoding_pmi_select (cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], uint32_t nof_symbols, + float noise_estimate, int nof_layers, uint32_t *pmi, + float sinr[SRSLTE_MAX_CODEBOOKS]) { + int ret; + + if (sinr == NULL || pmi == NULL) { + ERROR("Null pointer"); + ret = SRSLTE_ERROR_INVALID_INPUTS; + } else if (nof_layers == 1) { + ret = srslte_precoding_pmi_select_1l(h, nof_symbols, noise_estimate, pmi, sinr); + } else if (nof_layers == 2) { + ret = srslte_precoding_pmi_select_2l(h, nof_symbols, noise_estimate, pmi, sinr); + } else { + ERROR("Wrong number of layers"); + ret = SRSLTE_ERROR_INVALID_INPUTS; + } + + return ret; +} + +// Generic implementation of ZF 2x2 Spatial Multiplexity equalizer +int srslte_predecoding_multiplex_2x2_zf(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], + cf_t *x[SRSLTE_MAX_LAYERS], int codebook_idx, int nof_symbols) { + int i = 0; + float norm = 1.0; + + switch(codebook_idx) { + case 0: + norm = (float) M_SQRT2; + break; + case 1: + case 2: + norm = 2.0f; + break; + default: + fprintf(stderr, "Wrong codebook_idx=%d\n", codebook_idx); + return SRSLTE_ERROR; + } + +#ifdef LV_HAVE_AVX + for (/* i = 0*/; i < nof_symbols; i += 4) { + __m256 _h00 = _mm256_load_ps((float*)&(h[0][0][i])); + __m256 _h01 = _mm256_load_ps((float*)&(h[0][1][i])); + __m256 _h10 = _mm256_load_ps((float*)&(h[1][0][i])); + __m256 _h11 = _mm256_load_ps((float*)&(h[1][1][i])); + + __m256 h00, h01, h10, h11; + switch (codebook_idx) { + case 0: + h00 = _h00; + h01 = _h10; + h10 = _h01; + h11 = _h11; + break; + case 1: + h00 = _mm256_add_ps(_h00, _h10); + h01 = _mm256_sub_ps(_h00, _h10); + h10 = _mm256_add_ps(_h01, _h11); + h11 = _mm256_sub_ps(_h01, _h11); + break; + case 2: + h00 = _mm256_add_ps(_h00, _MM256_MULJ_PS(_h10)); + h01 = _mm256_sub_ps(_h00, _MM256_MULJ_PS(_h10)); + h10 = _mm256_add_ps(_h01, _MM256_MULJ_PS(_h11)); + h11 = _mm256_sub_ps(_h01, _MM256_MULJ_PS(_h11)); + break; + default: + fprintf(stderr, "Wrong codebook_idx=%d\n", codebook_idx); + return SRSLTE_ERROR; + } + + __m256 y0 = _mm256_load_ps((float *) &y[0][i]); + __m256 y1 = _mm256_load_ps((float *) &y[1][i]); + + __m256 x0, x1; + + srslte_algebra_2x2_zf_avx(y0, y1, h00, h01, h10, h11, &x0, &x1, norm); + + _mm256_store_ps((float *) &x[0][i], x0); + _mm256_store_ps((float *) &x[1][i], x1); + + } + if (i > nof_symbols) { + i -= 4; + } +#endif /* LV_HAVE_AVX */ + +#ifdef LV_HAVE_SSE + for (/* i = 0*/; i < nof_symbols; i += 2) { + __m128 _h00 = _mm_load_ps((float*)&(h[0][0][i])); + __m128 _h01 = _mm_load_ps((float*)&(h[0][1][i])); + __m128 _h10 = _mm_load_ps((float*)&(h[1][0][i])); + __m128 _h11 = _mm_load_ps((float*)&(h[1][1][i])); + + __m128 h00, h01, h10, h11; + switch (codebook_idx) { + case 0: + h00 = _h00; + h01 = _h10; + h10 = _h01; + h11 = _h11; + break; + case 1: + h00 = _mm_add_ps(_h00, _h10); + h01 = _mm_sub_ps(_h00, _h10); + h10 = _mm_add_ps(_h01, _h11); + h11 = _mm_sub_ps(_h01, _h11); + break; + case 2: + h00 = _mm_add_ps(_h00, _MM_MULJ_PS(_h10)); + h01 = _mm_sub_ps(_h00, _MM_MULJ_PS(_h10)); + h10 = _mm_add_ps(_h01, _MM_MULJ_PS(_h11)); + h11 = _mm_sub_ps(_h01, _MM_MULJ_PS(_h11)); + break; + default: + fprintf(stderr, "Wrong codebook_idx=%d\n", codebook_idx); + return SRSLTE_ERROR; + } + + __m128 y0 = _mm_load_ps((float *) &y[0][i]); + __m128 y1 = _mm_load_ps((float *) &y[1][i]); + + __m128 x0, x1; + + srslte_algebra_2x2_zf_sse(y0, y1, h00, h01, h10, h11, &x0, &x1, norm); + + _mm_store_ps((float *) &x[0][i], x0); + _mm_store_ps((float *) &x[1][i], x1); + + } + if (i > nof_symbols) { + i -= 2; + } +#endif /* LV_HAVE_SSE */ + + for (/*int i = 0*/; i < nof_symbols; i++) { + cf_t h00, h01, h10, h11, det; + + switch(codebook_idx) { + case 0: + h00 = h[0][0][i]; + h01 = h[1][0][i]; + h10 = h[0][1][i]; + h11 = h[1][1][i]; + break; + case 1: + h00 = h[0][0][i] + h[1][0][i]; + h01 = h[0][0][i] - h[1][0][i]; + h10 = h[0][1][i] + h[1][1][i]; + h11 = h[0][1][i] - h[1][1][i]; + break; + case 2: + h00 = h[0][0][i] + _Complex_I*h[1][0][i]; + h01 = h[0][0][i] - _Complex_I*h[1][0][i]; + h10 = h[0][1][i] + _Complex_I*h[1][1][i]; + h11 = h[0][1][i] - _Complex_I*h[1][1][i]; + break; + default: + fprintf(stderr, "Wrong codebook_idx=%d\n", codebook_idx); + return SRSLTE_ERROR; + } + + det = (h00 * h11 - h01 * h10); + det = conjf(det) * (norm / (crealf(det) * crealf(det) + cimagf(det) * cimagf(det))); + + x[0][i] = (+h11 * y[0][i] - h01 * y[1][i]) * det; + x[1][i] = (-h10 * y[0][i] + h00 * y[1][i]) * det; + } + return SRSLTE_SUCCESS; +} + +// Generic implementation of MRC 2x1 (two antennas into one layer) Spatial Multiplexing equalizer +int srslte_predecoding_multiplex_2x1_mrc(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], + cf_t *x[SRSLTE_MAX_LAYERS], int codebook_idx, int nof_symbols) { + int i = 0; + +#ifdef LV_HAVE_AVX + for (/* i = 0*/; i < nof_symbols; i += 4) { + __m256 _h00 = _mm256_load_ps((float*)&(h[0][0][i])); + __m256 _h01 = _mm256_load_ps((float*)&(h[0][1][i])); + __m256 _h10 = _mm256_load_ps((float*)&(h[1][0][i])); + __m256 _h11 = _mm256_load_ps((float*)&(h[1][1][i])); + + __m256 h0, h1; + switch (codebook_idx) { + case 0: + h0 = _mm256_add_ps(_h00, _h10); + h1 = _mm256_add_ps(_h01, _h11); + break; + case 1: + h0 = _mm256_sub_ps(_h00, _h10); + h1 = _mm256_sub_ps(_h01, _h11); + break; + case 2: + h0 = _mm256_add_ps(_h00, _mm256_permute_ps(_MM256_CONJ_PS(_h10), 0b10110001)); + h1 = _mm256_add_ps(_h01, _mm256_permute_ps(_MM256_CONJ_PS(_h11), 0b10110001)); + break; + case 3: + h0 = _mm256_sub_ps(_h00, _mm256_permute_ps(_MM256_CONJ_PS(_h10), 0b10110001)); + h1 = _mm256_sub_ps(_h01, _mm256_permute_ps(_MM256_CONJ_PS(_h11), 0b10110001)); + break; + default: + fprintf(stderr, "Wrong codebook_idx=%d\n", codebook_idx); + return SRSLTE_ERROR; + } + + __m256 h0_2 = _mm256_mul_ps(h0, h0); + __m256 h1_2 = _mm256_mul_ps(h1, h1); + __m256 hh0 = _mm256_add_ps(_mm256_movehdup_ps(h0_2), _mm256_moveldup_ps(h0_2)); + __m256 hh1 = _mm256_add_ps(_mm256_movehdup_ps(h1_2), _mm256_moveldup_ps(h1_2)); + __m256 hh = _mm256_add_ps(hh0, hh1); + __m256 hhrec = _mm256_rcp_ps(hh); + + hhrec = _mm256_mul_ps(hhrec, (__m256){(float) M_SQRT2, (float) M_SQRT2, (float) M_SQRT2, (float) M_SQRT2, + (float) M_SQRT2,(float) M_SQRT2, (float) M_SQRT2, (float) M_SQRT2}); + __m256 y0 = _mm256_load_ps((float*)&y[0][i]); + __m256 y1 = _mm256_load_ps((float*)&y[1][i]); + + __m256 x0 = _mm256_add_ps(_MM256_PROD_PS(_MM256_CONJ_PS(h0), y0), _MM256_PROD_PS(_MM256_CONJ_PS(h1), y1)); + x0 = _mm256_mul_ps(hhrec, x0); + + _mm256_store_ps((float*)&x[0][i], x0); + + } + if (i > nof_symbols) { + i -= 4; + } +#endif /* LV_HAVE_AVX */ + +#ifdef LV_HAVE_SSE + for (/* i = 0*/; i < nof_symbols; i += 2) { + __m128 _h00 = _mm_load_ps((float*)&(h[0][0][i])); + __m128 _h01 = _mm_load_ps((float*)&(h[0][1][i])); + __m128 _h10 = _mm_load_ps((float*)&(h[1][0][i])); + __m128 _h11 = _mm_load_ps((float*)&(h[1][1][i])); + + __m128 h0, h1; + switch (codebook_idx) { + case 0: + h0 = _mm_add_ps(_h00, _h10); + h1 = _mm_add_ps(_h01, _h11); + break; + case 1: + h0 = _mm_sub_ps(_h00, _h10); + h1 = _mm_sub_ps(_h01, _h11); + break; + case 2: + h0 = _mm_add_ps(_h00, _mm_permute_ps(_MM_CONJ_PS(_h10), 0b10110001)); + h1 = _mm_add_ps(_h01, _mm_permute_ps(_MM_CONJ_PS(_h11), 0b10110001)); + break; + case 3: + h0 = _mm_sub_ps(_h00, _mm_permute_ps(_MM_CONJ_PS(_h10), 0b10110001)); + h1 = _mm_sub_ps(_h01, _mm_permute_ps(_MM_CONJ_PS(_h11), 0b10110001)); + break; + default: + fprintf(stderr, "Wrong codebook_idx=%d\n", codebook_idx); + return SRSLTE_ERROR; + } + + __m128 h0_2 = _mm_mul_ps(h0, h0); + __m128 h1_2 = _mm_mul_ps(h1, h1); + __m128 hh0 = _mm_add_ps(_mm_movehdup_ps(h0_2), _mm_moveldup_ps(h0_2)); + __m128 hh1 = _mm_add_ps(_mm_movehdup_ps(h1_2), _mm_moveldup_ps(h1_2)); + __m128 hh = _mm_add_ps(hh0, hh1); + __m128 hhrec = _mm_rcp_ps(hh); + + hhrec = _mm_mul_ps(hhrec, (__m128){(float) M_SQRT2, (float) M_SQRT2, (float) M_SQRT2, (float) M_SQRT2}); + __m128 y0 = _mm_load_ps((float*)&y[0][i]); + __m128 y1 = _mm_load_ps((float*)&y[1][i]); + + __m128 x0 = _mm_add_ps(_MM_PROD_PS(_MM_CONJ_PS(h0), y0), _MM_PROD_PS(_MM_CONJ_PS(h1), y1)); + x0 = _mm_mul_ps(hhrec, x0); + + _mm_store_ps((float*)&x[0][i], x0); + + } + if (i > nof_symbols) { + i -= 2; + } +#endif /* LV_HAVE_SSE */ + + for (/*i = 0*/; i < nof_symbols; i += 1) { + cf_t h0, h1; + float hh; + + switch(codebook_idx) { + case 0: + h0 = h[0][0][i] + h[1][0][i]; + h1 = h[0][1][i] + h[1][1][i]; + break; + case 1: + h0 = h[0][0][i] - h[1][0][i]; + h1 = h[0][1][i] - h[1][1][i]; + break; + case 2: + h0 = h[0][0][i] + _Complex_I * h[1][0][i]; + h1 = h[0][1][i] + _Complex_I * h[1][1][i]; + break; + case 3: + h0 = h[0][0][i] - _Complex_I * h[1][0][i]; + h1 = h[0][1][i] - _Complex_I * h[1][1][i]; + break; + default: + fprintf(stderr, "Wrong codebook_idx=%d\n", codebook_idx); + return SRSLTE_ERROR; + } + + hh = (float) M_SQRT2/(crealf(h0)*crealf(h0) + cimagf(h0)*cimagf(h0) + crealf(h1)*crealf(h1) + cimagf(h1)*cimagf(h1)); + + x[0][i] = (conjf(h0) * y[0][i] + conjf(h1) * y[1][i]) * hh; + } + return SRSLTE_SUCCESS; +} + +int srslte_predecoding_multiplex_zf(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_layers, int codebook_idx, int nof_symbols) +{ + if (nof_ports == 2 && nof_rxant == 2) { + if (nof_layers == 2) { + return srslte_predecoding_multiplex_2x2_zf(y, h, x, codebook_idx, nof_symbols); + } else { + return srslte_predecoding_multiplex_2x1_mrc(y, h, x, codebook_idx, nof_symbols); + } + } else if (nof_ports == 4) { + fprintf(stderr, "Error predecoding CCD: Only 2 ports supported\n"); + } else { + fprintf(stderr, "Error predecoding CCD: Invalid combination of ports %d and rx antennax %d\n", nof_ports, nof_rxant); + } + return SRSLTE_ERROR; +} /* 36.211 v10.3.0 Section 6.3.4 */ -int srslte_predecoding_type_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_layers, int nof_symbols, srslte_mimo_type_t type, float noise_estimate) { +int srslte_predecoding_type_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_layers, + int codebook_idx, int nof_symbols, srslte_mimo_type_t type, float noise_estimate) { if (nof_ports > SRSLTE_MAX_PORTS) { fprintf(stderr, "Maximum number of ports is %d (nof_ports=%d)\n", SRSLTE_MAX_PORTS, @@ -722,10 +1277,11 @@ int srslte_predecoding_type_multi(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_ } break; case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX: - fprintf(stderr, "Spatial multiplexing not supported\n"); - return -1; + return srslte_predecoding_multiplex_zf(y, h, x, nof_rxant, nof_ports, nof_layers, codebook_idx, nof_symbols); + default: + return SRSLTE_ERROR; } - return 0; + return SRSLTE_ERROR; } @@ -813,9 +1369,70 @@ int srslte_precoding_cdd(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], } } +int srslte_precoding_multiplex(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], int nof_layers, int nof_ports, + int codebook_idx, uint32_t nof_symbols) +{ + int i; + if (nof_ports == 2) { + if (nof_layers == 1) { + switch(codebook_idx) { + case 0: + srslte_vec_sc_prod_cfc(x[0], 1.0f/sqrtf(2.0f), y[0], nof_symbols); + srslte_vec_sc_prod_cfc(x[0], 1.0f/sqrtf(2.0f), y[1], nof_symbols); + break; + case 1: + srslte_vec_sc_prod_cfc(x[0], 1.0f/sqrtf(2.0f), y[0], nof_symbols); + srslte_vec_sc_prod_cfc(x[0], -1.0f/sqrtf(2.0f), y[1], nof_symbols); + break; + case 2: + srslte_vec_sc_prod_cfc(x[0], 1.0f/sqrtf(2.0f), y[0], nof_symbols); + srslte_vec_sc_prod_ccc(x[0], _Complex_I/sqrtf(2.0f), y[1], nof_symbols); + break; + case 3: + srslte_vec_sc_prod_cfc(x[0], 1.0f/sqrtf(2.0f), y[0], nof_symbols); + srslte_vec_sc_prod_ccc(x[0], -_Complex_I/sqrtf(2.0f), y[1], nof_symbols); + break; + default: + fprintf(stderr, "Invalid multiplex combination: codebook_idx=%d, nof_layers=%d, nof_ports=%d\n", + codebook_idx, nof_layers, nof_ports); + return SRSLTE_ERROR; + } + } else if (nof_layers == 2) { + switch(codebook_idx) { + case 0: + srslte_vec_sc_prod_cfc(x[0], 1.0f/sqrtf(2.0f), y[0], nof_symbols); + srslte_vec_sc_prod_cfc(x[1], 1.0f/sqrtf(2.0f), y[1], nof_symbols); + break; + case 1: + for (i = 0; i < nof_symbols; i++) { + y[0][i] = 0.5f*x[0][i] + 0.5f*x[1][i]; + y[1][i] = 0.5f*x[0][i] - 0.5f*x[1][i]; + } + break; + case 2: + for (i = 0; i < nof_symbols; i++) { + y[0][i] = 0.5f*x[0][i] + 0.5f*x[1][i]; + y[1][i] = 0.5f*_Complex_I*x[0][i] - 0.5f*_Complex_I*x[1][i]; + } + break; + case 3: + default: + fprintf(stderr, "Invalid multiplex combination: codebook_idx=%d, nof_layers=%d, nof_ports=%d\n", + codebook_idx, nof_layers, nof_ports); + return SRSLTE_ERROR; + } + } else { + ERROR("Not implemented"); + } + } else { + ERROR("Not implemented"); + } + return SRSLTE_SUCCESS; +} + /* 36.211 v10.3.0 Section 6.3.4 */ int srslte_precoding_type(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], int nof_layers, - int nof_ports, int nof_symbols, srslte_mimo_type_t type) { + int nof_ports, int codebook_idx, int nof_symbols, srslte_mimo_type_t type) { if (nof_ports > SRSLTE_MAX_PORTS) { fprintf(stderr, "Maximum number of ports is %d (nof_ports=%d)\n", SRSLTE_MAX_PORTS, @@ -829,29 +1446,30 @@ int srslte_precoding_type(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], } switch (type) { - case SRSLTE_MIMO_TYPE_CDD: - return srslte_precoding_cdd(x, y, nof_layers, nof_ports, nof_symbols); - case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA: - if (nof_ports == 1 && nof_layers == 1) { - return srslte_precoding_single(x[0], y[0], nof_symbols); - } else { - fprintf(stderr, - "Number of ports and layers must be 1 for transmission on single antenna ports\n"); - return -1; - } - break; - case SRSLTE_MIMO_TYPE_TX_DIVERSITY: - if (nof_ports == nof_layers) { - return srslte_precoding_diversity(x, y, nof_ports, nof_symbols); - } else { - fprintf(stderr, - "Error number of layers must equal number of ports in transmit diversity\n"); - return -1; - } - case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX: - fprintf(stderr, "Spatial multiplexing not supported\n"); - return -1; + case SRSLTE_MIMO_TYPE_CDD: + return srslte_precoding_cdd(x, y, nof_layers, nof_ports, nof_symbols); + case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA: + if (nof_ports == 1 && nof_layers == 1) { + return srslte_precoding_single(x[0], y[0], nof_symbols); + } else { + fprintf(stderr, + "Number of ports and layers must be 1 for transmission on single antenna ports\n"); + return -1; + } + break; + case SRSLTE_MIMO_TYPE_TX_DIVERSITY: + if (nof_ports == nof_layers) { + return srslte_precoding_diversity(x, y, nof_ports, nof_symbols); + } else { + fprintf(stderr, + "Error number of layers must equal number of ports in transmit diversity\n"); + return -1; + } + case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX: + return srslte_precoding_multiplex(x, y, nof_layers, nof_ports, codebook_idx, nof_symbols); + default: + return SRSLTE_ERROR; } - return 0; + return SRSLTE_ERROR; } diff --git a/lib/src/phy/mimo/test/CMakeLists.txt b/lib/src/phy/mimo/test/CMakeLists.txt index 42e262550..e0894a24d 100644 --- a/lib/src/phy/mimo/test/CMakeLists.txt +++ b/lib/src/phy/mimo/test/CMakeLists.txt @@ -52,7 +52,14 @@ 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) -add_test(precoding_cdd_2x2 precoding_test -m cdd -l 2 -p 2 -r 2) - +add_test(precoding_cdd_2x2 precoding_test -m cdd -l 2 -p 2 -r 2 -n 14000) + +add_test(precoding_multiplex_1l_cb0 precoding_test -m multiplex -l 1 -p 2 -r 2 -n 14000 -c 0) +add_test(precoding_multiplex_1l_cb1 precoding_test -m multiplex -l 1 -p 2 -r 2 -n 14000 -c 1) +add_test(precoding_multiplex_1l_cb2 precoding_test -m multiplex -l 1 -p 2 -r 2 -n 14000 -c 2) +add_test(precoding_multiplex_1l_cb3 precoding_test -m multiplex -l 1 -p 2 -r 2 -n 14000 -c 3) +add_test(precoding_multiplex_2l_cb0 precoding_test -m multiplex -l 2 -p 2 -r 2 -n 14000 -c 0) +add_test(precoding_multiplex_2l_cb1 precoding_test -m multiplex -l 2 -p 2 -r 2 -n 14000 -c 1) +add_test(precoding_multiplex_2l_cb2 precoding_test -m multiplex -l 2 -p 2 -r 2 -n 14000 -c 2) diff --git a/lib/src/phy/mimo/test/precoder_test.c b/lib/src/phy/mimo/test/precoder_test.c index cf8dac89a..bc23004f1 100644 --- a/lib/src/phy/mimo/test/precoder_test.c +++ b/lib/src/phy/mimo/test/precoder_test.c @@ -38,6 +38,7 @@ #define MSE_THRESHOLD 0.0005 int nof_symbols = 1000; +uint32_t codebook_idx = 0; int nof_layers = 1, nof_tx_ports = 1, nof_rx_ports = 1, nof_re = 1; char *mimo_type_name = NULL; @@ -46,11 +47,12 @@ void usage(char *prog) { "Usage: %s -m [single|diversity|multiplex|cdd] -l [nof_layers] -p [nof_tx_ports]\n" " -r [nof_rx_ports]\n", prog); printf("\t-n num_symbols [Default %d]\n", nof_symbols); + printf("\t-c codebook_idx [Default %d]\n\n", codebook_idx); } void parse_args(int argc, char **argv) { int opt; - while ((opt = getopt(argc, argv, "mplnr")) != -1) { + while ((opt = getopt(argc, argv, "mplnrc")) != -1) { switch (opt) { case 'n': nof_symbols = atoi(argv[optind]); @@ -67,6 +69,9 @@ void parse_args(int argc, char **argv) { case 'm': mimo_type_name = argv[optind]; break; + case 'c': + codebook_idx = (uint32_t) atoi(argv[optind]); + break; default: usage(argv[0]); exit(-1); @@ -116,16 +121,13 @@ void populate_channel_single(cf_t *h) { void populate_channel(srslte_mimo_type_t type, cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]) { switch (type) { + case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX: case SRSLTE_MIMO_TYPE_CDD: populate_channel_cdd(h, (uint32_t) nof_re); break; case SRSLTE_MIMO_TYPE_TX_DIVERSITY: populate_channel_diversity(h, (uint32_t) nof_re); break; - case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX: - fprintf(stderr, "Error: not implemented channel emulator\n"); - exit(-1); - //break; case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA: default: populate_channel_single(h[0][0]); @@ -158,6 +160,9 @@ int main(int argc, char **argv) { case SRSLTE_MIMO_TYPE_TX_DIVERSITY: nof_re = nof_layers*nof_symbols; break; + case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX: + nof_re = nof_symbols; + break; case SRSLTE_MIMO_TYPE_CDD: nof_re = nof_symbols*nof_tx_ports/nof_layers; if (nof_rx_ports != 2 || nof_tx_ports != 2) { @@ -223,7 +228,7 @@ int main(int argc, char **argv) { } /* Execute Precoding (Tx) */ - if (srslte_precoding_type(x, y, nof_layers, nof_tx_ports, nof_symbols, type) < 0) { + if (srslte_precoding_type(x, y, nof_layers, nof_tx_ports, codebook_idx, nof_symbols, type) < 0) { fprintf(stderr, "Error layer mapper encoder\n"); exit(-1); } @@ -246,7 +251,7 @@ int main(int argc, char **argv) { struct timeval t[3]; gettimeofday(&t[1], NULL); srslte_predecoding_type_multi(r, h, xr, nof_rx_ports, nof_tx_ports, nof_layers, - nof_re, type, 0); + codebook_idx, nof_re, type, 0); gettimeofday(&t[2], NULL); get_time_interval(t); printf("Execution Time: %ld us\n", t[0].tv_usec); diff --git a/lib/src/phy/phch/pdsch.c b/lib/src/phy/phch/pdsch.c index 5d85a3ec2..8cdfd0884 100644 --- a/lib/src/phy/phch/pdsch.c +++ b/lib/src/phy/phch/pdsch.c @@ -387,7 +387,7 @@ int srslte_pdsch_cfg(srslte_pdsch_cfg_t *cfg, srslte_cell_t cell, srslte_ra_dl_g * If dci_msg is NULL, the grant is assumed to be already stored in cfg->grant */ int srslte_pdsch_cfg_multi(srslte_pdsch_cfg_t *cfg, srslte_cell_t cell, srslte_ra_dl_grant_t *grant, uint32_t cfi, - uint32_t sf_idx, uint32_t rvidx, uint32_t rvidx2) + uint32_t sf_idx, uint32_t rvidx, uint32_t rvidx2, srslte_mimo_type_t mimo_type, uint32_t pmi) { if (cfg) { if (grant) { @@ -399,7 +399,7 @@ int srslte_pdsch_cfg_multi(srslte_pdsch_cfg_t *cfg, srslte_cell_t cell, srslte_r } if (srslte_cbsegm(&cfg->cb_segm2, (uint32_t) cfg->grant.mcs2.tbs)) { - fprintf(stderr, "Error computing Codeblock (2) segmentation for TBS=%d\n", cfg->grant.mcs.tbs); + fprintf(stderr, "Error computing Codeblock (2) segmentation for TBS=%d\n", cfg->grant.mcs2.tbs); return SRSLTE_ERROR; } @@ -407,19 +407,41 @@ int srslte_pdsch_cfg_multi(srslte_pdsch_cfg_t *cfg, srslte_cell_t cell, srslte_r cfg->sf_idx = sf_idx; cfg->rv = rvidx; cfg->rv2 = rvidx2; + cfg->mimo_type = mimo_type; - if (cell.nof_ports == 1 && grant->nof_tb == 1) { - cfg->mimo_type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA; - cfg->nof_layers = 1; - } else if (cell.nof_ports == 2 && grant->nof_tb == 1) { - cfg->mimo_type = SRSLTE_MIMO_TYPE_TX_DIVERSITY; - cfg->nof_layers = 2; - } else if (cell.nof_ports == 2 && grant->nof_tb == 2) { - cfg->mimo_type = SRSLTE_MIMO_TYPE_CDD; - cfg->nof_layers = 2; - } else { - INFO("nof_ports=%d, nof_tb=%d are not consistent\n", cell.nof_ports, grant->nof_tb); - return SRSLTE_ERROR; + /* Check and configure PDSCH transmission modes */ + switch(mimo_type) { + case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA: + if (grant->nof_tb != 1) { + ERROR("Number of transport blocks is not supported for single transmission mode."); + return SRSLTE_ERROR; + } + cfg->nof_layers = 1; + break; + case SRSLTE_MIMO_TYPE_TX_DIVERSITY: + if (grant->nof_tb != 1) { + ERROR("Number of transport blocks is not supported for transmit diversity mode."); + return SRSLTE_ERROR; + } + cfg->nof_layers = 2; + break; + case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX: + if (grant->nof_tb == 1) { + cfg->codebook_idx = pmi; + cfg->nof_layers = 1; + } else { + cfg->codebook_idx = pmi + 1; + cfg->nof_layers = 2; + } + INFO("PDSCH configured for Spatial Multiplex; nof_codewords=%d; nof_layers=%d; codebook_idx=%d;\n", grant->nof_tb, cfg->nof_layers, cfg->codebook_idx); + break; + case SRSLTE_MIMO_TYPE_CDD: + if (grant->nof_tb != 2) { + ERROR("Number of transport blocks is not supported for CDD transmission mode."); + return SRSLTE_ERROR; + } + cfg->nof_layers = 2; + break; } return SRSLTE_SUCCESS; @@ -498,9 +520,9 @@ int srslte_pdsch_decode_multi(srslte_pdsch_t *q, cfg != NULL) { - INFO("Decoding PDSCH SF: %d, RNTI: 0x%x, Mod %s, TBS: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d, C_prb=%d\n", + INFO("Decoding PDSCH SF: %d, RNTI: 0x%x, Mod %s, TBS: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: [%d %d], C_prb=%d\n", cfg->sf_idx, rnti, srslte_mod_string(cfg->grant.mcs.mod), cfg->grant.mcs.tbs, cfg->nbits.nof_re, - cfg->nbits.nof_bits, cfg->rv, cfg->grant.nof_prb); + cfg->nbits.nof_bits, cfg->rv, cfg->rv2, cfg->grant.nof_prb); /* number of layers equals number of ports */ for (i = 0; i < q->cell.nof_ports; i++) { @@ -525,17 +547,19 @@ int srslte_pdsch_decode_multi(srslte_pdsch_t *q, } } } - + + INFO("PDSCH Layer demapper and predecode: mimo_type=%d, nof_layers=%d, nof_tb=%d\n", cfg->mimo_type, + cfg->nof_layers, cfg->grant.nof_tb); if (q->cell.nof_ports == 1) { /* no need for layer demapping */ srslte_predecoding_single_multi(q->symbols, q->ce[0], q->d, q->nof_rx_antennas, cfg->nbits.nof_re, noise_estimate); } else { int nof_symbols [SRSLTE_MAX_CODEWORDS]; - nof_symbols[0] = cfg->nbits.nof_re * cfg->grant.nof_tb / q->cell.nof_ports; - nof_symbols[1] = cfg->nbits2.nof_re * cfg->grant.nof_tb / q->cell.nof_ports; + nof_symbols[0] = cfg->nbits.nof_re * cfg->grant.nof_tb / cfg->nof_layers; + nof_symbols[1] = cfg->nbits2.nof_re * cfg->grant.nof_tb / cfg->nof_layers; srslte_predecoding_type_multi(q->symbols, q->ce, x, q->nof_rx_antennas, q->cell.nof_ports, cfg->nof_layers, - cfg->nbits.nof_re, cfg->mimo_type, 0.0); + cfg->codebook_idx, cfg->nbits.nof_re, cfg->mimo_type, 0.0); srslte_layerdemap_type(x, (cf_t *[SRSLTE_MAX_CODEWORDS]) {q->d, q->d2}, cfg->nof_layers, cfg->grant.nof_tb, nof_symbols[0], nof_symbols, cfg->mimo_type); } @@ -616,6 +640,79 @@ int srslte_pdsch_decode_multi(srslte_pdsch_t *q, } } +int srslte_pdsch_ri_pmi_select(srslte_pdsch_t *q, + srslte_pdsch_cfg_t *cfg, + cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], float noise_estimate, uint32_t nof_ce, + uint32_t *ri, uint32_t *pmi, + float *current_sinr) { + uint32_t best_pmi_1l; + uint32_t best_pmi_2l; + float sinr_1l[SRSLTE_MAX_CODEBOOKS]; + float sinr_2l[SRSLTE_MAX_CODEBOOKS]; + float best_sinr_1l = 0.0; + float best_sinr_2l = 0.0; + int n1, n2; + + if (q->cell.nof_ports == 2 && q->nof_rx_antennas == 2) { + n1 = srslte_precoding_pmi_select(ce, nof_ce, noise_estimate, 1, &best_pmi_1l, sinr_1l); + if (n1 < 0) { + ERROR("PMI Select for 1 layer"); + return SRSLTE_ERROR; + } + + n2 = srslte_precoding_pmi_select(ce, nof_ce, noise_estimate, 2, &best_pmi_2l, sinr_2l); + if (n2 < 0) { + ERROR("PMI Select for 2 layer"); + return SRSLTE_ERROR; + } + + for (int i = 0; i < n1; i++) { + if (sinr_1l[i] > best_sinr_1l) { + best_sinr_1l = sinr_1l[i]; + } + } + + for (int i = 0; i < n2; i++) { + if (sinr_2l[i] > best_sinr_2l) { + best_sinr_2l = sinr_2l[i]; + } + } + + /* Set RI */ + if (ri != NULL) { + *ri = (best_sinr_1l > best_sinr_2l) ? 1 : 2; + } + + /* Set PMI */ + if (pmi != NULL) { + *pmi = (best_sinr_1l > best_sinr_2l) ? best_pmi_1l : best_pmi_2l; + } + + /* Set current condition number */ + if (current_sinr != NULL) { + if (cfg->nof_layers == 1) { + *current_sinr = sinr_1l[cfg->codebook_idx]; + } else if (cfg->nof_layers == 2) { + *current_sinr = sinr_2l[cfg->codebook_idx - 1]; + }else { + ERROR("Not implemented number of layers"); + return SRSLTE_ERROR; + } + } + + /* Print Trace */ + if (ri != NULL && pmi != NULL && current_sinr != NULL) { + INFO("PDSCH Select RI=%d; PMI=%d; Current SINR=%.1fdB (nof_layers=%d, codebook_idx=%d)\n", *ri, *pmi, + 10*log10(*current_sinr), cfg->nof_layers, cfg->codebook_idx); + } + } else { + ERROR("Not implemented configuration"); + return SRSLTE_ERROR_INVALID_INPUTS; + } + + return SRSLTE_SUCCESS; +} + int srslte_pdsch_encode(srslte_pdsch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbuffer_tx_t *softbuffer, uint8_t *data, uint16_t rnti, cf_t *sf_symbols[SRSLTE_MAX_PORTS]) @@ -785,7 +882,7 @@ int srslte_pdsch_encode_multi(srslte_pdsch_t *q, if (q->cell.nof_ports > 1) { int nof_symbols = srslte_layermap_type((cf_t *[SRSLTE_MAX_CODEWORDS]) {q->d, q->d2}, x, cfg->grant.nof_tb, cfg->nof_layers, (int[SRSLTE_MAX_CODEWORDS]) {cfg->nbits.nof_re, cfg->nbits2.nof_re}, cfg->mimo_type); - srslte_precoding_type(x, q->symbols, q->cell.nof_ports, cfg->nof_layers, + srslte_precoding_type(x, q->symbols, cfg->nof_layers, q->cell.nof_ports, cfg->codebook_idx, nof_symbols, cfg->mimo_type); } else { memcpy(q->symbols[0], q->d, cfg->nbits.nof_re * sizeof(cf_t)); diff --git a/lib/src/phy/phch/test/CMakeLists.txt b/lib/src/phy/phch/test/CMakeLists.txt index 1c9846c76..832f18d1f 100644 --- a/lib/src/phy/phch/test/CMakeLists.txt +++ b/lib/src/phy/phch/test/CMakeLists.txt @@ -85,28 +85,79 @@ target_link_libraries(pdsch_test srslte_phy) add_test(pdsch_test_qpsk pdsch_test -m 10 -n 50 -r 1) add_test(pdsch_test_qam16 pdsch_test -m 20 -n 100) add_test(pdsch_test_qam16 pdsch_test -m 20 -n 100 -r 2) -add_test(pdsch_test_qam64 pdsch_test -m 28 -n 100) - -add_test(pdsch_test_sin_6 pdsch_test -p 1 -a 2 -w 1 -n 6) -add_test(pdsch_test_sin_12 pdsch_test -p 1 -a 2 -w 1 -n 12) -add_test(pdsch_test_sin_25 pdsch_test -p 1 -a 2 -w 1 -n 25) -add_test(pdsch_test_sin_50 pdsch_test -p 1 -a 2 -w 1 -n 50) -add_test(pdsch_test_sin_75 pdsch_test -p 1 -a 2 -w 1 -n 75) -add_test(pdsch_test_sin_100 pdsch_test -p 1 -a 2 -w 1 -n 100 -m 28) - -add_test(pdsch_test_div_6 pdsch_test -p 2 -a 2 -w 1 -n 6) -add_test(pdsch_test_div_12 pdsch_test -p 2 -a 2 -w 1 -n 12) -add_test(pdsch_test_div_25 pdsch_test -p 2 -a 2 -w 1 -n 25) -add_test(pdsch_test_div_50 pdsch_test -p 2 -a 2 -w 1 -n 50) -add_test(pdsch_test_div_75 pdsch_test -p 2 -a 2 -w 1 -n 75) -add_test(pdsch_test_div_100 pdsch_test -p 2 -a 2 -w 1 -n 100 -m 28) - -add_test(pdsch_test_cdd_6 pdsch_test -p 2 -a 2 -w 2 -n 6) -add_test(pdsch_test_cdd_12 pdsch_test -p 2 -a 2 -w 2 -n 12) -add_test(pdsch_test_cdd_25 pdsch_test -p 2 -a 2 -w 2 -n 25) -add_test(pdsch_test_cdd_50 pdsch_test -p 2 -a 2 -w 2 -n 50) -add_test(pdsch_test_cdd_75 pdsch_test -p 2 -a 2 -w 2 -n 75) -add_test(pdsch_test_cdd_100 pdsch_test -p 2 -a 2 -w 2 -n 100 -m 28 -M 28) +add_test(pdsch_test_qam64 pdsch_test -n 100) + +# PDSCH test for single transmision mode and 2 Rx antennas +add_test(pdsch_test_sin_6 pdsch_test -x single -a 2 -n 6) +add_test(pdsch_test_sin_12 pdsch_test -x single -a 2 -n 12) +add_test(pdsch_test_sin_25 pdsch_test -x single -a 2 -n 25) +add_test(pdsch_test_sin_50 pdsch_test -x single -a 2 -n 50) +add_test(pdsch_test_sin_75 pdsch_test -x single -a 2 -n 75) +add_test(pdsch_test_sin_100 pdsch_test -x single -a 2 -n 100) + +# PDSCH test for transmit diversity transmision mode (1 codeword) +add_test(pdsch_test_div_6 pdsch_test -x diversity -a 2 -n 6) +add_test(pdsch_test_div_12 pdsch_test -x diversity -a 2 -n 12) +add_test(pdsch_test_div_25 pdsch_test -x diversity -a 2 -n 25) +add_test(pdsch_test_div_50 pdsch_test -x diversity -a 2 -n 50) +add_test(pdsch_test_div_75 pdsch_test -x diversity -a 2 -n 75) +add_test(pdsch_test_div_100 pdsch_test -x diversity -a 2 -n 100) + +# PDSCH test for CDD transmision mode (2 codeword) +add_test(pdsch_test_cdd_6 pdsch_test -x cdd -a 2 -t 0 -n 6) +add_test(pdsch_test_cdd_12 pdsch_test -x cdd -a 2 -t 0 -n 12) +add_test(pdsch_test_cdd_25 pdsch_test -x cdd -a 2 -t 0 -n 25) +add_test(pdsch_test_cdd_50 pdsch_test -x cdd -a 2 -t 0 -n 50) +add_test(pdsch_test_cdd_75 pdsch_test -x cdd -a 2 -t 0 -n 75) +add_test(pdsch_test_cdd_100 pdsch_test -x cdd -a 2 -t 0 -n 100) + +# PDSCH test for Spatial Multiplex transmision mode with PMI = 0 (1 codeword) +add_test(pdsch_test_multiplex1cw_p0_6 pdsch_test -x multiplex -a 2 -p 0 -n 6) +add_test(pdsch_test_multiplex1cw_p0_12 pdsch_test -x multiplex -a 2 -p 0 -n 12) +add_test(pdsch_test_multiplex1cw_p0_25 pdsch_test -x multiplex -a 2 -p 0 -n 25) +add_test(pdsch_test_multiplex1cw_p0_50 pdsch_test -x multiplex -a 2 -p 0 -n 50) +add_test(pdsch_test_multiplex1cw_p0_75 pdsch_test -x multiplex -a 2 -p 0 -n 75) +add_test(pdsch_test_multiplex1cw_p0_100 pdsch_test -x multiplex -a 2 -p 0 -n 100) + +# PDSCH test for Spatial Multiplex transmision mode with PMI = 1 (1 codeword) +add_test(pdsch_test_multiplex1cw_p1_6 pdsch_test -x multiplex -a 2 -p 1 -n 6) +add_test(pdsch_test_multiplex1cw_p1_12 pdsch_test -x multiplex -a 2 -p 1 -n 12) +add_test(pdsch_test_multiplex1cw_p1_25 pdsch_test -x multiplex -a 2 -p 1 -n 25) +add_test(pdsch_test_multiplex1cw_p1_50 pdsch_test -x multiplex -a 2 -p 1 -n 50) +add_test(pdsch_test_multiplex1cw_p1_75 pdsch_test -x multiplex -a 2 -p 1 -n 75) +add_test(pdsch_test_multiplex1cw_p1_100 pdsch_test -x multiplex -a 2 -p 1 -n 100) + +# PDSCH test for Spatial Multiplex transmision mode with PMI = 2 (1 codeword) +add_test(pdsch_test_multiplex1cw_p2_6 pdsch_test -x multiplex -a 2 -p 2 -n 6) +add_test(pdsch_test_multiplex1cw_p2_12 pdsch_test -x multiplex -a 2 -p 2 -n 12) +add_test(pdsch_test_multiplex1cw_p2_25 pdsch_test -x multiplex -a 2 -p 2 -n 25) +add_test(pdsch_test_multiplex1cw_p2_50 pdsch_test -x multiplex -a 2 -p 2 -n 50) +add_test(pdsch_test_multiplex1cw_p2_75 pdsch_test -x multiplex -a 2 -p 2 -n 75) +add_test(pdsch_test_multiplex1cw_p2_100 pdsch_test -x multiplex -a 2 -p 2 -n 100) + +# PDSCH test for Spatial Multiplex transmision mode with PMI = 3 (1 codeword) +add_test(pdsch_test_multiplex1cw_p3_6 pdsch_test -x multiplex -a 2 -p 3 -n 6) +add_test(pdsch_test_multiplex1cw_p3_12 pdsch_test -x multiplex -a 2 -p 3 -n 12) +add_test(pdsch_test_multiplex1cw_p3_25 pdsch_test -x multiplex -a 2 -p 3 -n 25) +add_test(pdsch_test_multiplex1cw_p3_50 pdsch_test -x multiplex -a 2 -p 3 -n 50) +add_test(pdsch_test_multiplex1cw_p3_75 pdsch_test -x multiplex -a 2 -p 3 -n 75) +add_test(pdsch_test_multiplex1cw_p3_100 pdsch_test -x multiplex -a 2 -p 3 -n 100) + +# PDSCH test for Spatial Multiplex transmision mode with PMI = 0 (2 codeword) +add_test(pdsch_test_multiplex2cw_p0_6 pdsch_test -x multiplex -a 2 -t 0 -p 0 -n 6) +add_test(pdsch_test_multiplex2cw_p0_12 pdsch_test -x multiplex -a 2 -t 0 -p 0 -n 12) +add_test(pdsch_test_multiplex2cw_p0_25 pdsch_test -x multiplex -a 2 -t 0 -p 0 -n 25) +add_test(pdsch_test_multiplex2cw_p0_50 pdsch_test -x multiplex -a 2 -t 0 -p 0 -n 50) +add_test(pdsch_test_multiplex2cw_p0_75 pdsch_test -x multiplex -a 2 -t 0 -p 0 -n 75) +add_test(pdsch_test_multiplex2cw_p0_100 pdsch_test -x multiplex -a 2 -t 0 -p 0 -n 100) + +# PDSCH test for Spatial Multiplex transmision mode with PMI = 1 (2 codeword) +add_test(pdsch_test_multiplex2cw_p1_6 pdsch_test -x multiplex -a 2 -t 0 -p 1 -n 6) +add_test(pdsch_test_multiplex2cw_p1_12 pdsch_test -x multiplex -a 2 -t 0 -p 1 -n 12) +add_test(pdsch_test_multiplex2cw_p1_25 pdsch_test -x multiplex -a 2 -t 0 -p 1 -n 25) +add_test(pdsch_test_multiplex2cw_p1_50 pdsch_test -x multiplex -a 2 -t 0 -p 1 -n 50) +add_test(pdsch_test_multiplex2cw_p1_75 pdsch_test -x multiplex -a 2 -t 0 -p 1 -n 75) +add_test(pdsch_test_multiplex2cw_p1_100 pdsch_test -x multiplex -a 2 -t 0 -p 1 -n 100) ######################################################################## # FILE TEST diff --git a/lib/src/phy/phch/test/pdsch_test.c b/lib/src/phy/phch/test/pdsch_test.c index 2dc21bab4..8c79cc836 100644 --- a/lib/src/phy/phch/test/pdsch_test.c +++ b/lib/src/phy/phch/test/pdsch_test.c @@ -52,15 +52,17 @@ srslte_cell_t cell = { SRSLTE_PHICH_R_1_6 // PHICH resources }; +char mimo_type_str [32] = "single"; +srslte_mimo_type_t mimo_type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA; uint32_t cfi = 2; uint32_t mcs = 0; uint32_t mcs2 = 0; uint32_t subframe = 1; uint32_t rv_idx = 0; -uint32_t rv_idx2 = 0; +uint32_t rv_idx2 = 1; uint16_t rnti = 1234; -uint32_t nof_tb = 1; uint32_t nof_rx_antennas = 1; +uint32_t pmi = 0; char *input_file = NULL; void usage(char *prog) { @@ -74,16 +76,16 @@ void usage(char *prog) { printf("\t-t rv_idx2 [Default %d]\n", rv_idx2); printf("\t-R rnti [Default %d]\n", rnti); printf("\t-F cfi [Default %d]\n", cfi); - printf("\t-p cell.nof_ports [Default %d]\n", cell.nof_ports); + printf("\t-x Transmission mode [single|diversity|cdd|multiplex] [Default %s]\n", mimo_type_str); printf("\t-n cell.nof_prb [Default %d]\n", cell.nof_prb); - printf("\t-w nof_tb [Default %d]\n", nof_tb); printf("\t-a nof_rx_antennas [Default %d]\n", nof_rx_antennas); + printf("\t-p pmi (multiplex only) [Default %d]\n", pmi); printf("\t-v [set srslte_verbose to debug, default none]\n"); } void parse_args(int argc, char **argv) { int opt; - while ((opt = getopt(argc, argv, "fmMcsrtRFpnwav")) != -1) { + while ((opt = getopt(argc, argv, "fmMcsrtRFpnavx")) != -1) { switch(opt) { case 'f': input_file = argv[optind]; @@ -109,8 +111,11 @@ void parse_args(int argc, char **argv) { case 'F': cfi = atoi(argv[optind]); break; + case 'x': + strncpy(mimo_type_str, argv[optind], 32); + break; case 'p': - cell.nof_ports = atoi(argv[optind]); + pmi = (uint32_t) atoi(argv[optind]); break; case 'n': cell.nof_prb = atoi(argv[optind]); @@ -118,9 +123,6 @@ void parse_args(int argc, char **argv) { case 'c': cell.id = atoi(argv[optind]); break; - case 'w': - nof_tb = (uint32_t) atoi(argv[optind]); - break; case 'a': nof_rx_antennas = (uint32_t) atoi(argv[optind]); break; @@ -165,14 +167,43 @@ int main(int argc, char **argv) { bzero(rx_slot_symbols, sizeof(cf_t*)*SRSLTE_MAX_PORTS); bzero(softbuffers_tx, sizeof(srslte_softbuffer_tx_t)*SRSLTE_MAX_CODEWORDS); bzero(softbuffers_rx, sizeof(srslte_softbuffer_rx_t)*SRSLTE_MAX_CODEWORDS); - + + /* Parse transmission mode */ + if (srslte_str2mimotype(mimo_type_str, &mimo_type)) { + ERROR("Wrong transmission mode."); + goto quit; + } + + switch(mimo_type) { + + case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA: + cell.nof_ports = 1; + break; + case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX: + case SRSLTE_MIMO_TYPE_CDD: + if (nof_rx_antennas < 2) { + ERROR("At least two receiving antennas are required"); + goto quit; + } + case SRSLTE_MIMO_TYPE_TX_DIVERSITY: + default: + cell.nof_ports = 2; + break; + } + srslte_ra_dl_dci_t dci; bzero(&dci, sizeof(srslte_ra_dl_dci_t)); - dci.mcs_idx = mcs; - dci.rv_idx = rv_idx; dci.type0_alloc.rbg_bitmask = 0xffffffff; - dci.tb_en[0] = true; - if (nof_tb > 1) { + + /* If transport block 0 is enabled */ + if (mcs != 0 || rv_idx != 1) { + dci.mcs_idx = mcs; + dci.rv_idx = rv_idx; + dci.tb_en[0] = true; + } + + /* If transport block 0 is disabled */ + if (mcs2 != 0 || rv_idx2 != 1) { dci.mcs_idx_1 = mcs2; dci.rv_idx_1 = rv_idx2; dci.tb_en[1] = true; @@ -183,7 +214,9 @@ int main(int argc, char **argv) { fprintf(stderr, "Error computing resource allocation\n"); return ret; } - + + + #ifdef DO_OFDM srslte_ofdm_tx_init(&ofdm_tx, cell.cp, cell.nof_prb); srslte_ofdm_rx_init(&ofdm_rx, cell.cp, cell.nof_prb); @@ -201,24 +234,9 @@ int main(int argc, char **argv) { #endif /* DO_OFDM */ /* Configure PDSCH */ - if (srslte_pdsch_cfg_multi(&pdsch_cfg, cell, &grant, cfi, subframe, rv_idx, rv_idx2)) { + if (srslte_pdsch_cfg_multi(&pdsch_cfg, cell, &grant, cfi, subframe, rv_idx, rv_idx2, mimo_type, pmi)) { fprintf(stderr, "Error configuring PDSCH\n"); - exit(-1); - } - - /* Select MIMO mode */ - if (cell.nof_ports == 1 && nof_tb == 1) { - pdsch_cfg.mimo_type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA; - pdsch_cfg.nof_layers = 1; - } else if (cell.nof_ports == 2 && nof_tb == 1) { - pdsch_cfg.mimo_type = SRSLTE_MIMO_TYPE_TX_DIVERSITY; - pdsch_cfg.nof_layers = 2; - } else if (cell.nof_ports == 2 && nof_tb == 2) { - pdsch_cfg.mimo_type = SRSLTE_MIMO_TYPE_CDD; - pdsch_cfg.nof_layers = 2; - } else { - fprintf(stderr, "nof_ports=%d, nof_tb=%d are not consistent\n", cell.nof_ports, nof_tb); - exit(-1); + goto quit; } /* init memory */ @@ -250,7 +268,7 @@ int main(int argc, char **argv) { } if (grant.mcs2.tbs) { - data[1] = srslte_vec_malloc(sizeof(uint8_t) * grant.mcs.tbs); + data[1] = srslte_vec_malloc(sizeof(uint8_t) * grant.mcs2.tbs); if (!data[1]) { perror("srslte_vec_malloc"); goto quit; @@ -264,7 +282,7 @@ int main(int argc, char **argv) { srslte_pdsch_set_rnti(&pdsch_rx, rnti); - for (i = 0; i < nof_tb; i++) { + for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { if (srslte_softbuffer_rx_init(&softbuffers_rx[i], cell.nof_prb)) { fprintf(stderr, "Error initiating RX soft buffer\n"); goto quit; @@ -306,7 +324,7 @@ int main(int argc, char **argv) { srslte_filesource_t fsrc; if (srslte_filesource_init(&fsrc, input_file, SRSLTE_COMPLEX_FLOAT_BIN)) { fprintf(stderr, "Error opening file %s\n", input_file); - exit(-1); + goto quit; } #ifdef DO_OFDM srslte_filesource_read(&fsrc, rx_slot_symbols, SRSLTE_SF_LEN_PRB(cell.nof_prb)); @@ -332,7 +350,7 @@ int main(int argc, char **argv) { srslte_pdsch_set_rnti(&pdsch_tx, rnti); - for (i = 0; i < nof_tb; i++) { + for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { if (srslte_softbuffer_tx_init(&softbuffers_tx[i], cell.nof_prb)) { fprintf(stderr, "Error initiating TX soft buffer\n"); goto quit; @@ -438,7 +456,7 @@ int main(int argc, char **argv) { quit: srslte_pdsch_free(&pdsch_tx); srslte_pdsch_free(&pdsch_rx); - for (i = 0; i < nof_tb; i++) { + for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { srslte_softbuffer_tx_free(&softbuffers_tx[i]); srslte_softbuffer_rx_free(&softbuffers_rx[i]); diff --git a/lib/src/phy/phch/test/pdsch_test_mex.c b/lib/src/phy/phch/test/pdsch_test_mex.c index 204154130..5093c326d 100644 --- a/lib/src/phy/phch/test/pdsch_test_mex.c +++ b/lib/src/phy/phch/test/pdsch_test_mex.c @@ -202,10 +202,17 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) ce[i][j] = srslte_vec_malloc(SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp) * sizeof(cf_t)); } } - uint8_t *data_bytes = srslte_vec_malloc(sizeof(uint8_t) * grant.mcs.tbs/8); - if (!data_bytes) { + uint8_t *data_bytes[SRSLTE_MAX_CODEWORDS]; + data_bytes[0] = srslte_vec_malloc(sizeof(uint8_t) * grant.mcs.tbs/8); + if (!data_bytes[0]) { return; } + + data_bytes[1] = srslte_vec_malloc(sizeof(uint8_t) * grant.mcs2.tbs/8); + if (!data_bytes[1]) { + return; + } + srslte_sch_set_max_noi(&pdsch.dl_sch, max_iterations); bool input_fft_allocated = false; @@ -272,7 +279,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) } uint8_t *data = malloc(grant.mcs.tbs); - srslte_bit_unpack_vector(data_bytes, data, grant.mcs.tbs); + srslte_bit_unpack_vector(data_bytes[0], data, grant.mcs.tbs); if (nlhs >= 1) { plhs[0] = mxCreateLogicalScalar(r == 0); @@ -323,7 +330,11 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) } } } - free(data_bytes); + for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { + if (data_bytes[i]) { + free(data_bytes[i]); + } + } free(data); return; diff --git a/lib/src/phy/ue/ue_dl.c b/lib/src/phy/ue/ue_dl.c index 3b1a83466..c068f5899 100644 --- a/lib/src/phy/ue/ue_dl.c +++ b/lib/src/phy/ue/ue_dl.c @@ -38,8 +38,8 @@ #define CURRENT_SFLEN_RE SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp) -static srslte_dci_format_t ue_formats[] = {SRSLTE_DCI_FORMAT1A, SRSLTE_DCI_FORMAT1, SRSLTE_DCI_FORMAT2A}; // Only TM1 and TM2 are currently supported -const uint32_t nof_ue_formats = 3; +static srslte_dci_format_t ue_formats[] = {SRSLTE_DCI_FORMAT1A, SRSLTE_DCI_FORMAT1, SRSLTE_DCI_FORMAT2A, SRSLTE_DCI_FORMAT2}; // Only TM1, TM2, TM3 and TM4 are currently supported +const uint32_t nof_ue_formats = 4; static srslte_dci_format_t common_formats[] = {SRSLTE_DCI_FORMAT1A,SRSLTE_DCI_FORMAT1C}; const uint32_t nof_common_formats = 2; @@ -284,12 +284,33 @@ int srslte_ue_dl_decode_estimate(srslte_ue_dl_t *q, uint32_t sf_idx, uint32_t *c int srslte_ue_dl_cfg_grant(srslte_ue_dl_t *q, srslte_ra_dl_grant_t *grant, uint32_t cfi, uint32_t sf_idx, uint32_t rvidx) { - return srslte_pdsch_cfg_multi(&q->pdsch_cfg, q->cell, grant, cfi, sf_idx, rvidx, 0); + return srslte_pdsch_cfg_multi(&q->pdsch_cfg, q->cell, grant, cfi, sf_idx, rvidx, 0, SRSLTE_MIMO_TYPE_SINGLE_ANTENNA, 0); } -int srslte_ue_dl_cfg_grant_multi(srslte_ue_dl_t *q, srslte_ra_dl_grant_t *grant, uint32_t cfi, uint32_t sf_idx, uint32_t rvidx, uint32_t rvidx2) +int srslte_ue_dl_cfg_grant_multi(srslte_ue_dl_t *q, srslte_ra_dl_grant_t *grant, uint32_t cfi, uint32_t sf_idx, + uint32_t rvidx, uint32_t rvidx2, srslte_mimo_type_t mimo_type, uint32_t pinfo) { - return srslte_pdsch_cfg_multi(&q->pdsch_cfg, q->cell, grant, cfi, sf_idx, rvidx, rvidx2); + uint32_t pmi = 0; + + /* Translates Precoding Information (pinfo) to Precoding matrix Index (pmi) as 3GPP 36.212 Table 5.3.3.1.5-4 */ + if (q->pdsch_cfg.mimo_type == SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX) { + if (q->pdsch_cfg.grant.nof_tb == 1) { + if (pinfo > 0 && pinfo < 5) { + pmi = pinfo - 1; + } else { + ERROR("Not Implemented"); + return SRSLTE_ERROR; + } + } else { + if (pinfo < 2) { + pmi = pinfo; + } else { + ERROR("Not Implemented"); + return SRSLTE_ERROR; + } + } + } + return srslte_pdsch_cfg_multi(&q->pdsch_cfg, q->cell, grant, cfi, sf_idx, rvidx, rvidx2, mimo_type, pmi); } int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, cf_t *input, uint8_t *data, uint32_t tti, uint16_t rnti) @@ -303,6 +324,7 @@ int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, cf_t *input, uint8_t *data, uint int srslte_ue_dl_decode_rnti_multi(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint8_t *data[SRSLTE_MAX_CODEWORDS], uint32_t tti, uint16_t rnti) { + srslte_mimo_type_t mimo_type; srslte_dci_msg_t dci_msg; srslte_ra_dl_dci_t dci_unpacked; srslte_ra_dl_grant_t grant; @@ -355,7 +377,39 @@ int srslte_ue_dl_decode_rnti_multi(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_POR } } - if (srslte_ue_dl_cfg_grant_multi(q, &grant, cfi, sf_idx, rvidx, rvidx2)) { + switch(dci_msg.format) { + case SRSLTE_DCI_FORMAT1: + case SRSLTE_DCI_FORMAT1A: + mimo_type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA; + break; + case SRSLTE_DCI_FORMAT2: + if (grant.nof_tb == 1 && dci_unpacked.pinfo == 0) { + mimo_type = SRSLTE_MIMO_TYPE_TX_DIVERSITY; + } else { + mimo_type = SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX; + } + break; + case SRSLTE_DCI_FORMAT2A: + if (grant.nof_tb == 1 && dci_unpacked.pinfo == 0) { + mimo_type = SRSLTE_MIMO_TYPE_TX_DIVERSITY; + } else { + mimo_type = SRSLTE_MIMO_TYPE_CDD; + } + break; + + /* Not implemented formats */ + case SRSLTE_DCI_FORMAT0: + case SRSLTE_DCI_FORMAT1C: + case SRSLTE_DCI_FORMAT1B: + case SRSLTE_DCI_FORMAT1D: + case SRSLTE_DCI_FORMAT2B: + default: + ERROR("Transmission mode not supported."); + return SRSLTE_ERROR; + } + + if (srslte_ue_dl_cfg_grant_multi(q, &grant, cfi, sf_idx, rvidx, rvidx2, mimo_type, dci_unpacked.pinfo)) { + ERROR("Configuing PDSCH"); return SRSLTE_ERROR; } @@ -374,7 +428,10 @@ int srslte_ue_dl_decode_rnti_multi(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_POR q->pkt_errors++; } else if (ret == SRSLTE_ERROR_INVALID_INPUTS) { fprintf(stderr, "Error calling srslte_pdsch_decode()\n"); - } + } + + /* If we are in TM4 (Closed-Loop MIMO), compute condition number */ + } /* @@ -395,6 +452,13 @@ int srslte_ue_dl_decode_rnti_multi(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_POR } } +int srslte_ue_dl_ri_pmi_select(srslte_ue_dl_t *q, uint32_t *ri, uint32_t *pmi, float *current_sinr) { + float noise_estimate = srslte_chest_dl_get_noise_estimate(&q->chest); + return srslte_pdsch_ri_pmi_select(&q->pdsch, &q->pdsch_cfg, q->ce_m, noise_estimate, + SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp), + ri, pmi, current_sinr); +} + uint32_t srslte_ue_dl_get_ncce(srslte_ue_dl_t *q) { return q->last_location.ncce; } diff --git a/lib/src/phy/utils/algebra.c b/lib/src/phy/utils/algebra.c new file mode 100644 index 000000000..69ac08749 --- /dev/null +++ b/lib/src/phy/utils/algebra.c @@ -0,0 +1,72 @@ +/** + * + * \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/phy/utils/algebra.h" + +#ifdef LV_HAVE_SSE + +inline void srslte_algebra_2x2_zf_sse(__m128 y0, __m128 y1, __m128 h00, __m128 h01, __m128 h10, __m128 h11, + __m128 *x0, __m128 *x1, float norm) { + __m128 detmult1 = _MM_PROD_PS(h00, h11); + __m128 detmult2 = _MM_PROD_PS(h01, h10); + + __m128 det = _mm_sub_ps(detmult1, detmult2); + __m128 detconj = _MM_CONJ_PS(det); + __m128 detabs2 = _MM_PROD_PS(det, detconj); + __m128 detabs2rec = _mm_rcp_ps(detabs2); + detabs2rec = _mm_moveldup_ps(detabs2rec); + __m128 detrec = _mm_mul_ps(_mm_mul_ps(detconj, detabs2rec), + (__m128) {norm, norm, norm, norm}); + + *x0 = _MM_PROD_PS(_mm_sub_ps(_MM_PROD_PS(h11, y0), _MM_PROD_PS(h01, y1)), detrec); + *x1 = _MM_PROD_PS(_mm_sub_ps(_MM_PROD_PS(h00, y1), _MM_PROD_PS(h10, y0)), detrec); +} + +#endif /* LV_HAVE_SSE */ + +#ifdef LV_HAVE_AVX + +inline void srslte_algebra_2x2_zf_avx(__m256 y0, __m256 y1, __m256 h00, __m256 h01, __m256 h10, __m256 h11, + __m256 *x0, __m256 *x1, float norm) { + __m256 detmult1 = _MM256_PROD_PS(h00, h11); + __m256 detmult2 = _MM256_PROD_PS(h01, h10); + + __m256 det = _mm256_sub_ps(detmult1, detmult2); + __m256 detconj = _MM256_CONJ_PS(det); + __m256 sqdet = _mm256_mul_ps(det, det); + __m256 detabs2 = _mm256_add_ps(_mm256_movehdup_ps(sqdet), _mm256_moveldup_ps(sqdet)); + __m256 detabs2rec = _mm256_rcp_ps(detabs2); + __m256 detrec = _mm256_mul_ps(_mm256_mul_ps(detconj, detabs2rec), + (__m256) {norm, norm, norm, norm, norm, norm, norm, norm}); + + *x0 = _MM256_PROD_PS(_mm256_sub_ps(_MM256_PROD_PS(h11, y0), _MM256_PROD_PS(h01, y1)), detrec); + *x1 = _MM256_PROD_PS(_mm256_sub_ps(_MM256_PROD_PS(h00, y1), _MM256_PROD_PS(h10, y0)), detrec); +} + +#endif /* LV_HAVE_AVX */ From 2d1166e3fa23d4230b9518b690e4a76aa2a8c3a1 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Thu, 17 Aug 2017 10:13:03 +0200 Subject: [PATCH 06/60] Added FMA flag --- cmake/modules/FindSSE.cmake | 40 +++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/cmake/modules/FindSSE.cmake b/cmake/modules/FindSSE.cmake index 30be8a206..3440f01c1 100644 --- a/cmake/modules/FindSSE.cmake +++ b/cmake/modules/FindSSE.cmake @@ -7,6 +7,7 @@ include(CheckCSourceRuns) option(ENABLE_SSE "Enable compile-time SSE4.1 support." ON) option(ENABLE_AVX "Enable compile-time AVX support." ON) option(ENABLE_AVX2 "Enable compile-time AVX2 support." ON) +option(ENABLE_FMA "Enable compile-time FMA support." ON) if (ENABLE_SSE) # @@ -97,8 +98,43 @@ if (ENABLE_SSE) if (HAVE_AVX2) message(STATUS "AVX2 is enabled - target CPU must support it") endif() - endif() + endif() + + if (ENABLE_FMA) + + # + # Check compiler for AVX intrinsics + # + if (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_CLANG ) + set(CMAKE_REQUIRED_FLAGS "-mfma") + check_c_source_runs(" + #include + int main() + { + __m256 a, b, c, r; + const float src[8] = { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f }; + float dst[8]; + a = _mm256_loadu_ps( src ); + b = _mm256_loadu_ps( src ); + c = _mm256_loadu_ps( src ); + r = _mm256_fmadd_ps( a, b, c ); + _mm256_storeu_ps( dst, r ); + int i = 0; + for( i = 0; i < 8; i++ ){ + if( ( src[i] * src[i] + src[i] ) != dst[i] ){ + return -1; + } + } + return 0; + }" + HAVE_FMA) + endif() + + if (HAVE_FMA) + message(STATUS "FMA is enabled - target CPU must support it") + endif() + endif() endif() -mark_as_advanced(HAVE_SSE, HAVE_AVX, HAVE_AVX2) +mark_as_advanced(HAVE_SSE, HAVE_AVX, HAVE_AVX2, HAVE_FMA) From d1709e06af56e78d5d179f34d07ada79dd8bbd32 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Thu, 17 Aug 2017 10:14:37 +0200 Subject: [PATCH 07/60] Added algebra SSE, AVX (+FMA) implementatiokns with test --- lib/include/srslte/phy/utils/algebra.h | 129 ++++++-- lib/src/phy/utils/algebra.c | 224 +++++++++++-- lib/src/phy/utils/test/CMakeLists.txt | 9 + lib/src/phy/utils/test/algebra_test.c | 415 +++++++++++++++++++++++++ 4 files changed, 737 insertions(+), 40 deletions(-) create mode 100644 lib/src/phy/utils/test/algebra_test.c diff --git a/lib/include/srslte/phy/utils/algebra.h b/lib/include/srslte/phy/utils/algebra.h index 41d5e0025..8e731a29f 100644 --- a/lib/include/srslte/phy/utils/algebra.h +++ b/lib/include/srslte/phy/utils/algebra.h @@ -29,42 +29,127 @@ #include "srslte/config.h" -#ifdef LV_HAVE_SSE +/* + * Generic Macros + */ +#define RANDOM_CF() (((float)rand())/((float)RAND_MAX) + _Complex_I*((float)rand())/((float)RAND_MAX)) -#define _MM_MULJ_PS(X) _mm_permute_ps(_MM_CONJ_PS(X), 0b10110001) -#define _MM_CONJ_PS(X) (_mm_xor_ps(X, (__m128){0.0f, -0.0f, 0.0f, -0.0f})) +/* + * SSE Macros + */ +#ifdef LV_HAVE_SSE +#define _MM_SWAP(X) ((__m128)_mm_shuffle_ps(X, X, _MM_SHUFFLE(2,3,0,1))) +#define _MM_PERM(X) ((__m128)_mm_shuffle_ps(X, X, _MM_SHUFFLE(2,1,3,0))) +#define _MM_MULJ_PS(X) _MM_SWAP(_MM_CONJ_PS(X)) +#define _MM_CONJ_PS(X) (_mm_xor_ps(X, _mm_set_ps(-0.0f, 0.0f, -0.0f, 0.0f))) +#define _MM_SQMOD_PS(X) _MM_PERM(_mm_hadd_ps(_mm_mul_ps(X,X), _mm_set_ps(0.0f, 0.0f, 0.0f, 0.0f))) #define _MM_PROD_PS(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))) -SRSLTE_API void srslte_algebra_2x2_zf_sse(__m128 y0, - __m128 y1, - __m128 h00, - __m128 h01, - __m128 h10, - __m128 h11, - __m128 *x0, - __m128 *x1, - float norm); - #endif /* LV_HAVE_SSE */ + +/* + * AVX Macros + */ #ifdef LV_HAVE_AVX #define _MM256_MULJ_PS(X) _mm256_permute_ps(_MM256_CONJ_PS(X), 0b10110001) -#define _MM256_CONJ_PS(X) (_mm256_xor_ps(X, (__m256){0.0f, -0.0f, 0.0f, -0.0f, 0.0f, -0.0f, 0.0f, -0.0f})) +#define _MM256_CONJ_PS(X) (_mm256_xor_ps(X, _mm256_set_ps(-0.0f, 0.0f, -0.0f, 0.0f, -0.0f, 0.0f, -0.0f, 0.0f))) + +#ifdef LV_HAVE_FMA +#define _MM256_SQMOD_PS(A, B) _mm256_permute_ps(_mm256_hadd_ps(_mm256_fmadd_ps(A, A, _mm256_mul_ps(B,B)), \ + _mm256_set_ps(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), 0b11011100) +#define _MM256_PROD_PS(a, b) _mm256_fmaddsub_ps(a,_mm256_moveldup_ps(b),\ + _mm256_mul_ps(_mm256_shuffle_ps(a,a,0xB1),_mm256_movehdup_ps(b))) +#else +#define _MM256_SQMOD_PS(A, B) _mm256_permute_ps(_mm256_hadd_ps(_mm256_add_ps(_mm256_mul_ps(A,A), _mm256_mul_ps(B,B)), \ + _mm256_set_ps(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), 0b11011100) #define _MM256_PROD_PS(a, b) _mm256_addsub_ps(_mm256_mul_ps(a,_mm256_moveldup_ps(b)),\ _mm256_mul_ps(_mm256_shuffle_ps(a,a,0xB1),_mm256_movehdup_ps(b))) +#endif /* LV_HAVE_FMA */ +#endif /* LV_HAVE_AVX */ + +/* + * AVX extension with FMA Macros + */ +#ifdef LV_HAVE_FMA + +#define _MM256_SQMOD_ADD_PS(A, B, C) _mm256_permute_ps(_mm256_hadd_ps(_mm256_fmadd_ps(A, A, _mm256_fmadd_ps(B, B, C)),\ + _mm256_set_ps(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), 0b11011100) + +#define _MM256_PROD_ADD_PS(A, B, C) _mm256_fmaddsub_ps(A,_mm256_moveldup_ps(B),\ + _mm256_fmaddsub_ps(_mm256_shuffle_ps(A,A,0xB1),_mm256_movehdup_ps(B), C)) + +#define _MM256_PROD_SUB_PS(A, B, C) _mm256_fmaddsub_ps(A,_mm256_moveldup_ps(B),\ + _mm256_fmsubadd_ps(_mm256_shuffle_ps(A,A,0xB1),_mm256_movehdup_ps(B), C)) +#endif /* LV_HAVE_FMA */ + +/* Generic implementation for complex reciprocal */ +SRSLTE_API cf_t srslte_algebra_cf_recip_gen(cf_t a); + +/* Generic implementation for 2x2 determinant */ +SRSLTE_API cf_t srslte_algebra_2x2_det_gen(cf_t a00, cf_t a01, cf_t a10, cf_t a11); -SRSLTE_API void srslte_algebra_2x2_zf_avx(__m256 y0, - __m256 y1, - __m256 h00, - __m256 h01, - __m256 h10, - __m256 h11, - __m256 *x0, - __m256 *x1, +/* Generic implementation for 2x2 Matrix Inversion */ +SRSLTE_API void srslte_algebra_2x2_inv_gen(cf_t a00, cf_t a01, cf_t a10, cf_t a11, + cf_t *r00, cf_t *r01, cf_t *r10, cf_t *r11); + +/* Generic implementation for Zero Forcing (ZF) solver */ +SRSLTE_API void srslte_algebra_2x2_zf_gen(cf_t y0, cf_t y1, + cf_t h00, cf_t h01, cf_t h10, cf_t h11, + cf_t *x0, cf_t *x1, + float norm); + +/* Generic implementation for Minimum Mean Squared Error (MMSE) solver */ +SRSLTE_API void srslte_algebra_2x2_mmse_gen(cf_t y0, cf_t y1, + cf_t h00, cf_t h01, cf_t h10, cf_t h11, + cf_t *x0, cf_t *x1, + float noise_estimate, + float norm); + +#ifdef LV_HAVE_SSE + +/* SSE implementation for complex reciprocal */ +SRSLTE_API __m128 srslte_algebra_cf_recip_sse(__m128 a); + +/* SSE implementation for 2x2 determinant */ +SRSLTE_API __m128 srslte_algebra_2x2_det_sse(__m128 a00, __m128 a01, __m128 a10, __m128 a11); + +/* SSE implementation for Zero Forcing (ZF) solver */ +SRSLTE_API void srslte_algebra_2x2_zf_sse(__m128 y0, __m128 y1, + __m128 h00, __m128 h01, __m128 h10, __m128 h11, + __m128 *x0, __m128 *x1, + float norm); + +/* SSE implementation for Minimum Mean Squared Error (MMSE) solver */ +SRSLTE_API void srslte_algebra_2x2_mmse_sse(__m128 y0, __m128 y1, + __m128 h00, __m128 h01, __m128 h10, __m128 h11, + __m128 *x0, __m128 *x1, + float noise_estimate, float norm); + +#endif /* LV_HAVE_SSE */ + +#ifdef LV_HAVE_AVX + +/* AVX implementation for complex reciprocal */ +SRSLTE_API __m256 srslte_algebra_cf_recip_avx(__m256 a); + +/* AVX implementation for 2x2 determinant */ +SRSLTE_API __m256 srslte_algebra_2x2_det_avx(__m256 a00, __m256 a01, __m256 a10, __m256 a11); + +/* AVX implementation for Zero Forcing (ZF) solver */ +SRSLTE_API void srslte_algebra_2x2_zf_avx(__m256 y0, __m256 y1, + __m256 h00, __m256 h01, __m256 h10, __m256 h11, + __m256 *x0, __m256 *x1, float norm); +/* AVX implementation for Minimum Mean Squared Error (MMSE) solver */ +SRSLTE_API void srslte_algebra_2x2_mmse_avx(__m256 y0, __m256 y1, + __m256 h00, __m256 h01, __m256 h10, __m256 h11, + __m256 *x0, __m256 *x1, + float noise_estimate, float norm); + #endif /* LV_HAVE_AVX */ #endif //SRSLTE_ALGEBRA_H diff --git a/lib/src/phy/utils/algebra.c b/lib/src/phy/utils/algebra.c index 69ac08749..3d1de2ffa 100644 --- a/lib/src/phy/utils/algebra.c +++ b/lib/src/phy/utils/algebra.c @@ -24,49 +24,237 @@ * */ - +#include #include #include "srslte/phy/utils/algebra.h" + +/* Generic implementation for complex reciprocal */ +inline cf_t srslte_algebra_cf_recip_gen(cf_t a) { + return conjf(a) / (crealf(a) * crealf(a) + cimagf(a) * cimagf(a)); +} + +/* Generic implementation for 2x2 determinant */ +inline cf_t srslte_algebra_2x2_det_gen(cf_t a00, cf_t a01, cf_t a10, cf_t a11) { + return a00 * a11 - a01 * a10; +} + +/* 2x2 Matrix inversion, generic implementation */ +inline void srslte_algebra_2x2_inv_gen(cf_t a00, cf_t a01, cf_t a10, cf_t a11, + cf_t *r00, cf_t *r01, cf_t *r10, cf_t *r11) { + cf_t div = srslte_algebra_cf_recip_gen(srslte_algebra_2x2_det_gen(a00, a01, a10, a11)); + *r00 = a11 * div; + *r01 = -a01 * div; + *r10 = -a10 * div; + *r11 = a00 * div; +} + +/* Generic implementation for Zero Forcing (ZF) solver */ +inline void srslte_algebra_2x2_zf_gen(cf_t y0, cf_t y1, cf_t h00, cf_t h01, cf_t h10, cf_t h11, + cf_t *x0, cf_t *x1, float norm) { + cf_t _norm = srslte_algebra_cf_recip_gen(srslte_algebra_2x2_det_gen(h00, h01, h10, h11)) * norm; + *x0 = (y0 * h11 - h01 * y1) * _norm; + *x1 = (y1 * h00 - h10 * y0) * _norm; +} + +/* Generic implementation for Minimum Mean Squared Error (MMSE) solver */ +inline void srslte_algebra_2x2_mmse_gen(cf_t y0, cf_t y1, cf_t h00, cf_t h01, cf_t h10, cf_t h11, + cf_t *x0, cf_t *x1, float noise_estimate, float norm) { + /* Create conjugated matrix */ + cf_t _h00 = conjf(h00); + cf_t _h01 = conjf(h01); + cf_t _h10 = conjf(h10); + cf_t _h11 = conjf(h11); + + /* 1. A = H' x H + No*/ + cf_t a00 = _h00 * h00 + _h10 * h10 + noise_estimate; + cf_t a01 = _h00 * h01 + _h10 * h11; + cf_t a10 = _h01 * h00 + _h11 * h10; + cf_t a11 = _h01 * h01 + _h11 * h11 + noise_estimate; + + /* 2. B = inv(H' x H + No) = inv(A) */ + cf_t b00 = a11; + cf_t b01 = -a01; + cf_t b10 = -a10; + cf_t b11 = a00; + cf_t _norm = norm * srslte_algebra_cf_recip_gen(srslte_algebra_2x2_det_gen(a00, a01, a10, a11)); + + + /* 3. W = inv(H' x H + No) x H' = B x H' */ + cf_t w00 = b00 * _h00 + b01 * _h01; + cf_t w01 = b00 * _h10 + b01 * _h11; + cf_t w10 = b10 * _h00 + b11 * _h01; + cf_t w11 = b10 * _h10 + b11 * _h11; + + /* 4. X = W x Y */ + *x0 = (y0 * w00 + y1 * w01) * _norm; + *x1 = (y0 * w10 + y1 * w11) * _norm; +} + #ifdef LV_HAVE_SSE +/* SSE implementation for complex reciprocal */ +inline __m128 srslte_algebra_cf_recip_sse(__m128 a) { + __m128 conj = _MM_CONJ_PS(a); + __m128 sqabs = _mm_mul_ps(a, a); + sqabs = _mm_add_ps(_mm_movehdup_ps(sqabs), _mm_moveldup_ps(sqabs)); + + __m128 recp = _mm_rcp_ps(sqabs); + + return _mm_mul_ps(recp, conj); +} + +/* SSE implementation for 2x2 determinant */ +inline __m128 srslte_algebra_2x2_det_sse(__m128 a00, __m128 a01, __m128 a10, __m128 a11) { + return _mm_sub_ps(_MM_PROD_PS(a00, a11), _MM_PROD_PS(a01, a10)); +} + +/* SSE implementation for Zero Forcing (ZF) solver */ inline void srslte_algebra_2x2_zf_sse(__m128 y0, __m128 y1, __m128 h00, __m128 h01, __m128 h10, __m128 h11, __m128 *x0, __m128 *x1, float norm) { __m128 detmult1 = _MM_PROD_PS(h00, h11); __m128 detmult2 = _MM_PROD_PS(h01, h10); __m128 det = _mm_sub_ps(detmult1, detmult2); - __m128 detconj = _MM_CONJ_PS(det); - __m128 detabs2 = _MM_PROD_PS(det, detconj); - __m128 detabs2rec = _mm_rcp_ps(detabs2); - detabs2rec = _mm_moveldup_ps(detabs2rec); - __m128 detrec = _mm_mul_ps(_mm_mul_ps(detconj, detabs2rec), - (__m128) {norm, norm, norm, norm}); + __m128 detrec = _mm_mul_ps(srslte_algebra_cf_recip_sse(det), _mm_set1_ps(norm)); *x0 = _MM_PROD_PS(_mm_sub_ps(_MM_PROD_PS(h11, y0), _MM_PROD_PS(h01, y1)), detrec); *x1 = _MM_PROD_PS(_mm_sub_ps(_MM_PROD_PS(h00, y1), _MM_PROD_PS(h10, y0)), detrec); } +/* SSE implementation for Minimum Mean Squared Error (MMSE) solver */ +inline void srslte_algebra_2x2_mmse_sse(__m128 y0, __m128 y1, __m128 h00, __m128 h01, __m128 h10, __m128 h11, + __m128 *x0, __m128 *x1, float noise_estimate, float norm) { + __m128 _noise_estimate = _mm_set_ps(0.0f, noise_estimate, 0.0f, noise_estimate); + __m128 _norm = _mm_set1_ps(norm); + + /* Create conjugated matrix */ + __m128 _h00 = _MM_CONJ_PS(h00); + __m128 _h01 = _MM_CONJ_PS(h01); + __m128 _h10 = _MM_CONJ_PS(h10); + __m128 _h11 = _MM_CONJ_PS(h11); + + /* 1. A = H' x H + No*/ + __m128 a00 = _mm_add_ps(_mm_add_ps(_MM_SQMOD_PS(h00), _MM_SQMOD_PS(h10)), _noise_estimate); + __m128 a01 = _mm_add_ps(_MM_PROD_PS(_h00, h01), _MM_PROD_PS(_h10, h11)); + __m128 a10 = _mm_add_ps(_MM_PROD_PS(_h01, h00), _MM_PROD_PS(_h11, h10)); + __m128 a11 = _mm_add_ps(_mm_add_ps(_MM_SQMOD_PS(h01), _MM_SQMOD_PS(h11)), _noise_estimate); + + /* 2. B = inv(H' x H + No) = inv(A) */ + __m128 b00 = a11; + __m128 b01 = _mm_xor_ps(a01, _mm_set1_ps(-0.0f)); + __m128 b10 = _mm_xor_ps(a10, _mm_set1_ps(-0.0f)); + __m128 b11 = a00; + _norm = _mm_mul_ps(_norm, srslte_algebra_cf_recip_sse(srslte_algebra_2x2_det_sse(a00, a01, a10, a11))); + + + /* 3. W = inv(H' x H + No) x H' = B x H' */ + __m128 w00 = _mm_add_ps(_MM_PROD_PS(b00, _h00), _MM_PROD_PS(b01, _h01)); + __m128 w01 = _mm_add_ps(_MM_PROD_PS(b00, _h10), _MM_PROD_PS(b01, _h11)); + __m128 w10 = _mm_add_ps(_MM_PROD_PS(b10, _h00), _MM_PROD_PS(b11, _h01)); + __m128 w11 = _mm_add_ps(_MM_PROD_PS(b10, _h10), _MM_PROD_PS(b11, _h11)); + + /* 4. X = W x Y */ + *x0 = _MM_PROD_PS(_mm_add_ps(_MM_PROD_PS(y0, w00), _MM_PROD_PS(y1, w01)), _norm); + *x1 = _MM_PROD_PS(_mm_add_ps(_MM_PROD_PS(y0, w10), _MM_PROD_PS(y1, w11)), _norm); +} + #endif /* LV_HAVE_SSE */ #ifdef LV_HAVE_AVX +/* AVX implementation for complex reciprocal */ +inline __m256 srslte_algebra_cf_recip_avx(__m256 a) { + __m256 conj = _MM256_CONJ_PS(a); + __m256 sqabs = _mm256_mul_ps(a, a); + sqabs = _mm256_add_ps(_mm256_movehdup_ps(sqabs), _mm256_moveldup_ps(sqabs)); + + __m256 recp = _mm256_rcp_ps(sqabs); + + return _mm256_mul_ps(recp, conj); +} + +/* AVX implementation for 2x2 determinant */ +inline __m256 srslte_algebra_2x2_det_avx(__m256 a00, __m256 a01, __m256 a10, __m256 a11) { +#ifdef LV_HAVE_FMA + return _MM256_PROD_SUB_PS(a00, a11, _MM256_PROD_PS(a01, a10)); +#else + return _mm256_sub_ps(_MM256_PROD_PS(a00, a11), _MM256_PROD_PS(a01, a10)); +#endif /* LV_HAVE_FMA */ +} + +/* AVX implementation for Zero Forcing (ZF) solver */ inline void srslte_algebra_2x2_zf_avx(__m256 y0, __m256 y1, __m256 h00, __m256 h01, __m256 h10, __m256 h11, - __m256 *x0, __m256 *x1, float norm) { - __m256 detmult1 = _MM256_PROD_PS(h00, h11); - __m256 detmult2 = _MM256_PROD_PS(h01, h10); - - __m256 det = _mm256_sub_ps(detmult1, detmult2); - __m256 detconj = _MM256_CONJ_PS(det); - __m256 sqdet = _mm256_mul_ps(det, det); - __m256 detabs2 = _mm256_add_ps(_mm256_movehdup_ps(sqdet), _mm256_moveldup_ps(sqdet)); - __m256 detabs2rec = _mm256_rcp_ps(detabs2); - __m256 detrec = _mm256_mul_ps(_mm256_mul_ps(detconj, detabs2rec), - (__m256) {norm, norm, norm, norm, norm, norm, norm, norm}); + __m256 *x0, __m256 *x1, float norm) { + + __m256 det = srslte_algebra_2x2_det_avx(h00, h01, h10, h11); + __m256 detrec = _mm256_mul_ps(srslte_algebra_cf_recip_avx(det), _mm256_set1_ps(norm)); +#ifdef LV_HAVE_FMA + *x0 = _MM256_PROD_PS(_MM256_PROD_SUB_PS(h11, y0, _MM256_PROD_PS(h01, y1)), detrec); + *x1 = _MM256_PROD_PS(_MM256_PROD_SUB_PS(h00, y1, _MM256_PROD_PS(h10, y0)), detrec); +#else *x0 = _MM256_PROD_PS(_mm256_sub_ps(_MM256_PROD_PS(h11, y0), _MM256_PROD_PS(h01, y1)), detrec); *x1 = _MM256_PROD_PS(_mm256_sub_ps(_MM256_PROD_PS(h00, y1), _MM256_PROD_PS(h10, y0)), detrec); +#endif /* LV_HAVE_FMA */ +} + +/* AVX implementation for Minimum Mean Squared Error (MMSE) solver */ +inline void srslte_algebra_2x2_mmse_avx(__m256 y0, __m256 y1, __m256 h00, __m256 h01, __m256 h10, __m256 h11, + __m256 *x0, __m256 *x1, float noise_estimate, float norm) { + __m256 _noise_estimate = _mm256_set_ps(0.0f, noise_estimate, 0.0f, noise_estimate, + 0.0f, noise_estimate, 0.0f, noise_estimate); + __m256 _norm = _mm256_set1_ps(norm); + + /* Create conjugated matrix */ + __m256 _h00 = _MM256_CONJ_PS(h00); + __m256 _h01 = _MM256_CONJ_PS(h01); + __m256 _h10 = _MM256_CONJ_PS(h10); + __m256 _h11 = _MM256_CONJ_PS(h11); + + /* 1. A = H' x H + No*/ +#ifdef LV_HAVE_FMA + __m256 a00 = _MM256_SQMOD_ADD_PS(h00, h10, _noise_estimate); + __m256 a01 = _MM256_PROD_ADD_PS(_h00, h01, _MM256_PROD_PS(_h10, h11)); + __m256 a10 = _MM256_PROD_ADD_PS(_h01, h00, _MM256_PROD_PS(_h11, h10)); + __m256 a11 = _MM256_SQMOD_ADD_PS(h01, h11, _noise_estimate); +#else + __m256 a00 = _mm256_add_ps(_MM256_SQMOD_PS(h00, h10), _noise_estimate); + __m256 a01 = _mm256_add_ps(_MM256_PROD_PS(_h00, h01), _MM256_PROD_PS(_h10, h11)); + __m256 a10 = _mm256_add_ps(_MM256_PROD_PS(_h01, h00), _MM256_PROD_PS(_h11, h10)); + __m256 a11 = _mm256_add_ps(_MM256_SQMOD_PS(h01, h11), _noise_estimate); +#endif /* LV_HAVE_FMA */ + + /* 2. B = inv(H' x H + No) = inv(A) */ + __m256 b00 = a11; + __m256 b01 = _mm256_xor_ps(a01, _mm256_set1_ps(-0.0f)); + __m256 b10 = _mm256_xor_ps(a10, _mm256_set1_ps(-0.0f)); + __m256 b11 = a00; + _norm = _mm256_mul_ps(_norm, srslte_algebra_cf_recip_avx(srslte_algebra_2x2_det_avx(a00, a01, a10, a11))); + + + /* 3. W = inv(H' x H + No) x H' = B x H' */ +#ifdef LV_HAVE_FMA + __m256 w00 = _MM256_PROD_ADD_PS(b00, _h00, _MM256_PROD_PS(b01, _h01)); + __m256 w01 = _MM256_PROD_ADD_PS(b00, _h10, _MM256_PROD_PS(b01, _h11)); + __m256 w10 = _MM256_PROD_ADD_PS(b10, _h00, _MM256_PROD_PS(b11, _h01)); + __m256 w11 = _MM256_PROD_ADD_PS(b10, _h10, _MM256_PROD_PS(b11, _h11)); +#else + __m256 w00 = _mm256_add_ps(_MM256_PROD_PS(b00, _h00), _MM256_PROD_PS(b01, _h01)); + __m256 w01 = _mm256_add_ps(_MM256_PROD_PS(b00, _h10), _MM256_PROD_PS(b01, _h11)); + __m256 w10 = _mm256_add_ps(_MM256_PROD_PS(b10, _h00), _MM256_PROD_PS(b11, _h01)); + __m256 w11 = _mm256_add_ps(_MM256_PROD_PS(b10, _h10), _MM256_PROD_PS(b11, _h11)); +#endif /* LV_HAVE_FMA */ + + /* 4. X = W x Y */ +#ifdef LV_HAVE_FMA + *x0 = _MM256_PROD_PS(_MM256_PROD_ADD_PS(y0, w00, _MM256_PROD_PS(y1, w01)), _norm); + *x1 = _MM256_PROD_PS(_MM256_PROD_ADD_PS(y0, w10, _MM256_PROD_PS(y1, w11)), _norm); +#else + *x0 = _MM256_PROD_PS(_mm256_add_ps(_MM256_PROD_PS(y0, w00), _MM256_PROD_PS(y1, w01)), _norm); + *x1 = _MM256_PROD_PS(_mm256_add_ps(_MM256_PROD_PS(y0, w10), _MM256_PROD_PS(y1, w11)), _norm); +#endif /* LV_HAVE_FMA */ } #endif /* LV_HAVE_AVX */ diff --git a/lib/src/phy/utils/test/CMakeLists.txt b/lib/src/phy/utils/test/CMakeLists.txt index 494c20c16..1f516da8f 100644 --- a/lib/src/phy/utils/test/CMakeLists.txt +++ b/lib/src/phy/utils/test/CMakeLists.txt @@ -33,3 +33,12 @@ add_test(dft_dc dft_test -b -d) # Backwards first & handle dc internally add_test(dft_odd dft_test -N 255) # Odd-length add_test(dft_odd_dc dft_test -N 255 -b -d) # Odd-length, backwards first, handle dc +######################################################################## +# Algebra TEST +######################################################################## + +add_executable(algebra_test algebra_test.c) +target_link_libraries(algebra_test srslte_phy) + +add_test(algebra_2x2_zf_solver_test algebra_test -z) +add_test(algebra_2x2_mmse_solver_test algebra_test -m) diff --git a/lib/src/phy/utils/test/algebra_test.c b/lib/src/phy/utils/test/algebra_test.c new file mode 100644 index 000000000..a5bc7e773 --- /dev/null +++ b/lib/src/phy/utils/test/algebra_test.c @@ -0,0 +1,415 @@ +/** + * + * \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 +#include +#include +#include +#include +#include + +#include "srslte/phy/utils/algebra.h" + + +bool zf_solver = false; +bool mmse_solver = false; +bool verbose = false; + +double elapsed_us(struct timeval *ts_start, struct timeval *ts_end) { + if (ts_end->tv_usec > ts_start->tv_usec) { + return ((double) ts_end->tv_sec - (double) ts_start->tv_sec) * 1000000 + + (double) ts_end->tv_usec - (double) ts_start->tv_usec; + } else { + return ((double) ts_end->tv_sec - (double) ts_start->tv_sec - 1) * 1000000 + + ((double) ts_end->tv_usec + 1000000) - (double) ts_start->tv_usec; + } +} + +#define NOF_REPETITIONS 1000 +#define RUN_TEST(FUNCTION) /*TYPE NAME (void)*/ { \ + int i;\ + struct timeval start, end;\ + gettimeofday(&start, NULL); \ + bool ret = true; \ + for (i = 0; i < NOF_REPETITIONS; i++) {ret &= FUNCTION ();}\ + gettimeofday(&end, NULL);\ + if (verbose) printf("%32s: %s ... %6.2f us/call\n", #FUNCTION, (ret)?"Pass":"Fail", \ + elapsed_us(&start, &end)/NOF_REPETITIONS);\ + passed &= ret;\ +} + +void usage(char *prog) { + printf("Usage: %s [mzvh]\n", prog); + printf("\t-m Test Minimum Mean Squared Error (MMSE) solver\n"); + printf("\t-z Test Zero Forcing (ZF) solver\n"); + printf("\t-v Verbose\n"); + printf("\t-h Show this message\n"); +} + +void parse_args(int argc, char **argv) { + int opt; + while ((opt = getopt(argc, argv, "mzvh")) != -1) { + switch (opt) { + case 'm': + mmse_solver = true; + break; + case 'z': + zf_solver = true; + break; + case 'v': + verbose = true; + break; + case 'h': + default: + usage(argv[0]); + exit(-1); + } + } +} + +bool test_zf_solver_gen(void) { + cf_t x0, x1, cf_error0, cf_error1; + float error; + + cf_t x0_gold = RANDOM_CF(); + cf_t x1_gold = RANDOM_CF(); + cf_t h00 = RANDOM_CF(); + cf_t h01 = RANDOM_CF(); + cf_t h10 = RANDOM_CF(); + cf_t h11 = (1 - h01 * h10) / h00; + cf_t y0 = x0_gold * h00 + x1_gold * h01; + cf_t y1 = x0_gold * h10 + x1_gold * h11; + + srslte_algebra_2x2_zf_gen(y0, y1, h00, h01, h10, h11, &x0, &x1, 1.0f); + + cf_error0 = x0 - x0_gold; + cf_error1 = x1 - x1_gold; + error = crealf(cf_error0) * crealf(cf_error0) + cimagf(cf_error0) * cimagf(cf_error0) + + crealf(cf_error1) * crealf(cf_error1) + cimagf(cf_error1) * cimagf(cf_error1); + + return (error < 1e-6); +} + +bool test_mmse_solver_gen(void) { + cf_t x0, x1, cf_error0, cf_error1; + float error; + + cf_t x0_gold = RANDOM_CF(); + cf_t x1_gold = RANDOM_CF(); + cf_t h00 = RANDOM_CF(); + cf_t h01 = RANDOM_CF(); + cf_t h10 = RANDOM_CF(); + cf_t h11 = (1 - h01 * h10) / h00; + cf_t y0 = x0_gold * h00 + x1_gold * h01; + cf_t y1 = x0_gold * h10 + x1_gold * h11; + + srslte_algebra_2x2_mmse_gen(y0, y1, h00, h01, h10, h11, &x0, &x1, 0.0f, 1.0f); + + cf_error0 = x0 - x0_gold; + cf_error1 = x1 - x1_gold; + error = crealf(cf_error0) * crealf(cf_error0) + cimagf(cf_error0) * cimagf(cf_error0) + + crealf(cf_error1) * crealf(cf_error1) + cimagf(cf_error1) * cimagf(cf_error1); + + return (error < 1e-6); +} + +#ifdef LV_HAVE_SSE + +bool test_zf_solver_sse(void) { + cf_t cf_error0, cf_error1; + float error = 0.0f; + + cf_t x0_gold_1 = RANDOM_CF(); + cf_t x1_gold_1 = RANDOM_CF(); + cf_t h00_1 = RANDOM_CF(); + cf_t h01_1 = RANDOM_CF(); + cf_t h10_1 = RANDOM_CF(); + cf_t h11_1 = (1 - h01_1 * h10_1) / h00_1; + cf_t y0_1 = x0_gold_1 * h00_1 + x1_gold_1 * h01_1; + cf_t y1_1 = x0_gold_1 * h10_1 + x1_gold_1 * h11_1; + + cf_t x0_gold_2 = RANDOM_CF(); + cf_t x1_gold_2 = RANDOM_CF(); + cf_t h00_2 = RANDOM_CF(); + cf_t h01_2 = RANDOM_CF(); + cf_t h10_2 = RANDOM_CF(); + cf_t h11_2 = (1 - h01_2 * h10_2) / h00_2; + cf_t y0_2 = x0_gold_2 * h00_2 + x1_gold_2 * h01_2; + cf_t y1_2 = x0_gold_2 * h10_2 + x1_gold_2 * h11_2; + + __m128 _y0 = _mm_set_ps(cimagf(y0_1), crealf(y0_1), cimagf(y0_2), crealf(y0_2)); + __m128 _y1 = _mm_set_ps(cimagf(y1_1), crealf(y1_1), cimagf(y1_2), crealf(y1_2)); + + __m128 _h00 = _mm_set_ps(cimagf(h00_1), crealf(h00_1), cimagf(h00_2), crealf(h00_2)); + __m128 _h01 = _mm_set_ps(cimagf(h01_1), crealf(h01_1), cimagf(h01_2), crealf(h01_2)); + __m128 _h10 = _mm_set_ps(cimagf(h10_1), crealf(h10_1), cimagf(h10_2), crealf(h10_2)); + __m128 _h11 = _mm_set_ps(cimagf(h11_1), crealf(h11_1), cimagf(h11_2), crealf(h11_2)); + + __m128 _x0, _x1; + + srslte_algebra_2x2_zf_sse(_y0, _y1, _h00, _h01, _h10, _h11, &_x0, &_x1, 1.0f); + + + __attribute__((aligned(128))) cf_t x0[2]; + __attribute__((aligned(128))) cf_t x1[2]; + + _mm_store_ps((float *) x0, _x0); + _mm_store_ps((float *) x1, _x1); + + cf_error0 = x0[1] - x0_gold_1; + cf_error1 = x1[1] - x1_gold_1; + error += crealf(cf_error0) * crealf(cf_error0) + cimagf(cf_error0) * cimagf(cf_error0) + + crealf(cf_error1) * crealf(cf_error1) + cimagf(cf_error1) * cimagf(cf_error1); + + cf_error0 = x0[0] - x0_gold_2; + cf_error1 = x1[0] - x1_gold_2; + error += crealf(cf_error0) * crealf(cf_error0) + cimagf(cf_error0) * cimagf(cf_error0) + + crealf(cf_error1) * crealf(cf_error1) + cimagf(cf_error1) * cimagf(cf_error1); + + return (error < 1e-3); +} + +bool test_mmse_solver_sse(void) { + cf_t cf_error0, cf_error1; + float error = 0.0f; + + cf_t x0_gold_1 = RANDOM_CF(); + cf_t x1_gold_1 = RANDOM_CF(); + cf_t h00_1 = RANDOM_CF(); + cf_t h01_1 = RANDOM_CF(); + cf_t h10_1 = RANDOM_CF(); + cf_t h11_1 = (1 - h01_1 * h10_1) / h00_1; + cf_t y0_1 = x0_gold_1 * h00_1 + x1_gold_1 * h01_1; + cf_t y1_1 = x0_gold_1 * h10_1 + x1_gold_1 * h11_1; + + cf_t x0_gold_2 = RANDOM_CF(); + cf_t x1_gold_2 = RANDOM_CF(); + cf_t h00_2 = RANDOM_CF(); + cf_t h01_2 = RANDOM_CF(); + cf_t h10_2 = RANDOM_CF(); + cf_t h11_2 = (1 - h01_2 * h10_2) / h00_2; + cf_t y0_2 = x0_gold_2 * h00_2 + x1_gold_2 * h01_2; + cf_t y1_2 = x0_gold_2 * h10_2 + x1_gold_2 * h11_2; + + __m128 _y0 = _mm_set_ps(cimagf(y0_1), crealf(y0_1), cimagf(y0_2), crealf(y0_2)); + __m128 _y1 = _mm_set_ps(cimagf(y1_1), crealf(y1_1), cimagf(y1_2), crealf(y1_2)); + + __m128 _h00 = _mm_set_ps(cimagf(h00_1), crealf(h00_1), cimagf(h00_2), crealf(h00_2)); + __m128 _h01 = _mm_set_ps(cimagf(h01_1), crealf(h01_1), cimagf(h01_2), crealf(h01_2)); + __m128 _h10 = _mm_set_ps(cimagf(h10_1), crealf(h10_1), cimagf(h10_2), crealf(h10_2)); + __m128 _h11 = _mm_set_ps(cimagf(h11_1), crealf(h11_1), cimagf(h11_2), crealf(h11_2)); + + __m128 _x0, _x1; + + srslte_algebra_2x2_mmse_sse(_y0, _y1, _h00, _h01, _h10, _h11, &_x0, &_x1, 0.0f, 1.0f); + + + __attribute__((aligned(128))) cf_t x0[2]; + __attribute__((aligned(128))) cf_t x1[2]; + + _mm_store_ps((float *) x0, _x0); + _mm_store_ps((float *) x1, _x1); + + cf_error0 = x0[1] - x0_gold_1; + cf_error1 = x1[1] - x1_gold_1; + error += crealf(cf_error0) * crealf(cf_error0) + cimagf(cf_error0) * cimagf(cf_error0) + + crealf(cf_error1) * crealf(cf_error1) + cimagf(cf_error1) * cimagf(cf_error1); + + cf_error0 = x0[0] - x0_gold_2; + cf_error1 = x1[0] - x1_gold_2; + error += crealf(cf_error0) * crealf(cf_error0) + cimagf(cf_error0) * cimagf(cf_error0) + + crealf(cf_error1) * crealf(cf_error1) + cimagf(cf_error1) * cimagf(cf_error1); + + return (error < 1e-3); +} + +#endif /* LV_HAVE_SSE */ + +#ifdef LV_HAVE_AVX + +bool test_zf_solver_avx(void) { + cf_t cf_error0, cf_error1; + float error = 0.0f; + + cf_t x0_gold_1 = RANDOM_CF(); + cf_t x1_gold_1 = RANDOM_CF(); + cf_t h00_1 = RANDOM_CF(); + cf_t h01_1 = RANDOM_CF(); + cf_t h10_1 = RANDOM_CF(); + cf_t h11_1 = (1 - h01_1 * h10_1) / h00_1; + cf_t y0_1 = x0_gold_1 * h00_1 + x1_gold_1 * h01_1; + cf_t y1_1 = x0_gold_1 * h10_1 + x1_gold_1 * h11_1; + + cf_t x0_gold_2 = RANDOM_CF(); + cf_t x1_gold_2 = RANDOM_CF(); + cf_t h00_2 = RANDOM_CF(); + cf_t h01_2 = RANDOM_CF(); + cf_t h10_2 = RANDOM_CF(); + cf_t h11_2 = (1 - h01_2 * h10_2) / h00_2; + cf_t y0_2 = x0_gold_2 * h00_2 + x1_gold_2 * h01_2; + cf_t y1_2 = x0_gold_2 * h10_2 + x1_gold_2 * h11_2; + + __m256 _y0 = _mm256_set_ps(cimagf(y0_1), crealf(y0_1), cimagf(y0_2), crealf(y0_2), + cimagf(y0_1), crealf(y0_1), cimagf(y0_2), crealf(y0_2)); + __m256 _y1 = _mm256_set_ps(cimagf(y1_1), crealf(y1_1), cimagf(y1_2), crealf(y1_2), + cimagf(y1_1), crealf(y1_1), cimagf(y1_2), crealf(y1_2)); + + __m256 _h00 = _mm256_set_ps(cimagf(h00_1), crealf(h00_1), cimagf(h00_2), crealf(h00_2), + cimagf(h00_1), crealf(h00_1), cimagf(h00_2), crealf(h00_2)); + __m256 _h01 = _mm256_set_ps(cimagf(h01_1), crealf(h01_1), cimagf(h01_2), crealf(h01_2), + cimagf(h01_1), crealf(h01_1), cimagf(h01_2), crealf(h01_2)); + __m256 _h10 = _mm256_set_ps(cimagf(h10_1), crealf(h10_1), cimagf(h10_2), crealf(h10_2), + cimagf(h10_1), crealf(h10_1), cimagf(h10_2), crealf(h10_2)); + __m256 _h11 = _mm256_set_ps(cimagf(h11_1), crealf(h11_1), cimagf(h11_2), crealf(h11_2), + cimagf(h11_1), crealf(h11_1), cimagf(h11_2), crealf(h11_2)); + + __m256 _x0, _x1; + + srslte_algebra_2x2_zf_avx(_y0, _y1, _h00, _h01, _h10, _h11, &_x0, &_x1, 1.0f); + + + __attribute__((aligned(256))) cf_t x0[4]; + __attribute__((aligned(256))) cf_t x1[4]; + + _mm256_store_ps((float *) x0, _x0); + _mm256_store_ps((float *) x1, _x1); + + cf_error0 = x0[1] - x0_gold_1; + cf_error1 = x1[1] - x1_gold_1; + error += crealf(cf_error0) * crealf(cf_error0) + cimagf(cf_error0) * cimagf(cf_error0) + + crealf(cf_error1) * crealf(cf_error1) + cimagf(cf_error1) * cimagf(cf_error1); + + cf_error0 = x0[0] - x0_gold_2; + cf_error1 = x1[0] - x1_gold_2; + error += crealf(cf_error0) * crealf(cf_error0) + cimagf(cf_error0) * cimagf(cf_error0) + + crealf(cf_error1) * crealf(cf_error1) + cimagf(cf_error1) * cimagf(cf_error1); + + return (error < 1e-3); +} + +bool test_mmse_solver_avx(void) { + cf_t cf_error0, cf_error1; + float error = 0.0f; + + cf_t x0_gold_1 = RANDOM_CF(); + cf_t x1_gold_1 = RANDOM_CF(); + cf_t h00_1 = RANDOM_CF(); + cf_t h01_1 = RANDOM_CF(); + cf_t h10_1 = RANDOM_CF(); + cf_t h11_1 = (1 - h01_1 * h10_1) / h00_1; + cf_t y0_1 = x0_gold_1 * h00_1 + x1_gold_1 * h01_1; + cf_t y1_1 = x0_gold_1 * h10_1 + x1_gold_1 * h11_1; + + cf_t x0_gold_2 = RANDOM_CF(); + cf_t x1_gold_2 = RANDOM_CF(); + cf_t h00_2 = RANDOM_CF(); + cf_t h01_2 = RANDOM_CF(); + cf_t h10_2 = RANDOM_CF(); + cf_t h11_2 = (1 - h01_2 * h10_2) / h00_2; + cf_t y0_2 = x0_gold_2 * h00_2 + x1_gold_2 * h01_2; + cf_t y1_2 = x0_gold_2 * h10_2 + x1_gold_2 * h11_2; + + __m256 _y0 = _mm256_set_ps(cimagf(y0_1), crealf(y0_1), cimagf(y0_2), crealf(y0_2), + cimagf(y0_1), crealf(y0_1), cimagf(y0_2), crealf(y0_2)); + __m256 _y1 = _mm256_set_ps(cimagf(y1_1), crealf(y1_1), cimagf(y1_2), crealf(y1_2), + cimagf(y1_1), crealf(y1_1), cimagf(y1_2), crealf(y1_2)); + + __m256 _h00 = _mm256_set_ps(cimagf(h00_1), crealf(h00_1), cimagf(h00_2), crealf(h00_2), + cimagf(h00_1), crealf(h00_1), cimagf(h00_2), crealf(h00_2)); + __m256 _h01 = _mm256_set_ps(cimagf(h01_1), crealf(h01_1), cimagf(h01_2), crealf(h01_2), + cimagf(h01_1), crealf(h01_1), cimagf(h01_2), crealf(h01_2)); + __m256 _h10 = _mm256_set_ps(cimagf(h10_1), crealf(h10_1), cimagf(h10_2), crealf(h10_2), + cimagf(h10_1), crealf(h10_1), cimagf(h10_2), crealf(h10_2)); + __m256 _h11 = _mm256_set_ps(cimagf(h11_1), crealf(h11_1), cimagf(h11_2), crealf(h11_2), + cimagf(h11_1), crealf(h11_1), cimagf(h11_2), crealf(h11_2)); + + __m256 _x0, _x1; + + srslte_algebra_2x2_mmse_avx(_y0, _y1, _h00, _h01, _h10, _h11, &_x0, &_x1, 0.0f, 1.0f); + + + __attribute__((aligned(256))) cf_t x0[4]; + __attribute__((aligned(256))) cf_t x1[4]; + + _mm256_store_ps((float *) x0, _x0); + _mm256_store_ps((float *) x1, _x1); + + cf_error0 = x0[1] - x0_gold_1; + cf_error1 = x1[1] - x1_gold_1; + error += crealf(cf_error0) * crealf(cf_error0) + cimagf(cf_error0) * cimagf(cf_error0) + + crealf(cf_error1) * crealf(cf_error1) + cimagf(cf_error1) * cimagf(cf_error1); + + cf_error0 = x0[0] - x0_gold_2; + cf_error1 = x1[0] - x1_gold_2; + error += crealf(cf_error0) * crealf(cf_error0) + cimagf(cf_error0) * cimagf(cf_error0) + + crealf(cf_error1) * crealf(cf_error1) + cimagf(cf_error1) * cimagf(cf_error1); + + return (error < 1e-3); +} + +#endif /* LV_HAVE_AVX */ + + +int main(int argc, char **argv) { + bool passed = true; + int ret = 0; + + parse_args(argc, argv); + + if (zf_solver) { + RUN_TEST(test_zf_solver_gen); + +#ifdef LV_HAVE_SSE + RUN_TEST(test_zf_solver_sse); +#endif /* LV_HAVE_SSE */ + +#ifdef LV_HAVE_AVX + RUN_TEST(test_zf_solver_avx); +#endif /* LV_HAVE_AVX */ + } + + if (mmse_solver) { + RUN_TEST(test_mmse_solver_gen); + +#ifdef LV_HAVE_SSE + RUN_TEST(test_mmse_solver_sse); +#endif /* LV_HAVE_SSE */ + + +#ifdef LV_HAVE_AVX + RUN_TEST(test_mmse_solver_avx); +#endif /* LV_HAVE_AVX */ + } + + printf("%s!\n", (passed) ? "Ok" : "Failed"); + + if (!passed) { + exit(ret); + } + + exit(ret); +} From a9d9c92205e6050367f0bea73b4242d9b76e5b48 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Thu, 17 Aug 2017 10:17:48 +0200 Subject: [PATCH 08/60] Added MMSE in SSE and AVX plus subroutines refactor --- lib/include/srslte/phy/common/phy_common.h | 5 + lib/include/srslte/phy/mimo/precoding.h | 14 +- lib/src/phy/mimo/precoding.c | 1622 ++++++++++++++++---- lib/src/phy/mimo/test/CMakeLists.txt | 15 +- lib/src/phy/mimo/test/precoder_test.c | 62 +- lib/src/phy/mimo/test/predecoder_mex.c | 34 +- 6 files changed, 1430 insertions(+), 322 deletions(-) diff --git a/lib/include/srslte/phy/common/phy_common.h b/lib/include/srslte/phy/common/phy_common.h index e1c6f1b0d..9859bdfb0 100644 --- a/lib/include/srslte/phy/common/phy_common.h +++ b/lib/include/srslte/phy/common/phy_common.h @@ -175,6 +175,11 @@ typedef enum SRSLTE_API { SRSLTE_MIMO_TYPE_CDD } srslte_mimo_type_t; +typedef enum SRSLTE_API { + SRSLTE_MIMO_DECODER_ZF, + SRSLTE_MIMO_DECODER_MMSE +} srslte_mimo_decoder_t; + typedef enum SRSLTE_API { SRSLTE_MOD_BPSK = 0, SRSLTE_MOD_QPSK, diff --git a/lib/include/srslte/phy/mimo/precoding.h b/lib/include/srslte/phy/mimo/precoding.h index 222c085b6..b32b975d2 100644 --- a/lib/include/srslte/phy/mimo/precoding.h +++ b/lib/include/srslte/phy/mimo/precoding.h @@ -107,6 +107,8 @@ SRSLTE_API int srslte_predecoding_type(cf_t *y, srslte_mimo_type_t type, float noise_estimate); +SRSLTE_API void srslte_predecoding_set_mimo_decoder (srslte_mimo_decoder_t _mimo_decoder); + SRSLTE_API int srslte_predecoding_type_multi(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS], @@ -118,11 +120,11 @@ SRSLTE_API int srslte_predecoding_type_multi(cf_t *y[SRSLTE_MAX_PORTS], srslte_mimo_type_t type, float noise_estimate); -int srslte_precoding_pmi_select (cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], - uint32_t nof_symbols, - float noise_estimate, - int nof_layers, - uint32_t *pmi, - float sinr[SRSLTE_MAX_CODEBOOKS]); +SRSLTE_API int srslte_precoding_pmi_select(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], + uint32_t nof_symbols, + float noise_estimate, + int nof_layers, + uint32_t *pmi, + float sinr[SRSLTE_MAX_CODEBOOKS]); #endif /* PRECODING_H_ */ diff --git a/lib/src/phy/mimo/precoding.c b/lib/src/phy/mimo/precoding.c index ba950f196..37081d225 100644 --- a/lib/src/phy/mimo/precoding.c +++ b/lib/src/phy/mimo/precoding.c @@ -36,21 +36,20 @@ #include "srslte/phy/utils/debug.h" #ifdef LV_HAVE_SSE -#include -#include +#include +#include "srslte/phy/utils/algebra.h" 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 -#include -#include - +#include "srslte/phy/utils/algebra.h" 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 +static srslte_mimo_decoder_t mimo_decoder = SRSLTE_MIMO_DECODER_MMSE; /************************************************ * @@ -569,7 +568,7 @@ int srslte_precoding_mimo_2x2_gen(cf_t W[2][2], cf_t *y[SRSLTE_MAX_PORTS], cf_t return SRSLTE_SUCCESS; } -// SSE implementation of ZF 2x2 CCD equalizer +// AVX implementation of ZF 2x2 CCD equalizer #ifdef LV_HAVE_AVX int srslte_predecoding_ccd_2x2_zf_avx(cf_t *y[SRSLTE_MAX_PORTS], @@ -578,7 +577,10 @@ int srslte_predecoding_ccd_2x2_zf_avx(cf_t *y[SRSLTE_MAX_PORTS], uint32_t nof_symbols) { uint32_t i = 0; - for (i = 0; i < nof_symbols; i += 4) { + __m256 mask0 = _mm256_setr_ps(+0.0f, +0.0f, -0.0f, -0.0f, +0.0f, +0.0f, -0.0f, -0.0f); + __m256 mask1 = _mm256_setr_ps(-0.0f, -0.0f, +0.0f, +0.0f, -0.0f, -0.0f, +0.0f, +0.0f); + + for (i = 0; i < nof_symbols - 3; i += 4) { /* Load channel */ __m256 h00i = _mm256_load_ps((float *) &h[0][0][i]); __m256 h01i = _mm256_load_ps((float *) &h[0][1][i]); @@ -586,14 +588,10 @@ int srslte_predecoding_ccd_2x2_zf_avx(cf_t *y[SRSLTE_MAX_PORTS], __m256 h11i = _mm256_load_ps((float *) &h[1][1][i]); /* Apply precoding */ - __m256 h00 = _mm256_add_ps(h00i, _mm256_xor_ps(h10i, - (__m256) {+0.0f, +0.0f, -0.0f, -0.0f, +0.0f, +0.0f, -0.0f, -0.0f})); - __m256 h10 = _mm256_add_ps(h01i, _mm256_xor_ps(h11i, - (__m256) {+0.0f, +0.0f, -0.0f, -0.0f, +0.0f, +0.0f, -0.0f, -0.0f})); - __m256 h01 = _mm256_add_ps(h00i, _mm256_xor_ps(h10i, - (__m256) {-0.0f, -0.0f, +0.0f, +0.0f, -0.0f, -0.0f, +0.0f, +0.0f})); - __m256 h11 = _mm256_add_ps(h01i, _mm256_xor_ps(h11i, - (__m256) {-0.0f, -0.0f, +0.0f, +0.0f, -0.0f, -0.0f, +0.0f, +0.0f})); + __m256 h00 = _mm256_add_ps(h00i, _mm256_xor_ps(h10i, mask0)); + __m256 h10 = _mm256_add_ps(h01i, _mm256_xor_ps(h11i, mask0)); + __m256 h01 = _mm256_add_ps(h00i, _mm256_xor_ps(h10i, mask1)); + __m256 h11 = _mm256_add_ps(h01i, _mm256_xor_ps(h11i, mask1)); __m256 y0 = _mm256_load_ps((float *) &y[0][i]); __m256 y1 = _mm256_load_ps((float *) &y[1][i]); @@ -619,7 +617,7 @@ int srslte_predecoding_ccd_2x2_zf_sse(cf_t *y[SRSLTE_MAX_PORTS], uint32_t nof_symbols) { uint32_t i = 0; - for (i = 0; i < nof_symbols; i += 2) { + for (i = 0; i < nof_symbols - 1; i += 2) { /* Load channel */ __m128 h00i = _mm_load_ps((float *) &h[0][0][i]); __m128 h01i = _mm_load_ps((float *) &h[0][1][i]); @@ -627,10 +625,10 @@ int srslte_predecoding_ccd_2x2_zf_sse(cf_t *y[SRSLTE_MAX_PORTS], __m128 h11i = _mm_load_ps((float *) &h[1][1][i]); /* Apply precoding */ - __m128 h00 = _mm_add_ps(h00i, _mm_xor_ps(h10i, (__m128) {+0.0f, +0.0f, -0.0f, -0.0f})); - __m128 h10 = _mm_add_ps(h01i, _mm_xor_ps(h11i, (__m128) {+0.0f, +0.0f, -0.0f, -0.0f})); - __m128 h01 = _mm_add_ps(h00i, _mm_xor_ps(h10i, (__m128) {-0.0f, -0.0f, +0.0f, +0.0f})); - __m128 h11 = _mm_add_ps(h01i, _mm_xor_ps(h11i, (__m128) {-0.0f, -0.0f, +0.0f, +0.0f})); + __m128 h00 = _mm_add_ps(h00i, _mm_xor_ps(h10i, _mm_setr_ps(+0.0f, +0.0f, -0.0f, -0.0f))); + __m128 h10 = _mm_add_ps(h01i, _mm_xor_ps(h11i, _mm_setr_ps(+0.0f, +0.0f, -0.0f, -0.0f))); + __m128 h01 = _mm_add_ps(h00i, _mm_xor_ps(h10i, _mm_setr_ps(-0.0f, -0.0f, +0.0f, +0.0f))); + __m128 h11 = _mm_add_ps(h01i, _mm_xor_ps(h11i, _mm_setr_ps(-0.0f, -0.0f, +0.0f, +0.0f))); __m128 y0 = _mm_load_ps((float *) &y[0][i]); __m128 y1 = _mm_load_ps((float *) &y[1][i]); @@ -681,7 +679,7 @@ int srslte_predecoding_ccd_2x2_zf_gen(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_ return SRSLTE_SUCCESS; } -int srslte_predecoding_ccd_zf(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS], +int srslte_predecoding_ccd_zf(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_layers, int nof_symbols) { if (nof_ports == 2 && nof_rxant == 2) { @@ -707,223 +705,137 @@ int srslte_predecoding_ccd_zf(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORT return SRSLTE_ERROR; } -/* PMI Select for 1 layer */ -int srslte_precoding_pmi_select_1l (cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], uint32_t nof_symbols, - float noise_estimate, uint32_t *pmi, - float sinr_list[SRSLTE_MAX_CODEBOOKS]) { - -#define SQRT1_2 ((float)M_SQRT1_2); - float max_sinr = 0.0; - uint32_t i, count; - - for (i = 0; i < 4; i++) { - sinr_list[i] = 0; - count = 0; - - for (uint32_t j = 0; j < nof_symbols; j += 100) { - /* 0. Load channel matrix */ - cf_t h00 = h[0][0][j]; - cf_t h01 = h[1][0][j]; - cf_t h10 = h[0][1][j]; - cf_t h11 = h[1][1][j]; +// AVX implementation of MMSE 2x2 CCD equalizer +#ifdef LV_HAVE_AVX - /* 1. B = W'* H' */ - cf_t a0, a1; - switch(i) { - case 0: - a0 = conjf(h00) + conjf(h01); - a1 = conjf(h10) + conjf(h11); - break; - case 1: - a0 = conjf(h00) - conjf(h01); - a1 = conjf(h10) - conjf(h11); - break; - case 2: - a0 = conjf(h00) - _Complex_I * conjf(h01); - a1 = conjf(h10) - _Complex_I * conjf(h11); - break; - case 3: - a0 = conjf(h00) + _Complex_I * conjf(h01); - a1 = conjf(h10) + _Complex_I * conjf(h11); - break; - } - a0 *= SQRT1_2; - a1 *= SQRT1_2; +int srslte_predecoding_ccd_2x2_mmse_avx(cf_t *y[SRSLTE_MAX_PORTS], + cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], + cf_t *x[SRSLTE_MAX_LAYERS], + uint32_t nof_symbols, float noise_estimate) { + uint32_t i = 0; - /* 2. B = W' * H' * H = A * H */ - cf_t b0 = a0*h00 + a1*h10; - cf_t b1 = a0*h01 + a1*h11; + for (i = 0; i < nof_symbols - 3; i += 4) { + /* Load channel */ + __m256 h00i = _mm256_load_ps((float *) &h[0][0][i]); + __m256 h01i = _mm256_load_ps((float *) &h[0][1][i]); + __m256 h10i = _mm256_load_ps((float *) &h[1][0][i]); + __m256 h11i = _mm256_load_ps((float *) &h[1][1][i]); - /* 3. C = W' * H' * H * W' = B * W */ - cf_t c; - switch(i) { - case 0: - c = b0 + b1; - break; - case 1: - c = b0 - b1; - break; - case 2: - c = b0 + _Complex_I*b1; - break; - case 3: - c = b0 - _Complex_I*b1; - break; - default: - return SRSLTE_ERROR; - } - c *= SQRT1_2; + /* Apply precoding */ + __m256 h00 = _mm256_add_ps(h00i, _mm256_xor_ps(h10i, _mm256_setr_ps(+0.0f, +0.0f, -0.0f, -0.0f, +0.0f, +0.0f, -0.0f, -0.0f))); + __m256 h10 = _mm256_add_ps(h01i, _mm256_xor_ps(h11i, _mm256_setr_ps(+0.0f, +0.0f, -0.0f, -0.0f, +0.0f, +0.0f, -0.0f, -0.0f))); + __m256 h01 = _mm256_add_ps(h00i, _mm256_xor_ps(h10i, _mm256_setr_ps(-0.0f, -0.0f, +0.0f, +0.0f, -0.0f, -0.0f, +0.0f, +0.0f))); + __m256 h11 = _mm256_add_ps(h01i, _mm256_xor_ps(h11i, _mm256_setr_ps(-0.0f, -0.0f, +0.0f, +0.0f, -0.0f, -0.0f, +0.0f, +0.0f))); - /* Add for averaging */ - sinr_list[i] += crealf(c); + __m256 y0 = _mm256_load_ps((float *) &y[0][i]); + __m256 y1 = _mm256_load_ps((float *) &y[1][i]); - count ++; - } + __m256 x0, x1; - /* Divide average by noise */ - sinr_list[i] /= noise_estimate*count; + srslte_algebra_2x2_mmse_avx(y0, y1, h00, h01, h10, h11, &x0, &x1, noise_estimate, 2.0f); - if (sinr_list[i] > max_sinr) { - max_sinr = sinr_list[i]; - *pmi = i; - } + _mm256_store_ps((float *) &x[0][i], x0); + _mm256_store_ps((float *) &x[1][i], x1); } - INFO("Precoder PMI Select for 1 layer SINR=[%.1fdB; %.1fdB; %.1fdB; %.1fdB] PMI=%d\n", 10*log10(sinr_list[0]), 10*log10(sinr_list[1]), - 10*log10(sinr_list[2]), 10*log10(sinr_list[3]), *pmi); - - return i; + return nof_symbols; } +#endif /* LV_HAVE_AVX */ -/* PMI Select for 2 layers */ -int srslte_precoding_pmi_select_2l (cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], uint32_t nof_symbols, - float noise_estimate, uint32_t *pmi, - float sinr_list[SRSLTE_MAX_CODEBOOKS]) { - - float max_sinr = 0.0; - uint32_t i, count; - - for (i = 0; i < 2; i++) { - sinr_list[i] = 0; - count = 0; +// SSE implementation of ZF 2x2 CCD equalizer +#ifdef LV_HAVE_SSE - for (uint32_t j = 0; j < nof_symbols; j += 100) { - /* 0. Load channel matrix */ - cf_t h00 = h[0][0][j]; - cf_t h01 = h[1][0][j]; - cf_t h10 = h[0][1][j]; - cf_t h11 = h[1][1][j]; +int srslte_predecoding_ccd_2x2_mmse_sse(cf_t *y[SRSLTE_MAX_PORTS], + cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], + cf_t *x[SRSLTE_MAX_LAYERS], + uint32_t nof_symbols, float noise_estimate) { + uint32_t i = 0; - /* 1. B = W'* H' */ - cf_t a00, a01, a10, a11; - switch(i) { - case 0: - a00 = conjf(h00) + conjf(h01); - a01 = conjf(h10) + conjf(h11); - a10 = conjf(h00) - conjf(h01); - a11 = conjf(h10) - conjf(h11); - break; - case 1: - a00 = conjf(h00) - _Complex_I*conjf(h01); - a01 = conjf(h10) - _Complex_I*conjf(h11); - a10 = conjf(h00) + _Complex_I*conjf(h01); - a11 = conjf(h10) + _Complex_I*conjf(h11); - break; - default: - return SRSLTE_ERROR; - } - a00 *= 0.5f; - a01 *= 0.5f; - a10 *= 0.5f; - a11 *= 0.5f; + for (i = 0; i < nof_symbols - 1; i += 2) { + /* Load channel */ + __m128 h00i = _mm_load_ps((float *) &h[0][0][i]); + __m128 h01i = _mm_load_ps((float *) &h[0][1][i]); + __m128 h10i = _mm_load_ps((float *) &h[1][0][i]); + __m128 h11i = _mm_load_ps((float *) &h[1][1][i]); - /* 2. B = W' * H' * H = A * H */ - cf_t b00 = a00*h00 + a01*h10; - cf_t b01 = a00*h01 + a01*h11; - cf_t b10 = a10*h00 + a11*h10; - cf_t b11 = a10*h01 + a11*h11; + /* Apply precoding */ + __m128 h00 = _mm_add_ps(h00i, _mm_xor_ps(h10i, _mm_setr_ps(+0.0f, +0.0f, -0.0f, -0.0f))); + __m128 h10 = _mm_add_ps(h01i, _mm_xor_ps(h11i, _mm_setr_ps(+0.0f, +0.0f, -0.0f, -0.0f))); + __m128 h01 = _mm_add_ps(h00i, _mm_xor_ps(h10i, _mm_setr_ps(-0.0f, -0.0f, +0.0f, +0.0f))); + __m128 h11 = _mm_add_ps(h01i, _mm_xor_ps(h11i, _mm_setr_ps(-0.0f, -0.0f, +0.0f, +0.0f))); - /* 3. C = W' * H' * H * W' = B * W */ - cf_t c00, c01, c10, c11; - switch(i) { - case 0: - c00 = b00 + b01; - c01 = b00 - b01; - c10 = b10 + b11; - c11 = b10 - b11; - break; - case 1: - c00 = b00 + _Complex_I*b01; - c01 = b00 - _Complex_I*b01; - c10 = b10 + _Complex_I*b11; - c11 = b10 - _Complex_I*b11; - break; - default: - return SRSLTE_ERROR; - } - c00 *= 0.5; - c01 *= 0.5; - c10 *= 0.5; - c11 *= 0.5; + __m128 y0 = _mm_load_ps((float *) &y[0][i]); + __m128 y1 = _mm_load_ps((float *) &y[1][i]); - /* 4. C += noise * I */ - c00 += noise_estimate; - c11 += noise_estimate; + __m128 x0, x1; - /* 5. detC */ - cf_t detC = c00*c11 - c01*c10; - cf_t inv_detC = conjf(detC)/(crealf(detC)*crealf(detC) + cimagf(detC)*cimagf(detC)); + srslte_algebra_2x2_mmse_sse(y0, y1, h00, h01, h10, h11, &x0, &x1, noise_estimate, 2.0f); - cf_t den0 = noise_estimate*c00*inv_detC; - cf_t den1 = noise_estimate*c11*inv_detC; + _mm_store_ps((float *) &x[0][i], x0); + _mm_store_ps((float *) &x[1][i], x1); + } - float gamma0 = crealf((conjf(den0)/(crealf(den0)*crealf(den0) + cimagf(den0)*cimagf(den0))) - 1); - float gamma1 = crealf((conjf(den1)/(crealf(den1)*crealf(den1) + cimagf(den1)*cimagf(den1))) - 1); + return nof_symbols; +} +#endif /* LV_HAVE_SSE */ - /* Add for averaging */ - sinr_list[i] += (gamma0 + gamma1); +// Generic implementation of ZF 2x2 CCD equalizer +int srslte_predecoding_ccd_2x2_mmse_gen(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS], + int nof_symbols, float noise_estimate) { + cf_t h00, h01, h10, h11; + for (int i = 0; i < nof_symbols; i++) { - count ++; - } + // Even precoder + h00 = +h[0][0][i] + h[1][0][i]; + h10 = +h[0][1][i] + h[1][1][i]; + h01 = +h[0][0][i] - h[1][0][i]; + h11 = +h[0][1][i] - h[1][1][i]; + srslte_algebra_2x2_mmse_gen(y[0][i], y[1][i], h00, h01, h10, h11, &x[0][i], &x[1][i], noise_estimate, 2.0f); - /* Divide average by noise */ - sinr_list[i] /= (2*count); + i++; - if (sinr_list[i] > max_sinr) { - max_sinr = sinr_list[i]; - *pmi = i; - } + // Odd precoder + h00 = h[0][0][i] - h[1][0][i]; + h10 = h[0][1][i] - h[1][1][i]; + h01 = h[0][0][i] + h[1][0][i]; + h11 = h[0][1][i] + h[1][1][i]; + srslte_algebra_2x2_mmse_gen(y[0][i], y[1][i], h00, h01, h10, h11, &x[0][i], &x[1][i], noise_estimate, 2.0f); } - - INFO("Precoder PMI Select for 2 layers SINR=[%.1fdB; %.1fdB] PMI=%d\n", 10*log10(sinr_list[0]), 10*log10(sinr_list[1]), *pmi); - - return i; + return SRSLTE_SUCCESS; } -int srslte_precoding_pmi_select (cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], uint32_t nof_symbols, - float noise_estimate, int nof_layers, uint32_t *pmi, - float sinr[SRSLTE_MAX_CODEBOOKS]) { - int ret; - if (sinr == NULL || pmi == NULL) { - ERROR("Null pointer"); - ret = SRSLTE_ERROR_INVALID_INPUTS; - } else if (nof_layers == 1) { - ret = srslte_precoding_pmi_select_1l(h, nof_symbols, noise_estimate, pmi, sinr); - } else if (nof_layers == 2) { - ret = srslte_precoding_pmi_select_2l(h, nof_symbols, noise_estimate, pmi, sinr); +int srslte_predecoding_ccd_mmse(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_layers, int nof_symbols, float noise_estimate) +{ + if (nof_ports == 2 && nof_rxant == 2) { + if (nof_layers == 2) { +#ifdef LV_HAVE_AVX + return srslte_predecoding_ccd_2x2_mmse_avx(y, h, x, nof_symbols, noise_estimate); +#else + #ifdef LV_HAVE_SSE + return srslte_predecoding_ccd_2x2_mmse_sse(y, h, x, nof_symbols, noise_estimate); +#else + return srslte_predecoding_ccd_2x2_mmse_gen(y, h, x, nof_symbols, noise_estimate); +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX */ + } else { + fprintf(stderr, "Error predecoding CCD: Invalid number of layers %d\n", nof_layers); + return -1; + } + } else if (nof_ports == 4) { + fprintf(stderr, "Error predecoding CCD: Only 2 ports supported\n"); } else { - ERROR("Wrong number of layers"); - ret = SRSLTE_ERROR_INVALID_INPUTS; + fprintf(stderr, "Error predecoding CCD: Invalid combination of ports %d and rx antennax %d\n", nof_ports, nof_rxant); } - - return ret; + return SRSLTE_ERROR; } +#ifdef LV_HAVE_AVX + // Generic implementation of ZF 2x2 Spatial Multiplexity equalizer -int srslte_predecoding_multiplex_2x2_zf(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], +int srslte_predecoding_multiplex_2x2_zf_avx(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS], int codebook_idx, int nof_symbols) { - int i = 0; float norm = 1.0; switch(codebook_idx) { @@ -935,12 +847,11 @@ int srslte_predecoding_multiplex_2x2_zf(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLT norm = 2.0f; break; default: - fprintf(stderr, "Wrong codebook_idx=%d\n", codebook_idx); + ERROR("Wrong codebook_idx=%d", codebook_idx); return SRSLTE_ERROR; } -#ifdef LV_HAVE_AVX - for (/* i = 0*/; i < nof_symbols; i += 4) { + for (int i = 0; i < nof_symbols - 3; i += 4) { __m256 _h00 = _mm256_load_ps((float*)&(h[0][0][i])); __m256 _h01 = _mm256_load_ps((float*)&(h[0][1][i])); __m256 _h10 = _mm256_load_ps((float*)&(h[1][0][i])); @@ -982,13 +893,33 @@ int srslte_predecoding_multiplex_2x2_zf(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLT _mm256_store_ps((float *) &x[1][i], x1); } - if (i > nof_symbols) { - i -= 4; - } + + return SRSLTE_SUCCESS; +} + #endif /* LV_HAVE_AVX */ #ifdef LV_HAVE_SSE - for (/* i = 0*/; i < nof_symbols; i += 2) { + +// SSE implementation of ZF 2x2 Spatial Multiplexity equalizer +int srslte_predecoding_multiplex_2x2_zf_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], + cf_t *x[SRSLTE_MAX_LAYERS], int codebook_idx, int nof_symbols) { + float norm = 1.0; + + switch(codebook_idx) { + case 0: + norm = (float) M_SQRT2; + break; + case 1: + case 2: + norm = 2.0f; + break; + default: + ERROR("Wrong codebook_idx=%d", codebook_idx); + return SRSLTE_ERROR; + } + + for (int i = 0; i < nof_symbols - 1; i += 2) { __m128 _h00 = _mm_load_ps((float*)&(h[0][0][i])); __m128 _h01 = _mm_load_ps((float*)&(h[0][1][i])); __m128 _h10 = _mm_load_ps((float*)&(h[1][0][i])); @@ -1030,12 +961,32 @@ int srslte_predecoding_multiplex_2x2_zf(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLT _mm_store_ps((float *) &x[1][i], x1); } - if (i > nof_symbols) { - i -= 2; - } + + return SRSLTE_SUCCESS; +} + #endif /* LV_HAVE_SSE */ - for (/*int i = 0*/; i < nof_symbols; i++) { + +// Generic implementation of ZF 2x2 Spatial Multiplexity equalizer +int srslte_predecoding_multiplex_2x2_zf_gen(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], + cf_t *x[SRSLTE_MAX_LAYERS], int codebook_idx, int nof_symbols) { + float norm = 1.0; + + switch(codebook_idx) { + case 0: + norm = (float) M_SQRT2; + break; + case 1: + case 2: + norm = 2.0f; + break; + default: + fprintf(stderr, "Wrong codebook_idx=%d\n", codebook_idx); + return SRSLTE_ERROR; + } + + for (int i = 0; i < nof_symbols; i++) { cf_t h00, h01, h10, h11, det; switch(codebook_idx) { @@ -1071,22 +1022,211 @@ int srslte_predecoding_multiplex_2x2_zf(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLT return SRSLTE_SUCCESS; } -// Generic implementation of MRC 2x1 (two antennas into one layer) Spatial Multiplexing equalizer -int srslte_predecoding_multiplex_2x1_mrc(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], - cf_t *x[SRSLTE_MAX_LAYERS], int codebook_idx, int nof_symbols) { - int i = 0; - #ifdef LV_HAVE_AVX - for (/* i = 0*/; i < nof_symbols; i += 4) { - __m256 _h00 = _mm256_load_ps((float*)&(h[0][0][i])); - __m256 _h01 = _mm256_load_ps((float*)&(h[0][1][i])); - __m256 _h10 = _mm256_load_ps((float*)&(h[1][0][i])); - __m256 _h11 = _mm256_load_ps((float*)&(h[1][1][i])); - __m256 h0, h1; - switch (codebook_idx) { - case 0: - h0 = _mm256_add_ps(_h00, _h10); +// AVX implementation of ZF 2x2 Spatial Multiplexity equalizer +int srslte_predecoding_multiplex_2x2_mmse_avx(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], + cf_t *x[SRSLTE_MAX_LAYERS], int codebook_idx, int nof_symbols, + float noise_estimate) { + float norm = 1.0; + + switch(codebook_idx) { + case 0: + norm = (float) M_SQRT2; + break; + case 1: + case 2: + norm = 2.0f; + break; + default: + fprintf(stderr, "Wrong codebook_idx=%d\n", codebook_idx); + return SRSLTE_ERROR; + } + + for (int i = 0; i < nof_symbols; i += 4) { + __m256 _h00 = _mm256_load_ps((float*)&(h[0][0][i])); + __m256 _h01 = _mm256_load_ps((float*)&(h[0][1][i])); + __m256 _h10 = _mm256_load_ps((float*)&(h[1][0][i])); + __m256 _h11 = _mm256_load_ps((float*)&(h[1][1][i])); + + __m256 h00, h01, h10, h11; + switch (codebook_idx) { + case 0: + h00 = _h00; + h01 = _h10; + h10 = _h01; + h11 = _h11; + break; + case 1: + h00 = _mm256_add_ps(_h00, _h10); + h01 = _mm256_sub_ps(_h00, _h10); + h10 = _mm256_add_ps(_h01, _h11); + h11 = _mm256_sub_ps(_h01, _h11); + break; + case 2: + h00 = _mm256_add_ps(_h00, _MM256_MULJ_PS(_h10)); + h01 = _mm256_sub_ps(_h00, _MM256_MULJ_PS(_h10)); + h10 = _mm256_add_ps(_h01, _MM256_MULJ_PS(_h11)); + h11 = _mm256_sub_ps(_h01, _MM256_MULJ_PS(_h11)); + break; + default: + fprintf(stderr, "Wrong codebook_idx=%d\n", codebook_idx); + return SRSLTE_ERROR; + } + + __m256 y0 = _mm256_load_ps((float *) &y[0][i]); + __m256 y1 = _mm256_load_ps((float *) &y[1][i]); + + __m256 x0, x1; + + srslte_algebra_2x2_mmse_avx(y0, y1, h00, h01, h10, h11, &x0, &x1, noise_estimate, norm); + + _mm256_store_ps((float *) &x[0][i], x0); + _mm256_store_ps((float *) &x[1][i], x1); + + } + + return SRSLTE_SUCCESS; +} + +#endif /* LV_HAVE_AVX */ + + +#ifdef LV_HAVE_SSE + +// SSE implementation of ZF 2x2 Spatial Multiplexity equalizer +int srslte_predecoding_multiplex_2x2_mmse_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], + cf_t *x[SRSLTE_MAX_LAYERS], int codebook_idx, int nof_symbols, + float noise_estimate) { + float norm; + + switch(codebook_idx) { + case 0: + norm = (float) M_SQRT2; + break; + case 1: + case 2: + norm = 2.0f; + break; + default: + fprintf(stderr, "Wrong codebook_idx=%d\n", codebook_idx); + return SRSLTE_ERROR; + } + + for (int i = 0; i < nof_symbols - 1; i += 2) { + __m128 _h00 = _mm_load_ps((float*)&(h[0][0][i])); + __m128 _h01 = _mm_load_ps((float*)&(h[0][1][i])); + __m128 _h10 = _mm_load_ps((float*)&(h[1][0][i])); + __m128 _h11 = _mm_load_ps((float*)&(h[1][1][i])); + + __m128 h00, h01, h10, h11; + switch (codebook_idx) { + case 0: + h00 = _h00; + h01 = _h10; + h10 = _h01; + h11 = _h11; + break; + case 1: + h00 = _mm_add_ps(_h00, _h10); + h01 = _mm_sub_ps(_h00, _h10); + h10 = _mm_add_ps(_h01, _h11); + h11 = _mm_sub_ps(_h01, _h11); + break; + case 2: + h00 = _mm_add_ps(_h00, _MM_MULJ_PS(_h10)); + h01 = _mm_sub_ps(_h00, _MM_MULJ_PS(_h10)); + h10 = _mm_add_ps(_h01, _MM_MULJ_PS(_h11)); + h11 = _mm_sub_ps(_h01, _MM_MULJ_PS(_h11)); + break; + default: + fprintf(stderr, "Wrong codebook_idx=%d\n", codebook_idx); + return SRSLTE_ERROR; + } + + __m128 y0 = _mm_load_ps((float *) &y[0][i]); + __m128 y1 = _mm_load_ps((float *) &y[1][i]); + + __m128 x0, x1; + + srslte_algebra_2x2_mmse_sse(y0, y1, h00, h01, h10, h11, &x0, &x1, noise_estimate, norm); + + _mm_store_ps((float *) &x[0][i], x0); + _mm_store_ps((float *) &x[1][i], x1); + + } + + return SRSLTE_SUCCESS; +} +#endif /* LV_HAVE_SSE */ + +// Generic implementation of ZF 2x2 Spatial Multiplexity equalizer +int srslte_predecoding_multiplex_2x2_mmse_gen(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], + cf_t *x[SRSLTE_MAX_LAYERS], int codebook_idx, int nof_symbols, + float noise_estimate) { + float norm = 1.0; + + switch(codebook_idx) { + case 0: + norm = (float) M_SQRT2; + break; + case 1: + case 2: + norm = 2.0f; + break; + default: + ERROR("Wrong codebook_idx=%d", codebook_idx); + return SRSLTE_ERROR; + } + + for (int i = 0; i < nof_symbols; i++) { + cf_t h00, h01, h10, h11; + + switch(codebook_idx) { + case 0: + h00 = h[0][0][i]; + h01 = h[1][0][i]; + h10 = h[0][1][i]; + h11 = h[1][1][i]; + break; + case 1: + h00 = h[0][0][i] + h[1][0][i]; + h01 = h[0][0][i] - h[1][0][i]; + h10 = h[0][1][i] + h[1][1][i]; + h11 = h[0][1][i] - h[1][1][i]; + break; + case 2: + h00 = h[0][0][i] + _Complex_I*h[1][0][i]; + h01 = h[0][0][i] - _Complex_I*h[1][0][i]; + h10 = h[0][1][i] + _Complex_I*h[1][1][i]; + h11 = h[0][1][i] - _Complex_I*h[1][1][i]; + break; + default: + fprintf(stderr, "Wrong codebook_idx=%d\n", codebook_idx); + return SRSLTE_ERROR; + } + + srslte_algebra_2x2_mmse_gen(y[0][i], y[1][i], h00, h01, h10, h11, &x[0][i], &x[1][i], noise_estimate, norm); + } + return SRSLTE_SUCCESS; +} + +#ifdef LV_HAVE_AVX + +// Generic implementation of MRC 2x1 (two antennas into one layer) Spatial Multiplexing equalizer +int srslte_predecoding_multiplex_2x1_mrc_avx(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], + cf_t *x[SRSLTE_MAX_LAYERS], int codebook_idx, int nof_symbols) { + + for (int i = 0; i < nof_symbols - 3; i += 4) { + __m256 _h00 = _mm256_load_ps((float*)&(h[0][0][i])); + __m256 _h01 = _mm256_load_ps((float*)&(h[0][1][i])); + __m256 _h10 = _mm256_load_ps((float*)&(h[1][0][i])); + __m256 _h11 = _mm256_load_ps((float*)&(h[1][1][i])); + + __m256 h0, h1; + switch (codebook_idx) { + case 0: + h0 = _mm256_add_ps(_h00, _h10); h1 = _mm256_add_ps(_h01, _h11); break; case 1: @@ -1094,12 +1234,12 @@ int srslte_predecoding_multiplex_2x1_mrc(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSL h1 = _mm256_sub_ps(_h01, _h11); break; case 2: - h0 = _mm256_add_ps(_h00, _mm256_permute_ps(_MM256_CONJ_PS(_h10), 0b10110001)); - h1 = _mm256_add_ps(_h01, _mm256_permute_ps(_MM256_CONJ_PS(_h11), 0b10110001)); + h0 = _mm256_add_ps(_h00, _MM256_MULJ_PS(_h10)); + h1 = _mm256_add_ps(_h01, _MM256_MULJ_PS(_h11)); break; case 3: - h0 = _mm256_sub_ps(_h00, _mm256_permute_ps(_MM256_CONJ_PS(_h10), 0b10110001)); - h1 = _mm256_sub_ps(_h01, _mm256_permute_ps(_MM256_CONJ_PS(_h11), 0b10110001)); + h0 = _mm256_sub_ps(_h00, _MM256_MULJ_PS(_h10)); + h1 = _mm256_sub_ps(_h01, _MM256_MULJ_PS(_h11)); break; default: fprintf(stderr, "Wrong codebook_idx=%d\n", codebook_idx); @@ -1113,8 +1253,7 @@ int srslte_predecoding_multiplex_2x1_mrc(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSL __m256 hh = _mm256_add_ps(hh0, hh1); __m256 hhrec = _mm256_rcp_ps(hh); - hhrec = _mm256_mul_ps(hhrec, (__m256){(float) M_SQRT2, (float) M_SQRT2, (float) M_SQRT2, (float) M_SQRT2, - (float) M_SQRT2,(float) M_SQRT2, (float) M_SQRT2, (float) M_SQRT2}); + hhrec = _mm256_mul_ps(hhrec, _mm256_set1_ps((float) M_SQRT2)); __m256 y0 = _mm256_load_ps((float*)&y[0][i]); __m256 y1 = _mm256_load_ps((float*)&y[1][i]); @@ -1124,13 +1263,20 @@ int srslte_predecoding_multiplex_2x1_mrc(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSL _mm256_store_ps((float*)&x[0][i], x0); } - if (i > nof_symbols) { - i -= 4; - } + + return SRSLTE_SUCCESS; +} + #endif /* LV_HAVE_AVX */ + +// SSE implementation of MRC 2x1 (two antennas into one layer) Spatial Multiplexing equalizer #ifdef LV_HAVE_SSE - for (/* i = 0*/; i < nof_symbols; i += 2) { + +int srslte_predecoding_multiplex_2x1_mrc_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], + cf_t *x[SRSLTE_MAX_LAYERS], int codebook_idx, int nof_symbols) { + + for (int i = 0; i < nof_symbols - 1; i += 2) { __m128 _h00 = _mm_load_ps((float*)&(h[0][0][i])); __m128 _h01 = _mm_load_ps((float*)&(h[0][1][i])); __m128 _h10 = _mm_load_ps((float*)&(h[1][0][i])); @@ -1147,12 +1293,12 @@ int srslte_predecoding_multiplex_2x1_mrc(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSL h1 = _mm_sub_ps(_h01, _h11); break; case 2: - h0 = _mm_add_ps(_h00, _mm_permute_ps(_MM_CONJ_PS(_h10), 0b10110001)); - h1 = _mm_add_ps(_h01, _mm_permute_ps(_MM_CONJ_PS(_h11), 0b10110001)); + h0 = _mm_add_ps(_h00, _MM_MULJ_PS(_h10)); + h1 = _mm_add_ps(_h01, _MM_MULJ_PS(_h11)); break; case 3: - h0 = _mm_sub_ps(_h00, _mm_permute_ps(_MM_CONJ_PS(_h10), 0b10110001)); - h1 = _mm_sub_ps(_h01, _mm_permute_ps(_MM_CONJ_PS(_h11), 0b10110001)); + h0 = _mm_sub_ps(_h00, _MM_MULJ_PS(_h10)); + h1 = _mm_sub_ps(_h01, _MM_MULJ_PS(_h11)); break; default: fprintf(stderr, "Wrong codebook_idx=%d\n", codebook_idx); @@ -1166,7 +1312,7 @@ int srslte_predecoding_multiplex_2x1_mrc(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSL __m128 hh = _mm_add_ps(hh0, hh1); __m128 hhrec = _mm_rcp_ps(hh); - hhrec = _mm_mul_ps(hhrec, (__m128){(float) M_SQRT2, (float) M_SQRT2, (float) M_SQRT2, (float) M_SQRT2}); + hhrec = _mm_mul_ps(hhrec, _mm_set1_ps((float) M_SQRT2)); __m128 y0 = _mm_load_ps((float*)&y[0][i]); __m128 y1 = _mm_load_ps((float*)&y[1][i]); @@ -1177,12 +1323,16 @@ int srslte_predecoding_multiplex_2x1_mrc(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSL _mm_store_ps((float*)&x[0][i], x0); } - if (i > nof_symbols) { - i -= 2; - } + + return SRSLTE_SUCCESS; +} + #endif /* LV_HAVE_SSE */ - for (/*i = 0*/; i < nof_symbols; i += 1) { +// Generic implementation of MRC 2x1 (two antennas into one layer) Spatial Multiplexing equalizer +int srslte_predecoding_multiplex_2x1_mrc_gen(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], + cf_t *x[SRSLTE_MAX_LAYERS], int codebook_idx, int nof_symbols) { + for (int i = 0; i < nof_symbols; i += 1) { cf_t h0, h1; float hh; @@ -1215,23 +1365,59 @@ int srslte_predecoding_multiplex_2x1_mrc(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSL return SRSLTE_SUCCESS; } -int srslte_predecoding_multiplex_zf(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_layers, int codebook_idx, int nof_symbols) +int srslte_predecoding_multiplex(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_layers, int codebook_idx, int nof_symbols, + float noise_estimate) { if (nof_ports == 2 && nof_rxant == 2) { if (nof_layers == 2) { - return srslte_predecoding_multiplex_2x2_zf(y, h, x, codebook_idx, nof_symbols); + switch (mimo_decoder) { + case SRSLTE_MIMO_DECODER_ZF: +#ifdef LV_HAVE_AVX + return srslte_predecoding_multiplex_2x2_zf_avx(y, h, x, codebook_idx, nof_symbols); +#else +#ifdef LV_HAVE_SSE + return srslte_predecoding_multiplex_2x2_zf_sse(y, h, x, codebook_idx, nof_symbols); +#else + return srslte_predecoding_multiplex_2x2_zf_gen(y, h, x, codebook_idx, nof_symbols); +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX */ + break; + case SRSLTE_MIMO_DECODER_MMSE: +#ifdef LV_HAVE_AVX + return srslte_predecoding_multiplex_2x2_mmse_avx(y, h, x, codebook_idx, nof_symbols, noise_estimate); +#else +#ifdef LV_HAVE_SSE + return srslte_predecoding_multiplex_2x2_mmse_sse(y, h, x, codebook_idx, nof_symbols, noise_estimate); +#else + return srslte_predecoding_multiplex_2x2_mmse_gen(y, h, x, codebook_idx, nof_symbols, noise_estimate); +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX */ + break; + } } else { - return srslte_predecoding_multiplex_2x1_mrc(y, h, x, codebook_idx, nof_symbols); +#ifdef LV_HAVE_AVX + return srslte_predecoding_multiplex_2x1_mrc_avx(y, h, x, codebook_idx, nof_symbols); +#else +#ifdef LV_HAVE_SSE + return srslte_predecoding_multiplex_2x1_mrc_sse(y, h, x, codebook_idx, nof_symbols); +#else + return srslte_predecoding_multiplex_2x1_mrc_gen(y, h, x, codebook_idx, nof_symbols); +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX */ } } else if (nof_ports == 4) { - fprintf(stderr, "Error predecoding CCD: Only 2 ports supported\n"); + ERROR("Error predecoding CCD: Only 2 ports supported"); } else { fprintf(stderr, "Error predecoding CCD: Invalid combination of ports %d and rx antennax %d\n", nof_ports, nof_rxant); } return SRSLTE_ERROR; } +void srslte_predecoding_set_mimo_decoder (srslte_mimo_decoder_t _mimo_decoder) { + mimo_decoder = _mimo_decoder; +} + /* 36.211 v10.3.0 Section 6.3.4 */ int srslte_predecoding_type_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_layers, @@ -1251,7 +1437,14 @@ int srslte_predecoding_type_multi(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_ switch (type) { case SRSLTE_MIMO_TYPE_CDD: if (nof_layers >= 2 && nof_layers <= 4) { - return srslte_predecoding_ccd_zf(y, h, x, nof_rxant, nof_ports, nof_layers, nof_symbols); + switch (mimo_decoder) { + case SRSLTE_MIMO_DECODER_ZF: + return srslte_predecoding_ccd_zf(y, h, x, nof_rxant, nof_ports, nof_layers, nof_symbols); + break; + case SRSLTE_MIMO_DECODER_MMSE: + return srslte_predecoding_ccd_mmse(y, h, x, nof_rxant, nof_ports, nof_layers, nof_symbols, noise_estimate); + break; + } } else { fprintf(stderr, "Invalid number of layers %d\n", nof_layers); @@ -1277,7 +1470,8 @@ int srslte_predecoding_type_multi(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_ } break; case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX: - return srslte_predecoding_multiplex_zf(y, h, x, nof_rxant, nof_ports, nof_layers, codebook_idx, nof_symbols); + return srslte_predecoding_multiplex(y, h, x, nof_rxant, nof_ports, nof_layers, codebook_idx, nof_symbols, + noise_estimate); default: return SRSLTE_ERROR; } @@ -1344,39 +1538,102 @@ int srslte_precoding_diversity(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PO } } -int srslte_precoding_cdd(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], int nof_layers, int nof_ports, int nof_symbols) +#ifdef LV_HAVE_AVX + +int srslte_precoding_cdd_2x2_avx(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], int nof_symbols) { - int i; - if (nof_ports == 2) { - if (nof_layers != 2) { - fprintf(stderr, "Invalid number of layers %d for 2 ports\n", nof_layers); - return -1; - } - for (i = 0; i < nof_symbols; i++) { - y[0][i] = (x[0][i]+x[1][i])/2; - y[1][i] = (x[0][i]-x[1][i])/2; - i++; - y[0][i] = (x[0][i]+x[1][i])/2; - y[1][i] = (-x[0][i]+x[1][i])/2; - } - return 2 * i; - } else if (nof_ports == 4) { - fprintf(stderr, "Not implemented\n"); - return -1; - } else { - fprintf(stderr, "Number of ports must be 2 or 4 for transmit diversity (nof_ports=%d)\n", nof_ports); - return -1; + __m256 norm_avx = _mm256_set1_ps(0.5f); + for (int i = 0; i < nof_symbols - 3; i += 4) { + __m256 x0 = _mm256_load_ps((float*) &x[0][i]); + __m256 x1 = _mm256_load_ps((float*) &x[1][i]); + + __m256 y0 = _mm256_mul_ps(norm_avx, _mm256_add_ps(x0, x1)); + + x0 = _mm256_xor_ps(x0, _mm256_setr_ps(+0.0f, +0.0f, -0.0f, -0.0f, +0.0f, +0.0f, -0.0f, -0.0f)); + x1 = _mm256_xor_ps(x1, _mm256_set_ps(+0.0f, +0.0f, -0.0f, -0.0f, +0.0f, +0.0f, -0.0f, -0.0f)); + + __m256 y1 = _mm256_mul_ps(norm_avx, _mm256_add_ps(x0, x1)); + + _mm256_store_ps((float*)&y[0][i], y0); + _mm256_store_ps((float*)&y[1][i], y1); } + + return 2*nof_symbols; } -int srslte_precoding_multiplex(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], int nof_layers, int nof_ports, - int codebook_idx, uint32_t nof_symbols) +#endif /* LV_HAVE_AVX */ + +#ifdef LV_HAVE_SSE + +int srslte_precoding_cdd_2x2_sse(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], int nof_symbols) { - int i; - if (nof_ports == 2) { - if (nof_layers == 1) { - switch(codebook_idx) { - case 0: + __m128 norm_sse = _mm_set1_ps(0.5f); + for (int i = 0; i < nof_symbols - 1; i += 2) { + __m128 x0 = _mm_load_ps((float*) &x[0][i]); + __m128 x1 = _mm_load_ps((float*) &x[1][i]); + + __m128 y0 = _mm_mul_ps(norm_sse, _mm_add_ps(x0, x1)); + + x0 = _mm_xor_ps(x0, _mm_setr_ps(+0.0f, +0.0f, -0.0f, -0.0f)); + x1 = _mm_xor_ps(x1, _mm_set_ps(+0.0f, +0.0f, -0.0f, -0.0f)); + + __m128 y1 = _mm_mul_ps(norm_sse, _mm_add_ps(x0, x1)); + + _mm_store_ps((float*)&y[0][i], y0); + _mm_store_ps((float*)&y[1][i], y1); + } + + return 2 * nof_symbols; +} + +#endif /* LV_HAVE_SSE */ + + +int srslte_precoding_cdd_2x2_gen(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], int nof_symbols) +{ + for (int i = 0; i < nof_symbols; i++) { + y[0][i] = (x[0][i]+x[1][i])/2.0f; + y[1][i] = (x[0][i]-x[1][i])/2.0f; + i++; + y[0][i] = (x[0][i]+x[1][i])/2.0f; + y[1][i] = (-x[0][i]+x[1][i])/2.0f; + } + return 2 * nof_symbols; +} + +int srslte_precoding_cdd(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], int nof_layers, int nof_ports, int nof_symbols) +{ + if (nof_ports == 2) { + if (nof_layers != 2) { + fprintf(stderr, "Invalid number of layers %d for 2 ports\n", nof_layers); + return -1; + } +#ifdef LV_HAVE_AVX + return srslte_precoding_cdd_2x2_avx(x, y, nof_symbols); +#else +#ifdef LV_HAVE_SSE + return srslte_precoding_cdd_2x2_sse(x, y, nof_symbols); +#else + return srslte_precoding_cdd_2x2_gen(x, y, nof_symbols); +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX */ + } else if (nof_ports == 4) { + fprintf(stderr, "Not implemented\n"); + return -1; + } else { + fprintf(stderr, "Number of ports must be 2 or 4 for transmit diversity (nof_ports=%d)\n", nof_ports); + return -1; + } +} + +int srslte_precoding_multiplex(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], int nof_layers, int nof_ports, + int codebook_idx, uint32_t nof_symbols) +{ + int i = 0; + if (nof_ports == 2) { + if (nof_layers == 1) { + switch(codebook_idx) { + case 0: srslte_vec_sc_prod_cfc(x[0], 1.0f/sqrtf(2.0f), y[0], nof_symbols); srslte_vec_sc_prod_cfc(x[0], 1.0f/sqrtf(2.0f), y[1], nof_symbols); break; @@ -1404,13 +1661,65 @@ int srslte_precoding_multiplex(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PO srslte_vec_sc_prod_cfc(x[1], 1.0f/sqrtf(2.0f), y[1], nof_symbols); break; case 1: - for (i = 0; i < nof_symbols; i++) { +#ifdef LV_HAVE_AVX + for (; i < nof_symbols - 3; i += 4) { + __m256 x0 = _mm256_load_ps((float*)&x[0][i]); + __m256 x1 = _mm256_load_ps((float*)&x[1][i]); + + __m256 y0 = _mm256_mul_ps(_mm256_set1_ps(0.5f), _mm256_add_ps(x0, x1)); + __m256 y1 = _mm256_mul_ps(_mm256_set1_ps(0.5f), _mm256_sub_ps(x0, x1)); + + _mm256_store_ps((float*)&y[0][i], y0); + _mm256_store_ps((float*)&y[1][i], y1); + } +#endif /* LV_HAVE_AVX */ + +#ifdef LV_HAVE_SSE + for (; i < nof_symbols - 1; i += 2) { + __m128 x0 = _mm_load_ps((float*)&x[0][i]); + __m128 x1 = _mm_load_ps((float*)&x[1][i]); + + __m128 y0 = _mm_mul_ps(_mm_set1_ps(0.5f), _mm_add_ps(x0, x1)); + __m128 y1 = _mm_mul_ps(_mm_set1_ps(0.5f), _mm_sub_ps(x0, x1)); + + _mm_store_ps((float*)&y[0][i], y0); + _mm_store_ps((float*)&y[1][i], y1); + } +#endif /* LV_HAVE_SSE */ + + for (; i < nof_symbols; i++) { y[0][i] = 0.5f*x[0][i] + 0.5f*x[1][i]; y[1][i] = 0.5f*x[0][i] - 0.5f*x[1][i]; } break; case 2: - for (i = 0; i < nof_symbols; i++) { +#ifdef LV_HAVE_AVX + for (; i < nof_symbols - 3; i += 4) { + __m256 x0 = _mm256_load_ps((float*)&x[0][i]); + __m256 x1 = _mm256_load_ps((float*)&x[1][i]); + + __m256 y0 = _mm256_mul_ps(_mm256_set1_ps(0.5f), _mm256_add_ps(x0, x1)); + __m256 y1 = _mm256_mul_ps(_mm256_set1_ps(0.5f), _MM256_MULJ_PS(_mm256_sub_ps(x0, x1))); + + _mm256_store_ps((float*)&y[0][i], y0); + _mm256_store_ps((float*)&y[1][i], y1); + } +#endif /* LV_HAVE_AVX */ + +#ifdef LV_HAVE_SSE + for (; i < nof_symbols - 1; i += 2) { + __m128 x0 = _mm_load_ps((float*)&x[0][i]); + __m128 x1 = _mm_load_ps((float*)&x[1][i]); + + __m128 y0 = _mm_mul_ps(_mm_set1_ps(0.5f), _mm_add_ps(x0, x1)); + __m128 y1 = _mm_mul_ps(_mm_set1_ps(0.5f), _MM_MULJ_PS(_mm_sub_ps(x0, x1))); + + _mm_store_ps((float*)&y[0][i], y0); + _mm_store_ps((float*)&y[1][i], y1); + } +#endif /* LV_HAVE_SSE */ + + for (; i < nof_symbols; i++) { y[0][i] = 0.5f*x[0][i] + 0.5f*x[1][i]; y[1][i] = 0.5f*_Complex_I*x[0][i] - 0.5f*_Complex_I*x[1][i]; } @@ -1473,3 +1782,744 @@ int srslte_precoding_type(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], return SRSLTE_ERROR; } +#define PMI_SEL_PRECISION 24 + +/* PMI Select for 1 layer */ +int srslte_precoding_pmi_select_1l_gen(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], uint32_t nof_symbols, + float noise_estimate, uint32_t *pmi, + float sinr_list[SRSLTE_MAX_CODEBOOKS]) { + +#define SQRT1_2 ((float)M_SQRT1_2) + float max_sinr = 0.0; + uint32_t i, count; + + for (i = 0; i < 4; i++) { + sinr_list[i] = 0; + count = 0; + + for (uint32_t j = 0; j < nof_symbols; j += PMI_SEL_PRECISION) { + /* 0. Load channel matrix */ + cf_t h00 = h[0][0][j]; + cf_t h01 = h[1][0][j]; + cf_t h10 = h[0][1][j]; + cf_t h11 = h[1][1][j]; + + /* 1. B = W'* H' */ + cf_t a0, a1; + switch (i) { + case 0: + a0 = conjf(h00) + conjf(h01); + a1 = conjf(h10) + conjf(h11); + break; + case 1: + a0 = conjf(h00) - conjf(h01); + a1 = conjf(h10) - conjf(h11); + break; + case 2: + a0 = conjf(h00) - _Complex_I * conjf(h01); + a1 = conjf(h10) - _Complex_I * conjf(h11); + break; + case 3: + a0 = conjf(h00) + _Complex_I * conjf(h01); + a1 = conjf(h10) + _Complex_I * conjf(h11); + break; + } + a0 *= SQRT1_2; + a1 *= SQRT1_2; + + /* 2. B = W' * H' * H = A * H */ + cf_t b0 = a0 * h00 + a1 * h10; + cf_t b1 = a0 * h01 + a1 * h11; + + /* 3. C = W' * H' * H * W' = B * W */ + cf_t c; + switch (i) { + case 0: + c = b0 + b1; + break; + case 1: + c = b0 - b1; + break; + case 2: + c = b0 + _Complex_I * b1; + break; + case 3: + c = b0 - _Complex_I * b1; + break; + default: + return SRSLTE_ERROR; + } + c *= SQRT1_2; + + /* Add for averaging */ + sinr_list[i] += crealf(c); + + count++; + } + + /* Divide average by noise */ + sinr_list[i] /= noise_estimate * count; + + if (sinr_list[i] > max_sinr) { + max_sinr = sinr_list[i]; + *pmi = i; + } + } + + return i; +} + +#ifdef LV_HAVE_SSE + +/* PMI Select for 1 layer */ +int srslte_precoding_pmi_select_1l_sse(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], uint32_t nof_symbols, + float noise_estimate, uint32_t *pmi, + float sinr_list[SRSLTE_MAX_CODEBOOKS]) { + float max_sinr = 0.0; + uint32_t i, count; + __m128 sse_norm = _mm_set1_ps(0.5f); + + for (i = 0; i < 4; i++) { + sinr_list[i] = 0; + count = 0; + + for (uint32_t j = 0; j < nof_symbols - PMI_SEL_PRECISION * 2 + 1; j += PMI_SEL_PRECISION * 2) { + /* 0. Load channel matrix */ + __m128 h00 = _mm_set_ps(crealf(h[0][0][j]), + cimagf(h[0][0][j]), + crealf(h[0][0][j + PMI_SEL_PRECISION]), + cimagf(h[0][0][j + PMI_SEL_PRECISION])); + __m128 h01 = _mm_set_ps(crealf(h[1][0][j]), + cimagf(h[1][0][j]), + crealf(h[1][0][j + PMI_SEL_PRECISION]), + cimagf(h[1][0][j + PMI_SEL_PRECISION])); + __m128 h10 = _mm_set_ps(crealf(h[0][1][j]), + cimagf(h[0][1][j]), + crealf(h[0][1][j + PMI_SEL_PRECISION]), + cimagf(h[0][1][j + PMI_SEL_PRECISION])); + __m128 h11 = _mm_set_ps(crealf(h[1][1][j]), + cimagf(h[1][1][j]), + crealf(h[1][1][j + PMI_SEL_PRECISION]), + cimagf(h[1][1][j + PMI_SEL_PRECISION])); + + /* 1. B = W'* H' */ + __m128 a0, a1; + switch (i) { + case 0: + a0 = _mm_add_ps(_MM_CONJ_PS(h00), _MM_CONJ_PS(h01)); + a1 = _mm_add_ps(_MM_CONJ_PS(h10), _MM_CONJ_PS(h11)); + break; + case 1: + a0 = _mm_sub_ps(_MM_CONJ_PS(h00), _MM_CONJ_PS(h01)); + a1 = _mm_sub_ps(_MM_CONJ_PS(h10), _MM_CONJ_PS(h11)); + break; + case 2: + a0 = _mm_add_ps(_MM_CONJ_PS(h00), _MM_MULJ_PS(_MM_CONJ_PS(h01))); + a1 = _mm_add_ps(_MM_CONJ_PS(h10), _MM_MULJ_PS(_MM_CONJ_PS(h11))); + break; + case 3: + a0 = _mm_sub_ps(_MM_CONJ_PS(h00), _MM_MULJ_PS(_MM_CONJ_PS(h01))); + a1 = _mm_sub_ps(_MM_CONJ_PS(h10), _MM_MULJ_PS(_MM_CONJ_PS(h11))); + break; + } + + /* 2. B = W' * H' * H = A * H */ + __m128 b0 = _mm_add_ps(_MM_PROD_PS(a0, h00), _MM_PROD_PS(a1, h10)); + __m128 b1 = _mm_add_ps(_MM_PROD_PS(a0, h01), _MM_PROD_PS(a1, h11)); + + /* 3. C = W' * H' * H * W' = B * W */ + __m128 c; + switch (i) { + case 0: + c = _mm_add_ps(b0, b1); + break; + case 1: + c = _mm_sub_ps(b0, b1); + break; + case 2: + c = _mm_sub_ps(b0, _MM_MULJ_PS(b1)); + break; + case 3: + c = _mm_add_ps(b0, _MM_MULJ_PS(b1)); + break; + default: + return SRSLTE_ERROR; + } + c = _mm_mul_ps(c, sse_norm); + + /* Add for averaging */ + __attribute__((aligned(128))) float gamma[4]; + _mm_store_ps(gamma, c); + sinr_list[i] += gamma[0] + gamma[2]; + + count += 2; + } + + /* Divide average by noise */ + sinr_list[i] /= noise_estimate * count; + + if (sinr_list[i] > max_sinr) { + max_sinr = sinr_list[i]; + *pmi = i; + } + } + + return i; +} + +#endif /* LV_HAVE_SSE */ + +#ifdef LV_HAVE_AVX + +/* PMI Select for 1 layer */ +int srslte_precoding_pmi_select_1l_avx(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], uint32_t nof_symbols, + float noise_estimate, uint32_t *pmi, + float sinr_list[SRSLTE_MAX_CODEBOOKS]) { + float max_sinr = 0.0; + uint32_t i, count; + __m256 avx_norm = _mm256_set1_ps(0.5f); + + for (i = 0; i < 4; i++) { + sinr_list[i] = 0; + count = 0; + + for (uint32_t j = 0; j < nof_symbols - PMI_SEL_PRECISION * 4 + 1; j += PMI_SEL_PRECISION * 4) { + /* 0. Load channel matrix */ + __m256 h00 = _mm256_set_ps(crealf(h[0][0][j]), + cimagf(h[0][0][j]), + crealf(h[0][0][j + PMI_SEL_PRECISION]), + cimagf(h[0][0][j + PMI_SEL_PRECISION]), + crealf(h[0][0][j + PMI_SEL_PRECISION * 2]), + cimagf(h[0][0][j + PMI_SEL_PRECISION * 2]), + crealf(h[0][0][j + PMI_SEL_PRECISION * 3]), + cimagf(h[0][0][j + PMI_SEL_PRECISION * 3])); + __m256 h01 = _mm256_set_ps(crealf(h[1][0][j]), + cimagf(h[1][0][j]), + crealf(h[1][0][j + PMI_SEL_PRECISION]), + cimagf(h[1][0][j + PMI_SEL_PRECISION]), + crealf(h[1][0][j + PMI_SEL_PRECISION * 2]), + cimagf(h[1][0][j + PMI_SEL_PRECISION * 2]), + crealf(h[1][0][j + PMI_SEL_PRECISION * 3]), + cimagf(h[1][0][j + PMI_SEL_PRECISION * 3])); + __m256 h10 = _mm256_set_ps(crealf(h[0][1][j]), + cimagf(h[0][1][j]), + crealf(h[0][1][j + PMI_SEL_PRECISION]), + cimagf(h[0][1][j + PMI_SEL_PRECISION]), + crealf(h[0][1][j + PMI_SEL_PRECISION * 2]), + cimagf(h[0][1][j + PMI_SEL_PRECISION * 2]), + crealf(h[0][1][j + PMI_SEL_PRECISION * 3]), + cimagf(h[0][1][j + PMI_SEL_PRECISION * 3])); + __m256 h11 = _mm256_set_ps(crealf(h[1][1][j]), + cimagf(h[1][1][j]), + crealf(h[1][1][j + PMI_SEL_PRECISION]), + cimagf(h[1][1][j + PMI_SEL_PRECISION]), + crealf(h[1][1][j + PMI_SEL_PRECISION * 2]), + cimagf(h[1][1][j + PMI_SEL_PRECISION * 2]), + crealf(h[1][1][j + PMI_SEL_PRECISION * 3]), + cimagf(h[1][1][j + PMI_SEL_PRECISION * 3])); + + /* 1. B = W'* H' */ + __m256 a0, a1; + switch (i) { + case 0: + a0 = _mm256_add_ps(_MM256_CONJ_PS(h00), _MM256_CONJ_PS(h01)); + a1 = _mm256_add_ps(_MM256_CONJ_PS(h10), _MM256_CONJ_PS(h11)); + break; + case 1: + a0 = _mm256_sub_ps(_MM256_CONJ_PS(h00), _MM256_CONJ_PS(h01)); + a1 = _mm256_sub_ps(_MM256_CONJ_PS(h10), _MM256_CONJ_PS(h11)); + break; + case 2: + a0 = _mm256_add_ps(_MM256_CONJ_PS(h00), _MM256_MULJ_PS(_MM256_CONJ_PS(h01))); + a1 = _mm256_add_ps(_MM256_CONJ_PS(h10), _MM256_MULJ_PS(_MM256_CONJ_PS(h11))); + break; + default: + a0 = _mm256_sub_ps(_MM256_CONJ_PS(h00), _MM256_MULJ_PS(_MM256_CONJ_PS(h01))); + a1 = _mm256_sub_ps(_MM256_CONJ_PS(h10), _MM256_MULJ_PS(_MM256_CONJ_PS(h11))); + break; + } + + /* 2. B = W' * H' * H = A * H */ +#ifdef LV_HAVE_FMA + __m256 b0 = _MM256_PROD_ADD_PS(a0, h00, _MM256_PROD_PS(a1, h10)); + __m256 b1 = _MM256_PROD_ADD_PS(a0, h01, _MM256_PROD_PS(a1, h11)); +#else + __m256 b0 = _mm256_add_ps(_MM256_PROD_PS(a0, h00), _MM256_PROD_PS(a1, h10)); + __m256 b1 = _mm256_add_ps(_MM256_PROD_PS(a0, h01), _MM256_PROD_PS(a1, h11)); +#endif /* LV_HAVE_FMA */ + + /* 3. C = W' * H' * H * W' = B * W */ + __m256 c; + switch (i) { + case 0: + c = _mm256_add_ps(b0, b1); + break; + case 1: + c = _mm256_sub_ps(b0, b1); + break; + case 2: + c = _mm256_sub_ps(b0, _MM256_MULJ_PS(b1)); + break; + case 3: + c = _mm256_add_ps(b0, _MM256_MULJ_PS(b1)); + break; + default: + return SRSLTE_ERROR; + } + c = _mm256_mul_ps(c, avx_norm); + + /* Add for averaging */ + __attribute__((aligned(256))) float gamma[8]; + _mm256_store_ps(gamma, c); + sinr_list[i] += gamma[0] + gamma[2] + gamma[4] + gamma[6]; + + count += 4; + } + + /* Divide average by noise */ + sinr_list[i] /= noise_estimate * count; + + if (sinr_list[i] > max_sinr) { + max_sinr = sinr_list[i]; + *pmi = i; + } + } + + return i; +} + +#endif /* LV_HAVE_AVX */ + +int srslte_precoding_pmi_select_1l(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], uint32_t nof_symbols, + float noise_estimate, uint32_t *pmi, + float sinr_list[SRSLTE_MAX_CODEBOOKS]) { + int ret; +#ifdef LV_HAVE_AVX + ret = srslte_precoding_pmi_select_1l_avx(h, nof_symbols, noise_estimate, pmi, sinr_list); +#else + #ifdef LV_HAVE_SSE + ret = srslte_precoding_pmi_select_1l_sse(h, nof_symbols, noise_estimate, pmi, sinr_list); +#else + ret = srslte_precoding_pmi_select_1l_gen(h, nof_symbols, noise_estimate, pmi, sinr_list); +#endif +#endif + INFO("Precoder PMI Select for 1 layer SINR=[%.1fdB; %.1fdB; %.1fdB; %.1fdB] PMI=%d\n", 10 * log10(sinr_list[0]), + 10 * log10(sinr_list[1]), 10 * log10(sinr_list[2]), 10 * log10(sinr_list[3]), *pmi); + + return ret; +} + +int srslte_precoding_pmi_select_2l_gen(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], uint32_t nof_symbols, + float noise_estimate, uint32_t *pmi, + float sinr_list[SRSLTE_MAX_CODEBOOKS]) { + + float max_sinr = 0.0; + uint32_t i, count; + + for (i = 0; i < 2; i++) { + sinr_list[i] = 0; + count = 0; + + for (uint32_t j = 0; j < nof_symbols; j += PMI_SEL_PRECISION) { + /* 0. Load channel matrix */ + cf_t h00 = h[0][0][j]; + cf_t h01 = h[1][0][j]; + cf_t h10 = h[0][1][j]; + cf_t h11 = h[1][1][j]; + + /* 1. B = W'* H' */ + cf_t a00, a01, a10, a11; + switch (i) { + case 0: + a00 = conjf(h00) + conjf(h01); + a01 = conjf(h10) + conjf(h11); + a10 = conjf(h00) - conjf(h01); + a11 = conjf(h10) - conjf(h11); + break; + case 1: + a00 = conjf(h00) - _Complex_I * conjf(h01); + a01 = conjf(h10) - _Complex_I * conjf(h11); + a10 = conjf(h00) + _Complex_I * conjf(h01); + a11 = conjf(h10) + _Complex_I * conjf(h11); + break; + default: + return SRSLTE_ERROR; + } + + /* 2. B = W' * H' * H = A * H */ + cf_t b00 = a00 * h00 + a01 * h10; + cf_t b01 = a00 * h01 + a01 * h11; + cf_t b10 = a10 * h00 + a11 * h10; + cf_t b11 = a10 * h01 + a11 * h11; + + /* 3. C = W' * H' * H * W' = B * W */ + cf_t c00, c01, c10, c11; + switch (i) { + case 0: + c00 = b00 + b01; + c01 = b00 - b01; + c10 = b10 + b11; + c11 = b10 - b11; + break; + case 1: + c00 = b00 + _Complex_I * b01; + c01 = b00 - _Complex_I * b01; + c10 = b10 + _Complex_I * b11; + c11 = b10 - _Complex_I * b11; + break; + default: + return SRSLTE_ERROR; + } + c00 *= 0.25; + c01 *= 0.25; + c10 *= 0.25; + c11 *= 0.25; + + /* 4. C += noise * I */ + c00 += noise_estimate; + c11 += noise_estimate; + + /* 5. detC */ + cf_t detC = c00 * c11 - c01 * c10; + cf_t inv_detC = conjf(detC) / (crealf(detC) * crealf(detC) + cimagf(detC) * cimagf(detC)); + + cf_t den0 = noise_estimate * c00 * inv_detC; + cf_t den1 = noise_estimate * c11 * inv_detC; + + float gamma0 = crealf((conjf(den0) / (crealf(den0) * crealf(den0) + cimagf(den0) * cimagf(den0))) - 1); + float gamma1 = crealf((conjf(den1) / (crealf(den1) * crealf(den1) + cimagf(den1) * cimagf(den1))) - 1); + + /* Add for averaging */ + sinr_list[i] += (gamma0 + gamma1); + + count++; + } + + /* Divide average by noise */ + sinr_list[i] /= (2 * count); + + if (sinr_list[i] > max_sinr) { + max_sinr = sinr_list[i]; + *pmi = i; + } + } + + return i; +} + +#ifdef LV_HAVE_SSE + +int srslte_precoding_pmi_select_2l_sse(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], uint32_t nof_symbols, + float noise_estimate, uint32_t *pmi, + float sinr_list[SRSLTE_MAX_CODEBOOKS]) { + + float max_sinr = 0.0; + uint32_t i, count; + + __m128 sse_noise_estimate = (__m128) {noise_estimate, 0.0f, noise_estimate, 0.0f}; + + for (i = 0; i < 2; i++) { + sinr_list[i] = 0; + count = 0; + + for (uint32_t j = 0; j < nof_symbols - PMI_SEL_PRECISION * 2 + 1; j += PMI_SEL_PRECISION * 2) { + /* 0. Load channel matrix */ + __m128 h00 = _mm_set_ps(crealf(h[0][0][j]), + cimagf(h[0][0][j]), + crealf(h[0][0][j + PMI_SEL_PRECISION]), + cimagf(h[0][0][j + PMI_SEL_PRECISION])); + __m128 h01 = _mm_set_ps(crealf(h[1][0][j]), + cimagf(h[1][0][j]), + crealf(h[1][0][j + PMI_SEL_PRECISION]), + cimagf(h[1][0][j + PMI_SEL_PRECISION])); + __m128 h10 = _mm_set_ps(crealf(h[0][1][j]), + cimagf(h[0][1][j]), + crealf(h[0][1][j + PMI_SEL_PRECISION]), + cimagf(h[0][1][j + PMI_SEL_PRECISION])); + __m128 h11 = _mm_set_ps(crealf(h[1][1][j]), + cimagf(h[1][1][j]), + crealf(h[1][1][j + PMI_SEL_PRECISION]), + cimagf(h[1][1][j + PMI_SEL_PRECISION])); + + /* 1. B = W'* H' */ + __m128 a00, a01, a10, a11; + switch (i) { + case 0: + a00 = _mm_add_ps(_MM_CONJ_PS(h00), _MM_CONJ_PS(h01)); + a01 = _mm_add_ps(_MM_CONJ_PS(h10), _MM_CONJ_PS(h11)); + a10 = _mm_sub_ps(_MM_CONJ_PS(h00), _MM_CONJ_PS(h01)); + a11 = _mm_sub_ps(_MM_CONJ_PS(h10), _MM_CONJ_PS(h11)); + break; + case 1: + a00 = _mm_sub_ps(_MM_CONJ_PS(h00), _MM_MULJ_PS(_MM_CONJ_PS(h01))); + a01 = _mm_sub_ps(_MM_CONJ_PS(h10), _MM_MULJ_PS(_MM_CONJ_PS(h11))); + a10 = _mm_add_ps(_MM_CONJ_PS(h00), _MM_MULJ_PS(_MM_CONJ_PS(h01))); + a11 = _mm_add_ps(_MM_CONJ_PS(h10), _MM_MULJ_PS(_MM_CONJ_PS(h11))); + break; + default: + return SRSLTE_ERROR; + } + + /* 2. B = W' * H' * H = A * H */ + __m128 b00 = _mm_add_ps(_MM_PROD_PS(a00, h00), _MM_PROD_PS(a01, h10)); + __m128 b01 = _mm_add_ps(_MM_PROD_PS(a00, h01), _MM_PROD_PS(a01, h11)); + __m128 b10 = _mm_add_ps(_MM_PROD_PS(a10, h00), _MM_PROD_PS(a11, h10)); + __m128 b11 = _mm_add_ps(_MM_PROD_PS(a10, h01), _MM_PROD_PS(a11, h11)); + + /* 3. C = W' * H' * H * W' = B * W */ + __m128 c00, c01, c10, c11; + switch (i) { + case 0: + c00 = _mm_add_ps(b00, b01); + c01 = _mm_sub_ps(b00, b01); + c10 = _mm_add_ps(b10, b11); + c11 = _mm_sub_ps(b10, b11); + break; + case 1: + c00 = _mm_add_ps(b00, _MM_MULJ_PS(b01)); + c01 = _mm_sub_ps(b00, _MM_MULJ_PS(b01)); + c10 = _mm_add_ps(b10, _MM_MULJ_PS(b11)); + c11 = _mm_sub_ps(b10, _MM_MULJ_PS(b11)); + break; + default: + return SRSLTE_ERROR; + } + c00 = _mm_mul_ps(c00, _mm_set1_ps(0.25f)); + c01 = _mm_mul_ps(c01, _mm_set1_ps(0.25f)); + c10 = _mm_mul_ps(c10, _mm_set1_ps(0.25f)); + c11 = _mm_mul_ps(c11, _mm_set1_ps(0.25f)); + + /* 4. C += noise * I */ + c00 = _mm_add_ps(c00, sse_noise_estimate); + c11 = _mm_add_ps(c11, sse_noise_estimate); + + /* 5. detC */ + __m128 detC = _mm_sub_ps(_MM_PROD_PS(c00, c11), _MM_PROD_PS(c01, c10)); + __m128 inv_detC = srslte_algebra_cf_recip_sse(detC); + + __m128 den0 = _MM_PROD_PS(c00, inv_detC); + __m128 den1 = _MM_PROD_PS(c11, inv_detC); + + __m128 gamma0 = _mm_sub_ps(srslte_algebra_cf_recip_sse(den0), _mm_set1_ps(1.0f)); + __m128 gamma1 = _mm_sub_ps(srslte_algebra_cf_recip_sse(den1), _mm_set1_ps(1.0f)); + + /* Add for averaging */ + __m128 sum = _MM_SWAP(_mm_add_ps(gamma0, gamma1)); + __m128 sinr_sse = _mm_hadd_ps(sum, sum); + __attribute__((aligned(128))) float sinr[4]; + _mm_store_ps(sinr, sinr_sse); + + sinr_list[i] += sinr[0]; + + count += 2; + } + + /* Divide average by noise */ + sinr_list[i] /= (2 * count * noise_estimate); + + if (sinr_list[i] > max_sinr) { + max_sinr = sinr_list[i]; + *pmi = i; + } + } + + return i; +} + +#endif /* LV_HAVE_SSE */ + +#ifdef LV_HAVE_AVX + +int srslte_precoding_pmi_select_2l_avx(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], uint32_t nof_symbols, + float noise_estimate, uint32_t *pmi, + float sinr_list[SRSLTE_MAX_CODEBOOKS]) { + + float max_sinr = 0.0; + uint32_t i, count; + + __m256 avx_noise_estimate = _mm256_setr_ps(noise_estimate, 0.0f, noise_estimate, 0.0f, + noise_estimate, 0.0f, noise_estimate, 0.0f); + __m256 avx_norm = _mm256_set1_ps(0.5f); + __m256 avx_ones = _mm256_set1_ps(1.0f); + + for (i = 0; i < 2; i++) { + sinr_list[i] = 0; + count = 0; + + for (uint32_t j = 0; j < nof_symbols - PMI_SEL_PRECISION * 4 + 1; j += PMI_SEL_PRECISION * 4) { + /* 0. Load channel matrix */ + __m256 h00 = _mm256_set_ps(crealf(h[0][0][j]), + cimagf(h[0][0][j]), + crealf(h[0][0][j + PMI_SEL_PRECISION]), + cimagf(h[0][0][j + PMI_SEL_PRECISION]), + crealf(h[0][0][j + PMI_SEL_PRECISION * 2]), + cimagf(h[0][0][j + PMI_SEL_PRECISION * 2]), + crealf(h[0][0][j + PMI_SEL_PRECISION * 3]), + cimagf(h[0][0][j + PMI_SEL_PRECISION * 3])); + __m256 h01 = _mm256_set_ps(crealf(h[1][0][j]), + cimagf(h[1][0][j]), + crealf(h[1][0][j + PMI_SEL_PRECISION]), + cimagf(h[1][0][j + PMI_SEL_PRECISION]), + crealf(h[1][0][j + PMI_SEL_PRECISION * 2]), + cimagf(h[1][0][j + PMI_SEL_PRECISION * 2]), + crealf(h[1][0][j + PMI_SEL_PRECISION * 3]), + cimagf(h[1][0][j + PMI_SEL_PRECISION * 3])); + __m256 h10 = _mm256_set_ps(crealf(h[0][1][j]), + cimagf(h[0][1][j]), + crealf(h[0][1][j + PMI_SEL_PRECISION]), + cimagf(h[0][1][j + PMI_SEL_PRECISION]), + crealf(h[0][1][j + PMI_SEL_PRECISION * 2]), + cimagf(h[0][1][j + PMI_SEL_PRECISION * 2]), + crealf(h[0][1][j + PMI_SEL_PRECISION * 3]), + cimagf(h[0][1][j + PMI_SEL_PRECISION * 3])); + __m256 h11 = _mm256_set_ps(crealf(h[1][1][j]), + cimagf(h[1][1][j]), + crealf(h[1][1][j + PMI_SEL_PRECISION]), + cimagf(h[1][1][j + PMI_SEL_PRECISION]), + crealf(h[1][1][j + PMI_SEL_PRECISION * 2]), + cimagf(h[1][1][j + PMI_SEL_PRECISION * 2]), + crealf(h[1][1][j + PMI_SEL_PRECISION * 3]), + cimagf(h[1][1][j + PMI_SEL_PRECISION * 3])); + + /* 1. B = W'* H' */ + __m256 a00, a01, a10, a11; + switch (i) { + case 0: + a00 = _mm256_add_ps(_MM256_CONJ_PS(h00), _MM256_CONJ_PS(h01)); + a01 = _mm256_add_ps(_MM256_CONJ_PS(h10), _MM256_CONJ_PS(h11)); + a10 = _mm256_sub_ps(_MM256_CONJ_PS(h00), _MM256_CONJ_PS(h01)); + a11 = _mm256_sub_ps(_MM256_CONJ_PS(h10), _MM256_CONJ_PS(h11)); + break; + case 1: + a00 = _mm256_sub_ps(_MM256_CONJ_PS(h00), _MM256_MULJ_PS(_MM256_CONJ_PS(h01))); + a01 = _mm256_sub_ps(_MM256_CONJ_PS(h10), _MM256_MULJ_PS(_MM256_CONJ_PS(h11))); + a10 = _mm256_add_ps(_MM256_CONJ_PS(h00), _MM256_MULJ_PS(_MM256_CONJ_PS(h01))); + a11 = _mm256_add_ps(_MM256_CONJ_PS(h10), _MM256_MULJ_PS(_MM256_CONJ_PS(h11))); + break; + default: + return SRSLTE_ERROR; + } + a00 = _mm256_mul_ps(a00, avx_norm); + a01 = _mm256_mul_ps(a01, avx_norm); + a10 = _mm256_mul_ps(a10, avx_norm); + a11 = _mm256_mul_ps(a11, avx_norm); + + /* 2. B = W' * H' * H = A * H */ +#ifdef LV_HAVE_FMA + __m256 b00 = _MM256_PROD_ADD_PS(a00, h00, _MM256_PROD_PS(a01, h10)); + __m256 b01 = _MM256_PROD_ADD_PS(a00, h01, _MM256_PROD_PS(a01, h11)); + __m256 b10 = _MM256_PROD_ADD_PS(a10, h00, _MM256_PROD_PS(a11, h10)); + __m256 b11 = _MM256_PROD_ADD_PS(a10, h01, _MM256_PROD_PS(a11, h11)); +#else + __m256 b00 = _mm256_add_ps(_MM256_PROD_PS(a00, h00), _MM256_PROD_PS(a01, h10)); + __m256 b01 = _mm256_add_ps(_MM256_PROD_PS(a00, h01), _MM256_PROD_PS(a01, h11)); + __m256 b10 = _mm256_add_ps(_MM256_PROD_PS(a10, h00), _MM256_PROD_PS(a11, h10)); + __m256 b11 = _mm256_add_ps(_MM256_PROD_PS(a10, h01), _MM256_PROD_PS(a11, h11)); +#endif /* LV_HAVE_FMA */ + + /* 3. C = W' * H' * H * W' = B * W */ + __m256 c00, c01, c10, c11; + switch (i) { + case 0: + c00 = _mm256_add_ps(b00, b01); + c01 = _mm256_sub_ps(b00, b01); + c10 = _mm256_add_ps(b10, b11); + c11 = _mm256_sub_ps(b10, b11); + break; + case 1: + c00 = _mm256_add_ps(b00, _MM256_MULJ_PS(b01)); + c01 = _mm256_sub_ps(b00, _MM256_MULJ_PS(b01)); + c10 = _mm256_add_ps(b10, _MM256_MULJ_PS(b11)); + c11 = _mm256_sub_ps(b10, _MM256_MULJ_PS(b11)); + break; + default: + return SRSLTE_ERROR; + } + c00 = _mm256_mul_ps(c00, avx_norm); + c01 = _mm256_mul_ps(c01, avx_norm); + c10 = _mm256_mul_ps(c10, avx_norm); + c11 = _mm256_mul_ps(c11, avx_norm); + + /* 4. C += noise * I */ + c00 = _mm256_add_ps(c00, avx_noise_estimate); + c11 = _mm256_add_ps(c11, avx_noise_estimate); + + /* 5. detC */ +#ifdef LV_HAVE_FMA + __m256 detC = _MM256_PROD_SUB_PS(c00, c11, _MM256_PROD_PS(c01, c10)); +#else + __m256 detC = _mm256_sub_ps(_MM256_PROD_PS(c00, c11), _MM256_PROD_PS(c01, c10)); +#endif /* LV_HAVE_FMA */ + __m256 inv_detC = srslte_algebra_cf_recip_avx(detC); + + __m256 den0 = _MM256_PROD_PS(c00, inv_detC); + __m256 den1 = _MM256_PROD_PS(c11, inv_detC); + + __m256 gamma0 = _mm256_sub_ps(srslte_algebra_cf_recip_avx(den0), avx_ones); + __m256 gamma1 = _mm256_sub_ps(srslte_algebra_cf_recip_avx(den1), avx_ones); + + /* Add for averaging */ + __m256 sinr_avx = _mm256_permute_ps(_mm256_add_ps(gamma0, gamma1), 0b00101000); + __attribute__((aligned(256))) float sinr[8]; + _mm256_store_ps(sinr, sinr_avx); + + sinr_list[i] += sinr[0] + sinr[2] + sinr[4] + sinr[6]; + + count += 4; + } + + /* Divide average by noise */ + sinr_list[i] /= 2 * count * noise_estimate; + + if (sinr_list[i] > max_sinr) { + max_sinr = sinr_list[i]; + *pmi = i; + } + } + + return i; +} + +#endif /* LV_HAVE_AVX */ + +/* PMI Select for 2 layers */ +int srslte_precoding_pmi_select_2l(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], uint32_t nof_symbols, + float noise_estimate, uint32_t *pmi, + float sinr_list[SRSLTE_MAX_CODEBOOKS]) { + + int ret; +#ifdef LV_HAVE_AVX + ret = srslte_precoding_pmi_select_2l_avx(h, nof_symbols, noise_estimate, pmi, sinr_list); +#else + #ifdef LV_HAVE_SSE + ret = srslte_precoding_pmi_select_2l_sse(h, nof_symbols, noise_estimate, pmi, sinr_list); +#else + ret = srslte_precoding_pmi_select_2l_gen(h, nof_symbols, noise_estimate, pmi, sinr_list); +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX */ + + INFO("Precoder PMI Select for 2 layers SINR=[%.1fdB; %.1fdB] PMI=%d\n", 10 * log10(sinr_list[0]), + 10 * log10(sinr_list[1]), *pmi); + + return ret; +} + +int srslte_precoding_pmi_select(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], uint32_t nof_symbols, + float noise_estimate, int nof_layers, uint32_t *pmi, + float sinr[SRSLTE_MAX_CODEBOOKS]) { + int ret; + + if (sinr == NULL || pmi == NULL) { + ERROR("Null pointer"); + ret = SRSLTE_ERROR_INVALID_INPUTS; + } else if (nof_layers == 1) { + ret = srslte_precoding_pmi_select_1l(h, nof_symbols, noise_estimate, pmi, sinr); + } else if (nof_layers == 2) { + ret = srslte_precoding_pmi_select_2l(h, nof_symbols, noise_estimate, pmi, sinr); + } else { + ERROR("Wrong number of layers"); + ret = SRSLTE_ERROR_INVALID_INPUTS; + } + + return ret; +} diff --git a/lib/src/phy/mimo/test/CMakeLists.txt b/lib/src/phy/mimo/test/CMakeLists.txt index e0894a24d..2397bfc49 100644 --- a/lib/src/phy/mimo/test/CMakeLists.txt +++ b/lib/src/phy/mimo/test/CMakeLists.txt @@ -52,14 +52,21 @@ 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) -add_test(precoding_cdd_2x2 precoding_test -m cdd -l 2 -p 2 -r 2 -n 14000) +add_test(precoding_cdd_2x2_zf precoding_test -m cdd -l 2 -p 2 -r 2 -n 14000 -d zf) +add_test(precoding_cdd_2x2_mmse precoding_test -m cdd -l 2 -p 2 -r 2 -n 14000 -d mmse) add_test(precoding_multiplex_1l_cb0 precoding_test -m multiplex -l 1 -p 2 -r 2 -n 14000 -c 0) add_test(precoding_multiplex_1l_cb1 precoding_test -m multiplex -l 1 -p 2 -r 2 -n 14000 -c 1) add_test(precoding_multiplex_1l_cb2 precoding_test -m multiplex -l 1 -p 2 -r 2 -n 14000 -c 2) add_test(precoding_multiplex_1l_cb3 precoding_test -m multiplex -l 1 -p 2 -r 2 -n 14000 -c 3) -add_test(precoding_multiplex_2l_cb0 precoding_test -m multiplex -l 2 -p 2 -r 2 -n 14000 -c 0) -add_test(precoding_multiplex_2l_cb1 precoding_test -m multiplex -l 2 -p 2 -r 2 -n 14000 -c 1) -add_test(precoding_multiplex_2l_cb2 precoding_test -m multiplex -l 2 -p 2 -r 2 -n 14000 -c 2) +add_test(precoding_multiplex_2l_cb0_zf precoding_test -m multiplex -l 2 -p 2 -r 2 -n 14000 -c 0 -d zf) +add_test(precoding_multiplex_2l_cb1_zf precoding_test -m multiplex -l 2 -p 2 -r 2 -n 14000 -c 1 -d zf) +add_test(precoding_multiplex_2l_cb2_zf precoding_test -m multiplex -l 2 -p 2 -r 2 -n 14000 -c 2 -d zf) + + +add_test(precoding_multiplex_2l_cb0_mmse precoding_test -m multiplex -l 2 -p 2 -r 2 -n 14000 -c 0 -d mmse) +add_test(precoding_multiplex_2l_cb1_mmse precoding_test -m multiplex -l 2 -p 2 -r 2 -n 14000 -c 1 -d mmse) +add_test(precoding_multiplex_2l_cb2_mmse precoding_test -m multiplex -l 2 -p 2 -r 2 -n 14000 -c 2 -d mmse) + diff --git a/lib/src/phy/mimo/test/precoder_test.c b/lib/src/phy/mimo/test/precoder_test.c index bc23004f1..1bbd9e3c0 100644 --- a/lib/src/phy/mimo/test/precoder_test.c +++ b/lib/src/phy/mimo/test/precoder_test.c @@ -34,6 +34,7 @@ #include #include "srslte/srslte.h" +#include "srslte/phy/channel/ch_awgn.h" #define MSE_THRESHOLD 0.0005 @@ -41,18 +42,24 @@ int nof_symbols = 1000; uint32_t codebook_idx = 0; int nof_layers = 1, nof_tx_ports = 1, nof_rx_ports = 1, nof_re = 1; char *mimo_type_name = NULL; +char decoder_type_name [16] = "zf"; +float snr_db = 100.0f; void usage(char *prog) { printf( "Usage: %s -m [single|diversity|multiplex|cdd] -l [nof_layers] -p [nof_tx_ports]\n" " -r [nof_rx_ports]\n", prog); printf("\t-n num_symbols [Default %d]\n", nof_symbols); - printf("\t-c codebook_idx [Default %d]\n\n", codebook_idx); + printf("\t-c codebook_idx [Default %d]\n", codebook_idx); + printf("\t-s SNR in dB [Default %.1fdB]*\n", snr_db); + printf("\t-d decoder type [zf|mmse] [Default %s]\n", decoder_type_name); + printf("\n"); + printf("* Performance test example:\n\t for snr in {0..20..1}; do ./precoding_test -m single -s $snr; done; \n\n", decoder_type_name); } void parse_args(int argc, char **argv) { int opt; - while ((opt = getopt(argc, argv, "mplnrc")) != -1) { + while ((opt = getopt(argc, argv, "mplnrcds")) != -1) { switch (opt) { case 'n': nof_symbols = atoi(argv[optind]); @@ -72,6 +79,12 @@ void parse_args(int argc, char **argv) { case 'c': codebook_idx = (uint32_t) atoi(argv[optind]); break; + case 'd': + strncpy(decoder_type_name, argv[optind], 16); + break; + case 's': + snr_db = (float) atof(argv[optind]); + break; default: usage(argv[0]); exit(-1); @@ -134,8 +147,17 @@ void populate_channel(srslte_mimo_type_t type, cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_ } } +static void awgn(cf_t *y[SRSLTE_MAX_PORTS], uint32_t n, float snr) { + int i; + float std_dev = powf(10, - (snr + 3.0f) / 20.0f); + + for (i = 0; i < nof_rx_ports; i++) { + srslte_ch_awgn_c(y[i], y[i], std_dev, n); + } +} + int main(int argc, char **argv) { - int i, j, k; + int i, j, k, nof_errors = 0, ret = SRSLTE_SUCCESS; float mse; cf_t *x[SRSLTE_MAX_LAYERS], *r[SRSLTE_MAX_PORTS], *y[SRSLTE_MAX_PORTS], *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], *xr[SRSLTE_MAX_LAYERS]; @@ -247,27 +269,48 @@ int main(int argc, char **argv) { } } + awgn(r, (uint32_t) nof_re, snr_db); + + /* If CDD or Spatial muliplex choose decoder */ + if (strncmp(decoder_type_name, "zf", 16) == 0) { + srslte_predecoding_set_mimo_decoder(SRSLTE_MIMO_DECODER_ZF); + } else if (strncmp(decoder_type_name, "mmse", 16) == 0) { + srslte_predecoding_set_mimo_decoder(SRSLTE_MIMO_DECODER_MMSE); + } else { + ret = SRSLTE_ERROR; + goto quit; + } + + /* predecoding / equalization */ struct timeval t[3]; gettimeofday(&t[1], NULL); srslte_predecoding_type_multi(r, h, xr, nof_rx_ports, nof_tx_ports, nof_layers, - codebook_idx, nof_re, type, 0); + codebook_idx, nof_re, type, powf(10, -snr_db/10)); gettimeofday(&t[2], NULL); get_time_interval(t); - printf("Execution Time: %ld us\n", t[0].tv_usec); - + /* check errors */ mse = 0; for (i = 0; i < nof_layers; i++) { for (j = 0; j < nof_symbols; j++) { mse += cabsf(xr[i][j] - x[i][j]); + + if ((crealf(xr[i][j]) > 0) != (crealf(x[i][j]) > 0)) { + nof_errors ++; + } + if ((cimagf(xr[i][j]) > 0) != (cimagf(x[i][j]) > 0)) { + nof_errors ++; + } } } - printf("MSE: %f\n", mse/ nof_layers / nof_symbols ); + printf("SNR: %5.1fdB;\tExecution time: %5ldus;\tMSE: %.6f;\tBER: %.6f\n", snr_db, t[0].tv_usec, + mse / nof_layers / nof_symbols, (float) nof_errors / (4.0f * nof_re)); if (mse / nof_layers / nof_symbols > MSE_THRESHOLD) { - exit(-1); + ret = SRSLTE_ERROR; } + quit: /* Free all data */ for (i = 0; i < nof_layers; i++) { free(x[i]); @@ -284,6 +327,5 @@ int main(int argc, char **argv) { } } - printf("Ok\n"); - exit(0); + exit(ret); } diff --git a/lib/src/phy/mimo/test/predecoder_mex.c b/lib/src/phy/mimo/test/predecoder_mex.c index e04b390d0..0465e1ef4 100644 --- a/lib/src/phy/mimo/test/predecoder_mex.c +++ b/lib/src/phy/mimo/test/predecoder_mex.c @@ -35,8 +35,10 @@ #define HEST prhs[1] #define NEST prhs[2] #define NLAYERS prhs[3] -#define TXSCHEME prhs[4] -#define NOF_INPUTS 5 +#define NCW prhs[4] +#define TXSCHEME prhs[5] +#define CODEBOOK prhs[6] +#define NOF_INPUTS 7 void help() @@ -58,6 +60,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) uint32_t nof_layers; uint32_t nof_tx_ports = 1; uint32_t nof_codewords = 1; + uint32_t codebook_idx = 0; float noise_estimate = 0; cf_t *x[SRSLTE_MAX_LAYERS]; cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; @@ -81,6 +84,9 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) /* Read number of layers */ nof_layers = (uint32_t) mxGetScalar(NLAYERS); + /* Read number of codewords */ + nof_codewords = (uint32_t) mxGetScalar(NCW); + if (nof_layers > SRSLTE_MAX_LAYERS) { mexErrMsgTxt("Too many layers\n"); return; @@ -109,7 +115,8 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) } /* Print parameters trace */ - mexPrintf("nof_tx_ports=%d, nof_rx_ants=%d, nof_layers=%d, nof_symbols=%d\n", nof_tx_ports, nof_rx_ants, nof_layers, nof_symbols); + mexPrintf("nof_tx_ports=%d, nof_rx_ants=%d, nof_layers=%d, nof_codewords=%d, codebook_idx=%d, nof_symbols=%d\n", + nof_tx_ports, nof_rx_ants, nof_layers, nof_codewords, codebook_idx, nof_symbols); /* Read noise estimate */ if (nrhs >= NOF_INPUTS) { @@ -134,7 +141,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) /* Allocate memory for intermediate data */ for (i = 0; i < nof_tx_ports; i++) { - x[i] = srslte_vec_malloc(sizeof(cf_t) * nof_symbols); + x[i] = srslte_vec_malloc(sizeof(cf_t) * nof_symbols*nof_layers); } /* Allocate memory for channel estimate */ @@ -155,15 +162,9 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) mxGetString_700(TXSCHEME, txscheme, 32); } - 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 { + codebook_idx = (uint32_t) mxGetScalar(CODEBOOK); + + if (srslte_str2mimotype(txscheme, &type)) { mexPrintf("Unsupported TxScheme=%s\n", txscheme); return; } @@ -176,18 +177,19 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) /* Set output pointer */ cf_t *d[SRSLTE_MAX_CODEWORDS]; for (i = 0; i= 1) { - mexutils_write_cf(output, &plhs[0], nof_symbols*nof_layers*nof_rx_ants/nof_tx_ports, 1); + mexutils_write_cf(output, &plhs[0], nof_symbols, nof_codewords); } /* Free memory */ From 48d508aeba681f57796acea2ad631261686e0c43 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Thu, 17 Aug 2017 10:19:19 +0200 Subject: [PATCH 09/60] Added srs_lte_cpy for aligned copy which improves a bit performance for aligned data --- lib/include/srslte/phy/utils/vector.h | 3 +++ lib/src/phy/mimo/layermap.c | 8 +++++++- lib/src/phy/mimo/test/layermap_test.c | 6 +++--- lib/src/phy/utils/vector.c | 21 +++++++++++++++++++++ 4 files changed, 34 insertions(+), 4 deletions(-) diff --git a/lib/include/srslte/phy/utils/vector.h b/lib/include/srslte/phy/utils/vector.h index 74cd60172..c8d8d1942 100644 --- a/lib/include/srslte/phy/utils/vector.h +++ b/lib/include/srslte/phy/utils/vector.h @@ -172,6 +172,9 @@ SRSLTE_API void srslte_vec_abs_square_cf(cf_t *x, float *abs_square, uint32_t le /* argument of each vector element */ SRSLTE_API void srslte_vec_arg_cf(cf_t *x, float *arg, uint32_t len); +/* Copy 256 bit aligned vector */ +SRSLTE_API void srs_vec_cf_cpy(cf_t *src, cf_t *dst, int len); + #ifdef __cplusplus } #endif diff --git a/lib/src/phy/mimo/layermap.c b/lib/src/phy/mimo/layermap.c index 868bf2f6a..a5bfc8b92 100644 --- a/lib/src/phy/mimo/layermap.c +++ b/lib/src/phy/mimo/layermap.c @@ -28,6 +28,7 @@ #include #include #include +#include #include "srslte/phy/common/phy_common.h" #include "srslte/phy/mimo/layermap.h" @@ -51,7 +52,12 @@ int srslte_layermap_diversity(cf_t *d, cf_t *x[SRSLTE_MAX_LAYERS], int nof_layer int srslte_layermap_multiplex(cf_t *d[SRSLTE_MAX_CODEWORDS], cf_t *x[SRSLTE_MAX_LAYERS], int nof_cw, int nof_layers, int nof_symbols[SRSLTE_MAX_CODEWORDS]) { - if (nof_cw == 1) { + if (nof_cw == nof_layers) { + for (int i = 0; i < nof_cw; i++) { + srs_vec_cf_cpy(x[i], d[i], (uint32_t) nof_symbols[0]); + } + return nof_symbols[0]; + } else if (nof_cw == 1) { return srslte_layermap_diversity(d[0], x, nof_layers, nof_symbols[0]); } else { int n[2]; diff --git a/lib/src/phy/mimo/test/layermap_test.c b/lib/src/phy/mimo/test/layermap_test.c index 6fcc72682..6f026f9d0 100644 --- a/lib/src/phy/mimo/test/layermap_test.c +++ b/lib/src/phy/mimo/test/layermap_test.c @@ -96,19 +96,19 @@ int main(int argc, char **argv) { } for (i=0;i Date: Thu, 17 Aug 2017 10:23:03 +0200 Subject: [PATCH 10/60] Scalable PDSCH with MAX_CODEWORDS PDSCH plus decoding threads for bitrate increase --- lib/examples/cell_measurement.c | 2 +- lib/examples/pdsch_ue.c | 2 +- lib/include/srslte/phy/phch/pdsch.h | 68 ++- lib/include/srslte/phy/phch/ra.h | 7 + lib/include/srslte/phy/phch/sch.h | 7 + lib/include/srslte/phy/ue/ue_dl.h | 7 +- lib/include/srslte/phy/utils/debug.h | 7 +- lib/src/phy/phch/pdsch.c | 530 +++++++++++------- lib/src/phy/phch/sch.c | 35 +- lib/src/phy/phch/test/dlsch_encode_test_mex.c | 8 +- lib/src/phy/phch/test/pdsch_test.c | 27 +- lib/src/phy/phch/test/pdsch_test_mex.c | 6 +- lib/src/phy/ue/ue_dl.c | 8 +- srsue/src/phy/phch_worker.cc | 2 +- 14 files changed, 485 insertions(+), 231 deletions(-) diff --git a/lib/examples/cell_measurement.c b/lib/examples/cell_measurement.c index 9c7856daa..90b963db8 100644 --- a/lib/examples/cell_measurement.c +++ b/lib/examples/cell_measurement.c @@ -320,7 +320,7 @@ int main(int argc, char **argv) { } else if (n == 0) { printf("CFO: %+6.4f kHz, SFO: %+6.4f kHz, NOI: %.2f, PDCCH-Det: %.3f\r", srslte_ue_sync_get_cfo(&ue_sync)/1000, srslte_ue_sync_get_sfo(&ue_sync)/1000, - srslte_sch_average_noi(&ue_dl.pdsch.dl_sch), + srslte_pdsch_average_noi(&ue_dl.pdsch), (float) ue_dl.nof_detected/nof_trials); nof_trials++; } else { diff --git a/lib/examples/pdsch_ue.c b/lib/examples/pdsch_ue.c index 1c6059d9f..24bdba55b 100644 --- a/lib/examples/pdsch_ue.c +++ b/lib/examples/pdsch_ue.c @@ -846,7 +846,7 @@ void *plot_thread_run(void *arg) { plot_scatter_setNewData(&pscatequal_pdcch, ue_dl.pdcch.d, 36*ue_dl.pdcch.nof_cce); } - plot_scatter_setNewData(&pscatequal, ue_dl.pdsch.d, nof_symbols); + plot_scatter_setNewData(&pscatequal, ue_dl.pdsch.d[0], nof_symbols); if (plot_sf_idx == 1) { if (prog_args.net_port_signal > 0) { diff --git a/lib/include/srslte/phy/phch/pdsch.h b/lib/include/srslte/phy/phch/pdsch.h index fc250a7d5..b4620be69 100644 --- a/lib/include/srslte/phy/phch/pdsch.h +++ b/lib/include/srslte/phy/phch/pdsch.h @@ -35,6 +35,13 @@ #ifndef PDSCH_ #define PDSCH_ +#ifndef SRSLTE_SINGLE_THREAD + +#include +#include + +#endif /* SRSLTE_SINGLE_THREAD */ + #include "srslte/config.h" #include "srslte/phy/common/phy_common.h" #include "srslte/phy/mimo/precoding.h" @@ -48,11 +55,38 @@ #include "srslte/phy/phch/pdsch_cfg.h" typedef struct { - srslte_sequence_t seq[SRSLTE_NSUBFRAMES_X_FRAME]; - srslte_sequence_t seq2[SRSLTE_NSUBFRAMES_X_FRAME]; + srslte_sequence_t seq[SRSLTE_MAX_CODEWORDS][SRSLTE_NSUBFRAMES_X_FRAME]; bool sequence_generated; } srslte_pdsch_user_t; +#ifndef SRSLTE_SINGLE_THREAD + +typedef struct { + /* Thread identifier: they must set before thread creation */ + uint32_t codeword_idx; + void *pdsch_ptr; + + /* Configuration Encoder/Decoder: they must be set before posting start semaphore */ + srslte_pdsch_cfg_t *cfg; + uint16_t rnti; + + /* Encoder/Decoder data pointers: they must be set before posting start semaphore */ + uint8_t *data; + void *softbuffer; + + /* Execution status */ + int ret_status; + + /* Semaphores */ + sem_t start; + sem_t finish; + + /* Thread kill flag */ + bool quit; +} srslte_pdsch_thread_args_t; + +#endif /* SRSLTE_SINGLE_THREAD */ + /* PDSCH object */ typedef struct SRSLTE_API { srslte_cell_t cell; @@ -66,10 +100,8 @@ typedef struct SRSLTE_API { cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; /* Channel estimation (Rx only) */ cf_t *symbols[SRSLTE_MAX_PORTS]; /* PDSCH Encoded/Decoded Symbols */ cf_t *x[SRSLTE_MAX_LAYERS]; /* Layer mapped */ - cf_t *d; /* Modulated/Demodulated codeword 1 */ - cf_t *d2; /* Modulated/Demodulated codeword 2 */ - void *e; - void *e2; + cf_t *d[SRSLTE_MAX_CODEWORDS]; /* Modulated/Demodulated codewords */ + void *e[SRSLTE_MAX_CODEWORDS]; /* tx & rx objects */ srslte_modem_table_t mod[4]; @@ -77,8 +109,15 @@ typedef struct SRSLTE_API { // This is to generate the scrambling seq for multiple CRNTIs srslte_pdsch_user_t **users; - srslte_sch_t dl_sch; - + srslte_sch_t dl_sch[SRSLTE_MAX_CODEWORDS]; + +#ifndef SRSLTE_SINGLE_THREAD + + pthread_t threads[SRSLTE_MAX_CODEWORDS]; + srslte_pdsch_thread_args_t thread_args[SRSLTE_MAX_CODEWORDS]; + +#endif /* SRSLTE_SINGLE_THREAD */ + } srslte_pdsch_t; SRSLTE_API int srslte_pdsch_init(srslte_pdsch_t *q, @@ -151,7 +190,18 @@ SRSLTE_API int srslte_pdsch_decode_multi(srslte_pdsch_t *q, uint16_t rnti, uint8_t *data[SRSLTE_MAX_CODEWORDS]); -SRSLTE_API float srslte_pdsch_average_noi(srslte_pdsch_t *q); +SRSLTE_API int srslte_pdsch_ri_pmi_select(srslte_pdsch_t *q, + srslte_pdsch_cfg_t *cfg, + cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], + float noise_estimate, + uint32_t nof_ce, + uint32_t *ri, + uint32_t *pmi, + float *current_sinr); + +SRSLTE_API void srslte_pdsch_set_max_noi(srslte_pdsch_t *q, int max_iter); + +SRSLTE_API float srslte_pdsch_average_noi(srslte_pdsch_t *q); SRSLTE_API uint32_t srslte_pdsch_last_noi(srslte_pdsch_t *q); diff --git a/lib/include/srslte/phy/phch/ra.h b/lib/include/srslte/phy/phch/ra.h index 5fab0f10b..8a025ad97 100644 --- a/lib/include/srslte/phy/phch/ra.h +++ b/lib/include/srslte/phy/phch/ra.h @@ -223,6 +223,13 @@ SRSLTE_API void srslte_ra_dl_grant_to_nbits_multi(srslte_ra_dl_grant_t *grant, srslte_ra_nbits_t *nbits, srslte_ra_nbits_t *nbits2); +SRSLTE_API void srslte_ra_dl_grant_to_nbits_multi(srslte_ra_dl_grant_t *grant, + uint32_t cfi, + srslte_cell_t cell, + uint32_t sf_idx, + srslte_ra_nbits_t *nbits, + srslte_ra_nbits_t *nbits2); + SRSLTE_API uint32_t srslte_ra_dl_approx_nof_re(srslte_cell_t cell, uint32_t nof_prb, uint32_t nof_ctrl_symbols); diff --git a/lib/include/srslte/phy/phch/sch.h b/lib/include/srslte/phy/phch/sch.h index 128cfea6f..4fa1b3b0f 100644 --- a/lib/include/srslte/phy/phch/sch.h +++ b/lib/include/srslte/phy/phch/sch.h @@ -96,6 +96,13 @@ SRSLTE_API int srslte_dlsch_encode(srslte_sch_t *q, uint8_t *data, uint8_t *e_bits); +SRSLTE_API int srslte_dlsch_encode2(srslte_sch_t *q, + srslte_pdsch_cfg_t *cfg, + srslte_softbuffer_tx_t *softbuffer, + uint8_t *data, + uint8_t *e_bits, + int codeword_idx); + SRSLTE_API int srslte_dlsch_encode_multi(srslte_sch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbuffer_tx_t softbuffers[SRSLTE_MAX_CODEWORDS], diff --git a/lib/include/srslte/phy/ue/ue_dl.h b/lib/include/srslte/phy/ue/ue_dl.h index 0c77ba911..88442b93d 100644 --- a/lib/include/srslte/phy/ue/ue_dl.h +++ b/lib/include/srslte/phy/ue/ue_dl.h @@ -191,12 +191,17 @@ SRSLTE_API int srslte_ue_dl_decode_rnti(srslte_ue_dl_t * q, uint32_t tti, uint16_t rnti); -SRSLTE_API int srslte_ue_dl_decode_rnti_multi(srslte_ue_dl_t * q, +SRSLTE_API int srslte_ue_dl_decode_rnti_multi(srslte_ue_dl_t * q, cf_t *input[SRSLTE_MAX_PORTS], uint8_t *data[SRSLTE_MAX_CODEWORDS], uint32_t tti, uint16_t rnti); +SRSLTE_API int srslte_ue_dl_ri_pmi_select(srslte_ue_dl_t *q, + uint32_t *ri, + uint32_t *pmi, + float *current_sinr); + SRSLTE_API bool srslte_ue_dl_decode_phich(srslte_ue_dl_t *q, uint32_t sf_idx, uint32_t n_prb_lowest, diff --git a/lib/include/srslte/phy/utils/debug.h b/lib/include/srslte/phy/utils/debug.h index e1021bc2a..e4b4756f8 100644 --- a/lib/include/srslte/phy/utils/debug.h +++ b/lib/include/srslte/phy/utils/debug.h @@ -63,6 +63,11 @@ SRSLTE_API extern int srslte_verbose; #define INFO(_fmt, ...) if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO) \ fprintf(stdout, "[INFO]: " _fmt, __VA_ARGS__) -#define ERROR(_fmt) fprintf(stderr, "%s.%d: " _fmt "\n", __FILE__, __LINE__) +#if CMAKE_BUILD_TYPE==Debug +/* In debug mode, it prints out the */ +#define ERROR(_fmt, ...) fprintf(stderr, "%s.%d: " _fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__) +#else +#define ERROR(_fmt, ...) fprintf(stderr, "[ERROR in %s]:" _fmt "\n", __FUNCTION__, ##__VA_ARGS__) +#endif /* CMAKE_BUILD_TYPE==Debug */ #endif // DEBUG_H diff --git a/lib/src/phy/phch/pdsch.c b/lib/src/phy/phch/pdsch.c index 8cdfd0884..3ff2a910b 100644 --- a/lib/src/phy/phch/pdsch.c +++ b/lib/src/phy/phch/pdsch.c @@ -32,9 +32,13 @@ #include #include #include -#include -#include -#include + +#ifndef SRSLTE_SINGLE_THREAD + +#include +#include + +#endif /* SRSLTE_SINGLE_THREAD */ #include "prb_dl.h" #include "srslte/phy/phch/pdsch.h" @@ -60,6 +64,13 @@ extern int indices[100000]; extern int indices_ptr; #endif +#ifndef SRSLTE_SINGLE_THREAD + +static void *srslte_pdsch_encode_thread (void *arg); +static void *srslte_pdsch_decode_thread (void *arg); + +#endif /* SRSLTE_SINGLE_THREAD */ + float srslte_pdsch_coderate(uint32_t tbs, uint32_t nof_re) { return (float) (tbs + 24)/(nof_re); @@ -234,28 +245,38 @@ int srslte_pdsch_init_multi(srslte_pdsch_t *q, srslte_cell_t cell, uint32_t nof_ } srslte_modem_table_bytes(&q->mod[i]); } - - srslte_sch_init(&q->dl_sch); - - // Allocate int16_t for reception (LLRs) - q->e = srslte_vec_malloc(sizeof(int16_t) * q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM)); - if (!q->e) { - goto clean; - } - - q->e2 = srslte_vec_malloc(sizeof(int16_t) * q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM)); - if (!q->e) { - goto clean; - } - q->d = srslte_vec_malloc(sizeof(cf_t) * q->max_re); - if (!q->d) { - goto clean; - } + for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { + if (srslte_sch_init(&q->dl_sch[i])) { + ERROR("Initiating DL SCH"); + goto clean; + } - q->d2 = srslte_vec_malloc(sizeof(cf_t) * q->max_re); - if (!q->d) { - goto clean; + // Allocate int16_t for reception (LLRs) + q->e[i] = srslte_vec_malloc(sizeof(int16_t) * q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM)); + if (!q->e[i]) { + goto clean; + } + + q->d[i] = srslte_vec_malloc(sizeof(cf_t) * q->max_re); + if (!q->d[i]) { + goto clean; + } + +#ifndef SRSLTE_SINGLE_THREAD + if (sem_init(&q->thread_args[i].start, 0, 0)) { + ERROR("Creating semaphore"); + goto clean; + } + if (sem_init(&q->thread_args[i].finish, 0, 0)) { + ERROR("Creating semaphore"); + goto clean; + } + q->thread_args[i].codeword_idx = (uint32_t) i; + q->thread_args[i].pdsch_ptr = q; + pthread_create(&q->threads[i], NULL, (is_receiver) ? srslte_pdsch_decode_thread : srslte_pdsch_encode_thread, + (void *) &q->thread_args[i]); +#endif /* SRSLTE_SINGLE_THREAD */ } /* Layer mapped symbols memory allocation */ @@ -290,10 +311,11 @@ int srslte_pdsch_init_multi(srslte_pdsch_t *q, srslte_cell_t cell, uint32_t nof_ perror("malloc"); goto clean; } - - ret = SRSLTE_SUCCESS; - } - clean: + } + + ret = SRSLTE_SUCCESS; + + clean: if (ret == SRSLTE_ERROR) { srslte_pdsch_free(q); } @@ -315,18 +337,31 @@ int srslte_pdsch_init_rx_multi(srslte_pdsch_t *q, srslte_cell_t cell, uint32_t n void srslte_pdsch_free(srslte_pdsch_t *q) { int i; - if (q->e) { - free(q->e); - } - if (q->e2) { - free(q->e2); - } - if (q->d) { - free(q->d); - } - if (q->d2) { - free(q->d2); + for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { + +#ifndef SRSLTE_SINGLE_THREAD + /* Stop threads */ + q->thread_args[i].quit = true; + sem_post(&q->thread_args[i].start); + pthread_join(q->threads[i], NULL); + pthread_detach(q->threads[i]); + +#endif /* SRSLTE_SINGLE_THREAD */ + + if (q->e[i]) { + free(q->e[i]); + } + + if (q->d[i]) { + free(q->d[i]); + } + + /* Free sch objects */ + srslte_sch_free(&q->dl_sch[i]); + + } + for (i = 0; i < q->cell.nof_ports; i++) { if (q->x[i]) { free(q->x[i]); @@ -354,8 +389,6 @@ void srslte_pdsch_free(srslte_pdsch_t *q) { srslte_modem_table_free(&q->mod[i]); } - srslte_sch_free(&q->dl_sch); - bzero(q, sizeof(srslte_pdsch_t)); } @@ -454,18 +487,17 @@ int srslte_pdsch_cfg_multi(srslte_pdsch_cfg_t *cfg, srslte_cell_t cell, srslte_r * to execute, so shall be called once the final C-RNTI has been allocated for the session. */ int srslte_pdsch_set_rnti(srslte_pdsch_t *q, uint16_t rnti) { - uint32_t i; + uint32_t i, j; if (!q->users[rnti]) { q->users[rnti] = calloc(1, sizeof(srslte_pdsch_user_t)); if (q->users[rnti]) { for (i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) { - if (srslte_sequence_pdsch(&q->users[rnti]->seq[i], rnti, 0, 2 * i, q->cell.id, - q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM))) { - return SRSLTE_ERROR; - } - if (srslte_sequence_pdsch(&q->users[rnti]->seq2[i], rnti, 1, 2 * i, q->cell.id, - q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM))) { - return SRSLTE_ERROR; + for (j = 0; j < SRSLTE_MAX_CODEWORDS; j++) { + if (srslte_sequence_pdsch(&q->users[rnti]->seq[j][i], rnti, j, 2 * i, q->cell.id, + q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM))) { + ERROR("Generating scrambling sequence"); + return SRSLTE_ERROR; + } } } q->users[rnti]->sequence_generated = true; @@ -474,70 +506,194 @@ int srslte_pdsch_set_rnti(srslte_pdsch_t *q, uint16_t rnti) { return SRSLTE_SUCCESS; } +static inline int srslte_pdsch_codeword_encode(srslte_pdsch_t *pdsch, srslte_pdsch_cfg_t *cfg, + srslte_softbuffer_tx_t *softbuffer, uint16_t rnti, uint8_t *data, + uint32_t codeword_idx) { + srslte_sch_t *dl_sch = &pdsch->dl_sch[codeword_idx]; + srslte_ra_nbits_t *nbits = (codeword_idx == 0) ? &cfg->nbits : &cfg->nbits2; + srslte_ra_mcs_t *mcs = (codeword_idx == 0) ? &cfg->grant.mcs : &cfg->grant.mcs2; + + if (nbits->nof_bits) { + INFO("Encoding PDSCH SF: %d (TB %d), Mod %s, NofBits: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d\n", + cfg->sf_idx, codeword_idx, srslte_mod_string(mcs->mod), mcs->tbs, + nbits->nof_re, nbits->nof_bits, (codeword_idx == 0) ? cfg->rv : cfg->rv2); + + /* Channel coding */ + if (srslte_dlsch_encode2(dl_sch, cfg, softbuffer, data, pdsch->e[codeword_idx], codeword_idx)) { + ERROR("Error encoding TB %d", codeword_idx); + return SRSLTE_ERROR; + } + + /* Bit scrambling */ + if (!pdsch->users[rnti]) { + srslte_sequence_t seq; + + if (srslte_sequence_pdsch(&seq, rnti, codeword_idx, 2 * cfg->sf_idx, pdsch->cell.id, nbits->nof_bits)) { + ERROR("Initialising scrambling sequence"); + return SRSLTE_ERROR; + } + srslte_scrambling_bytes(&seq, (uint8_t *) pdsch->e[codeword_idx], nbits->nof_bits); + srslte_sequence_free(&seq); + + } else { + srslte_scrambling_bytes(&pdsch->users[rnti]->seq[codeword_idx][cfg->sf_idx], + (uint8_t *) pdsch->e[codeword_idx], + nbits->nof_bits); + } + + /* Bit mapping */ + srslte_mod_modulate_bytes(&pdsch->mod[mcs->mod], + (uint8_t *) pdsch->e[codeword_idx], + pdsch->d[codeword_idx], nbits->nof_bits); + } + + return SRSLTE_SUCCESS; +} + + +#ifndef SRSLTE_SINGLE_THREAD + +static void *srslte_pdsch_encode_thread(void *arg) { + srslte_pdsch_thread_args_t *q = (srslte_pdsch_thread_args_t *) arg; + uint32_t codeword_idx = q->codeword_idx; + + INFO("[PDSCH Encoder CW %d] waiting for data\n", codeword_idx); + + sem_wait(&q->start); + while (!q->quit) { + q->ret_status = srslte_pdsch_codeword_encode(q->pdsch_ptr, q->cfg, q->softbuffer, q->rnti, q->data, codeword_idx); + + /* Post finish semaphore */ + sem_post(&q->finish); + + /* Wait for next loop */ + sem_wait(&q->start); + } + + pthread_exit(NULL); + return q; +} + +#endif /* SRSLTE_SINGLE_THREAD */ + +static inline int srslte_pdsch_codeword_decode(srslte_pdsch_t *pdsch, srslte_pdsch_cfg_t *cfg, + srslte_softbuffer_rx_t *softbuffer, uint16_t rnti, uint8_t *data, + uint32_t codeword_idx) { + srslte_sch_t *dl_sch = &pdsch->dl_sch[codeword_idx]; + srslte_ra_nbits_t *nbits = (codeword_idx == 0) ? &cfg->nbits : &cfg->nbits2; + srslte_ra_mcs_t *mcs = (codeword_idx == 0) ? &cfg->grant.mcs : &cfg->grant.mcs2; + + if (nbits->nof_bits) { + INFO("Decoding PDSCH SF: %d (TB %d), Mod %s, NofBits: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d\n", + cfg->sf_idx, codeword_idx, srslte_mod_string(mcs->mod), mcs->tbs, + nbits->nof_re, nbits->nof_bits, (codeword_idx == 0) ? cfg->rv : cfg->rv2); + + srslte_demod_soft_demodulate_s(mcs->mod, pdsch->d[codeword_idx], pdsch->e[codeword_idx], cfg->nbits.nof_re); + + if (pdsch->users[rnti] && pdsch->users[rnti]->sequence_generated) { + srslte_scrambling_s_offset(&pdsch->users[rnti]->seq[codeword_idx][cfg->sf_idx], pdsch->e[codeword_idx], + 0, nbits->nof_bits); + } else { + srslte_sequence_t seq; + if (srslte_sequence_pdsch(&seq, rnti, codeword_idx, 2 * cfg->sf_idx, pdsch->cell.id, nbits->nof_bits)) { + ERROR("Initialising scrambling sequence"); + return SRSLTE_ERROR; + } + srslte_scrambling_s_offset(&seq, pdsch->e[codeword_idx], codeword_idx, nbits->nof_bits); + srslte_sequence_free(&seq); + } + + return srslte_dlsch_decode2(dl_sch, cfg, softbuffer, pdsch->e[codeword_idx], data, codeword_idx); + } + + return SRSLTE_SUCCESS; +} + +#ifndef SRSLTE_SINGLE_THREAD + +static void *srslte_pdsch_decode_thread(void *arg) { + srslte_pdsch_thread_args_t *q = (srslte_pdsch_thread_args_t *) arg; + uint32_t codeword_idx = q->codeword_idx; + + INFO("[PDSCH Encoder CW %d] waiting for data\n", codeword_idx); + + sem_wait(&q->start); + while (!q->quit) { + q->ret_status = srslte_pdsch_codeword_decode(q->pdsch_ptr, q->cfg, q->softbuffer, q->rnti, q->data, codeword_idx); + + /* Post finish semaphore */ + sem_post(&q->finish); + + /* Wait for next loop */ + sem_wait(&q->start); + } + + pthread_exit(NULL); + return q; +} + +#endif /* SRSLTE_SINGLE_THREAD */ + + void srslte_pdsch_free_rnti(srslte_pdsch_t* q, uint16_t rnti) { if (q->users[rnti]) { for (int i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) { - srslte_sequence_free(&q->users[rnti]->seq[i]); - srslte_sequence_free(&q->users[rnti]->seq2[i]); + for (int j = 0; j < SRSLTE_MAX_CODEWORDS; j++) { + srslte_sequence_free(&q->users[rnti]->seq[j][i]); + } } free(q->users[rnti]); - q->users[rnti] = NULL; + q->users[rnti] = NULL; } } -int srslte_pdsch_decode(srslte_pdsch_t *q, +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, cf_t *ce[SRSLTE_MAX_PORTS], float noise_estimate, + uint16_t rnti, uint8_t *data) { - cf_t *_sf_symbols[SRSLTE_MAX_PORTS]; + cf_t *_sf_symbols[SRSLTE_MAX_PORTS]; cf_t *_ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; - - _sf_symbols[0] = sf_symbols; + + _sf_symbols[0] = sf_symbols; for (int i=0;icell.nof_ports;i++) { - _ce[i][0] = ce[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, +int srslte_pdsch_decode_multi(srslte_pdsch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbuffer_rx_t softbuffers[SRSLTE_MAX_CODEWORDS], - cf_t *sf_symbols[SRSLTE_MAX_PORTS], cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], float noise_estimate, + 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[SRSLTE_MAX_CODEWORDS]) { /* Set pointers for layermapping & precoding */ - uint32_t i, n; + uint32_t i; cf_t *x[SRSLTE_MAX_LAYERS]; int ret = 0; if (q != NULL && sf_symbols != NULL && - data != NULL && + data != NULL && cfg != NULL) { - + INFO("Decoding PDSCH SF: %d, RNTI: 0x%x, Mod %s, TBS: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: [%d %d], C_prb=%d\n", - cfg->sf_idx, rnti, srslte_mod_string(cfg->grant.mcs.mod), cfg->grant.mcs.tbs, cfg->nbits.nof_re, + cfg->sf_idx, rnti, srslte_mod_string(cfg->grant.mcs.mod), cfg->grant.mcs.tbs, cfg->nbits.nof_re, cfg->nbits.nof_bits, cfg->rv, cfg->rv2, cfg->grant.nof_prb); - /* number of layers equals number of ports */ - for (i = 0; i < q->cell.nof_ports; i++) { - x[i] = q->x[i]; - } - memset(&x[q->cell.nof_ports], 0, sizeof(cf_t*) * (SRSLTE_MAX_LAYERS - q->cell.nof_ports)); - 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); + int 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); @@ -545,25 +701,42 @@ int srslte_pdsch_decode_multi(srslte_pdsch_t *q, fprintf(stderr, "Error expecting %d symbols but got %d\n", cfg->nbits.nof_re, n); return SRSLTE_ERROR; } - } + } } INFO("PDSCH Layer demapper and predecode: mimo_type=%d, nof_layers=%d, nof_tb=%d\n", cfg->mimo_type, cfg->nof_layers, cfg->grant.nof_tb); if (q->cell.nof_ports == 1) { /* no need for layer demapping */ - srslte_predecoding_single_multi(q->symbols, q->ce[0], q->d, q->nof_rx_antennas, cfg->nbits.nof_re, noise_estimate); + srslte_predecoding_single_multi(q->symbols, q->ce[0], q->d[0], q->nof_rx_antennas, cfg->nbits.nof_re, noise_estimate); } else { int nof_symbols [SRSLTE_MAX_CODEWORDS]; nof_symbols[0] = cfg->nbits.nof_re * cfg->grant.nof_tb / cfg->nof_layers; nof_symbols[1] = cfg->nbits2.nof_re * cfg->grant.nof_tb / cfg->nof_layers; - srslte_predecoding_type_multi(q->symbols, q->ce, x, q->nof_rx_antennas, q->cell.nof_ports, cfg->nof_layers, - cfg->codebook_idx, cfg->nbits.nof_re, cfg->mimo_type, 0.0); - srslte_layerdemap_type(x, (cf_t *[SRSLTE_MAX_CODEWORDS]) {q->d, q->d2}, cfg->nof_layers, cfg->grant.nof_tb, - nof_symbols[0], nof_symbols, cfg->mimo_type); + if (cfg->nof_layers == cfg->grant.nof_tb) { + for (i = 0; i < cfg->nof_layers; i++) { + x[i] = q->d[i]; + } + + srslte_predecoding_type_multi(q->symbols, q->ce, x, q->nof_rx_antennas, q->cell.nof_ports, cfg->nof_layers, + cfg->codebook_idx, cfg->nbits.nof_re, cfg->mimo_type, noise_estimate); + + } else { + /* number of layers equals number of ports */ + for (i = 0; i < cfg->nof_layers; i++) { + x[i] = q->x[i]; + } + memset(&x[cfg->nof_layers], 0, sizeof(cf_t*) * (SRSLTE_MAX_LAYERS - cfg->nof_layers)); + + srslte_predecoding_type_multi(q->symbols, q->ce, x, q->nof_rx_antennas, q->cell.nof_ports, cfg->nof_layers, + cfg->codebook_idx, cfg->nbits.nof_re, cfg->mimo_type, noise_estimate); + + srslte_layerdemap_type(x, q->d, cfg->nof_layers, cfg->grant.nof_tb, + nof_symbols[0], nof_symbols, cfg->mimo_type); + } } - + if (SRSLTE_VERBOSE_ISDEBUG()) { char filename[FILENAME_MAX]; for (int j = 0; j < q->nof_rx_antennas; j++) { @@ -586,47 +759,33 @@ int srslte_pdsch_decode_multi(srslte_pdsch_t *q, DEBUG("SAVED FILE pdsch_symbols.dat: symbols after equalization\n",0); srslte_vec_save_file("pdsch_symbols.dat", q->d, cfg->nbits.nof_re*sizeof(cf_t)); } - - /* demodulate symbols - * The MAX-log-MAP algorithm used in turbo decoding is unsensitive to SNR estimation, - * thus we don't need tot set it in the LLRs normalization - */ - if (cfg->nbits.nof_bits) { - INFO("Decoding CW 0 (%d bits)\n", cfg->nbits.nof_bits); - srslte_demod_soft_demodulate_s(cfg->grant.mcs.mod, q->d, q->e, cfg->nbits.nof_re); - if (q->users[rnti] && q->users[rnti]->sequence_generated) { - srslte_scrambling_s_offset(&q->users[rnti]->seq[cfg->sf_idx], q->e, 0, cfg->nbits.nof_bits); - } else { - srslte_sequence_t seq; - if (srslte_sequence_pdsch(&seq, rnti, 0, 2 * cfg->sf_idx, q->cell.id, cfg->nbits.nof_bits)) { - return SRSLTE_ERROR; - } - srslte_scrambling_s_offset(&seq, q->e, 0, cfg->nbits.nof_bits); - srslte_sequence_free(&seq); - } +#ifndef SRSLTE_SINGLE_THREAD - ret |= srslte_dlsch_decode2(&q->dl_sch, cfg, &softbuffers[0], q->e, data[0], 0); + for (i = 0; i < cfg->grant.nof_tb; i++) { + srslte_pdsch_thread_args_t *thread_args = &q->thread_args[i]; + thread_args->cfg = cfg; + thread_args->softbuffer = &softbuffers[i]; + thread_args->data = data[i]; + thread_args->rnti = rnti; + sem_post(&thread_args->start); } - if (cfg->nbits2.nof_bits) { - INFO("Decoding CW 1 (%d bits)\n", cfg->nbits2.nof_bits); - srslte_demod_soft_demodulate_s(cfg->grant.mcs2.mod, q->d2, q->e2, cfg->nbits2.nof_re); - - if (q->users[rnti] && q->users[rnti]->sequence_generated) { - srslte_scrambling_s_offset(&q->users[rnti]->seq2[cfg->sf_idx], q->e2, 0, cfg->nbits2.nof_bits); - } else { - srslte_sequence_t seq; - if (srslte_sequence_pdsch(&seq, rnti, 1, 2 * cfg->sf_idx, q->cell.id, cfg->nbits2.nof_bits)) { - return SRSLTE_ERROR; - } - srslte_scrambling_s_offset(&seq, q->e2, 0, cfg->nbits2.nof_bits); - srslte_sequence_free(&seq); - } - - ret |= srslte_dlsch_decode2(&q->dl_sch, cfg, &softbuffers[1], q->e2, data[1], 1); + for (i = 0; i < cfg->grant.nof_tb; i++) { + srslte_pdsch_thread_args_t *thread_args = &q->thread_args[i]; + sem_wait(&thread_args->finish); + ret |= thread_args->ret_status; } +#else + /* demodulate symbols + * The MAX-log-MAP algorithm used in turbo decoding is unsensitive to SNR estimation, + * thus we don't need tot set it in the LLRs normalization + */ + for (uint32_t tb = 0; tb < cfg->grant.nof_tb; tb ++) { + ret |= srslte_pdsch_codeword_decode(q, cfg, &softbuffers[tb], rnti, data[tb], tb); + } +#endif /* SRSLTE_SINGLE_THREAD */ if (SRSLTE_VERBOSE_ISDEBUG()) { DEBUG("SAVED FILE llr.dat: LLR estimates after demodulation and descrambling\n",0); @@ -634,7 +793,7 @@ int srslte_pdsch_decode_multi(srslte_pdsch_t *q, } return ret; - + } else { return SRSLTE_ERROR_INVALID_INPUTS; } @@ -688,13 +847,13 @@ int srslte_pdsch_ri_pmi_select(srslte_pdsch_t *q, *pmi = (best_sinr_1l > best_sinr_2l) ? best_pmi_1l : best_pmi_2l; } - /* Set current condition number */ - if (current_sinr != NULL) { + /* Set current SINR */ + if (current_sinr != NULL && cfg->mimo_type == SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX) { if (cfg->nof_layers == 1) { *current_sinr = sinr_1l[cfg->codebook_idx]; } else if (cfg->nof_layers == 2) { *current_sinr = sinr_2l[cfg->codebook_idx - 1]; - }else { + } else { ERROR("Not implemented number of layers"); return SRSLTE_ERROR; } @@ -713,16 +872,16 @@ int srslte_pdsch_ri_pmi_select(srslte_pdsch_t *q, return SRSLTE_SUCCESS; } -int srslte_pdsch_encode(srslte_pdsch_t *q, +int srslte_pdsch_encode(srslte_pdsch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbuffer_tx_t *softbuffer, - uint8_t *data, uint16_t rnti, cf_t *sf_symbols[SRSLTE_MAX_PORTS]) + uint8_t *data, uint16_t rnti, cf_t *sf_symbols[SRSLTE_MAX_PORTS]) { - + int i; /* Set pointers for layermapping & precoding */ cf_t *x[SRSLTE_MAX_LAYERS]; - int ret = SRSLTE_ERROR_INVALID_INPUTS; - + int ret = SRSLTE_ERROR_INVALID_INPUTS; + if (q != NULL && cfg != NULL) { @@ -732,11 +891,11 @@ int srslte_pdsch_encode(srslte_pdsch_t *q, return SRSLTE_ERROR_INVALID_INPUTS; } } - + if (cfg->grant.mcs.tbs == 0) { - return SRSLTE_ERROR_INVALID_INPUTS; + return SRSLTE_ERROR_INVALID_INPUTS; } - + if (cfg->nbits.nof_re > q->max_re) { fprintf(stderr, "Error too many RE per subframe (%d). PDSCH configured for %d RE (%d PRB)\n", @@ -745,7 +904,7 @@ int srslte_pdsch_encode(srslte_pdsch_t *q, } INFO("Encoding PDSCH SF: %d, Mod %s, NofBits: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d\n", - cfg->sf_idx, srslte_mod_string(cfg->grant.mcs.mod), cfg->grant.mcs.tbs, + cfg->sf_idx, srslte_mod_string(cfg->grant.mcs.mod), cfg->grant.mcs.tbs, cfg->nbits.nof_re, cfg->nbits.nof_bits, cfg->rv); /* number of layers equals number of ports */ @@ -754,28 +913,28 @@ int srslte_pdsch_encode(srslte_pdsch_t *q, } memset(&x[q->cell.nof_ports], 0, sizeof(cf_t*) * (SRSLTE_MAX_LAYERS - q->cell.nof_ports)); - if (srslte_dlsch_encode(&q->dl_sch, cfg, softbuffer, data, q->e)) { + if (srslte_dlsch_encode(&q->dl_sch[0], cfg, softbuffer, data, q->e[0])) { fprintf(stderr, "Error encoding TB\n"); return SRSLTE_ERROR; } /* scramble */ if (q->users[rnti] && q->users[rnti]->sequence_generated) { - srslte_scrambling_bytes(&q->users[rnti]->seq[cfg->sf_idx], (uint8_t*) q->e, cfg->nbits.nof_bits); + srslte_scrambling_bytes(&q->users[rnti]->seq[0][cfg->sf_idx], (uint8_t*) q->e[0], cfg->nbits.nof_bits); } else { srslte_sequence_t seq; if (srslte_sequence_pdsch(&seq, rnti, 0, 2 * cfg->sf_idx, q->cell.id, cfg->nbits.nof_bits)) { return SRSLTE_ERROR; } - srslte_scrambling_bytes(&seq, (uint8_t*) q->e, cfg->nbits.nof_bits); + srslte_scrambling_bytes(&seq, (uint8_t*) q->e[0], cfg->nbits.nof_bits); srslte_sequence_free(&seq); } - - srslte_mod_modulate_bytes(&q->mod[cfg->grant.mcs.mod], (uint8_t*) q->e, q->d, cfg->nbits.nof_bits); - + + srslte_mod_modulate_bytes(&q->mod[cfg->grant.mcs.mod], (uint8_t*) q->e[0], q->d[0], cfg->nbits.nof_bits); + /* TODO: only diversity supported */ if (q->cell.nof_ports > 1) { - srslte_layermap_diversity(q->d, x, q->cell.nof_ports, cfg->nbits.nof_re); + srslte_layermap_diversity(q->d[0], x, q->cell.nof_ports, cfg->nbits.nof_re); srslte_precoding_diversity(x, q->symbols, q->cell.nof_ports, cfg->nbits.nof_re / q->cell.nof_ports); } else { @@ -786,10 +945,10 @@ int srslte_pdsch_encode(srslte_pdsch_t *q, for (i = 0; i < q->cell.nof_ports; i++) { srslte_pdsch_put(q, q->symbols[i], sf_symbols[i], &cfg->grant, cfg->nbits.lstart, cfg->sf_idx); } - + ret = SRSLTE_SUCCESS; - } - return ret; + } + return ret; } int srslte_pdsch_encode_multi(srslte_pdsch_t *q, @@ -822,73 +981,57 @@ int srslte_pdsch_encode_multi(srslte_pdsch_t *q, return SRSLTE_ERROR_INVALID_INPUTS; } - INFO("Encoding PDSCH SF: %d (TB 1), Mod %s, NofBits: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d\n", - cfg->sf_idx, srslte_mod_string(cfg->grant.mcs.mod), cfg->grant.mcs.tbs, - cfg->nbits.nof_re, cfg->nbits.nof_bits, cfg->rv); - if (cfg->grant.nof_tb > 1) { - INFO("Encoding PDSCH SF: %d (TB 2), Mod %s, NofBits: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d\n", - cfg->sf_idx, srslte_mod_string(cfg->grant.mcs2.mod), cfg->grant.mcs2.tbs, - cfg->nbits.nof_re, cfg->nbits.nof_bits, cfg->rv2); - } +#ifndef SRSLTE_SINGLE_THREAD - /* number of layers equals number of ports */ - for (i = 0; i < q->cell.nof_ports; i++) { - x[i] = q->x[i]; + for (int tb = 0; tb < cfg->grant.nof_tb; tb++) { + srslte_pdsch_thread_args_t *thread_args = &q->thread_args[tb]; + thread_args->cfg = cfg; + thread_args->softbuffer = &softbuffers[tb]; + thread_args->data = data[tb]; + thread_args->rnti = rnti; + sem_post(&thread_args->start); } - memset(&x[q->cell.nof_ports], 0, sizeof(cf_t *) * (SRSLTE_MAX_LAYERS - q->cell.nof_ports)); - if (srslte_dlsch_encode_multi(&q->dl_sch, cfg, softbuffers, data, (uint8_t *[SRSLTE_MAX_CODEWORDS]) {q->e, q->e2})) { - fprintf(stderr, "Error encoding TB\n"); - return SRSLTE_ERROR; + for (int tb = 0; tb < cfg->grant.nof_tb; tb++) { + srslte_pdsch_thread_args_t *thread_args = &q->thread_args[tb]; + sem_wait(&thread_args->finish); + ret |= thread_args->ret_status; } - /* scramble */ - if (!q->users[rnti]) { - srslte_sequence_t seq; +#else + for (uint32_t tb = 0; tb < cfg->grant.nof_tb; tb ++) { + ret |= srslte_pdsch_codeword_encode(q, cfg, &softbuffers[tb], rnti, data[tb], tb); + } +#endif /* SRSLTE_SINGLE_THREAD */ - if (cfg->nbits.nof_bits) { - if (srslte_sequence_pdsch(&seq, rnti, 0, 2 * cfg->sf_idx, q->cell.id, cfg->nbits.nof_bits)) { - return SRSLTE_ERROR; + if (q->cell.nof_ports > 1) { + int nof_symbols; + /* If number of layers is equal to transport blocks (codewords) skip layer mapping */ + if (cfg->nof_layers == cfg->grant.nof_tb) { + for (i = 0; i < cfg->nof_layers; i++) { + x[i] = q->d[i]; } - srslte_scrambling_bytes(&seq, (uint8_t *) q->e, cfg->nbits.nof_bits); - srslte_sequence_free(&seq); - } - - if (cfg->nbits2.nof_bits) { - if (srslte_sequence_pdsch(&seq, rnti, 1, 2 * cfg->sf_idx, q->cell.id, cfg->nbits2.nof_bits)) { - return SRSLTE_ERROR; + nof_symbols = cfg->nbits.nof_re; + } else { + /* Initialise layer map pointers */ + for (i = 0; i < cfg->nof_layers; i++) { + x[i] = q->x[i]; } - srslte_scrambling_bytes(&seq, (uint8_t *) q->e2, cfg->nbits2.nof_bits); - srslte_sequence_free(&seq); - } - } else { - if (cfg->nbits.nof_bits) { - srslte_scrambling_bytes(&q->users[rnti]->seq[cfg->sf_idx], (uint8_t *) q->e, cfg->nbits.nof_bits); - } + memset(&x[cfg->nof_layers], 0, sizeof(cf_t *) * (SRSLTE_MAX_LAYERS - cfg->nof_layers)); - if (cfg->nbits2.nof_bits) { - srslte_scrambling_bytes(&q->users[rnti]->seq2[cfg->sf_idx], (uint8_t *) q->e2, cfg->nbits2.nof_bits); + nof_symbols = srslte_layermap_type(q->d, x, cfg->grant.nof_tb, cfg->nof_layers, + (int[SRSLTE_MAX_CODEWORDS]) {cfg->nbits.nof_re, cfg->nbits2.nof_re}, cfg->mimo_type); } - } - - if (cfg->nbits.nof_bits) { - srslte_mod_modulate_bytes(&q->mod[cfg->grant.mcs.mod], (uint8_t *) q->e, q->d, cfg->nbits.nof_bits); - } - if (cfg->nbits2.nof_bits) { - srslte_mod_modulate_bytes(&q->mod[cfg->grant.mcs2.mod], (uint8_t *) q->e2, q->d2, cfg->nbits2.nof_bits); - } - - if (q->cell.nof_ports > 1) { - int nof_symbols = srslte_layermap_type((cf_t *[SRSLTE_MAX_CODEWORDS]) {q->d, q->d2}, x, cfg->grant.nof_tb, cfg->nof_layers, - (int[SRSLTE_MAX_CODEWORDS]) {cfg->nbits.nof_re, cfg->nbits2.nof_re}, cfg->mimo_type); + /* Precode */ srslte_precoding_type(x, q->symbols, cfg->nof_layers, q->cell.nof_ports, cfg->codebook_idx, nof_symbols, cfg->mimo_type); } else { - memcpy(q->symbols[0], q->d, cfg->nbits.nof_re * sizeof(cf_t)); + memcpy(q->symbols[0], q->d[0], cfg->nbits.nof_re * sizeof(cf_t)); } /* mapping to resource elements */ + for (i = 0; i < q->cell.nof_ports; i++) { srslte_pdsch_put(q, q->symbols[i], sf_symbols[i], &cfg->grant, cfg->nbits.lstart, cfg->sf_idx); } @@ -898,13 +1041,18 @@ int srslte_pdsch_encode_multi(srslte_pdsch_t *q, return ret; } -float srslte_pdsch_average_noi(srslte_pdsch_t *q) -{ - return q->dl_sch.average_nof_iterations; +void srslte_pdsch_set_max_noi(srslte_pdsch_t *q, int max_iter) { + for (int cw = 0; cw < SRSLTE_MAX_CODEWORDS; cw++) { + srslte_sch_set_max_noi(&q->dl_sch[cw], max_iter); + } +} + +float srslte_pdsch_average_noi(srslte_pdsch_t *q) { + return q->dl_sch[0].average_nof_iterations; } uint32_t srslte_pdsch_last_noi(srslte_pdsch_t *q) { - return q->dl_sch.nof_iterations; + return q->dl_sch[0].nof_iterations; } diff --git a/lib/src/phy/phch/sch.c b/lib/src/phy/phch/sch.c index 1caacacc9..4b78f6228 100644 --- a/lib/src/phy/phch/sch.c +++ b/lib/src/phy/phch/sch.c @@ -528,24 +528,25 @@ int srslte_dlsch_decode2(srslte_sch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbu int16_t *e_bits, uint8_t *data, int codeword_idx) { uint32_t Nl = 1; + int ret = SRSLTE_ERROR; if (cfg->nof_layers != cfg->grant.nof_tb) { Nl = 2; } if (codeword_idx == 0) { - return decode_tb(q, softbuffer, &cfg->cb_segm, + ret = decode_tb(q, softbuffer, &cfg->cb_segm, cfg->grant.Qm*Nl, cfg->rv, cfg->nbits.nof_bits, e_bits, data); - } - - if (codeword_idx == 1) { - return decode_tb(q, softbuffer, &cfg->cb_segm2, + } else if (codeword_idx == 1) { + ret = decode_tb(q, softbuffer, &cfg->cb_segm2, cfg->grant.Qm2*Nl, cfg->rv2, cfg->nbits2.nof_bits, e_bits, data); + } else { + ERROR("Not implemented"); } - return SRSLTE_ERROR; + return ret; } /** @@ -567,6 +568,28 @@ int srslte_dlsch_encode(srslte_sch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbuf data, e_bits); } +int srslte_dlsch_encode2(srslte_sch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbuffer_tx_t *softbuffer, + uint8_t *data, uint8_t *e_bits, int codeword_idx) { + int ret = SRSLTE_ERROR; + uint32_t Nl = 1; + + if (cfg->nof_layers != cfg->grant.nof_tb) { + Nl = 2; + } + + if(codeword_idx == 0) { + /* Codeword 1 shall be encoded */ + ret = encode_tb(q, softbuffer, &cfg->cb_segm, cfg->grant.Qm*Nl, cfg->rv, cfg->nbits.nof_bits, data, e_bits); + } else if(codeword_idx == 1) { + /* Codeword 2 shall be encoded */ + ret = encode_tb(q, softbuffer, &cfg->cb_segm2, cfg->grant.Qm2*Nl, cfg->rv2, cfg->nbits2.nof_bits, data, e_bits); + } else { + ERROR("Not implemented"); + } + + return ret; +} + int srslte_dlsch_encode_multi(srslte_sch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbuffer_tx_t softbuffers[SRSLTE_MAX_CODEWORDS], uint8_t *data[SRSLTE_MAX_CODEWORDS], uint8_t *e_bits[SRSLTE_MAX_CODEWORDS]) { diff --git a/lib/src/phy/phch/test/dlsch_encode_test_mex.c b/lib/src/phy/phch/test/dlsch_encode_test_mex.c index f391ab111..c6181d9c5 100644 --- a/lib/src/phy/phch/test/dlsch_encode_test_mex.c +++ b/lib/src/phy/phch/test/dlsch_encode_test_mex.c @@ -46,7 +46,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) int i; srslte_sch_t dlsch; srslte_pdsch_cfg_t cfg; - srslte_softbuffer_tx_t *softbuffers[SRSLTE_MAX_CODEWORDS]; + srslte_softbuffer_tx_t softbuffers[SRSLTE_MAX_CODEWORDS]; uint32_t nof_codewords = 1; memset(&dlsch, 0, sizeof(srslte_sch_t)); @@ -107,8 +107,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) /* Initialise buffers */ for (i = 0; i < nof_codewords; i++) { - softbuffers[i] = srslte_vec_malloc(sizeof(srslte_softbuffer_tx_t)); - if (srslte_softbuffer_tx_init(softbuffers[i], cell.nof_prb)) { + if (srslte_softbuffer_tx_init(&softbuffers[i], cell.nof_prb)) { mexErrMsgTxt("Error initiating DL-SCH soft buffer\n"); return; } @@ -151,8 +150,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) free(e_bits); free(e_bits_unpacked); for (i = 0; i < nof_codewords; i++) { - srslte_softbuffer_tx_free(softbuffers[i]); - free(softbuffers[i]); + srslte_softbuffer_tx_free(&softbuffers[i]); } return; } diff --git a/lib/src/phy/phch/test/pdsch_test.c b/lib/src/phy/phch/test/pdsch_test.c index 8c79cc836..180e689d6 100644 --- a/lib/src/phy/phch/test/pdsch_test.c +++ b/lib/src/phy/phch/test/pdsch_test.c @@ -155,7 +155,8 @@ int main(int argc, char **argv) { int ret = -1; struct timeval t[3]; srslte_softbuffer_tx_t softbuffers_tx[SRSLTE_MAX_CODEWORDS]; - + int M=10; + parse_args(argc,argv); /* Initialise to zeros */ @@ -265,6 +266,7 @@ int main(int argc, char **argv) { perror("srslte_vec_malloc"); goto quit; } + bzero(data[0], sizeof(uint8_t) * grant.mcs.tbs); } if (grant.mcs2.tbs) { @@ -273,6 +275,7 @@ int main(int argc, char **argv) { perror("srslte_vec_malloc"); goto quit; } + bzero(data[1], sizeof(uint8_t) * grant.mcs2.tbs); } if (srslte_pdsch_init_rx_multi(&pdsch_rx, cell, nof_rx_antennas)) { @@ -388,10 +391,18 @@ int main(int argc, char **argv) { } pdsch_cfg.rv = rv_idx; pdsch_cfg.rv2 = rv_idx2; - if (srslte_pdsch_encode_multi(&pdsch_tx, &pdsch_cfg, softbuffers_tx, data, rnti, tx_slot_symbols)) { - fprintf(stderr, "Error encoding PDSCH\n"); - goto quit; + gettimeofday(&t[1], NULL); + for (k = 0; k < M; k++) { + if (srslte_pdsch_encode_multi(&pdsch_tx, &pdsch_cfg, softbuffers_tx, data, rnti, tx_slot_symbols)) { + ERROR("Error encoding PDSCH"); + goto quit; + } } + gettimeofday(&t[2], NULL); + get_time_interval(t); + printf("ENCODED in %.2f (PHY bitrate=%.2f Mbps. Processing bitrate=%.2f Mbps)\n", + (float) t[0].tv_usec/M, (float) (grant.mcs.tbs + grant.mcs2.tbs)/1000.0f, + (float) (grant.mcs.tbs + grant.mcs2.tbs)*M/t[0].tv_usec); #ifdef DO_OFDM for (i = 0; i < cell.nof_ports; i++) { @@ -422,9 +433,9 @@ int main(int argc, char **argv) { } - int M=10; - int r=0; - srslte_sch_set_max_noi(&pdsch_rx.dl_sch, 10); + int r=0; + srslte_pdsch_set_max_noi(&pdsch_rx, 10); + gettimeofday(&t[1], NULL); for (k = 0; k < M; k++) { #ifdef DO_OFDM @@ -443,7 +454,7 @@ int main(int argc, char **argv) { } gettimeofday(&t[2], NULL); get_time_interval(t); - INFO("DECODED %s in %.2f (PHY bitrate=%.2f Mbps. Processing bitrate=%.2f Mbps)\n", r?"Error":"OK", + printf("DECODED %s in %.2f (PHY bitrate=%.2f Mbps. Processing bitrate=%.2f Mbps)\n", r?"Error":"OK", (float) t[0].tv_usec/M, (float) (grant.mcs.tbs + grant.mcs2.tbs)/1000.0f, (float) (grant.mcs.tbs + grant.mcs2.tbs)*M/t[0].tv_usec); if (r) { diff --git a/lib/src/phy/phch/test/pdsch_test_mex.c b/lib/src/phy/phch/test/pdsch_test_mex.c index 5093c326d..eb198bcbe 100644 --- a/lib/src/phy/phch/test/pdsch_test_mex.c +++ b/lib/src/phy/phch/test/pdsch_test_mex.c @@ -213,7 +213,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) return; } - srslte_sch_set_max_noi(&pdsch.dl_sch, max_iterations); + srslte_pdsch_set_max_noi(&pdsch, max_iterations); bool input_fft_allocated = false; int r=-1; @@ -291,10 +291,10 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) mexutils_write_cf(pdsch.symbols[0], &plhs[2], cfg.nbits.nof_re, 1); } if (nlhs >= 4) { - mexutils_write_cf(pdsch.d, &plhs[3], cfg.nbits.nof_re, 1); + mexutils_write_cf(pdsch.d[0], &plhs[3], cfg.nbits.nof_re, 1); } if (nlhs >= 5) { - mexutils_write_s(pdsch.e, &plhs[4], cfg.nbits.nof_bits, 1); + mexutils_write_s(pdsch.e[0], &plhs[4], cfg.nbits.nof_bits, 1); } if (nlhs >= 6) { uint32_t len = nof_antennas*cell.nof_ports*SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp); diff --git a/lib/src/phy/ue/ue_dl.c b/lib/src/phy/ue/ue_dl.c index c068f5899..85e851a3e 100644 --- a/lib/src/phy/ue/ue_dl.c +++ b/lib/src/phy/ue/ue_dl.c @@ -293,19 +293,19 @@ int srslte_ue_dl_cfg_grant_multi(srslte_ue_dl_t *q, srslte_ra_dl_grant_t *grant, uint32_t pmi = 0; /* Translates Precoding Information (pinfo) to Precoding matrix Index (pmi) as 3GPP 36.212 Table 5.3.3.1.5-4 */ - if (q->pdsch_cfg.mimo_type == SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX) { - if (q->pdsch_cfg.grant.nof_tb == 1) { + if (mimo_type == SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX) { + if (grant->nof_tb == 1) { if (pinfo > 0 && pinfo < 5) { pmi = pinfo - 1; } else { - ERROR("Not Implemented"); + ERROR("Not Implemented (nof_tb=%d, pinfo=%d)", q->pdsch_cfg.grant.nof_tb, pinfo); return SRSLTE_ERROR; } } else { if (pinfo < 2) { pmi = pinfo; } else { - ERROR("Not Implemented"); + ERROR("Not Implemented (nof_tb=%d, pinfo=%d)", q->pdsch_cfg.grant.nof_tb, pinfo); return SRSLTE_ERROR; } } diff --git a/srsue/src/phy/phch_worker.cc b/srsue/src/phy/phch_worker.cc index ef3640a40..fce931837 100644 --- a/srsue/src/phy/phch_worker.cc +++ b/srsue/src/phy/phch_worker.cc @@ -432,7 +432,7 @@ bool phch_worker::decode_pdsch_multi(srslte_ra_dl_grant_t *grant, uint8_t *paylo /* Set decoder iterations */ if (phy->args->pdsch_max_its > 0) { - srslte_sch_set_max_noi(&ue_dl.pdsch.dl_sch, phy->args->pdsch_max_its); + srslte_pdsch_set_max_noi(&ue_dl.pdsch, phy->args->pdsch_max_its); } From 801b210511a39d84635af5bca5ee372fc7aab0ee Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Thu, 17 Aug 2017 10:23:28 +0200 Subject: [PATCH 11/60] Include open RF multi --- lib/include/srslte/phy/rf/rf.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/include/srslte/phy/rf/rf.h b/lib/include/srslte/phy/rf/rf.h index bc74d17e7..42b2a691d 100644 --- a/lib/include/srslte/phy/rf/rf.h +++ b/lib/include/srslte/phy/rf/rf.h @@ -73,7 +73,12 @@ SRSLTE_API int srslte_rf_open(srslte_rf_t *h, SRSLTE_API int srslte_rf_open_multi(srslte_rf_t *h, char *args, - uint32_t nof_rx_antennas); + uint32_t nof_rx_antennas); + +SRSLTE_API int srslte_rf_open_multi2(srslte_rf_t *h, + char *args, + uint32_t nof_tx_antennas, + uint32_t nof_rx_antennas); SRSLTE_API int srslte_rf_open_multi2(srslte_rf_t *h, char *args, From f2db2db81b21e2a7291553a1fd6ec0a30bb4000d Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Thu, 17 Aug 2017 16:23:43 +0200 Subject: [PATCH 12/60] Added PMI select C test and solved bugs (golden vectors generated from reference script) --- lib/src/phy/mimo/precoding.c | 106 ++++++------- lib/src/phy/mimo/test/CMakeLists.txt | 9 ++ lib/src/phy/mimo/test/pmi_select_test.c | 144 +++++++++++++++++ lib/src/phy/mimo/test/pmi_select_test.h | 203 ++++++++++++++++++++++++ 4 files changed, 406 insertions(+), 56 deletions(-) create mode 100644 lib/src/phy/mimo/test/pmi_select_test.c create mode 100644 lib/src/phy/mimo/test/pmi_select_test.h diff --git a/lib/src/phy/mimo/precoding.c b/lib/src/phy/mimo/precoding.c index 37081d225..a79b75b0a 100644 --- a/lib/src/phy/mimo/precoding.c +++ b/lib/src/phy/mimo/precoding.c @@ -25,7 +25,6 @@ */ #include -#include #include #include #include @@ -1985,7 +1984,7 @@ int srslte_precoding_pmi_select_1l_avx(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORT for (uint32_t j = 0; j < nof_symbols - PMI_SEL_PRECISION * 4 + 1; j += PMI_SEL_PRECISION * 4) { /* 0. Load channel matrix */ - __m256 h00 = _mm256_set_ps(crealf(h[0][0][j]), + __m256 h00 = _mm256_setr_ps(crealf(h[0][0][j]), cimagf(h[0][0][j]), crealf(h[0][0][j + PMI_SEL_PRECISION]), cimagf(h[0][0][j + PMI_SEL_PRECISION]), @@ -1993,7 +1992,7 @@ int srslte_precoding_pmi_select_1l_avx(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORT cimagf(h[0][0][j + PMI_SEL_PRECISION * 2]), crealf(h[0][0][j + PMI_SEL_PRECISION * 3]), cimagf(h[0][0][j + PMI_SEL_PRECISION * 3])); - __m256 h01 = _mm256_set_ps(crealf(h[1][0][j]), + __m256 h01 = _mm256_setr_ps(crealf(h[1][0][j]), cimagf(h[1][0][j]), crealf(h[1][0][j + PMI_SEL_PRECISION]), cimagf(h[1][0][j + PMI_SEL_PRECISION]), @@ -2001,7 +2000,7 @@ int srslte_precoding_pmi_select_1l_avx(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORT cimagf(h[1][0][j + PMI_SEL_PRECISION * 2]), crealf(h[1][0][j + PMI_SEL_PRECISION * 3]), cimagf(h[1][0][j + PMI_SEL_PRECISION * 3])); - __m256 h10 = _mm256_set_ps(crealf(h[0][1][j]), + __m256 h10 = _mm256_setr_ps(crealf(h[0][1][j]), cimagf(h[0][1][j]), crealf(h[0][1][j + PMI_SEL_PRECISION]), cimagf(h[0][1][j + PMI_SEL_PRECISION]), @@ -2009,7 +2008,7 @@ int srslte_precoding_pmi_select_1l_avx(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORT cimagf(h[0][1][j + PMI_SEL_PRECISION * 2]), crealf(h[0][1][j + PMI_SEL_PRECISION * 3]), cimagf(h[0][1][j + PMI_SEL_PRECISION * 3])); - __m256 h11 = _mm256_set_ps(crealf(h[1][1][j]), + __m256 h11 = _mm256_setr_ps(crealf(h[1][1][j]), cimagf(h[1][1][j]), crealf(h[1][1][j + PMI_SEL_PRECISION]), cimagf(h[1][1][j + PMI_SEL_PRECISION]), @@ -2030,13 +2029,13 @@ int srslte_precoding_pmi_select_1l_avx(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORT a1 = _mm256_sub_ps(_MM256_CONJ_PS(h10), _MM256_CONJ_PS(h11)); break; case 2: - a0 = _mm256_add_ps(_MM256_CONJ_PS(h00), _MM256_MULJ_PS(_MM256_CONJ_PS(h01))); - a1 = _mm256_add_ps(_MM256_CONJ_PS(h10), _MM256_MULJ_PS(_MM256_CONJ_PS(h11))); - break; - default: a0 = _mm256_sub_ps(_MM256_CONJ_PS(h00), _MM256_MULJ_PS(_MM256_CONJ_PS(h01))); a1 = _mm256_sub_ps(_MM256_CONJ_PS(h10), _MM256_MULJ_PS(_MM256_CONJ_PS(h11))); break; + default: + a0 = _mm256_add_ps(_MM256_CONJ_PS(h00), _MM256_MULJ_PS(_MM256_CONJ_PS(h01))); + a1 = _mm256_add_ps(_MM256_CONJ_PS(h10), _MM256_MULJ_PS(_MM256_CONJ_PS(h11))); + break; } /* 2. B = W' * H' * H = A * H */ @@ -2058,10 +2057,10 @@ int srslte_precoding_pmi_select_1l_avx(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORT c = _mm256_sub_ps(b0, b1); break; case 2: - c = _mm256_sub_ps(b0, _MM256_MULJ_PS(b1)); + c = _mm256_add_ps(b0, _MM256_MULJ_PS(b1)); break; case 3: - c = _mm256_add_ps(b0, _MM256_MULJ_PS(b1)); + c = _mm256_sub_ps(b0, _MM256_MULJ_PS(b1)); break; default: return SRSLTE_ERROR; @@ -2216,7 +2215,9 @@ int srslte_precoding_pmi_select_2l_sse(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORT float max_sinr = 0.0; uint32_t i, count; - __m128 sse_noise_estimate = (__m128) {noise_estimate, 0.0f, noise_estimate, 0.0f}; + __m128 sse_noise_estimate = _mm_setr_ps(noise_estimate, 0.0f, noise_estimate, 0.0f); + __m128 sse_norm = _mm_set1_ps(0.25f); + __m128 sse_ones = _mm_set1_ps(1.0f); for (i = 0; i < 2; i++) { sinr_list[i] = 0; @@ -2224,22 +2225,22 @@ int srslte_precoding_pmi_select_2l_sse(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORT for (uint32_t j = 0; j < nof_symbols - PMI_SEL_PRECISION * 2 + 1; j += PMI_SEL_PRECISION * 2) { /* 0. Load channel matrix */ - __m128 h00 = _mm_set_ps(crealf(h[0][0][j]), - cimagf(h[0][0][j]), - crealf(h[0][0][j + PMI_SEL_PRECISION]), - cimagf(h[0][0][j + PMI_SEL_PRECISION])); - __m128 h01 = _mm_set_ps(crealf(h[1][0][j]), - cimagf(h[1][0][j]), - crealf(h[1][0][j + PMI_SEL_PRECISION]), - cimagf(h[1][0][j + PMI_SEL_PRECISION])); - __m128 h10 = _mm_set_ps(crealf(h[0][1][j]), - cimagf(h[0][1][j]), - crealf(h[0][1][j + PMI_SEL_PRECISION]), - cimagf(h[0][1][j + PMI_SEL_PRECISION])); - __m128 h11 = _mm_set_ps(crealf(h[1][1][j]), - cimagf(h[1][1][j]), - crealf(h[1][1][j + PMI_SEL_PRECISION]), - cimagf(h[1][1][j + PMI_SEL_PRECISION])); + __m128 h00 = _mm_setr_ps(crealf(h[0][0][j]), + cimagf(h[0][0][j]), + crealf(h[0][0][j + PMI_SEL_PRECISION]), + cimagf(h[0][0][j + PMI_SEL_PRECISION])); + __m128 h01 = _mm_setr_ps(crealf(h[1][0][j]), + cimagf(h[1][0][j]), + crealf(h[1][0][j + PMI_SEL_PRECISION]), + cimagf(h[1][0][j + PMI_SEL_PRECISION])); + __m128 h10 = _mm_setr_ps(crealf(h[0][1][j]), + cimagf(h[0][1][j]), + crealf(h[0][1][j + PMI_SEL_PRECISION]), + cimagf(h[0][1][j + PMI_SEL_PRECISION])); + __m128 h11 = _mm_setr_ps(crealf(h[1][1][j]), + cimagf(h[1][1][j]), + crealf(h[1][1][j + PMI_SEL_PRECISION]), + cimagf(h[1][1][j + PMI_SEL_PRECISION])); /* 1. B = W'* H' */ __m128 a00, a01, a10, a11; @@ -2284,38 +2285,38 @@ int srslte_precoding_pmi_select_2l_sse(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORT default: return SRSLTE_ERROR; } - c00 = _mm_mul_ps(c00, _mm_set1_ps(0.25f)); - c01 = _mm_mul_ps(c01, _mm_set1_ps(0.25f)); - c10 = _mm_mul_ps(c10, _mm_set1_ps(0.25f)); - c11 = _mm_mul_ps(c11, _mm_set1_ps(0.25f)); + c00 = _mm_mul_ps(c00, sse_norm); + c01 = _mm_mul_ps(c01, sse_norm); + c10 = _mm_mul_ps(c10, sse_norm); + c11 = _mm_mul_ps(c11, sse_norm); /* 4. C += noise * I */ c00 = _mm_add_ps(c00, sse_noise_estimate); c11 = _mm_add_ps(c11, sse_noise_estimate); /* 5. detC */ - __m128 detC = _mm_sub_ps(_MM_PROD_PS(c00, c11), _MM_PROD_PS(c01, c10)); + __m128 detC = srslte_algebra_2x2_det_sse(c00, c01, c10, c11); __m128 inv_detC = srslte_algebra_cf_recip_sse(detC); + inv_detC = _mm_mul_ps(sse_noise_estimate, inv_detC); __m128 den0 = _MM_PROD_PS(c00, inv_detC); __m128 den1 = _MM_PROD_PS(c11, inv_detC); - __m128 gamma0 = _mm_sub_ps(srslte_algebra_cf_recip_sse(den0), _mm_set1_ps(1.0f)); - __m128 gamma1 = _mm_sub_ps(srslte_algebra_cf_recip_sse(den1), _mm_set1_ps(1.0f)); + __m128 gamma0 = _mm_sub_ps(_mm_rcp_ps(den0), sse_ones); + __m128 gamma1 = _mm_sub_ps(_mm_rcp_ps(den1), sse_ones); /* Add for averaging */ - __m128 sum = _MM_SWAP(_mm_add_ps(gamma0, gamma1)); - __m128 sinr_sse = _mm_hadd_ps(sum, sum); + __m128 sinr_sse = _mm_add_ps(gamma0, gamma1); __attribute__((aligned(128))) float sinr[4]; _mm_store_ps(sinr, sinr_sse); - sinr_list[i] += sinr[0]; + sinr_list[i] += sinr[0] + sinr[2]; count += 2; } /* Divide average by noise */ - sinr_list[i] /= (2 * count * noise_estimate); + sinr_list[i] /= 2 * count; if (sinr_list[i] > max_sinr) { max_sinr = sinr_list[i]; @@ -2339,7 +2340,7 @@ int srslte_precoding_pmi_select_2l_avx(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORT __m256 avx_noise_estimate = _mm256_setr_ps(noise_estimate, 0.0f, noise_estimate, 0.0f, noise_estimate, 0.0f, noise_estimate, 0.0f); - __m256 avx_norm = _mm256_set1_ps(0.5f); + __m256 avx_norm = _mm256_set1_ps(0.25f); __m256 avx_ones = _mm256_set1_ps(1.0f); for (i = 0; i < 2; i++) { @@ -2348,7 +2349,7 @@ int srslte_precoding_pmi_select_2l_avx(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORT for (uint32_t j = 0; j < nof_symbols - PMI_SEL_PRECISION * 4 + 1; j += PMI_SEL_PRECISION * 4) { /* 0. Load channel matrix */ - __m256 h00 = _mm256_set_ps(crealf(h[0][0][j]), + __m256 h00 = _mm256_setr_ps(crealf(h[0][0][j]), cimagf(h[0][0][j]), crealf(h[0][0][j + PMI_SEL_PRECISION]), cimagf(h[0][0][j + PMI_SEL_PRECISION]), @@ -2356,7 +2357,7 @@ int srslte_precoding_pmi_select_2l_avx(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORT cimagf(h[0][0][j + PMI_SEL_PRECISION * 2]), crealf(h[0][0][j + PMI_SEL_PRECISION * 3]), cimagf(h[0][0][j + PMI_SEL_PRECISION * 3])); - __m256 h01 = _mm256_set_ps(crealf(h[1][0][j]), + __m256 h01 = _mm256_setr_ps(crealf(h[1][0][j]), cimagf(h[1][0][j]), crealf(h[1][0][j + PMI_SEL_PRECISION]), cimagf(h[1][0][j + PMI_SEL_PRECISION]), @@ -2364,7 +2365,7 @@ int srslte_precoding_pmi_select_2l_avx(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORT cimagf(h[1][0][j + PMI_SEL_PRECISION * 2]), crealf(h[1][0][j + PMI_SEL_PRECISION * 3]), cimagf(h[1][0][j + PMI_SEL_PRECISION * 3])); - __m256 h10 = _mm256_set_ps(crealf(h[0][1][j]), + __m256 h10 = _mm256_setr_ps(crealf(h[0][1][j]), cimagf(h[0][1][j]), crealf(h[0][1][j + PMI_SEL_PRECISION]), cimagf(h[0][1][j + PMI_SEL_PRECISION]), @@ -2372,7 +2373,7 @@ int srslte_precoding_pmi_select_2l_avx(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORT cimagf(h[0][1][j + PMI_SEL_PRECISION * 2]), crealf(h[0][1][j + PMI_SEL_PRECISION * 3]), cimagf(h[0][1][j + PMI_SEL_PRECISION * 3])); - __m256 h11 = _mm256_set_ps(crealf(h[1][1][j]), + __m256 h11 = _mm256_setr_ps(crealf(h[1][1][j]), cimagf(h[1][1][j]), crealf(h[1][1][j + PMI_SEL_PRECISION]), cimagf(h[1][1][j + PMI_SEL_PRECISION]), @@ -2399,10 +2400,6 @@ int srslte_precoding_pmi_select_2l_avx(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORT default: return SRSLTE_ERROR; } - a00 = _mm256_mul_ps(a00, avx_norm); - a01 = _mm256_mul_ps(a01, avx_norm); - a10 = _mm256_mul_ps(a10, avx_norm); - a11 = _mm256_mul_ps(a11, avx_norm); /* 2. B = W' * H' * H = A * H */ #ifdef LV_HAVE_FMA @@ -2445,18 +2442,15 @@ int srslte_precoding_pmi_select_2l_avx(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORT c11 = _mm256_add_ps(c11, avx_noise_estimate); /* 5. detC */ -#ifdef LV_HAVE_FMA - __m256 detC = _MM256_PROD_SUB_PS(c00, c11, _MM256_PROD_PS(c01, c10)); -#else - __m256 detC = _mm256_sub_ps(_MM256_PROD_PS(c00, c11), _MM256_PROD_PS(c01, c10)); -#endif /* LV_HAVE_FMA */ + __m256 detC = srslte_algebra_2x2_det_avx(c00, c01, c10, c11); __m256 inv_detC = srslte_algebra_cf_recip_avx(detC); + inv_detC = _mm256_mul_ps(avx_noise_estimate, inv_detC); __m256 den0 = _MM256_PROD_PS(c00, inv_detC); __m256 den1 = _MM256_PROD_PS(c11, inv_detC); - __m256 gamma0 = _mm256_sub_ps(srslte_algebra_cf_recip_avx(den0), avx_ones); - __m256 gamma1 = _mm256_sub_ps(srslte_algebra_cf_recip_avx(den1), avx_ones); + __m256 gamma0 = _mm256_sub_ps(_mm256_rcp_ps(den0), avx_ones); + __m256 gamma1 = _mm256_sub_ps(_mm256_rcp_ps(den1), avx_ones); /* Add for averaging */ __m256 sinr_avx = _mm256_permute_ps(_mm256_add_ps(gamma0, gamma1), 0b00101000); @@ -2469,7 +2463,7 @@ int srslte_precoding_pmi_select_2l_avx(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORT } /* Divide average by noise */ - sinr_list[i] /= 2 * count * noise_estimate; + sinr_list[i] /= 2 * count; if (sinr_list[i] > max_sinr) { max_sinr = sinr_list[i]; diff --git a/lib/src/phy/mimo/test/CMakeLists.txt b/lib/src/phy/mimo/test/CMakeLists.txt index 2397bfc49..cae668d9e 100644 --- a/lib/src/phy/mimo/test/CMakeLists.txt +++ b/lib/src/phy/mimo/test/CMakeLists.txt @@ -69,4 +69,13 @@ add_test(precoding_multiplex_2l_cb0_mmse precoding_test -m multiplex -l 2 -p 2 - add_test(precoding_multiplex_2l_cb1_mmse precoding_test -m multiplex -l 2 -p 2 -r 2 -n 14000 -c 1 -d mmse) add_test(precoding_multiplex_2l_cb2_mmse precoding_test -m multiplex -l 2 -p 2 -r 2 -n 14000 -c 2 -d mmse) +######################################################################## +# PMI SELECT TEST +######################################################################## + +add_executable(pmi_select_test pmi_select_test.c) +target_link_libraries(pmi_select_test srslte_phy) + +add_test(pmi_select_test pmi_select_test) + diff --git a/lib/src/phy/mimo/test/pmi_select_test.c b/lib/src/phy/mimo/test/pmi_select_test.c new file mode 100644 index 000000000..30d358e37 --- /dev/null +++ b/lib/src/phy/mimo/test/pmi_select_test.c @@ -0,0 +1,144 @@ +/** + * + * \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 +#include +#include +#include +#include +#include +#include +#include + + +#include "srslte/phy/utils/vector.h" +#include "srslte/phy/mimo/precoding.h" +#include "pmi_select_test.h" +#include "srslte/phy/utils/debug.h" + +int main(int argc, char **argv) { + cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; + float noise_estimate; + float sinr_1l[SRSLTE_MAX_CODEBOOKS]; + float sinr_2l[SRSLTE_MAX_CODEBOOKS]; + uint32_t pmi[2]; + uint32_t nof_symbols = (uint32_t) SRSLTE_SF_LEN_RE(6, SRSLTE_CP_NORM); + int ret = SRSLTE_ERROR; + + /* Allocate channels */ + for (int i = 0; i < SRSLTE_MAX_PORTS; i++) { + for (int j = 0; j < SRSLTE_MAX_PORTS; j++) { + h[i][j] = srslte_vec_malloc(sizeof(cf_t) * nof_symbols); + if (!h[i][j]) { + goto clean; + } + bzero(h[i][j], sizeof(cf_t) * nof_symbols); + } + } + + for (int c = 0; c < PMI_SELECT_TEST_NOF_CASES; c++) { + pmi_select_test_case_gold_t *gold = &pmi_select_test_case_gold[c]; + + /* Set channel */ + for (int i = 0; i < 2; i++) { + for (int j = 0; j < 2; j++) { + cf_t hij = gold->h[i][j]; + + for (int k = 0; k < nof_symbols; k++) { + h[i][j][k] = hij; + } + } + } + + /* Set noise estimate */ + noise_estimate = gold->n; + + /* PMI select for 1 layer */ + ret = srslte_precoding_pmi_select(h, nof_symbols, noise_estimate, 1, &pmi[0], sinr_1l); + if (ret < 0) { + ERROR("During PMI selection for 1 layer"); + goto clean; + } + + /* Check SINR for 1 layer */ + for (int i = 0; i < ret; i++) { + if (fabsf(gold->snri_1l[i] - sinr_1l[i]) > 0.1) { + ERROR("Test case %d failed computing 1 layer SINR for codebook %d (test=%.2f; gold=%.2f)\n", + c + 1, i, sinr_1l[i], gold->snri_1l[i]); + goto clean; + } + } + + /* Check PMI select for 1 layer*/ + if (pmi[0] != gold->pmi[0]) { + ERROR("Test case %d failed computing 1 layer PMI (test=%d; gold=%d)\n", c + 1, pmi[0], gold->pmi[0]); + goto clean; + } + + /* PMI select for 2 layer */ + ret = srslte_precoding_pmi_select(h, nof_symbols, noise_estimate, 2, &pmi[1], sinr_2l); + if (ret < 0) { + ERROR("During PMI selection for 2 layer"); + goto clean; + } + + /* Check SINR for 2 layer */ + for (int i = 0; i < ret; i++) { + if (fabsf(gold->snri_2l[i] - sinr_2l[i]) > 0.1) { + ERROR("Test case %d failed computing 2 layer SINR for codebook %d (test=%.2f; gold=%.2f)\n", + c + 1, i, sinr_2l[i], gold->snri_2l[i]); + goto clean; + } + } + + /* Check PMI select for 2 layer*/ + if (pmi[1] != gold->pmi[1]) { + ERROR("Test case %d failed computing 2 layer PMI (test=%d; gold=%d)\n", c + 1, pmi[1], gold->pmi[1]); + goto clean; + } + } + + /* Test passed */ + ret = SRSLTE_SUCCESS; + + clean: + for (int i = 0; i < SRSLTE_MAX_PORTS; i++) { + for (int j = 0; j < SRSLTE_MAX_PORTS; j++) { + if (h[i][j]) { + free(h[i][j]); + } + } + } + + if (ret) { + printf("Failed!\n"); + } else { + printf("Passed!\n"); + } + + return ret; +} \ No newline at end of file diff --git a/lib/src/phy/mimo/test/pmi_select_test.h b/lib/src/phy/mimo/test/pmi_select_test.h new file mode 100644 index 000000000..a55869a8b --- /dev/null +++ b/lib/src/phy/mimo/test/pmi_select_test.h @@ -0,0 +1,203 @@ +/** + * + * \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/. + * + */ + +#ifndef PMI_SELECT_TEST_H +#define PMI_SELECT_TEST_H + +#define PMI_SELECT_TEST_NOF_CASES 16 + +typedef struct { + cf_t h[2][2]; + float n; + float snri_1l[4]; + float snri_2l[2]; + uint32_t pmi[2]; +} pmi_select_test_case_gold_t; + +static pmi_select_test_case_gold_t pmi_select_test_case_gold [PMI_SELECT_TEST_NOF_CASES] = { + { /* Test case 1 */ + .h = { + {+0.103430f+0.455920f*_Complex_I, +0.042050f+0.751883f*_Complex_I}, + {-0.641951f-0.053356f*_Complex_I, +0.217847f+0.504428f*_Complex_I} + }, + .n = 0.181048, + .snri_1l = {5.793827f, 2.505115f, 3.350922f, 4.948020f}, + .snri_2l = {2.015732f, 1.848130f}, + .pmi = {0, 0}, + }, + { /* Test case 2 */ + .h = { + {-0.957328f-0.624816f*_Complex_I, -0.741457f-0.657570f*_Complex_I}, + {+0.720104f+0.351137f*_Complex_I, +0.593419f-0.200211f*_Complex_I} + }, + .n = 0.935527, + .snri_1l = {0.475069f, 3.077055f, 1.078656f, 2.473467f}, + .snri_2l = {0.747362f, 0.594324f}, + .pmi = {1, 0}, + }, + { /* Test case 3 */ + .h = { + {-0.047530f-0.118039f*_Complex_I, -0.195528f-0.724032f*_Complex_I}, + {-0.619953f+0.960678f*_Complex_I, -0.325868f-0.120700f*_Complex_I} + }, + .n = 0.803842, + .snri_1l = {1.331730f, 1.164592f, 1.660155f, 0.836167f}, + .snri_2l = {0.554942f, 0.579321f}, + .pmi = {2, 1}, + }, + { /* Test case 4 */ + .h = { + {+0.635330f-0.751786f*_Complex_I, -0.536944f-0.185884f*_Complex_I}, + {+0.282517f-0.864615f*_Complex_I, -0.484380f-0.780479f*_Complex_I} + }, + .n = 0.529556, + .snri_1l = {5.128973f, 0.465969f, 2.812367f, 2.782574f}, + .snri_2l = {1.381190f, 0.818813f}, + .pmi = {0, 0}, + }, + { /* Test case 5 */ + .h = { + {-0.576996f+0.964470f*_Complex_I, -0.948065f+0.902764f*_Complex_I}, + {+0.988240f-0.056784f*_Complex_I, +0.489282f+0.975071f*_Complex_I} + }, + .n = 0.852921, + .snri_1l = {2.772684f, 3.261802f, 5.698031f, 0.336455f}, + .snri_2l = {0.768370f, 1.469069f}, + .pmi = {2, 1}, + }, + { /* Test case 6 */ + .h = { + {-0.381846f-0.998609f*_Complex_I, +0.903472f-0.393687f*_Complex_I}, + {-0.772703f-0.261637f*_Complex_I, -0.765452f-0.759318f*_Complex_I} + }, + .n = 0.711912, + .snri_1l = {2.998736f, 2.538860f, 5.099274f, 0.438323f}, + .snri_2l = {0.809381f, 1.371548f}, + .pmi = {2, 1}, + }, + { /* Test case 7 */ + .h = { + {+0.915028f-0.780771f*_Complex_I, -0.355424f+0.447925f*_Complex_I}, + {+0.577968f+0.765204f*_Complex_I, +0.342972f-0.999014f*_Complex_I} + }, + .n = 0.101944, + .snri_1l = {12.424177f, 24.940449f, 5.411339f, 31.953288f}, + .snri_2l = {4.610588f, 7.664146f}, + .pmi = {3, 1}, + }, + { /* Test case 8 */ + .h = { + {-0.259232f-0.654765f*_Complex_I, +0.829378f-0.793859f*_Complex_I}, + {+0.997978f+0.212295f*_Complex_I, -0.659012f-0.176220f*_Complex_I} + }, + .n = 0.255783, + .snri_1l = {3.345813f, 9.635433f, 6.767844f, 6.213402f}, + .snri_2l = {3.215386f, 2.640976f}, + .pmi = {1, 0}, + }, + { /* Test case 9 */ + .h = { + {-0.596630f+0.244853f*_Complex_I, -0.624622f+0.316537f*_Complex_I}, + {+0.767545f-0.645831f*_Complex_I, +0.262828f+0.251697f*_Complex_I} + }, + .n = 0.876456, + .snri_1l = {0.367264f, 1.965908f, 1.215674f, 1.117498f}, + .snri_2l = {0.579923f, 0.479609f}, + .pmi = {1, 0}, + }, + { /* Test case 10 */ + .h = { + {-0.643594f+0.172442f*_Complex_I, +0.291148f-0.026254f*_Complex_I}, + {+0.768244f+0.678173f*_Complex_I, -0.498968f-0.896649f*_Complex_I} + }, + .n = 0.739473, + .snri_1l = {1.104856f, 2.455074f, 2.920106f, 0.639825f}, + .snri_2l = {0.557672f, 0.658911f}, + .pmi = {2, 1}, + }, + { /* Test case 11 */ + .h = { + {+0.109032f-0.285542f*_Complex_I, -0.141055f+0.318945f*_Complex_I}, + {+0.559445f-0.211656f*_Complex_I, -0.206665f-0.643045f*_Complex_I} + }, + .n = 0.054295, + .snri_1l = {8.472397f, 10.480333f, 4.074631f, 14.878099f}, + .snri_2l = {2.121444f, 2.979095f}, + .pmi = {3, 1}, + }, + { /* Test case 12 */ + .h = { + {-0.505758f-0.710501f*_Complex_I, +0.803627f+0.023333f*_Complex_I}, + {+0.964886f+0.987055f*_Complex_I, -0.031782f+0.525138f*_Complex_I} + }, + .n = 0.966024, + .snri_1l = {0.612742f, 3.102514f, 1.227107f, 2.488149f}, + .snri_2l = {0.848010f, 0.701000f}, + .pmi = {1, 0}, + }, + { /* Test case 13 */ + .h = { + {+0.859761f-0.737655f*_Complex_I, -0.527019f+0.509133f*_Complex_I}, + {-0.804956f-0.303794f*_Complex_I, -0.180451f-0.100433f*_Complex_I} + }, + .n = 0.199335, + .snri_1l = {4.402551f, 8.656756f, 10.092319f, 2.966987f}, + .snri_2l = {2.048224f, 2.462759f}, + .pmi = {2, 1}, + }, + { /* Test case 14 */ + .h = { + {+0.473036f+0.227467f*_Complex_I, -0.593265f-0.308456f*_Complex_I}, + {+0.536321f+0.445264f*_Complex_I, -0.517440f-0.765554f*_Complex_I} + }, + .n = 0.180788, + .snri_1l = {10.671400f, 0.736020f, 3.584109f, 7.823311f}, + .snri_2l = {2.029078f, 0.914443f}, + .pmi = {0, 0}, + }, + { /* Test case 15 */ + .h = { + {-0.612271f+0.338114f*_Complex_I, -0.278903f+0.914426f*_Complex_I}, + {-0.191213f-0.136670f*_Complex_I, -0.548440f+0.607628f*_Complex_I} + }, + .n = 0.798189, + .snri_1l = {2.309797f, 0.356735f, 0.731443f, 1.935089f}, + .snri_2l = {0.577612f, 0.490806f}, + .pmi = {0, 0}, + }, + { /* Test case 16 */ + .h = { + {+0.990482f+0.513519f*_Complex_I, -0.576391f+0.922553f*_Complex_I}, + {-0.341962f+0.139785f*_Complex_I, +0.524684f+0.217012f*_Complex_I} + }, + .n = 0.365092, + .snri_1l = {2.942635f, 4.964827f, 4.761949f, 3.145513f}, + .snri_2l = {1.291431f, 1.267123f}, + .pmi = {1, 0}, + }, +}; + +#endif /* PMI_SELECT_TEST_H */ From ed19a4d2006ce5c0ede56f78e5154db13bd18526 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Fri, 18 Aug 2017 16:48:21 +0200 Subject: [PATCH 13/60] Removed PDSCH threads and refactored RI/PMI select --- lib/include/srslte/phy/phch/pdsch.h | 57 +------- lib/include/srslte/phy/ue/ue_dl.h | 7 +- lib/src/phy/phch/pdsch.c | 212 +++------------------------- lib/src/phy/ue/ue_dl.c | 55 +++++++- 4 files changed, 82 insertions(+), 249 deletions(-) diff --git a/lib/include/srslte/phy/phch/pdsch.h b/lib/include/srslte/phy/phch/pdsch.h index b4620be69..9a9b16788 100644 --- a/lib/include/srslte/phy/phch/pdsch.h +++ b/lib/include/srslte/phy/phch/pdsch.h @@ -35,13 +35,6 @@ #ifndef PDSCH_ #define PDSCH_ -#ifndef SRSLTE_SINGLE_THREAD - -#include -#include - -#endif /* SRSLTE_SINGLE_THREAD */ - #include "srslte/config.h" #include "srslte/phy/common/phy_common.h" #include "srslte/phy/mimo/precoding.h" @@ -59,34 +52,6 @@ typedef struct { bool sequence_generated; } srslte_pdsch_user_t; -#ifndef SRSLTE_SINGLE_THREAD - -typedef struct { - /* Thread identifier: they must set before thread creation */ - uint32_t codeword_idx; - void *pdsch_ptr; - - /* Configuration Encoder/Decoder: they must be set before posting start semaphore */ - srslte_pdsch_cfg_t *cfg; - uint16_t rnti; - - /* Encoder/Decoder data pointers: they must be set before posting start semaphore */ - uint8_t *data; - void *softbuffer; - - /* Execution status */ - int ret_status; - - /* Semaphores */ - sem_t start; - sem_t finish; - - /* Thread kill flag */ - bool quit; -} srslte_pdsch_thread_args_t; - -#endif /* SRSLTE_SINGLE_THREAD */ - /* PDSCH object */ typedef struct SRSLTE_API { srslte_cell_t cell; @@ -111,13 +76,6 @@ typedef struct SRSLTE_API { srslte_sch_t dl_sch[SRSLTE_MAX_CODEWORDS]; -#ifndef SRSLTE_SINGLE_THREAD - - pthread_t threads[SRSLTE_MAX_CODEWORDS]; - srslte_pdsch_thread_args_t thread_args[SRSLTE_MAX_CODEWORDS]; - -#endif /* SRSLTE_SINGLE_THREAD */ - } srslte_pdsch_t; SRSLTE_API int srslte_pdsch_init(srslte_pdsch_t *q, @@ -190,14 +148,13 @@ SRSLTE_API int srslte_pdsch_decode_multi(srslte_pdsch_t *q, uint16_t rnti, uint8_t *data[SRSLTE_MAX_CODEWORDS]); -SRSLTE_API int srslte_pdsch_ri_pmi_select(srslte_pdsch_t *q, - srslte_pdsch_cfg_t *cfg, - cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], - float noise_estimate, - uint32_t nof_ce, - uint32_t *ri, - uint32_t *pmi, - float *current_sinr); +SRSLTE_API int srslte_pdsch_pmi_select(srslte_pdsch_t *q, + srslte_pdsch_cfg_t *cfg, + cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], + float noise_estimate, + uint32_t nof_ce, + uint32_t pmi[SRSLTE_MAX_LAYERS], + float sinr[SRSLTE_MAX_LAYERS][SRSLTE_MAX_CODEBOOKS]); SRSLTE_API void srslte_pdsch_set_max_noi(srslte_pdsch_t *q, int max_iter); diff --git a/lib/include/srslte/phy/ue/ue_dl.h b/lib/include/srslte/phy/ue/ue_dl.h index 88442b93d..0fc8f9422 100644 --- a/lib/include/srslte/phy/ue/ue_dl.h +++ b/lib/include/srslte/phy/ue/ue_dl.h @@ -94,7 +94,12 @@ typedef struct SRSLTE_API { cf_t *sf_symbols_m[SRSLTE_MAX_PORTS]; cf_t *ce[SRSLTE_MAX_PORTS]; // compatibility cf_t *ce_m[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; - + + /* RI, PMI and SINR for MIMO statistics */ + float sinr[SRSLTE_MAX_LAYERS][SRSLTE_MAX_CODEBOOKS]; + uint32_t pmi[SRSLTE_MAX_LAYERS]; + uint32_t ri; + srslte_dci_format_t dci_format; uint64_t pkt_errors; uint64_t pkts_total; diff --git a/lib/src/phy/phch/pdsch.c b/lib/src/phy/phch/pdsch.c index 3ff2a910b..31642751f 100644 --- a/lib/src/phy/phch/pdsch.c +++ b/lib/src/phy/phch/pdsch.c @@ -33,13 +33,6 @@ #include #include -#ifndef SRSLTE_SINGLE_THREAD - -#include -#include - -#endif /* SRSLTE_SINGLE_THREAD */ - #include "prb_dl.h" #include "srslte/phy/phch/pdsch.h" #include "srslte/phy/phch/sch.h" @@ -64,13 +57,6 @@ extern int indices[100000]; extern int indices_ptr; #endif -#ifndef SRSLTE_SINGLE_THREAD - -static void *srslte_pdsch_encode_thread (void *arg); -static void *srslte_pdsch_decode_thread (void *arg); - -#endif /* SRSLTE_SINGLE_THREAD */ - float srslte_pdsch_coderate(uint32_t tbs, uint32_t nof_re) { return (float) (tbs + 24)/(nof_re); @@ -263,20 +249,6 @@ int srslte_pdsch_init_multi(srslte_pdsch_t *q, srslte_cell_t cell, uint32_t nof_ goto clean; } -#ifndef SRSLTE_SINGLE_THREAD - if (sem_init(&q->thread_args[i].start, 0, 0)) { - ERROR("Creating semaphore"); - goto clean; - } - if (sem_init(&q->thread_args[i].finish, 0, 0)) { - ERROR("Creating semaphore"); - goto clean; - } - q->thread_args[i].codeword_idx = (uint32_t) i; - q->thread_args[i].pdsch_ptr = q; - pthread_create(&q->threads[i], NULL, (is_receiver) ? srslte_pdsch_decode_thread : srslte_pdsch_encode_thread, - (void *) &q->thread_args[i]); -#endif /* SRSLTE_SINGLE_THREAD */ } /* Layer mapped symbols memory allocation */ @@ -339,15 +311,6 @@ void srslte_pdsch_free(srslte_pdsch_t *q) { for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { -#ifndef SRSLTE_SINGLE_THREAD - /* Stop threads */ - q->thread_args[i].quit = true; - sem_post(&q->thread_args[i].start); - pthread_join(q->threads[i], NULL); - pthread_detach(q->threads[i]); - -#endif /* SRSLTE_SINGLE_THREAD */ - if (q->e[i]) { free(q->e[i]); } @@ -359,7 +322,6 @@ void srslte_pdsch_free(srslte_pdsch_t *q) { /* Free sch objects */ srslte_sch_free(&q->dl_sch[i]); - } for (i = 0; i < q->cell.nof_ports; i++) { @@ -506,7 +468,7 @@ int srslte_pdsch_set_rnti(srslte_pdsch_t *q, uint16_t rnti) { return SRSLTE_SUCCESS; } -static inline int srslte_pdsch_codeword_encode(srslte_pdsch_t *pdsch, srslte_pdsch_cfg_t *cfg, +static int srslte_pdsch_codeword_encode(srslte_pdsch_t *pdsch, srslte_pdsch_cfg_t *cfg, srslte_softbuffer_tx_t *softbuffer, uint16_t rnti, uint8_t *data, uint32_t codeword_idx) { srslte_sch_t *dl_sch = &pdsch->dl_sch[codeword_idx]; @@ -550,33 +512,7 @@ static inline int srslte_pdsch_codeword_encode(srslte_pdsch_t *pdsch, srslte_pds return SRSLTE_SUCCESS; } - -#ifndef SRSLTE_SINGLE_THREAD - -static void *srslte_pdsch_encode_thread(void *arg) { - srslte_pdsch_thread_args_t *q = (srslte_pdsch_thread_args_t *) arg; - uint32_t codeword_idx = q->codeword_idx; - - INFO("[PDSCH Encoder CW %d] waiting for data\n", codeword_idx); - - sem_wait(&q->start); - while (!q->quit) { - q->ret_status = srslte_pdsch_codeword_encode(q->pdsch_ptr, q->cfg, q->softbuffer, q->rnti, q->data, codeword_idx); - - /* Post finish semaphore */ - sem_post(&q->finish); - - /* Wait for next loop */ - sem_wait(&q->start); - } - - pthread_exit(NULL); - return q; -} - -#endif /* SRSLTE_SINGLE_THREAD */ - -static inline int srslte_pdsch_codeword_decode(srslte_pdsch_t *pdsch, srslte_pdsch_cfg_t *cfg, +static int srslte_pdsch_codeword_decode(srslte_pdsch_t *pdsch, srslte_pdsch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffer, uint16_t rnti, uint8_t *data, uint32_t codeword_idx) { srslte_sch_t *dl_sch = &pdsch->dl_sch[codeword_idx]; @@ -588,6 +524,10 @@ static inline int srslte_pdsch_codeword_decode(srslte_pdsch_t *pdsch, srslte_pds cfg->sf_idx, codeword_idx, srslte_mod_string(mcs->mod), mcs->tbs, nbits->nof_re, nbits->nof_bits, (codeword_idx == 0) ? cfg->rv : cfg->rv2); + /* demodulate symbols + * The MAX-log-MAP algorithm used in turbo decoding is unsensitive to SNR estimation, + * thus we don't need tot set it in the LLRs normalization + */ srslte_demod_soft_demodulate_s(mcs->mod, pdsch->d[codeword_idx], pdsch->e[codeword_idx], cfg->nbits.nof_re); if (pdsch->users[rnti] && pdsch->users[rnti]->sequence_generated) { @@ -609,32 +549,6 @@ static inline int srslte_pdsch_codeword_decode(srslte_pdsch_t *pdsch, srslte_pds return SRSLTE_SUCCESS; } -#ifndef SRSLTE_SINGLE_THREAD - -static void *srslte_pdsch_decode_thread(void *arg) { - srslte_pdsch_thread_args_t *q = (srslte_pdsch_thread_args_t *) arg; - uint32_t codeword_idx = q->codeword_idx; - - INFO("[PDSCH Encoder CW %d] waiting for data\n", codeword_idx); - - sem_wait(&q->start); - while (!q->quit) { - q->ret_status = srslte_pdsch_codeword_decode(q->pdsch_ptr, q->cfg, q->softbuffer, q->rnti, q->data, codeword_idx); - - /* Post finish semaphore */ - sem_post(&q->finish); - - /* Wait for next loop */ - sem_wait(&q->start); - } - - pthread_exit(NULL); - return q; -} - -#endif /* SRSLTE_SINGLE_THREAD */ - - void srslte_pdsch_free_rnti(srslte_pdsch_t* q, uint16_t rnti) { if (q->users[rnti]) { @@ -760,32 +674,9 @@ int srslte_pdsch_decode_multi(srslte_pdsch_t *q, srslte_vec_save_file("pdsch_symbols.dat", q->d, cfg->nbits.nof_re*sizeof(cf_t)); } -#ifndef SRSLTE_SINGLE_THREAD - - for (i = 0; i < cfg->grant.nof_tb; i++) { - srslte_pdsch_thread_args_t *thread_args = &q->thread_args[i]; - thread_args->cfg = cfg; - thread_args->softbuffer = &softbuffers[i]; - thread_args->data = data[i]; - thread_args->rnti = rnti; - sem_post(&thread_args->start); - } - - for (i = 0; i < cfg->grant.nof_tb; i++) { - srslte_pdsch_thread_args_t *thread_args = &q->thread_args[i]; - sem_wait(&thread_args->finish); - ret |= thread_args->ret_status; - } - -#else - /* demodulate symbols - * The MAX-log-MAP algorithm used in turbo decoding is unsensitive to SNR estimation, - * thus we don't need tot set it in the LLRs normalization - */ for (uint32_t tb = 0; tb < cfg->grant.nof_tb; tb ++) { ret |= srslte_pdsch_codeword_decode(q, cfg, &softbuffers[tb], rnti, data[tb], tb); } -#endif /* SRSLTE_SINGLE_THREAD */ if (SRSLTE_VERBOSE_ISDEBUG()) { DEBUG("SAVED FILE llr.dat: LLR estimates after demodulation and descrambling\n",0); @@ -799,71 +690,21 @@ int srslte_pdsch_decode_multi(srslte_pdsch_t *q, } } -int srslte_pdsch_ri_pmi_select(srslte_pdsch_t *q, - srslte_pdsch_cfg_t *cfg, - cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], float noise_estimate, uint32_t nof_ce, - uint32_t *ri, uint32_t *pmi, - float *current_sinr) { - uint32_t best_pmi_1l; - uint32_t best_pmi_2l; - float sinr_1l[SRSLTE_MAX_CODEBOOKS]; - float sinr_2l[SRSLTE_MAX_CODEBOOKS]; - float best_sinr_1l = 0.0; - float best_sinr_2l = 0.0; - int n1, n2; +int srslte_pdsch_pmi_select(srslte_pdsch_t *q, + srslte_pdsch_cfg_t *cfg, + cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], float noise_estimate, uint32_t nof_ce, + uint32_t pmi[SRSLTE_MAX_LAYERS], float sinr[SRSLTE_MAX_LAYERS][SRSLTE_MAX_CODEBOOKS]) { if (q->cell.nof_ports == 2 && q->nof_rx_antennas == 2) { - n1 = srslte_precoding_pmi_select(ce, nof_ce, noise_estimate, 1, &best_pmi_1l, sinr_1l); - if (n1 < 0) { - ERROR("PMI Select for 1 layer"); - return SRSLTE_ERROR; - } - - n2 = srslte_precoding_pmi_select(ce, nof_ce, noise_estimate, 2, &best_pmi_2l, sinr_2l); - if (n2 < 0) { - ERROR("PMI Select for 2 layer"); - return SRSLTE_ERROR; - } - - for (int i = 0; i < n1; i++) { - if (sinr_1l[i] > best_sinr_1l) { - best_sinr_1l = sinr_1l[i]; - } - } - - for (int i = 0; i < n2; i++) { - if (sinr_2l[i] > best_sinr_2l) { - best_sinr_2l = sinr_2l[i]; - } - } - - /* Set RI */ - if (ri != NULL) { - *ri = (best_sinr_1l > best_sinr_2l) ? 1 : 2; - } - - /* Set PMI */ - if (pmi != NULL) { - *pmi = (best_sinr_1l > best_sinr_2l) ? best_pmi_1l : best_pmi_2l; - } - - /* Set current SINR */ - if (current_sinr != NULL && cfg->mimo_type == SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX) { - if (cfg->nof_layers == 1) { - *current_sinr = sinr_1l[cfg->codebook_idx]; - } else if (cfg->nof_layers == 2) { - *current_sinr = sinr_2l[cfg->codebook_idx - 1]; - } else { - ERROR("Not implemented number of layers"); - return SRSLTE_ERROR; + for (int nof_layers = 1; nof_layers <= cfg->nof_layers; nof_layers++ ) { + if (sinr[nof_layers - 1] && pmi) { + if (srslte_precoding_pmi_select(ce, nof_ce, noise_estimate, nof_layers, &pmi[nof_layers - 1], + sinr[nof_layers - 1]) < 0) { + ERROR("PMI Select for %d layers", nof_layers); + return SRSLTE_ERROR; + } } } - - /* Print Trace */ - if (ri != NULL && pmi != NULL && current_sinr != NULL) { - INFO("PDSCH Select RI=%d; PMI=%d; Current SINR=%.1fdB (nof_layers=%d, codebook_idx=%d)\n", *ri, *pmi, - 10*log10(*current_sinr), cfg->nof_layers, cfg->codebook_idx); - } } else { ERROR("Not implemented configuration"); return SRSLTE_ERROR_INVALID_INPUTS; @@ -981,28 +822,9 @@ int srslte_pdsch_encode_multi(srslte_pdsch_t *q, return SRSLTE_ERROR_INVALID_INPUTS; } -#ifndef SRSLTE_SINGLE_THREAD - - for (int tb = 0; tb < cfg->grant.nof_tb; tb++) { - srslte_pdsch_thread_args_t *thread_args = &q->thread_args[tb]; - thread_args->cfg = cfg; - thread_args->softbuffer = &softbuffers[tb]; - thread_args->data = data[tb]; - thread_args->rnti = rnti; - sem_post(&thread_args->start); - } - - for (int tb = 0; tb < cfg->grant.nof_tb; tb++) { - srslte_pdsch_thread_args_t *thread_args = &q->thread_args[tb]; - sem_wait(&thread_args->finish); - ret |= thread_args->ret_status; - } - -#else for (uint32_t tb = 0; tb < cfg->grant.nof_tb; tb ++) { ret |= srslte_pdsch_codeword_encode(q, cfg, &softbuffers[tb], rnti, data[tb], tb); } -#endif /* SRSLTE_SINGLE_THREAD */ if (q->cell.nof_ports > 1) { int nof_symbols; diff --git a/lib/src/phy/ue/ue_dl.c b/lib/src/phy/ue/ue_dl.c index 85e851a3e..3f51a3036 100644 --- a/lib/src/phy/ue/ue_dl.c +++ b/lib/src/phy/ue/ue_dl.c @@ -454,9 +454,58 @@ int srslte_ue_dl_decode_rnti_multi(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_POR int srslte_ue_dl_ri_pmi_select(srslte_ue_dl_t *q, uint32_t *ri, uint32_t *pmi, float *current_sinr) { float noise_estimate = srslte_chest_dl_get_noise_estimate(&q->chest); - return srslte_pdsch_ri_pmi_select(&q->pdsch, &q->pdsch_cfg, q->ce_m, noise_estimate, - SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp), - ri, pmi, current_sinr); + float best_sinr = -INFINITY; + uint32_t best_pmi = 0, best_ri = 0; + + if (q->cell.nof_ports == 2 && q->nof_rx_antennas == 2) { + if (srslte_pdsch_pmi_select(&q->pdsch, &q->pdsch_cfg, q->ce_m, noise_estimate, + SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp), q->pmi, q->sinr)) { + ERROR("SINR calculation error"); + return SRSLTE_ERROR; + } + + /* Select the best Rank indicator (RI) and Precoding Matrix Indicator (PMI) */ + for (uint32_t nof_layers = 1; nof_layers <= q->pdsch_cfg.nof_layers; nof_layers++ ) { + if (q->sinr[nof_layers][q->pmi[nof_layers]] > best_sinr) { + best_sinr = q->sinr[nof_layers][q->pmi[nof_layers]]; + best_pmi = q->pmi[nof_layers]; + best_ri = nof_layers; + } + } + + /* Set RI */ + if (ri != NULL) { + *ri = best_ri; + } + + /* Set PMI */ + if (pmi != NULL) { + *pmi = best_pmi; + } + + /* Set current SINR */ + if (current_sinr != NULL && q->pdsch_cfg.mimo_type == SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX) { + if (q->pdsch_cfg.nof_layers == 1) { + *current_sinr = q->sinr[0][q->pdsch_cfg.codebook_idx]; + } else if (q->pdsch_cfg.nof_layers == 2) { + *current_sinr = q->sinr[1][q->pdsch_cfg.codebook_idx - 1]; + } else { + ERROR("Not implemented number of layers"); + return SRSLTE_ERROR; + } + } + + /* Print Trace */ + if (ri != NULL && pmi != NULL && current_sinr != NULL) { + INFO("PDSCH Select RI=%d; PMI=%d; Current SINR=%.1fdB (nof_layers=%d, codebook_idx=%d)\n", *ri, *pmi, + 10*log10(*current_sinr), q->pdsch_cfg.nof_layers, q->pdsch_cfg.codebook_idx); + } + } else { + ERROR("Not implemented configuration"); + return SRSLTE_ERROR_INVALID_INPUTS; + } + + return SRSLTE_SUCCESS; } uint32_t srslte_ue_dl_get_ncce(srslte_ue_dl_t *q) { From 9c9c07a845c7d150a476f0fe5a58a46e385624dd Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Mon, 21 Aug 2017 12:01:34 +0200 Subject: [PATCH 14/60] Improvement in how PDSCH UE shows downlink statistics. --- lib/examples/pdsch_ue.c | 64 ++++++++++++---------- lib/include/srslte/phy/common/phy_common.h | 2 + lib/src/phy/common/phy_common.c | 15 +++++ 3 files changed, 53 insertions(+), 28 deletions(-) diff --git a/lib/examples/pdsch_ue.c b/lib/examples/pdsch_ue.c index 24bdba55b..931a983fa 100644 --- a/lib/examples/pdsch_ue.c +++ b/lib/examples/pdsch_ue.c @@ -512,9 +512,14 @@ int main(int argc, char **argv) { // Variables for measurements uint32_t nframes=0; uint32_t ri = 0, pmi = 0; - float rsrp0=0.0, rsrp1=0.0, rsrq=0.0, noise=0.0, enodebrate = 0.0, uerate = 0.0, sinr = 0.0; + float rsrp0=0.0, rsrp1=0.0, rsrq=0.0, noise=0.0, enodebrate = 0.0, uerate = 0.0, + sinr[SRSLTE_MAX_LAYERS][SRSLTE_MAX_CODEBOOKS]; bool decode_pdsch = false; + for (int i = 0; i < SRSLTE_MAX_LAYERS; i++) { + bzero(sinr[i], sizeof(float)*SRSLTE_MAX_CODEBOOKS); + } + #ifndef DISABLE_RF if (prog_args.rf_gain < 0) { srslte_ue_sync_start_agc(&ue_sync, srslte_rf_set_rx_gain_th_wrapper_, cell_detect_config.init_agc); @@ -618,15 +623,6 @@ int main(int argc, char **argv) { enodebrate = SRSLTE_VEC_EMA((ue_dl.pdsch_cfg.grant.mcs.tbs + ue_dl.pdsch_cfg.grant.mcs2.tbs)/1000.0, enodebrate, 0.05); uerate = SRSLTE_VEC_EMA((n>0)?(ue_dl.pdsch_cfg.grant.mcs.tbs + ue_dl.pdsch_cfg.grant.mcs2.tbs)/1000.0:0.0, uerate, 0.01); - if (ue_dl.cell.nof_ports == 2 && ue_dl.pdsch.nof_rx_antennas == 2) { - float _sinr; - srslte_ue_dl_ri_pmi_select(&ue_dl, &ri, &pmi, &_sinr); - - if (!isinff(_sinr) && !isnanf(_sinr)) { - sinr = SRSLTE_VEC_EMA(_sinr, sinr, 0.05f); - } - } - nframes++; if (isnan(rsrq)) { rsrq = 0; @@ -658,23 +654,34 @@ int main(int argc, char **argv) { 100 * (1 - (float) ue_dl.nof_detected / nof_trials), (float) 100 * ue_dl.pkt_errors / ue_dl.pkts_total); } else { - printf("CFO: %+5.2f kHz, " - "SNR: %+5.1f dB | %+5.1f dB, " - "Rb: %6.2f / %6.2f Mbps, " - "PDCCH-Miss: %5.2f%%, " - "PDSCH-BLER: %5.2f%%, " - "SINR: %3.1f dB RI: %d PMI: %d \r", + /* Compute Rank Indicator (RI) and Precoding Matrix Indicator (PMI) */ + srslte_ue_dl_ri_pmi_select(&ue_dl, &ri, &pmi, NULL); + for (uint32_t nl = 0; nl < SRSLTE_MAX_LAYERS; nl++) { + for (uint32_t cb = 0; cb < SRSLTE_MAX_CODEBOOKS; cb ++) { + sinr[nl][cb] = SRSLTE_VEC_EMA(ue_dl.sinr[nl][cb], sinr[nl][cb], 0.05f); + } + } - srslte_ue_sync_get_cfo(&ue_sync) / 1000, - 10 * log10(rsrp0 / noise), - 10 * log10(rsrp1 / noise), - uerate, - enodebrate, - 100 * (1 - (float) ue_dl.nof_detected / nof_trials), - (float) 100 * ue_dl.pkt_errors / ue_dl.pkts_total, - 10 * log10(sinr), - ri, - pmi); + /* Print Results */ + printf("\033[K Tx scheme: %-10s\n", srslte_mimotype2str(ue_dl.pdsch_cfg.mimo_type)); + printf("\033[K nof layers: %d \n", ue_dl.pdsch_cfg.nof_layers); + printf("\033[Knof codewords: %d \n", ue_dl.pdsch_cfg.grant.nof_tb); + printf("\033[K CFO: %+5.2f kHz\n", srslte_ue_sync_get_cfo(&ue_sync) / 1000); + printf("\033[K SNR: %+5.1f dB | %+5.1f dB\n", 10 * log10(rsrp0 / noise), 10 * log10(rsrp1 / noise)); + printf("\033[K Rb: %6.2f / %6.2f Mbps (net/maximum)\n", uerate, enodebrate); + printf("\033[K PDCCH-Miss: %5.2f%%\n", 100 * (1 - (float) ue_dl.nof_detected / nof_trials)); + printf("\033[K PDSCH-BLER: %5.2f%%\n", (float) 100 * ue_dl.pkt_errors / ue_dl.pkts_total); + printf("\033[K PDSCH-BLER: %5.2f%%\n\n", (float) 100 * ue_dl.pkt_errors / ue_dl.pkts_total); + printf("\033[K\n"); + printf("\033[KSINR (dB) Vs RI and PMI:\n"); + printf("\033[K | RI | 1 | 2 |\n"); + printf("\033[K -------+-------+-------+\n"); + printf("\033[K P | 0 | %5.2f%c| %5.2f%c|\n", 10 * log10(sinr[0][0]), (ri == 1 && pmi == 0)?'*':' ', 10 * log10(sinr[1][0]), (ri == 2 && pmi == 0)?'*':' '); + printf("\033[K M | 1 | %5.2f%c| %5.2f%c|\n", 10 * log10(sinr[0][1]), (ri == 1 && pmi == 1)?'*':' ', 10 * log10(sinr[1][1]), (ri == 2 && pmi == 1)?'*':' '); + printf("\033[K I | 2 | %5.2f%c|-------+ \n", 10 * log10(sinr[0][2]), (ri == 1 && pmi == 2)?'*':' '); + printf("\033[K | 3 | %5.2f%c| \n", 10 * log10(sinr[0][3]), (ri == 1 && pmi == 3)?'*':' '); + printf("\033[K\n\n"); + printf("\033[20A"); } } break; @@ -683,7 +690,7 @@ int main(int argc, char **argv) { sfn++; if (sfn == 1024) { sfn = 0; - printf("\n"); + printf("\033[20B"); ue_dl.pkt_errors = 0; ue_dl.pkts_total = 0; ue_dl.nof_detected = 0; @@ -715,7 +722,8 @@ int main(int argc, char **argv) { sf_cnt++; } // Main loop - + printf("\033[20B"); + #ifndef DISABLE_GRAPHICS if (!prog_args.disable_plots) { if (!pthread_kill(plot_thread, 0)) { diff --git a/lib/include/srslte/phy/common/phy_common.h b/lib/include/srslte/phy/common/phy_common.h index 9859bdfb0..ad9be3e0f 100644 --- a/lib/include/srslte/phy/common/phy_common.h +++ b/lib/include/srslte/phy/common/phy_common.h @@ -282,6 +282,8 @@ SRSLTE_API int srslte_band_get_fd_region(enum band_geographical_area region, SRSLTE_API int srslte_str2mimotype(char *mimo_type_str, srslte_mimo_type_t *type); +SRSLTE_API char *srslte_mimotype2str(srslte_mimo_type_t mimo_type); + SRSLTE_API uint32_t srslte_tti_interval(uint32_t tti1, uint32_t tti2); diff --git a/lib/src/phy/common/phy_common.c b/lib/src/phy/common/phy_common.c index 7be57c63a..8a1d0cb4e 100644 --- a/lib/src/phy/common/phy_common.c +++ b/lib/src/phy/common/phy_common.c @@ -446,6 +446,21 @@ int srslte_str2mimotype(char *mimo_type_str, srslte_mimo_type_t *type) { return SRSLTE_SUCCESS; } +char *srslte_mimotype2str(srslte_mimo_type_t mimo_type) { + switch (mimo_type) { + case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA: + return "Single"; + case SRSLTE_MIMO_TYPE_TX_DIVERSITY: + return "Diversity"; + case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX: + return "Multiplex"; + case SRSLTE_MIMO_TYPE_CDD: + return "CDD"; + default: + return "N/A"; + } +} + float get_fd(struct lte_band *band, uint32_t dl_earfcn) { if (dl_earfcn >= band->dl_earfcn_offset) { return band->fd_low_mhz + 0.1*(dl_earfcn - band->dl_earfcn_offset); From cb4b4f4d4c40c254fdf22ae6fe743f844610063c Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Mon, 21 Aug 2017 12:03:03 +0200 Subject: [PATCH 15/60] Reduce of CFI to 1 for supporting modulation index 28. --- lib/examples/pdsch_enodeb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/examples/pdsch_enodeb.c b/lib/examples/pdsch_enodeb.c index 1275360a4..1ec9dc84b 100644 --- a/lib/examples/pdsch_enodeb.c +++ b/lib/examples/pdsch_enodeb.c @@ -65,7 +65,7 @@ srslte_cell_t cell = { int net_port = -1; // -1 generates random dataThat means there is some problem sending samples to the device -uint32_t cfi=3; +uint32_t cfi = 1; uint32_t mcs_idx = 1, last_mcs_idx = 1; int nof_frames = -1; char mimo_type_str[32] = "single"; From 2c07a1618946e4cb35cf8f0cb0222bfd05e53eb4 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Mon, 21 Aug 2017 16:53:12 +0200 Subject: [PATCH 16/60] DL grant parameter are now vectors of MAX_CODEWORDS --- lib/examples/pdsch_enodeb.c | 32 ++--- lib/examples/pdsch_ue.c | 20 +-- lib/include/srslte/phy/phch/pdsch.h | 7 +- lib/include/srslte/phy/phch/pdsch_cfg.h | 13 +- lib/include/srslte/phy/phch/ra.h | 10 +- lib/include/srslte/phy/phch/sch.h | 6 - lib/include/srslte/phy/ue/ue_dl.h | 5 +- lib/include/srslte/phy/utils/debug.h | 4 +- lib/src/phy/phch/pdsch.c | 176 +++++++++++------------- lib/src/phy/phch/ra.c | 71 ++++------ lib/src/phy/phch/sch.c | 80 ++--------- lib/src/phy/phch/test/pdsch_test.c | 130 ++++++++--------- lib/src/phy/ue/ue_dl.c | 61 ++++---- srsenb/src/phy/phch_worker.cc | 6 +- srsue/hdr/phy/phch_worker.h | 17 ++- srsue/src/phy/phch_worker.cc | 82 ++++++++--- 16 files changed, 331 insertions(+), 389 deletions(-) diff --git a/lib/examples/pdsch_enodeb.c b/lib/examples/pdsch_enodeb.c index 1ec9dc84b..1bc2d5230 100644 --- a/lib/examples/pdsch_enodeb.c +++ b/lib/examples/pdsch_enodeb.c @@ -86,7 +86,8 @@ srslte_pdsch_t pdsch; srslte_pdsch_cfg_t pdsch_cfg; srslte_softbuffer_tx_t softbuffers[SRSLTE_MAX_CODEWORDS]; srslte_regs_t regs; -srslte_ra_dl_dci_t ra_dl; +srslte_ra_dl_dci_t ra_dl; +int rvidx[SRSLTE_MAX_CODEWORDS] = {0, 0}; cf_t *sf_buffer[SRSLTE_MAX_PORTS] = {NULL}, *output_buffer [SRSLTE_MAX_PORTS] = {NULL}; int sf_n_re, sf_n_samples; @@ -423,7 +424,7 @@ int update_radl() { ra_dl.harq_process = 0; ra_dl.mcs_idx = mcs_idx; ra_dl.ndi = 0; - ra_dl.rv_idx = 0; + ra_dl.rv_idx = rvidx[0]; ra_dl.alloc_type = SRSLTE_RA_ALLOC_TYPE0; ra_dl.type0_alloc.rbg_bitmask = prbset_to_bitmask(); ra_dl.tb_en[0] = 1; @@ -431,7 +432,7 @@ int update_radl() { if (nof_tb > 1) { ra_dl.mcs_idx_1 = mcs_idx; ra_dl.ndi_1 = 0; - ra_dl.rv_idx_1 = 0; + ra_dl.rv_idx_1 = rvidx[1]; ra_dl.tb_en[1] = 1; } @@ -513,7 +514,7 @@ void *net_thread_fnc(void *arg) { n = srslte_netsource_read(&net_source, &data2[rpm], DATA_BUFF_SZ-rpm); if (n > 0) { // FIXME: I assume that both transport blocks have same size in case of 2 tb are active - int nbytes = 1 + (pdsch_cfg.grant.mcs.tbs + pdsch_cfg.grant.mcs2.tbs - 1) / 8; + int nbytes = 1 + (pdsch_cfg.grant.mcs[0].tbs + pdsch_cfg.grant.mcs[1].tbs - 1) / 8; rpm += n; INFO("received %d bytes. rpm=%d/%d\n",n,rpm,nbytes); wpm = 0; @@ -696,12 +697,11 @@ int main(int argc, char **argv) { INFO("Transmitting packet\n",0); } } else { - INFO("SF: %d, Generating %d random bits\n", sf_idx, pdsch_cfg.grant.mcs.tbs); - for (i = 0; i < pdsch_cfg.grant.mcs.tbs / 8; i++) { - data[0][i] = rand() % 256; - } - for (i = 0; i < pdsch_cfg.grant.mcs2.tbs / 8; i++) { - data[1][i] = rand() % 256; + INFO("SF: %d, Generating %d random bits\n", sf_idx, pdsch_cfg.grant.mcs[0].tbs + pdsch_cfg.grant.mcs[1].tbs); + for (uint32_t tb = 0; tb < pdsch_cfg.grant.nof_tb; tb++) { + for (i = 0; i < pdsch_cfg.grant.mcs[tb].tbs / 8; i++) { + data[tb][i] = (uint8_t) rand(); + } } /* Uncomment this to transmit on sf 0 and 5 only */ if (sf_idx != 0 && sf_idx != 5) { @@ -744,7 +744,7 @@ int main(int argc, char **argv) { /* Configure pdsch_cfg parameters */ srslte_ra_dl_grant_t grant; srslte_ra_dl_dci_to_grant(&ra_dl, cell.nof_prb, UE_CRNTI, &grant); - if (srslte_pdsch_cfg_multi(&pdsch_cfg, cell, &grant, cfi, sf_idx, 0, 0, pdsch_cfg.mimo_type, multiplex_pmi)) { + if (srslte_pdsch_cfg_multi(&pdsch_cfg, cell, &grant, cfi, sf_idx, rvidx, pdsch_cfg.mimo_type, multiplex_pmi)) { fprintf(stderr, "Error configuring PDSCH\n"); exit(-1); } @@ -757,13 +757,9 @@ int main(int argc, char **argv) { } if (net_port > 0 && net_packet_ready) { if (null_file_sink) { - srslte_bit_pack_vector(data[0], data_tmp, pdsch_cfg.grant.mcs.tbs); - if (srslte_netsink_write(&net_sink, data_tmp, 1+(pdsch_cfg.grant.mcs.tbs-1)/8) < 0) { - fprintf(stderr, "Error sending data through UDP socket\n"); - } - if (nof_tb > 1) { - srslte_bit_pack_vector(data[1], data_tmp, pdsch_cfg.grant.mcs2.tbs); - if (srslte_netsink_write(&net_sink, data_tmp, 1 + (pdsch_cfg.grant.mcs2.tbs - 1) / 8) < 0) { + for (uint32_t tb = 0; tb < pdsch_cfg.grant.nof_tb; tb++) { + srslte_bit_pack_vector(data[tb], data_tmp, pdsch_cfg.grant.mcs[tb].tbs); + if (srslte_netsink_write(&net_sink, data_tmp, 1 + (pdsch_cfg.grant.mcs[tb].tbs - 1) / 8) < 0) { fprintf(stderr, "Error sending data through UDP socket\n"); } } diff --git a/lib/examples/pdsch_ue.c b/lib/examples/pdsch_ue.c index 931a983fa..60cc0a4db 100644 --- a/lib/examples/pdsch_ue.c +++ b/lib/examples/pdsch_ue.c @@ -594,8 +594,10 @@ int main(int argc, char **argv) { /* Send data if socket active */ if (prog_args.net_port > 0) { // FIXME: UDP Data transmission does not work - srslte_netsink_write(&net_sink, data[0], 1 + (ue_dl.pdsch_cfg.grant.mcs.tbs - 1) / 8); - srslte_netsink_write(&net_sink, data[1], 1 + (ue_dl.pdsch_cfg.grant.mcs2.tbs - 1) / 8); + for (uint32_t tb = 0; tb < ue_dl.pdsch_cfg.grant.nof_tb; tb++) { + srslte_netsink_write(&net_sink, data[tb], 1 + (ue_dl.pdsch_cfg.grant.mcs[tb].tbs - 1) / 8); + + } } #ifdef PRINT_CHANGE_SCHEDULIGN @@ -616,12 +618,12 @@ int main(int argc, char **argv) { nof_trials++; - rsrq = SRSLTE_VEC_EMA(srslte_chest_dl_get_rsrq(&ue_dl.chest), rsrq, 0.1); - rsrp0 = SRSLTE_VEC_EMA(srslte_chest_dl_get_rsrp_port(&ue_dl.chest, 0), rsrp0, 0.05); - rsrp1 = SRSLTE_VEC_EMA(srslte_chest_dl_get_rsrp_port(&ue_dl.chest, 1), rsrp1, 0.05); - noise = SRSLTE_VEC_EMA(srslte_chest_dl_get_noise_estimate(&ue_dl.chest), noise, 0.05); - enodebrate = SRSLTE_VEC_EMA((ue_dl.pdsch_cfg.grant.mcs.tbs + ue_dl.pdsch_cfg.grant.mcs2.tbs)/1000.0, enodebrate, 0.05); - uerate = SRSLTE_VEC_EMA((n>0)?(ue_dl.pdsch_cfg.grant.mcs.tbs + ue_dl.pdsch_cfg.grant.mcs2.tbs)/1000.0:0.0, uerate, 0.01); + rsrq = SRSLTE_VEC_EMA(srslte_chest_dl_get_rsrq(&ue_dl.chest), rsrq, 0.1f); + rsrp0 = SRSLTE_VEC_EMA(srslte_chest_dl_get_rsrp_port(&ue_dl.chest, 0), rsrp0, 0.05f); + rsrp1 = SRSLTE_VEC_EMA(srslte_chest_dl_get_rsrp_port(&ue_dl.chest, 1), rsrp1, 0.05f); + noise = SRSLTE_VEC_EMA(srslte_chest_dl_get_noise_estimate(&ue_dl.chest), noise, 0.05f); + enodebrate = SRSLTE_VEC_EMA((ue_dl.pdsch_cfg.grant.mcs[0].tbs + ue_dl.pdsch_cfg.grant.mcs[1].tbs)/1000.0f, enodebrate, 0.05f); + uerate = SRSLTE_VEC_EMA((n>0)?(ue_dl.pdsch_cfg.grant.mcs[0].tbs + ue_dl.pdsch_cfg.grant.mcs[1].tbs)/1000.0f:0.0f, uerate, 0.01f); nframes++; if (isnan(rsrq)) { @@ -812,7 +814,7 @@ void *plot_thread_run(void *arg) { while(1) { sem_wait(&plot_sem); - uint32_t nof_symbols = ue_dl.pdsch_cfg.nbits.nof_re; + uint32_t nof_symbols = ue_dl.pdsch_cfg.nbits[0].nof_re; if (!prog_args.disable_plots_except_constellation) { for (i = 0; i < nof_re; i++) { tmp_plot[i] = 20 * log10f(cabsf(ue_dl.sf_symbols[i])); diff --git a/lib/include/srslte/phy/phch/pdsch.h b/lib/include/srslte/phy/phch/pdsch.h index 9a9b16788..99710b965 100644 --- a/lib/include/srslte/phy/phch/pdsch.h +++ b/lib/include/srslte/phy/phch/pdsch.h @@ -104,15 +104,14 @@ SRSLTE_API int srslte_pdsch_cfg(srslte_pdsch_cfg_t *cfg, srslte_ra_dl_grant_t *grant, uint32_t cfi, uint32_t sf_idx, - uint32_t rvidx); + int rvidx); SRSLTE_API int srslte_pdsch_cfg_multi(srslte_pdsch_cfg_t *cfg, srslte_cell_t cell, srslte_ra_dl_grant_t *grant, uint32_t cfi, uint32_t sf_idx, - uint32_t rvidx, - uint32_t rvidx2, + int rvidx[SRSLTE_MAX_CODEWORDS], srslte_mimo_type_t mimo_type, uint32_t pmi); @@ -156,7 +155,7 @@ SRSLTE_API int srslte_pdsch_pmi_select(srslte_pdsch_t *q, uint32_t pmi[SRSLTE_MAX_LAYERS], float sinr[SRSLTE_MAX_LAYERS][SRSLTE_MAX_CODEBOOKS]); -SRSLTE_API void srslte_pdsch_set_max_noi(srslte_pdsch_t *q, int max_iter); +SRSLTE_API void srslte_pdsch_set_max_noi(srslte_pdsch_t *q, uint32_t max_iter); SRSLTE_API float srslte_pdsch_average_noi(srslte_pdsch_t *q); diff --git a/lib/include/srslte/phy/phch/pdsch_cfg.h b/lib/include/srslte/phy/phch/pdsch_cfg.h index 9664d826d..eb4927fbb 100644 --- a/lib/include/srslte/phy/phch/pdsch_cfg.h +++ b/lib/include/srslte/phy/phch/pdsch_cfg.h @@ -40,14 +40,11 @@ #include "srslte/phy/fec/cbsegm.h" typedef struct SRSLTE_API { - srslte_cbsegm_t cb_segm; - srslte_cbsegm_t cb_segm2; - srslte_ra_dl_grant_t grant; - srslte_ra_nbits_t nbits; - srslte_ra_nbits_t nbits2; - uint32_t rv; - uint32_t rv2; - uint32_t sf_idx; + srslte_cbsegm_t cb_segm[SRSLTE_MAX_CODEWORDS]; + srslte_ra_dl_grant_t grant; + srslte_ra_nbits_t nbits[SRSLTE_MAX_CODEWORDS]; + uint32_t rv[SRSLTE_MAX_CODEWORDS]; + uint32_t sf_idx; uint32_t nof_layers; uint32_t codebook_idx; srslte_mimo_type_t mimo_type; diff --git a/lib/include/srslte/phy/phch/ra.h b/lib/include/srslte/phy/phch/ra.h index 8a025ad97..c99dba1a1 100644 --- a/lib/include/srslte/phy/phch/ra.h +++ b/lib/include/srslte/phy/phch/ra.h @@ -102,10 +102,8 @@ typedef struct SRSLTE_API { typedef struct SRSLTE_API { bool prb_idx[2][SRSLTE_MAX_PRB]; uint32_t nof_prb; - uint32_t Qm; - uint32_t Qm2; - srslte_ra_mcs_t mcs; - srslte_ra_mcs_t mcs2; + uint32_t Qm[SRSLTE_MAX_CODEWORDS]; + srslte_ra_mcs_t mcs[SRSLTE_MAX_CODEWORDS]; uint32_t nof_tb; } srslte_ra_dl_grant_t; @@ -206,8 +204,8 @@ SRSLTE_API int srslte_ra_dl_dci_to_grant(srslte_ra_dl_dci_t *dci, SRSLTE_API void srslte_ra_dl_grant_to_nbits(srslte_ra_dl_grant_t *grant, uint32_t cfi, srslte_cell_t cell, - uint32_t sf_idx, - srslte_ra_nbits_t *nbits); + uint32_t sf_idx, + srslte_ra_nbits_t nbits[SRSLTE_MAX_CODEWORDS]); SRSLTE_API void srslte_ra_dl_grant_to_nbits_multi(srslte_ra_dl_grant_t *grant, uint32_t cfi, diff --git a/lib/include/srslte/phy/phch/sch.h b/lib/include/srslte/phy/phch/sch.h index 4fa1b3b0f..a03387448 100644 --- a/lib/include/srslte/phy/phch/sch.h +++ b/lib/include/srslte/phy/phch/sch.h @@ -103,12 +103,6 @@ SRSLTE_API int srslte_dlsch_encode2(srslte_sch_t *q, uint8_t *e_bits, int codeword_idx); -SRSLTE_API int srslte_dlsch_encode_multi(srslte_sch_t *q, - srslte_pdsch_cfg_t *cfg, - srslte_softbuffer_tx_t softbuffers[SRSLTE_MAX_CODEWORDS], - uint8_t *data[SRSLTE_MAX_CODEWORDS], - uint8_t *e_bits[SRSLTE_MAX_CODEWORDS]); - SRSLTE_API int srslte_dlsch_decode(srslte_sch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffer, diff --git a/lib/include/srslte/phy/ue/ue_dl.h b/lib/include/srslte/phy/ue/ue_dl.h index 0fc8f9422..268a8c4d9 100644 --- a/lib/include/srslte/phy/ue/ue_dl.h +++ b/lib/include/srslte/phy/ue/ue_dl.h @@ -145,14 +145,13 @@ SRSLTE_API int srslte_ue_dl_cfg_grant(srslte_ue_dl_t *q, srslte_ra_dl_grant_t *grant, uint32_t cfi, uint32_t sf_idx, - uint32_t rvidx); + int rvidx); SRSLTE_API int srslte_ue_dl_cfg_grant_multi(srslte_ue_dl_t *q, srslte_ra_dl_grant_t *grant, uint32_t cfi, uint32_t sf_idx, - uint32_t rvidx, - uint32_t rvidx2, + int rvidx[SRSLTE_MAX_CODEWORDS], srslte_mimo_type_t mimo_type, uint32_t pinfo); diff --git a/lib/include/srslte/phy/utils/debug.h b/lib/include/srslte/phy/utils/debug.h index e4b4756f8..c88e1a3ce 100644 --- a/lib/include/srslte/phy/utils/debug.h +++ b/lib/include/srslte/phy/utils/debug.h @@ -58,10 +58,10 @@ SRSLTE_API extern int srslte_verbose; #define PRINT_NONE srslte_verbose=SRSLTE_VERBOSE_NONE #define DEBUG(_fmt, ...) if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_DEBUG) \ - fprintf(stdout, "[DEBUG]: " _fmt, __VA_ARGS__) + fprintf(stdout, "[DEBUG]: " _fmt, ##__VA_ARGS__) #define INFO(_fmt, ...) if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO) \ - fprintf(stdout, "[INFO]: " _fmt, __VA_ARGS__) + fprintf(stdout, "[INFO]: " _fmt, ##__VA_ARGS__) #if CMAKE_BUILD_TYPE==Debug /* In debug mode, it prints out the */ diff --git a/lib/src/phy/phch/pdsch.c b/lib/src/phy/phch/pdsch.c index 31642751f..35e10fedb 100644 --- a/lib/src/phy/phch/pdsch.c +++ b/lib/src/phy/phch/pdsch.c @@ -358,50 +358,35 @@ void srslte_pdsch_free(srslte_pdsch_t *q) { /* Configures the structure srslte_pdsch_cfg_t from the DL DCI allocation dci_msg. * If dci_msg is NULL, the grant is assumed to be already stored in cfg->grant */ -int srslte_pdsch_cfg(srslte_pdsch_cfg_t *cfg, srslte_cell_t cell, srslte_ra_dl_grant_t *grant, uint32_t cfi, uint32_t sf_idx, uint32_t rvidx) -{ - if (cfg) { - if (grant) { - memcpy(&cfg->grant, grant, sizeof(srslte_ra_dl_grant_t)); - } - if (srslte_cbsegm(&cfg->cb_segm, cfg->grant.mcs.tbs)) { - fprintf(stderr, "Error computing Codeblock segmentation for TBS=%d\n", cfg->grant.mcs.tbs); - return SRSLTE_ERROR; - } - srslte_ra_dl_grant_to_nbits(&cfg->grant, cfi, cell, sf_idx, &cfg->nbits); - cfg->sf_idx = sf_idx; - cfg->rv = rvidx; +int srslte_pdsch_cfg(srslte_pdsch_cfg_t *cfg, srslte_cell_t cell, srslte_ra_dl_grant_t *grant, uint32_t cfi, + uint32_t sf_idx, int rvidx) { + int _rvids[SRSLTE_MAX_CODEWORDS] = {1}; + _rvids[0] = rvidx; - return SRSLTE_SUCCESS; - } else { - return SRSLTE_ERROR_INVALID_INPUTS; - } + return srslte_pdsch_cfg_multi(cfg, cell, grant, cfi, sf_idx, _rvids, SRSLTE_MIMO_TYPE_SINGLE_ANTENNA, 0); } /* Configures the structure srslte_pdsch_cfg_t from the DL DCI allocation dci_msg. * If dci_msg is NULL, the grant is assumed to be already stored in cfg->grant */ int srslte_pdsch_cfg_multi(srslte_pdsch_cfg_t *cfg, srslte_cell_t cell, srslte_ra_dl_grant_t *grant, uint32_t cfi, - uint32_t sf_idx, uint32_t rvidx, uint32_t rvidx2, srslte_mimo_type_t mimo_type, uint32_t pmi) -{ + uint32_t sf_idx, int rvidx[SRSLTE_MAX_CODEWORDS], srslte_mimo_type_t mimo_type, + uint32_t pmi) { if (cfg) { if (grant) { memcpy(&cfg->grant, grant, sizeof(srslte_ra_dl_grant_t)); } - if (srslte_cbsegm(&cfg->cb_segm, (uint32_t) cfg->grant.mcs.tbs)) { - fprintf(stderr, "Error computing Codeblock (1) segmentation for TBS=%d\n", cfg->grant.mcs.tbs); - return SRSLTE_ERROR; - } - if (srslte_cbsegm(&cfg->cb_segm2, (uint32_t) cfg->grant.mcs2.tbs)) { - fprintf(stderr, "Error computing Codeblock (2) segmentation for TBS=%d\n", cfg->grant.mcs2.tbs); - return SRSLTE_ERROR; + for (int i = 0; i < grant->nof_tb; i++) { + if (srslte_cbsegm(&cfg->cb_segm[i], (uint32_t) cfg->grant.mcs[i].tbs)) { + fprintf(stderr, "Error computing Codeblock (1) segmentation for TBS=%d\n", cfg->grant.mcs[i].tbs); + return SRSLTE_ERROR; + } } + srslte_ra_dl_grant_to_nbits(&cfg->grant, cfi, cell, sf_idx, cfg->nbits); - srslte_ra_dl_grant_to_nbits_multi(&cfg->grant, cfi, cell, sf_idx, &cfg->nbits, &cfg->nbits2); cfg->sf_idx = sf_idx; - cfg->rv = rvidx; - cfg->rv2 = rvidx2; + memcpy(cfg->rv, rvidx, sizeof(uint32_t) * SRSLTE_MAX_CODEWORDS); cfg->mimo_type = mimo_type; /* Check and configure PDSCH transmission modes */ @@ -428,11 +413,12 @@ int srslte_pdsch_cfg_multi(srslte_pdsch_cfg_t *cfg, srslte_cell_t cell, srslte_r cfg->codebook_idx = pmi + 1; cfg->nof_layers = 2; } - INFO("PDSCH configured for Spatial Multiplex; nof_codewords=%d; nof_layers=%d; codebook_idx=%d;\n", grant->nof_tb, cfg->nof_layers, cfg->codebook_idx); + INFO("PDSCH configured for Spatial Multiplex; nof_codewords=%d; nof_layers=%d; codebook_idx=%d;\n", + grant->nof_tb, cfg->nof_layers, cfg->codebook_idx); break; case SRSLTE_MIMO_TYPE_CDD: if (grant->nof_tb != 2) { - ERROR("Number of transport blocks is not supported for CDD transmission mode."); + ERROR("Number of transport blocks (%d) is not supported for CDD transmission mode.", grant->nof_tb); return SRSLTE_ERROR; } cfg->nof_layers = 2; @@ -472,13 +458,14 @@ static int srslte_pdsch_codeword_encode(srslte_pdsch_t *pdsch, srslte_pdsch_cfg_ srslte_softbuffer_tx_t *softbuffer, uint16_t rnti, uint8_t *data, uint32_t codeword_idx) { srslte_sch_t *dl_sch = &pdsch->dl_sch[codeword_idx]; - srslte_ra_nbits_t *nbits = (codeword_idx == 0) ? &cfg->nbits : &cfg->nbits2; - srslte_ra_mcs_t *mcs = (codeword_idx == 0) ? &cfg->grant.mcs : &cfg->grant.mcs2; + srslte_ra_nbits_t *nbits = &cfg->nbits[codeword_idx]; + srslte_ra_mcs_t *mcs = &cfg->grant.mcs[codeword_idx]; + uint32_t rv = cfg->rv[codeword_idx]; if (nbits->nof_bits) { INFO("Encoding PDSCH SF: %d (TB %d), Mod %s, NofBits: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d\n", cfg->sf_idx, codeword_idx, srslte_mod_string(mcs->mod), mcs->tbs, - nbits->nof_re, nbits->nof_bits, (codeword_idx == 0) ? cfg->rv : cfg->rv2); + nbits->nof_re, nbits->nof_bits, rv); /* Channel coding */ if (srslte_dlsch_encode2(dl_sch, cfg, softbuffer, data, pdsch->e[codeword_idx], codeword_idx)) { @@ -516,19 +503,20 @@ static int srslte_pdsch_codeword_decode(srslte_pdsch_t *pdsch, srslte_pdsch_cfg_ srslte_softbuffer_rx_t *softbuffer, uint16_t rnti, uint8_t *data, uint32_t codeword_idx) { srslte_sch_t *dl_sch = &pdsch->dl_sch[codeword_idx]; - srslte_ra_nbits_t *nbits = (codeword_idx == 0) ? &cfg->nbits : &cfg->nbits2; - srslte_ra_mcs_t *mcs = (codeword_idx == 0) ? &cfg->grant.mcs : &cfg->grant.mcs2; + srslte_ra_nbits_t *nbits = &cfg->nbits[codeword_idx]; + srslte_ra_mcs_t *mcs = &cfg->grant.mcs[codeword_idx]; + uint32_t rv = cfg->rv[codeword_idx]; if (nbits->nof_bits) { INFO("Decoding PDSCH SF: %d (TB %d), Mod %s, NofBits: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d\n", cfg->sf_idx, codeword_idx, srslte_mod_string(mcs->mod), mcs->tbs, - nbits->nof_re, nbits->nof_bits, (codeword_idx == 0) ? cfg->rv : cfg->rv2); + nbits->nof_re, nbits->nof_bits, rv); /* demodulate symbols * The MAX-log-MAP algorithm used in turbo decoding is unsensitive to SNR estimation, * thus we don't need tot set it in the LLRs normalization */ - srslte_demod_soft_demodulate_s(mcs->mod, pdsch->d[codeword_idx], pdsch->e[codeword_idx], cfg->nbits.nof_re); + srslte_demod_soft_demodulate_s(mcs->mod, pdsch->d[codeword_idx], pdsch->e[codeword_idx], nbits->nof_re); if (pdsch->users[rnti] && pdsch->users[rnti]->sequence_generated) { srslte_scrambling_s_offset(&pdsch->users[rnti]->seq[codeword_idx][cfg->sf_idx], pdsch->e[codeword_idx], @@ -596,23 +584,22 @@ int srslte_pdsch_decode_multi(srslte_pdsch_t *q, cfg != NULL) { - INFO("Decoding PDSCH SF: %d, RNTI: 0x%x, Mod %s, TBS: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: [%d %d], C_prb=%d\n", - cfg->sf_idx, rnti, srslte_mod_string(cfg->grant.mcs.mod), cfg->grant.mcs.tbs, cfg->nbits.nof_re, - cfg->nbits.nof_bits, cfg->rv, cfg->rv2, cfg->grant.nof_prb); + INFO("Decoding PDSCH SF: %d, RNTI: 0x%x, NofSymbols: %d, C_prb=%d\n", + cfg->sf_idx, rnti, cfg->nbits[0].nof_re, cfg->grant.nof_prb); for (int j=0;jnof_rx_antennas;j++) { /* extract symbols */ - int 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); + int n = srslte_pdsch_get(q, sf_symbols[j], q->symbols[j], &cfg->grant, cfg->nbits[0].lstart, cfg->sf_idx); + if (n != cfg->nbits[0].nof_re) { + fprintf(stderr, "Error expecting %d symbols but got %d\n", cfg->nbits[0].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); + n = srslte_pdsch_get(q, ce[i][j], q->ce[i][j], &cfg->grant, cfg->nbits[0].lstart, cfg->sf_idx); + if (n != cfg->nbits[0].nof_re) { + fprintf(stderr, "Error expecting %d symbols but got %d\n", cfg->nbits[0].nof_re, n); return SRSLTE_ERROR; } } @@ -620,35 +607,31 @@ int srslte_pdsch_decode_multi(srslte_pdsch_t *q, INFO("PDSCH Layer demapper and predecode: mimo_type=%d, nof_layers=%d, nof_tb=%d\n", cfg->mimo_type, cfg->nof_layers, cfg->grant.nof_tb); - if (q->cell.nof_ports == 1) { - /* no need for layer demapping */ - srslte_predecoding_single_multi(q->symbols, q->ce[0], q->d[0], q->nof_rx_antennas, cfg->nbits.nof_re, noise_estimate); - } else { - int nof_symbols [SRSLTE_MAX_CODEWORDS]; - nof_symbols[0] = cfg->nbits.nof_re * cfg->grant.nof_tb / cfg->nof_layers; - nof_symbols[1] = cfg->nbits2.nof_re * cfg->grant.nof_tb / cfg->nof_layers; - - if (cfg->nof_layers == cfg->grant.nof_tb) { - for (i = 0; i < cfg->nof_layers; i++) { - x[i] = q->d[i]; - } + int nof_symbols [SRSLTE_MAX_CODEWORDS]; + nof_symbols[0] = cfg->nbits[0].nof_re * cfg->grant.nof_tb / cfg->nof_layers; + nof_symbols[1] = cfg->nbits[1].nof_re * cfg->grant.nof_tb / cfg->nof_layers; + + if (cfg->nof_layers == cfg->grant.nof_tb) { + /* Skip layer demap */ + for (i = 0; i < cfg->nof_layers; i++) { + x[i] = q->d[i]; + } - srslte_predecoding_type_multi(q->symbols, q->ce, x, q->nof_rx_antennas, q->cell.nof_ports, cfg->nof_layers, - cfg->codebook_idx, cfg->nbits.nof_re, cfg->mimo_type, noise_estimate); + srslte_predecoding_type_multi(q->symbols, q->ce, x, q->nof_rx_antennas, q->cell.nof_ports, cfg->nof_layers, + cfg->codebook_idx, cfg->nbits[0].nof_re, cfg->mimo_type, noise_estimate); - } else { - /* number of layers equals number of ports */ - for (i = 0; i < cfg->nof_layers; i++) { - x[i] = q->x[i]; - } - memset(&x[cfg->nof_layers], 0, sizeof(cf_t*) * (SRSLTE_MAX_LAYERS - cfg->nof_layers)); + } else { + /* number of layers equals number of ports */ + for (i = 0; i < cfg->nof_layers; i++) { + x[i] = q->x[i]; + } + memset(&x[cfg->nof_layers], 0, sizeof(cf_t*) * (SRSLTE_MAX_LAYERS - cfg->nof_layers)); - srslte_predecoding_type_multi(q->symbols, q->ce, x, q->nof_rx_antennas, q->cell.nof_ports, cfg->nof_layers, - cfg->codebook_idx, cfg->nbits.nof_re, cfg->mimo_type, noise_estimate); + srslte_predecoding_type_multi(q->symbols, q->ce, x, q->nof_rx_antennas, q->cell.nof_ports, cfg->nof_layers, + cfg->codebook_idx, cfg->nbits[0].nof_re, cfg->mimo_type, noise_estimate); - srslte_layerdemap_type(x, q->d, cfg->nof_layers, cfg->grant.nof_tb, - nof_symbols[0], nof_symbols, cfg->mimo_type); - } + srslte_layerdemap_type(x, q->d, cfg->nof_layers, cfg->grant.nof_tb, + nof_symbols[0], nof_symbols, cfg->mimo_type); } if (SRSLTE_VERBOSE_ISDEBUG()) { @@ -671,7 +654,7 @@ int srslte_pdsch_decode_multi(srslte_pdsch_t *q, } } DEBUG("SAVED FILE pdsch_symbols.dat: symbols after equalization\n",0); - srslte_vec_save_file("pdsch_symbols.dat", q->d, cfg->nbits.nof_re*sizeof(cf_t)); + srslte_vec_save_file("pdsch_symbols.dat", q->d, cfg->nbits[0].nof_re*sizeof(cf_t)); } for (uint32_t tb = 0; tb < cfg->grant.nof_tb; tb ++) { @@ -680,7 +663,7 @@ int srslte_pdsch_decode_multi(srslte_pdsch_t *q, if (SRSLTE_VERBOSE_ISDEBUG()) { DEBUG("SAVED FILE llr.dat: LLR estimates after demodulation and descrambling\n",0); - srslte_vec_save_file("llr.dat", q->e, cfg->nbits.nof_bits*sizeof(int16_t)); + srslte_vec_save_file("llr.dat", q->e, cfg->nbits[0].nof_bits*sizeof(int16_t)); } return ret; @@ -733,20 +716,20 @@ int srslte_pdsch_encode(srslte_pdsch_t *q, } } - if (cfg->grant.mcs.tbs == 0) { + if (cfg->grant.mcs[0].tbs == 0) { return SRSLTE_ERROR_INVALID_INPUTS; } - if (cfg->nbits.nof_re > q->max_re) { + if (cfg->nbits[0].nof_re > q->max_re) { fprintf(stderr, "Error too many RE per subframe (%d). PDSCH configured for %d RE (%d PRB)\n", - cfg->nbits.nof_re, q->max_re, q->cell.nof_prb); + cfg->nbits[0].nof_re, q->max_re, q->cell.nof_prb); return SRSLTE_ERROR_INVALID_INPUTS; } INFO("Encoding PDSCH SF: %d, Mod %s, NofBits: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d\n", - cfg->sf_idx, srslte_mod_string(cfg->grant.mcs.mod), cfg->grant.mcs.tbs, - cfg->nbits.nof_re, cfg->nbits.nof_bits, cfg->rv); + cfg->sf_idx, srslte_mod_string(cfg->grant.mcs[0].mod), cfg->grant.mcs[0].tbs, + cfg->nbits[0].nof_re, cfg->nbits[0].nof_bits, cfg->rv[0]); /* number of layers equals number of ports */ for (i = 0; i < q->cell.nof_ports; i++) { @@ -761,30 +744,30 @@ int srslte_pdsch_encode(srslte_pdsch_t *q, /* scramble */ if (q->users[rnti] && q->users[rnti]->sequence_generated) { - srslte_scrambling_bytes(&q->users[rnti]->seq[0][cfg->sf_idx], (uint8_t*) q->e[0], cfg->nbits.nof_bits); + srslte_scrambling_bytes(&q->users[rnti]->seq[0][cfg->sf_idx], (uint8_t*) q->e[0], cfg->nbits[0].nof_bits); } else { srslte_sequence_t seq; - if (srslte_sequence_pdsch(&seq, rnti, 0, 2 * cfg->sf_idx, q->cell.id, cfg->nbits.nof_bits)) { + if (srslte_sequence_pdsch(&seq, rnti, 0, 2 * cfg->sf_idx, q->cell.id, cfg->nbits[0].nof_bits)) { return SRSLTE_ERROR; } - srslte_scrambling_bytes(&seq, (uint8_t*) q->e[0], cfg->nbits.nof_bits); + srslte_scrambling_bytes(&seq, (uint8_t*) q->e[0], cfg->nbits[0].nof_bits); srslte_sequence_free(&seq); } - srslte_mod_modulate_bytes(&q->mod[cfg->grant.mcs.mod], (uint8_t*) q->e[0], q->d[0], cfg->nbits.nof_bits); + srslte_mod_modulate_bytes(&q->mod[cfg->grant.mcs[0].mod], (uint8_t*) q->e[0], q->d[0], cfg->nbits[0].nof_bits); /* TODO: only diversity supported */ if (q->cell.nof_ports > 1) { - srslte_layermap_diversity(q->d[0], x, q->cell.nof_ports, cfg->nbits.nof_re); + srslte_layermap_diversity(q->d[0], x, q->cell.nof_ports, cfg->nbits[0].nof_re); srslte_precoding_diversity(x, q->symbols, q->cell.nof_ports, - cfg->nbits.nof_re / q->cell.nof_ports); + cfg->nbits[0].nof_re / q->cell.nof_ports); } else { - memcpy(q->symbols[0], q->d, cfg->nbits.nof_re * sizeof(cf_t)); + memcpy(q->symbols[0], q->d, cfg->nbits[0].nof_re * sizeof(cf_t)); } /* mapping to resource elements */ for (i = 0; i < q->cell.nof_ports; i++) { - srslte_pdsch_put(q, q->symbols[i], sf_symbols[i], &cfg->grant, cfg->nbits.lstart, cfg->sf_idx); + srslte_pdsch_put(q, q->symbols[i], sf_symbols[i], &cfg->grant, cfg->nbits[0].lstart, cfg->sf_idx); } ret = SRSLTE_SUCCESS; @@ -810,15 +793,15 @@ int srslte_pdsch_encode_multi(srslte_pdsch_t *q, } } - /* If both transport block sizes are zero return error */ - if (cfg->grant.mcs.tbs == 0 && cfg->grant.mcs2.tbs == 0) { + /* If both transport block size is zero return error */ + if (cfg->grant.mcs[0].tbs == 0) { return SRSLTE_ERROR_INVALID_INPUTS; } - if (cfg->nbits.nof_re > q->max_re) { + if (cfg->nbits[0].nof_re > q->max_re) { fprintf(stderr, "Error too many RE per subframe (%d). PDSCH configured for %d RE (%d PRB)\n", - cfg->nbits.nof_re, q->max_re, q->cell.nof_prb); + cfg->nbits[0].nof_re, q->max_re, q->cell.nof_prb); return SRSLTE_ERROR_INVALID_INPUTS; } @@ -833,7 +816,7 @@ int srslte_pdsch_encode_multi(srslte_pdsch_t *q, for (i = 0; i < cfg->nof_layers; i++) { x[i] = q->d[i]; } - nof_symbols = cfg->nbits.nof_re; + nof_symbols = cfg->nbits[0].nof_re; } else { /* Initialise layer map pointers */ for (i = 0; i < cfg->nof_layers; i++) { @@ -842,20 +825,21 @@ int srslte_pdsch_encode_multi(srslte_pdsch_t *q, memset(&x[cfg->nof_layers], 0, sizeof(cf_t *) * (SRSLTE_MAX_LAYERS - cfg->nof_layers)); nof_symbols = srslte_layermap_type(q->d, x, cfg->grant.nof_tb, cfg->nof_layers, - (int[SRSLTE_MAX_CODEWORDS]) {cfg->nbits.nof_re, cfg->nbits2.nof_re}, cfg->mimo_type); + (int[SRSLTE_MAX_CODEWORDS]) {cfg->nbits[0].nof_re, cfg->nbits[1].nof_re}, + cfg->mimo_type); } /* Precode */ srslte_precoding_type(x, q->symbols, cfg->nof_layers, q->cell.nof_ports, cfg->codebook_idx, nof_symbols, cfg->mimo_type); } else { - memcpy(q->symbols[0], q->d[0], cfg->nbits.nof_re * sizeof(cf_t)); + memcpy(q->symbols[0], q->d[0], cfg->nbits[0].nof_re * sizeof(cf_t)); } /* mapping to resource elements */ for (i = 0; i < q->cell.nof_ports; i++) { - srslte_pdsch_put(q, q->symbols[i], sf_symbols[i], &cfg->grant, cfg->nbits.lstart, cfg->sf_idx); + srslte_pdsch_put(q, q->symbols[i], sf_symbols[i], &cfg->grant, cfg->nbits[0].lstart, cfg->sf_idx); } ret = SRSLTE_SUCCESS; @@ -863,7 +847,7 @@ int srslte_pdsch_encode_multi(srslte_pdsch_t *q, return ret; } -void srslte_pdsch_set_max_noi(srslte_pdsch_t *q, int max_iter) { +void srslte_pdsch_set_max_noi(srslte_pdsch_t *q, uint32_t max_iter) { for (int cw = 0; cw < SRSLTE_MAX_CODEWORDS; cw++) { srslte_sch_set_max_noi(&q->dl_sch[cw], max_iter); } diff --git a/lib/src/phy/phch/ra.c b/lib/src/phy/phch/ra.c index 635172762..a7fef1e42 100644 --- a/lib/src/phy/phch/ra.c +++ b/lib/src/phy/phch/ra.c @@ -492,44 +492,43 @@ static int dl_dci_to_grant_mcs(srslte_ra_dl_dci_t *dci, srslte_ra_dl_grant_t *gr fprintf(stderr, "Error decoding DCI: P/SI/RA-RNTI supports Format1A/1C only\n"); return SRSLTE_ERROR; } - grant->mcs.mod = SRSLTE_MOD_QPSK; - grant->mcs.tbs = (uint32_t) tbs; + grant->mcs[0].mod = SRSLTE_MOD_QPSK; + grant->mcs[0].tbs = (uint32_t) tbs; } else { n_prb = grant->nof_prb; if (dci->tb_en[0]) { - grant->mcs.idx = dci->mcs_idx; - tbs = dl_fill_ra_mcs(&grant->mcs, n_prb); + grant->mcs[0].idx = dci->mcs_idx; + tbs = dl_fill_ra_mcs(&grant->mcs[0], n_prb); if (tbs) { last_dl_tbs[dci->harq_process%8] = tbs; } else { // For mcs>=29, set last TBS received for this PID - grant->mcs.tbs = last_dl_tbs[dci->harq_process%8]; + grant->mcs[0].tbs = last_dl_tbs[dci->harq_process%8]; } } else { - grant->mcs.tbs = 0; + grant->mcs[0].tbs = 0; } if (dci->tb_en[1]) { - grant->mcs2.idx = dci->mcs_idx_1; - tbs = dl_fill_ra_mcs(&grant->mcs2, n_prb); + grant->mcs[1].idx = dci->mcs_idx_1; + tbs = dl_fill_ra_mcs(&grant->mcs[1], n_prb); if (tbs) { last_dl_tbs2[dci->harq_process%8] = tbs; } else { // For mcs>=29, set last TBS received for this PID - grant->mcs2.tbs = last_dl_tbs2[dci->harq_process%8]; + grant->mcs[1].tbs = last_dl_tbs2[dci->harq_process%8]; } } else { - grant->mcs2.tbs = 0; + grant->mcs[1].tbs = 0; } } grant->nof_tb = 0; - if (dci->tb_en[0]) { - grant->Qm = srslte_mod_bits_x_symbol(grant->mcs.mod); - grant->nof_tb++; - } - if (dci->tb_en[1]) { - grant->Qm2 = srslte_mod_bits_x_symbol(grant->mcs2.mod); - grant->nof_tb++; + for (int tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb++) { + if (dci->tb_en[tb]) { + grant->Qm[tb] = srslte_mod_bits_x_symbol(grant->mcs[tb].mod); + grant->nof_tb++; + } } + if (tbs < 0) { return SRSLTE_ERROR; } else { @@ -537,29 +536,16 @@ static int dl_dci_to_grant_mcs(srslte_ra_dl_dci_t *dci, srslte_ra_dl_grant_t *gr } } -void srslte_ra_dl_grant_to_nbits(srslte_ra_dl_grant_t *grant, uint32_t cfi, srslte_cell_t cell, uint32_t sf_idx, srslte_ra_nbits_t *nbits) +void srslte_ra_dl_grant_to_nbits(srslte_ra_dl_grant_t *grant, uint32_t cfi, srslte_cell_t cell, uint32_t sf_idx, + srslte_ra_nbits_t nbits [SRSLTE_MAX_CODEWORDS]) { // Compute number of RE - nbits->nof_re = srslte_ra_dl_grant_nof_re(grant, cell, sf_idx, cell.nof_prb<10?(cfi+1):cfi); - nbits->lstart = cell.nof_prb<10?(cfi+1):cfi; - nbits->nof_symb = 2*SRSLTE_CP_NSYMB(cell.cp)-nbits->lstart; - nbits->nof_bits = nbits->nof_re * grant->Qm; -} - -void srslte_ra_dl_grant_to_nbits_multi(srslte_ra_dl_grant_t *grant, uint32_t cfi, srslte_cell_t cell, uint32_t sf_idx, - srslte_ra_nbits_t *nbits, srslte_ra_nbits_t *nbits2) { - /* Compute number of RE for first transport block */ - nbits->nof_re = srslte_ra_dl_grant_nof_re(grant, cell, sf_idx, cell.nof_prb<10?(cfi+1):cfi); - nbits->lstart = cell.nof_prb<10?(cfi+1):cfi; - nbits->nof_symb = 2*SRSLTE_CP_NSYMB(cell.cp)-nbits->lstart; - nbits->nof_bits = nbits->nof_re * grant->Qm; - - /*/ Compute number of RE for second transport block */ - if (grant->nof_tb > 1) { - nbits2->nof_re = nbits->nof_re; - nbits2->lstart = nbits->lstart; - nbits2->nof_symb = 2 * SRSLTE_CP_NSYMB(cell.cp) - nbits2->lstart; - nbits2->nof_bits = nbits2->nof_re * grant->Qm2; + for (int i = 0; i < grant->nof_tb; i++) { + /* Compute number of RE for first transport block */ + nbits[i].nof_re = srslte_ra_dl_grant_nof_re(grant, cell, sf_idx, cell.nof_prb < 10 ? (cfi + 1) : cfi); + nbits[i].lstart = cell.nof_prb < 10 ? (cfi + 1) : cfi; + nbits[i].nof_symb = 2 * SRSLTE_CP_NSYMB(cell.cp) - nbits[0].lstart; + nbits[i].nof_bits = nbits[i].nof_re * grant->Qm[i]; } } @@ -834,10 +820,11 @@ void srslte_ra_dl_grant_fprint(FILE *f, srslte_ra_dl_grant_t *grant) { srslte_ra_prb_fprint(f, grant); fprintf(f, " - Number of PRBs:\t\t\t%d\n", grant->nof_prb); fprintf(f, " - Number of TBs:\t\t\t%d\n", grant->nof_tb); - fprintf(f, " - Modulation type:\t\t\t%s\n", srslte_mod_string(grant->mcs.mod)); - fprintf(f, " - Transport block size:\t\t%d\n", grant->mcs.tbs); - fprintf(f, " - Modulation type (TB2):\t\t%s\n", srslte_mod_string(grant->mcs2.mod)); - fprintf(f, " - Transport block size (TB2):\t\t%d\n", grant->mcs2.tbs); + for (int i = 0; i < grant->nof_tb; i++) { + fprintf(f, " - Transport block:\t\t\t%d\n", i); + fprintf(f, " -> Modulation type:\t\t\t%s\n", srslte_mod_string(grant->mcs[i].mod)); + fprintf(f, " -> Transport block size:\t\t%d\n", grant->mcs[i].tbs); + } } void srslte_ra_prb_fprint(FILE *f, srslte_ra_dl_grant_t *grant) { diff --git a/lib/src/phy/phch/sch.c b/lib/src/phy/phch/sch.c index 4b78f6228..e0002429e 100644 --- a/lib/src/phy/phch/sch.c +++ b/lib/src/phy/phch/sch.c @@ -514,39 +514,23 @@ static int decode_tb(srslte_sch_t *q, } } -int srslte_dlsch_decode(srslte_sch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffer, - int16_t *e_bits, uint8_t *data) -{ - return decode_tb(q, - softbuffer, &cfg->cb_segm, - cfg->grant.Qm, cfg->rv, cfg->nbits.nof_bits, - e_bits, data); +int srslte_dlsch_decode(srslte_sch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffer, + int16_t *e_bits, uint8_t *data) { + return srslte_dlsch_decode2(q, cfg, softbuffer, e_bits, data, 0); } int srslte_dlsch_decode2(srslte_sch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffer, - int16_t *e_bits, uint8_t *data, int codeword_idx) -{ + int16_t *e_bits, uint8_t *data, int codeword_idx) { uint32_t Nl = 1; - int ret = SRSLTE_ERROR; if (cfg->nof_layers != cfg->grant.nof_tb) { Nl = 2; } - if (codeword_idx == 0) { - ret = decode_tb(q, softbuffer, &cfg->cb_segm, - cfg->grant.Qm*Nl, cfg->rv, cfg->nbits.nof_bits, - e_bits, data); - } else if (codeword_idx == 1) { - ret = decode_tb(q, softbuffer, &cfg->cb_segm2, - cfg->grant.Qm2*Nl, cfg->rv2, cfg->nbits2.nof_bits, - e_bits, data); - } else { - ERROR("Not implemented"); - } - - return ret; + return decode_tb(q, softbuffer, &cfg->cb_segm[codeword_idx], + cfg->grant.Qm[codeword_idx] * Nl, cfg->rv[codeword_idx], cfg->nbits[codeword_idx].nof_bits, + e_bits, data); } /** @@ -562,64 +546,22 @@ int srslte_dlsch_decode2(srslte_sch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbu int srslte_dlsch_encode(srslte_sch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbuffer_tx_t *softbuffer, uint8_t *data, uint8_t *e_bits) { - return encode_tb(q, - softbuffer, &cfg->cb_segm, - cfg->grant.Qm, cfg->rv, cfg->nbits.nof_bits, - data, e_bits); + return srslte_dlsch_encode2(q, cfg, softbuffer, data, e_bits, 0); } int srslte_dlsch_encode2(srslte_sch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbuffer_tx_t *softbuffer, uint8_t *data, uint8_t *e_bits, int codeword_idx) { - int ret = SRSLTE_ERROR; uint32_t Nl = 1; if (cfg->nof_layers != cfg->grant.nof_tb) { Nl = 2; } - if(codeword_idx == 0) { - /* Codeword 1 shall be encoded */ - ret = encode_tb(q, softbuffer, &cfg->cb_segm, cfg->grant.Qm*Nl, cfg->rv, cfg->nbits.nof_bits, data, e_bits); - } else if(codeword_idx == 1) { - /* Codeword 2 shall be encoded */ - ret = encode_tb(q, softbuffer, &cfg->cb_segm2, cfg->grant.Qm2*Nl, cfg->rv2, cfg->nbits2.nof_bits, data, e_bits); - } else { - ERROR("Not implemented"); - } - - return ret; -} - -int srslte_dlsch_encode_multi(srslte_sch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbuffer_tx_t softbuffers[SRSLTE_MAX_CODEWORDS], - uint8_t *data[SRSLTE_MAX_CODEWORDS], uint8_t *e_bits[SRSLTE_MAX_CODEWORDS]) -{ - int ret = 0; - uint32_t Nl = 1; - - if (cfg->nof_layers != cfg->grant.nof_tb) { - Nl = 2; - } - - /* Check if codeword 1 shall be encoded */ - if(cfg->nbits.nof_bits) { - ret |= encode_tb(q, - &softbuffers[0], &cfg->cb_segm, - cfg->grant.Qm*Nl, cfg->rv, cfg->nbits.nof_bits, - data[0], e_bits[0]); - } - - /* Check if codeword 2 shall be encoded */ - if(cfg->nbits2.nof_bits) { - ret |= encode_tb(q, - &softbuffers[1], &cfg->cb_segm2, - cfg->grant.Qm2*Nl, cfg->rv2, cfg->nbits2.nof_bits, - data[1], e_bits[1]); - } - - return ret; + return encode_tb(q, softbuffer, &cfg->cb_segm[codeword_idx], cfg->grant.Qm[codeword_idx]*Nl, cfg->rv[codeword_idx], + cfg->nbits[codeword_idx].nof_bits, data, e_bits); } -/* Compute the interleaving function on-the-fly, because it depends on number of RI bits +/* Compute the interleaving function on-the-fly, because it depends on number of RI bits * Profiling show that the computation of this matrix is neglegible. */ static void ulsch_interleave_gen(uint32_t H_prime_total, uint32_t N_pusch_symbs, uint32_t Qm, diff --git a/lib/src/phy/phch/test/pdsch_test.c b/lib/src/phy/phch/test/pdsch_test.c index 180e689d6..777481d6a 100644 --- a/lib/src/phy/phch/test/pdsch_test.c +++ b/lib/src/phy/phch/test/pdsch_test.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include @@ -55,11 +54,9 @@ srslte_cell_t cell = { char mimo_type_str [32] = "single"; srslte_mimo_type_t mimo_type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA; uint32_t cfi = 2; -uint32_t mcs = 0; -uint32_t mcs2 = 0; +uint32_t mcs[SRSLTE_MAX_CODEWORDS] = {0, 0}; uint32_t subframe = 1; -uint32_t rv_idx = 0; -uint32_t rv_idx2 = 1; +int rv_idx[SRSLTE_MAX_CODEWORDS] = {0, 1}; uint16_t rnti = 1234; uint32_t nof_rx_antennas = 1; uint32_t pmi = 0; @@ -68,12 +65,12 @@ char *input_file = NULL; void usage(char *prog) { printf("Usage: %s [fmMcsrtRFpnwav] \n", prog); printf("\t-f read signal from file [Default generate it with pdsch_encode()]\n"); - printf("\t-m MCS [Default %d]\n", mcs); - printf("\t-M MCS2 [Default %d]\n", mcs2); + printf("\t-m MCS [Default %d]\n", mcs[0]); + printf("\t-M MCS2 [Default %d]\n", mcs[1]); printf("\t-c cell id [Default %d]\n", cell.id); printf("\t-s subframe [Default %d]\n", subframe); - printf("\t-r rv_idx [Default %d]\n", rv_idx); - printf("\t-t rv_idx2 [Default %d]\n", rv_idx2); + printf("\t-r rv_idx [Default %d]\n", rv_idx[0]); + printf("\t-t rv_idx2 [Default %d]\n", rv_idx[1]); printf("\t-R rnti [Default %d]\n", rnti); printf("\t-F cfi [Default %d]\n", cfi); printf("\t-x Transmission mode [single|diversity|cdd|multiplex] [Default %s]\n", mimo_type_str); @@ -91,19 +88,19 @@ void parse_args(int argc, char **argv) { input_file = argv[optind]; break; case 'm': - mcs = atoi(argv[optind]); + mcs[0] = (uint32_t) atoi(argv[optind]); break; case 'M': - mcs2 = (uint32_t) atoi(argv[optind]); + mcs[1] = (uint32_t) atoi(argv[optind]); break; case 's': subframe = atoi(argv[optind]); break; case 'r': - rv_idx = atoi(argv[optind]); + rv_idx[0] = (uint32_t) atoi(argv[optind]); break; case 't': - rv_idx2 = (uint32_t) atoi(argv[optind]); + rv_idx[1] = (uint32_t) atoi(argv[optind]); break; case 'R': rnti = atoi(argv[optind]); @@ -197,16 +194,16 @@ int main(int argc, char **argv) { dci.type0_alloc.rbg_bitmask = 0xffffffff; /* If transport block 0 is enabled */ - if (mcs != 0 || rv_idx != 1) { - dci.mcs_idx = mcs; - dci.rv_idx = rv_idx; + if (mcs[0] != 0 || rv_idx[0] != 1) { + dci.mcs_idx = mcs[0]; + dci.rv_idx = rv_idx[0]; dci.tb_en[0] = true; } /* If transport block 0 is disabled */ - if (mcs2 != 0 || rv_idx2 != 1) { - dci.mcs_idx_1 = mcs2; - dci.rv_idx_1 = rv_idx2; + if (mcs[1] != 0 || rv_idx[1] != 1) { + dci.mcs_idx_1 = mcs[1]; + dci.rv_idx_1 = rv_idx[1]; dci.tb_en[1] = true; } @@ -235,7 +232,7 @@ int main(int argc, char **argv) { #endif /* DO_OFDM */ /* Configure PDSCH */ - if (srslte_pdsch_cfg_multi(&pdsch_cfg, cell, &grant, cfi, subframe, rv_idx, rv_idx2, mimo_type, pmi)) { + if (srslte_pdsch_cfg_multi(&pdsch_cfg, cell, &grant, cfi, subframe, rv_idx, mimo_type, pmi)) { fprintf(stderr, "Error configuring PDSCH\n"); goto quit; } @@ -260,22 +257,15 @@ int main(int argc, char **argv) { } - if (grant.mcs.tbs) { - data[0] = srslte_vec_malloc(sizeof(uint8_t) * grant.mcs.tbs); - if (!data[0]) { - perror("srslte_vec_malloc"); - goto quit; - } - bzero(data[0], sizeof(uint8_t) * grant.mcs.tbs); - } - - if (grant.mcs2.tbs) { - data[1] = srslte_vec_malloc(sizeof(uint8_t) * grant.mcs2.tbs); - if (!data[1]) { - perror("srslte_vec_malloc"); - goto quit; + for (int i = 0; i < grant.nof_tb; i++) { + if (grant.mcs[i].tbs) { + data[i] = srslte_vec_malloc(sizeof(uint8_t) * grant.mcs[i].tbs); + if (!data[i]) { + perror("srslte_vec_malloc"); + goto quit; + } + bzero(data[i], sizeof(uint8_t) * grant.mcs[i].tbs); } - bzero(data[1], sizeof(uint8_t) * grant.mcs2.tbs); } if (srslte_pdsch_init_rx_multi(&pdsch_rx, cell, nof_rx_antennas)) { @@ -292,6 +282,7 @@ int main(int argc, char **argv) { } } + INFO(" Global:\n"); INFO(" nof_prb=%d\n", cell.nof_prb); INFO(" nof_ports=%d\n", cell.nof_ports); INFO(" id=%d\n", cell.id); @@ -300,28 +291,22 @@ int main(int argc, char **argv) { INFO(" phich_resources=%d\n", (int) cell.phich_resources); INFO(" nof_tb=%d\n", pdsch_cfg.grant.nof_tb); INFO(" nof_prb=%d\n", pdsch_cfg.grant.nof_prb); - INFO(" Qm=%d\n", pdsch_cfg.grant.Qm); - INFO(" Qm2=%d\n", pdsch_cfg.grant.Qm2); - INFO(" mcs.idx=0x%X\n", pdsch_cfg.grant.mcs.idx); - INFO(" mcs.tbs=%d\n", pdsch_cfg.grant.mcs.tbs); - INFO(" mcs.mod=%s\n", srslte_mod_string(pdsch_cfg.grant.mcs.mod)); - INFO(" mcs2.idx=0x%X\n", pdsch_cfg.grant.mcs2.idx); - INFO(" mcs2.tbs=%d\n", pdsch_cfg.grant.mcs2.tbs); - INFO(" mcs2.mod=%s\n", srslte_mod_string(pdsch_cfg.grant.mcs2.mod)); - INFO(" nof_layers=%d\n", pdsch_cfg.nof_layers); - INFO(" rv=%d\n", pdsch_cfg.rv); - INFO(" rv2=%d\n", pdsch_cfg.rv2); INFO(" sf_idx=%d\n", pdsch_cfg.sf_idx); - INFO(" mimo_type=%d\n", (int) pdsch_cfg.mimo_type); + INFO(" mimo_type=%s\n", srslte_mimotype2str(pdsch_cfg.mimo_type)); + INFO(" nof_layers=%d\n", pdsch_cfg.nof_layers); INFO(" nof_tb=%d\n", pdsch_cfg.grant.nof_tb); - INFO(" lstart=%d\n", pdsch_cfg.nbits.lstart); - INFO(" nof_bits=%d\n", pdsch_cfg.nbits.nof_bits); - INFO(" nof_re=%d\n", pdsch_cfg.nbits.nof_re); - INFO(" nof_symb=%d\n", pdsch_cfg.nbits.nof_symb); - INFO(" lstart=%d\n", pdsch_cfg.nbits2.lstart); - INFO(" nof_bits=%d\n", pdsch_cfg.nbits2.nof_bits); - INFO(" nof_re=%d\n", pdsch_cfg.nbits2.nof_re); - INFO(" nof_symb=%d\n", pdsch_cfg.nbits2.nof_symb); + for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { + INFO(" Tranport block index %d:\n", i); + INFO(" Qm=%d\n", pdsch_cfg.grant.Qm[i]); + INFO(" mcs.idx=0x%X\n", pdsch_cfg.grant.mcs[i].idx); + INFO(" mcs.tbs=%d\n", pdsch_cfg.grant.mcs[i].tbs); + INFO(" mcs.mod=%s\n", srslte_mod_string(pdsch_cfg.grant.mcs[i].mod)); + INFO(" rv=%d\n", pdsch_cfg.rv[i]); + INFO(" lstart=%d\n", pdsch_cfg.nbits[i].lstart); + INFO(" nof_bits=%d\n", pdsch_cfg.nbits[i].nof_bits); + INFO(" nof_re=%d\n", pdsch_cfg.nbits[i].nof_re); + INFO(" nof_symb=%d\n", pdsch_cfg.nbits[i].nof_symb); + } if (input_file) { srslte_filesource_t fsrc; @@ -368,29 +353,25 @@ int main(int argc, char **argv) { } } - for (i = 0; i < grant.mcs.tbs / 8; i++) { - data[0][i] = (uint8_t) (rand() % 256); - } - - for (i = 0; i < grant.mcs2.tbs / 8; i++) { - data[1][i] = (uint8_t) (rand() % 256); + for (i = 0; i< grant.nof_tb; i++) { + for (i = 0; i < grant.mcs[i].tbs / 8; i++) { + data[i][i] = (uint8_t) (rand() % 256); + } } /*uint8_t databit[100000]; srslte_bit_unpack_vector(data, databit, grant.mcs.tbs); srslte_vec_save_file("data_in", databit, grant.mcs.tbs);*/ - if (rv_idx) { + if (rv_idx[0] != 0 || rv_idx[1] != 0) { /* Do 1st transmission for rv_idx!=0 */ - pdsch_cfg.rv = 0; - pdsch_cfg.rv2 = 0; + bzero(pdsch_cfg.rv, sizeof(uint32_t)*SRSLTE_MAX_CODEWORDS); if (srslte_pdsch_encode_multi(&pdsch_tx, &pdsch_cfg, softbuffers_tx, data, rnti, tx_slot_symbols)) { fprintf(stderr, "Error encoding PDSCH\n"); goto quit; } } - pdsch_cfg.rv = rv_idx; - pdsch_cfg.rv2 = rv_idx2; + memcpy(pdsch_cfg.rv, rv_idx, sizeof(uint32_t)*SRSLTE_MAX_CODEWORDS); gettimeofday(&t[1], NULL); for (k = 0; k < M; k++) { if (srslte_pdsch_encode_multi(&pdsch_tx, &pdsch_cfg, softbuffers_tx, data, rnti, tx_slot_symbols)) { @@ -401,8 +382,8 @@ int main(int argc, char **argv) { gettimeofday(&t[2], NULL); get_time_interval(t); printf("ENCODED in %.2f (PHY bitrate=%.2f Mbps. Processing bitrate=%.2f Mbps)\n", - (float) t[0].tv_usec/M, (float) (grant.mcs.tbs + grant.mcs2.tbs)/1000.0f, - (float) (grant.mcs.tbs + grant.mcs2.tbs)*M/t[0].tv_usec); + (float) t[0].tv_usec/M, (float) (grant.mcs[0].tbs + grant.mcs[1].tbs)/1000.0f, + (float) (grant.mcs[0].tbs + grant.mcs[1].tbs)*M/t[0].tv_usec); #ifdef DO_OFDM for (i = 0; i < cell.nof_ports; i++) { @@ -444,19 +425,18 @@ int main(int argc, char **argv) { srslte_ofdm_rx_sf(&ofdm_rx, tx_sf_symbols[i], rx_slot_symbols[i]); } #endif - if (grant.mcs.tbs) { - srslte_softbuffer_rx_reset_tbs(&softbuffers_rx[0], (uint32_t) grant.mcs.tbs); - } - if (grant.mcs2.tbs) { - srslte_softbuffer_rx_reset_tbs(&softbuffers_rx[1], (uint32_t) grant.mcs2.tbs); + for (i = 0; i < grant.nof_tb; i++) { + if (grant.mcs[i].tbs) { + srslte_softbuffer_rx_reset_tbs(&softbuffers_rx[i], (uint32_t) grant.mcs[i].tbs); + } } r = srslte_pdsch_decode_multi(&pdsch_rx, &pdsch_cfg, softbuffers_rx, rx_slot_symbols, ce, 0, rnti, data); } gettimeofday(&t[2], NULL); get_time_interval(t); printf("DECODED %s in %.2f (PHY bitrate=%.2f Mbps. Processing bitrate=%.2f Mbps)\n", r?"Error":"OK", - (float) t[0].tv_usec/M, (float) (grant.mcs.tbs + grant.mcs2.tbs)/1000.0f, - (float) (grant.mcs.tbs + grant.mcs2.tbs)*M/t[0].tv_usec); + (float) t[0].tv_usec/M, (float) (grant.mcs[0].tbs + grant.mcs[1].tbs)/1000.0f, + (float) (grant.mcs[0].tbs + grant.mcs[1].tbs)*M/t[0].tv_usec); if (r) { ret = -1; goto quit; diff --git a/lib/src/phy/ue/ue_dl.c b/lib/src/phy/ue/ue_dl.c index 3f51a3036..47337a109 100644 --- a/lib/src/phy/ue/ue_dl.c +++ b/lib/src/phy/ue/ue_dl.c @@ -282,14 +282,16 @@ int srslte_ue_dl_decode_estimate(srslte_ue_dl_t *q, uint32_t sf_idx, uint32_t *c } -int srslte_ue_dl_cfg_grant(srslte_ue_dl_t *q, srslte_ra_dl_grant_t *grant, uint32_t cfi, uint32_t sf_idx, uint32_t rvidx) -{ - return srslte_pdsch_cfg_multi(&q->pdsch_cfg, q->cell, grant, cfi, sf_idx, rvidx, 0, SRSLTE_MIMO_TYPE_SINGLE_ANTENNA, 0); +int srslte_ue_dl_cfg_grant(srslte_ue_dl_t *q, srslte_ra_dl_grant_t *grant, uint32_t cfi, uint32_t sf_idx, + int rvidx) { + int _rvidx [SRSLTE_MAX_CODEWORDS] = {1}; + _rvidx[0] = rvidx; + + return srslte_pdsch_cfg_multi(&q->pdsch_cfg, q->cell, grant, cfi, sf_idx, _rvidx, SRSLTE_MIMO_TYPE_SINGLE_ANTENNA, 0); } int srslte_ue_dl_cfg_grant_multi(srslte_ue_dl_t *q, srslte_ra_dl_grant_t *grant, uint32_t cfi, uint32_t sf_idx, - uint32_t rvidx, uint32_t rvidx2, srslte_mimo_type_t mimo_type, uint32_t pinfo) -{ + int rvidx[SRSLTE_MAX_CODEWORDS], srslte_mimo_type_t mimo_type, uint32_t pinfo) { uint32_t pmi = 0; /* Translates Precoding Information (pinfo) to Precoding matrix Index (pmi) as 3GPP 36.212 Table 5.3.3.1.5-4 */ @@ -310,7 +312,7 @@ int srslte_ue_dl_cfg_grant_multi(srslte_ue_dl_t *q, srslte_ra_dl_grant_t *grant, } } } - return srslte_pdsch_cfg_multi(&q->pdsch_cfg, q->cell, grant, cfi, sf_idx, rvidx, rvidx2, mimo_type, pmi); + return srslte_pdsch_cfg_multi(&q->pdsch_cfg, q->cell, grant, cfi, sf_idx, rvidx, mimo_type, pmi); } int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, cf_t *input, uint8_t *data, uint32_t tti, uint16_t rnti) @@ -357,23 +359,28 @@ int srslte_ue_dl_decode_rnti_multi(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_POR /* ===== These lines of code are supposed to be MAC functionality === */ - uint32_t rvidx = 0; - uint32_t rvidx2 = 0; + int rvidx[SRSLTE_MAX_CODEWORDS] = {1}; if (dci_unpacked.rv_idx < 0) { uint32_t sfn = tti/10; - uint32_t k = (sfn/2)%4; - rvidx = ((uint32_t) ceilf((float)1.5*k))%4; - srslte_softbuffer_rx_reset_tbs(&q->softbuffers[0], (uint32_t) grant.mcs.tbs); - if (grant.nof_tb > 1) { - rvidx2 = ((uint32_t) ceilf((float)1.5*k))%4; - srslte_softbuffer_rx_reset_tbs(&q->softbuffers[1], (uint32_t) grant.mcs2.tbs); + uint32_t k = (sfn/2)%4; + for (int i = 0; i < grant.nof_tb; i++) { + rvidx[i] = ((uint32_t) ceilf((float) 1.5 * k)) % 4; + srslte_softbuffer_rx_reset_tbs(&q->softbuffers[i], (uint32_t) grant.mcs[i].tbs); } } else { - rvidx = (uint32_t) dci_unpacked.rv_idx; - srslte_softbuffer_rx_reset_tbs(&q->softbuffers[0], (uint32_t) grant.mcs.tbs); - if (grant.nof_tb > 1) { - rvidx2 = (uint32_t) dci_unpacked.rv_idx_1; - srslte_softbuffer_rx_reset_tbs(&q->softbuffers[1], (uint32_t) grant.mcs2.tbs); + for (int i = 0; i < grant.nof_tb; i++) { + switch(i) { + case 0: + rvidx[i] = (uint32_t) dci_unpacked.rv_idx; + break; + case 1: + rvidx[i] = (uint32_t) dci_unpacked.rv_idx_1; + break; + default: + ERROR("Wrong number of transport blocks"); + return SRSLTE_ERROR; + } + srslte_softbuffer_rx_reset_tbs(&q->softbuffers[i], (uint32_t) grant.mcs[i].tbs); } } @@ -408,7 +415,7 @@ int srslte_ue_dl_decode_rnti_multi(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_POR return SRSLTE_ERROR; } - if (srslte_ue_dl_cfg_grant_multi(q, &grant, cfi, sf_idx, rvidx, rvidx2, mimo_type, dci_unpacked.pinfo)) { + if (srslte_ue_dl_cfg_grant_multi(q, &grant, cfi, sf_idx, rvidx, mimo_type, dci_unpacked.pinfo)) { ERROR("Configuing PDSCH"); return SRSLTE_ERROR; } @@ -418,7 +425,7 @@ int srslte_ue_dl_decode_rnti_multi(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_POR q->nof_detected++; - if (q->pdsch_cfg.grant.mcs.mod > 0 && q->pdsch_cfg.grant.mcs.tbs >= 0) { + if (q->pdsch_cfg.grant.mcs[0].mod > 0 && q->pdsch_cfg.grant.mcs[0].tbs >= 0) { ret = srslte_pdsch_decode_multi(&q->pdsch, &q->pdsch_cfg, q->softbuffers, q->sf_symbols_m, q->ce_m, noise_estimate, @@ -446,7 +453,7 @@ int srslte_ue_dl_decode_rnti_multi(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_POR q->pkts_total++; if (found_dci == 1 && ret == SRSLTE_SUCCESS) { - return q->pdsch_cfg.grant.mcs.tbs; + return q->pdsch_cfg.grant.mcs[0].tbs; } else { return 0; } @@ -723,16 +730,16 @@ void srslte_ue_dl_save_signal(srslte_ue_dl_t *q, srslte_softbuffer_rx_t *softbuf srslte_vec_save_file("pdcch_llr", q->pdcch.llr, q->pdcch.nof_cce*72*sizeof(float)); - srslte_vec_save_file("pdsch_symbols", q->pdsch.d, q->pdsch_cfg.nbits.nof_re*sizeof(cf_t)); - srslte_vec_save_file("llr", q->pdsch.e, q->pdsch_cfg.nbits.nof_bits*sizeof(cf_t)); - int cb_len = q->pdsch_cfg.cb_segm.K1; - for (int i=0;ipdsch_cfg.cb_segm.C;i++) { + srslte_vec_save_file("pdsch_symbols", q->pdsch.d, q->pdsch_cfg.nbits[0].nof_re*sizeof(cf_t)); + srslte_vec_save_file("llr", q->pdsch.e, q->pdsch_cfg.nbits[0].nof_bits*sizeof(cf_t)); + int cb_len = q->pdsch_cfg.cb_segm[0].K1; + for (int i=0;ipdsch_cfg.cb_segm[0].C;i++) { char tmpstr[64]; snprintf(tmpstr,64,"rmout_%d.dat",i); srslte_vec_save_file(tmpstr, softbuffer->buffer_f[i], (3*cb_len+12)*sizeof(int16_t)); } printf("Saved files for tti=%d, sf=%d, cfi=%d, mcs=%d, rv=%d, rnti=0x%x\n", tti, tti%10, cfi, - q->pdsch_cfg.grant.mcs.idx, rv_idx, rnti); + q->pdsch_cfg.grant.mcs[0].idx, rv_idx, rnti); } diff --git a/srsenb/src/phy/phch_worker.cc b/srsenb/src/phy/phch_worker.cc index eca637635..40fbe4b1f 100644 --- a/srsenb/src/phy/phch_worker.cc +++ b/srsenb/src/phy/phch_worker.cc @@ -632,7 +632,7 @@ int phch_worker::encode_pdsch(srslte_enb_dl_pdsch_t *grants, uint32_t nof_grants if (LOG_THIS(rnti)) { uint8_t x = 0; uint8_t *ptr = grants[i].data; - uint32_t len = phy_grant.mcs.tbs/8; + uint32_t len = phy_grant.mcs[0].tbs / (uint32_t) 8; if (!ptr) { ptr = &x; len = 1; @@ -640,7 +640,7 @@ int phch_worker::encode_pdsch(srslte_enb_dl_pdsch_t *grants, uint32_t nof_grants log_h->info_hex(ptr, len, "PDSCH: rnti=0x%x, l_crb=%2d, %s, harq=%d, tbs=%d, mcs=%d, rv=%d, tti_tx=%d\n", rnti, phy_grant.nof_prb, grant_str, grants[i].grant.harq_process, - phy_grant.mcs.tbs/8, phy_grant.mcs.idx, grants[i].grant.rv_idx, tti_tx); + phy_grant.mcs[0].tbs/8, phy_grant.mcs[0].idx, grants[i].grant.rv_idx, tti_tx); } if (srslte_enb_dl_put_pdsch(&enb_dl, &phy_grant, grants[i].softbuffer, rnti, grants[i].grant.rv_idx, sf_idx, grants[i].data)) @@ -650,7 +650,7 @@ int phch_worker::encode_pdsch(srslte_enb_dl_pdsch_t *grants, uint32_t nof_grants } // Save metrics stats - ue_db[rnti].metrics_dl(phy_grant.mcs.idx); + ue_db[rnti].metrics_dl(phy_grant.mcs[0].idx); } } return SRSLTE_SUCCESS; diff --git a/srsue/hdr/phy/phch_worker.h b/srsue/hdr/phy/phch_worker.h index 8cdec22c2..ed1d7af26 100644 --- a/srsue/hdr/phy/phch_worker.h +++ b/srsue/hdr/phy/phch_worker.h @@ -76,9 +76,20 @@ private: /* ... for DL */ bool decode_pdcch_ul(mac_interface_phy::mac_grant_t *grant); bool decode_pdcch_dl(mac_interface_phy::mac_grant_t *grant); - bool decode_phich(bool *ack); - bool decode_pdsch(srslte_ra_dl_grant_t *grant, uint8_t *payload, srslte_softbuffer_rx_t* softbuffer, int rv, uint16_t rnti, uint32_t pid); - bool decode_pdsch_multi(srslte_ra_dl_grant_t *grant, uint8_t *payload[SRSLTE_MAX_CODEWORDS], srslte_softbuffer_rx_t softbuffers[SRSLTE_MAX_CODEWORDS], int rv, uint16_t rnti, uint32_t pid); + bool decode_phich(bool *ack); + + bool decode_pdsch(srslte_ra_dl_grant_t *grant, + uint8_t *payload, srslte_softbuffer_rx_t *softbuffer, + int rv, + uint16_t rnti, + uint32_t pid); + + bool decode_pdsch_multi(srslte_ra_dl_grant_t *grant, + uint8_t *payload[SRSLTE_MAX_CODEWORDS], + srslte_softbuffer_rx_t softbuffers[SRSLTE_MAX_CODEWORDS], + int rv[SRSLTE_MAX_CODEWORDS], + uint16_t rnti, + uint32_t pid); /* ... for UL */ void encode_pusch(srslte_ra_ul_grant_t *grant, uint8_t *payload, uint32_t current_tx_nb, srslte_softbuffer_tx_t *softbuffer, diff --git a/srsue/src/phy/phch_worker.cc b/srsue/src/phy/phch_worker.cc index fce931837..231190fb1 100644 --- a/srsue/src/phy/phch_worker.cc +++ b/srsue/src/phy/phch_worker.cc @@ -204,9 +204,9 @@ void phch_worker::work_imp() /* Decode PDSCH if instructed to do so */ dl_ack = dl_action.default_ack; if (dl_action.decode_enabled) { - dl_ack = decode_pdsch(&dl_action.phy_grant.dl, dl_action.payload_ptr, + dl_ack = decode_pdsch(&dl_action.phy_grant.dl, dl_action.payload_ptr, dl_action.softbuffer, dl_action.rv, dl_action.rnti, - dl_mac_grant.pid); + dl_mac_grant.pid); } if (dl_action.generate_ack_callback && dl_action.decode_enabled) { phy->mac->tb_decoded(dl_ack, dl_mac_grant.rnti_type, dl_mac_grant.pid); @@ -382,7 +382,7 @@ bool phch_worker::decode_pdcch_dl(srsue::mac_interface_phy::mac_grant_t* grant) /* Fill MAC grant structure */ grant->ndi = dci_unpacked.ndi; grant->pid = dci_unpacked.harq_process; - grant->n_bytes = grant->phy_grant.dl.mcs.tbs/8; + grant->n_bytes = grant->phy_grant.dl.mcs[0].tbs/8; grant->tti = tti; grant->rv = dci_unpacked.rv_idx; grant->rnti = dl_rnti; @@ -406,23 +406,70 @@ bool phch_worker::decode_pdcch_dl(srsue::mac_interface_phy::mac_grant_t* grant) } bool phch_worker::decode_pdsch(srslte_ra_dl_grant_t *grant, uint8_t *payload, - srslte_softbuffer_rx_t* softbuffer, int rv, uint16_t rnti, uint32_t harq_pid) -{ - return decode_pdsch_multi(grant, &payload, softbuffer, rv, rnti, harq_pid); + srslte_softbuffer_rx_t *softbuffer, int rv, + uint16_t rnti, uint32_t harq_pid) { + int _rv [SRSLTE_MAX_CODEWORDS] = {1}; + _rv[0] = rv; + + return decode_pdsch_multi(grant, &payload, softbuffer, _rv, rnti, harq_pid); } bool phch_worker::decode_pdsch_multi(srslte_ra_dl_grant_t *grant, uint8_t *payload[SRSLTE_MAX_CODEWORDS], - srslte_softbuffer_rx_t softbuffers[SRSLTE_MAX_CODEWORDS], int rv, uint16_t rnti, uint32_t harq_pid) -{ + srslte_softbuffer_rx_t softbuffers[SRSLTE_MAX_CODEWORDS], + int rv[SRSLTE_MAX_CODEWORDS], + uint16_t rnti, uint32_t harq_pid) { char timestr[64]; + bool valid_config = true; timestr[0]='\0'; - + srslte_mimo_type_t mimo_type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA; + + for (uint32_t tb = 0; tb < grant->nof_tb; tb++) { + if (rv[tb] < 0 || rv[tb] > 3) { + valid_config = false; + Error("Wrong RV (%d) for TB index %d", rv[tb], tb); + } + } + + switch(phy->config->dedicated.antenna_info_explicit_value.tx_mode) { + case LIBLTE_RRC_TRANSMISSION_MODE_1: + mimo_type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA; + break; + case LIBLTE_RRC_TRANSMISSION_MODE_2: + mimo_type = SRSLTE_MIMO_TYPE_TX_DIVERSITY; + break; + case LIBLTE_RRC_TRANSMISSION_MODE_3: + if (grant->nof_tb == 1) { + mimo_type = SRSLTE_MIMO_TYPE_TX_DIVERSITY; + } else if (grant->nof_tb == 2) { + mimo_type = SRSLTE_MIMO_TYPE_CDD; + } else { + Error("Wrong number of transport blocks (%d) for TM3\n", grant->nof_tb); + valid_config = false; + } + break; + + /* Not implemented cases */ + case LIBLTE_RRC_TRANSMISSION_MODE_4: + case LIBLTE_RRC_TRANSMISSION_MODE_5: + case LIBLTE_RRC_TRANSMISSION_MODE_6: + case LIBLTE_RRC_TRANSMISSION_MODE_7: + case LIBLTE_RRC_TRANSMISSION_MODE_8: + Error("Not implemented Tx mode (%d)\n", phy->config->dedicated.antenna_info_explicit_value.tx_mode); + break; + + /* Error cases */ + case LIBLTE_RRC_TRANSMISSION_MODE_N_ITEMS: + default: + Error("Wrong Tx mode (%d)\n", phy->config->dedicated.antenna_info_explicit_value.tx_mode); + valid_config = false; + } + Debug("DL Buffer TTI %d: Decoding PDSCH\n", tti); /* Setup PDSCH configuration for this CFI, SFIDX and RVIDX */ - if (rv >= 0 && rv <= 3) { - if (!srslte_ue_dl_cfg_grant(&ue_dl, grant, cfi, tti%10, rv)) { - if (ue_dl.pdsch_cfg.grant.mcs.mod > 0 && ue_dl.pdsch_cfg.grant.mcs.tbs >= 0) { + if (valid_config) { + if (!srslte_ue_dl_cfg_grant_multi(&ue_dl, grant, cfi, tti%10, rv, mimo_type, 0)) { + if (ue_dl.pdsch_cfg.grant.mcs[0].mod > 0 && ue_dl.pdsch_cfg.grant.mcs[0].tbs >= 0) { float noise_estimate = srslte_chest_dl_get_noise_estimate(&ue_dl.chest); @@ -451,7 +498,7 @@ bool phch_worker::decode_pdsch_multi(srslte_ra_dl_grant_t *grant, uint8_t *paylo Info("PDSCH: l_crb=%2d, harq=%d, tbs=%d, mcs=%d, rv=%d, crc=%s, snr=%.1f dB, n_iter=%d%s\n", grant->nof_prb, harq_pid, - grant->mcs.tbs/8, grant->mcs.idx, rv, + grant->mcs[0].tbs/8, grant->mcs[0].idx, rv, ack?"OK":"KO", 10*log10(srslte_chest_dl_get_snr(&ue_dl.chest)), srslte_pdsch_last_noi(&ue_dl.pdsch), @@ -461,7 +508,7 @@ bool phch_worker::decode_pdsch_multi(srslte_ra_dl_grant_t *grant, uint8_t *paylo //srslte_vec_save_file("pdsch", signal_buffer, sizeof(cf_t)*SRSLTE_SF_LEN_PRB(cell.nof_prb)); // Store metrics - dl_metrics.mcs = grant->mcs.idx; + dl_metrics.mcs = grant->mcs[0].idx; return ack; } else { @@ -470,8 +517,6 @@ bool phch_worker::decode_pdsch_multi(srslte_ra_dl_grant_t *grant, uint8_t *paylo } else { Error("Error configuring DL grant\n"); } - } else { - Error("Error RV is not set or is invalid (%d)\n", rv); } return true; } @@ -973,8 +1018,9 @@ int phch_worker::read_ce_abs(float *ce_abs) { int phch_worker::read_pdsch_d(cf_t* pdsch_d) { - memcpy(pdsch_d, ue_dl.pdsch.d, ue_dl.pdsch_cfg.nbits.nof_re*sizeof(cf_t)); - return ue_dl.pdsch_cfg.nbits.nof_re; + + memcpy(pdsch_d, ue_dl.pdsch.d, ue_dl.pdsch_cfg.nbits[0].nof_re*sizeof(cf_t)); + return ue_dl.pdsch_cfg.nbits[0].nof_re; } From 7e9e9a6a7d76da472ac193debb624ad9ebe0a771 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Mon, 21 Aug 2017 17:36:44 +0200 Subject: [PATCH 17/60] Included precoding information (pinfo) in grant and interfaced TM4 --- lib/include/srslte/phy/phch/ra.h | 1 + lib/include/srslte/phy/ue/ue_dl.h | 19 ++++++------------- lib/src/phy/phch/ra.c | 1 + lib/src/phy/ue/ue_dl.c | 24 ++++++++---------------- srsue/src/phy/phch_worker.cc | 14 ++++++++++++-- 5 files changed, 28 insertions(+), 31 deletions(-) diff --git a/lib/include/srslte/phy/phch/ra.h b/lib/include/srslte/phy/phch/ra.h index c99dba1a1..58e9585a5 100644 --- a/lib/include/srslte/phy/phch/ra.h +++ b/lib/include/srslte/phy/phch/ra.h @@ -105,6 +105,7 @@ typedef struct SRSLTE_API { uint32_t Qm[SRSLTE_MAX_CODEWORDS]; srslte_ra_mcs_t mcs[SRSLTE_MAX_CODEWORDS]; uint32_t nof_tb; + uint32_t pinfo; } srslte_ra_dl_grant_t; /** Unpacked DCI message for DL grant */ diff --git a/lib/include/srslte/phy/ue/ue_dl.h b/lib/include/srslte/phy/ue/ue_dl.h index 268a8c4d9..4101fadd9 100644 --- a/lib/include/srslte/phy/ue/ue_dl.h +++ b/lib/include/srslte/phy/ue/ue_dl.h @@ -141,19 +141,12 @@ SRSLTE_API int srslte_ue_dl_decode_estimate(srslte_ue_dl_t *q, uint32_t sf_idx, uint32_t *cfi); -SRSLTE_API int srslte_ue_dl_cfg_grant(srslte_ue_dl_t *q, - srslte_ra_dl_grant_t *grant, - uint32_t cfi, - uint32_t sf_idx, - int rvidx); - -SRSLTE_API int srslte_ue_dl_cfg_grant_multi(srslte_ue_dl_t *q, - srslte_ra_dl_grant_t *grant, - uint32_t cfi, - uint32_t sf_idx, - int rvidx[SRSLTE_MAX_CODEWORDS], - srslte_mimo_type_t mimo_type, - uint32_t pinfo); +SRSLTE_API int srslte_ue_dl_cfg_grant(srslte_ue_dl_t *q, + srslte_ra_dl_grant_t *grant, + uint32_t cfi, + uint32_t sf_idx, + int rvidx[SRSLTE_MAX_CODEWORDS], + srslte_mimo_type_t mimo_type); SRSLTE_API int srslte_ue_dl_find_ul_dci(srslte_ue_dl_t *q, uint32_t cfi, diff --git a/lib/src/phy/phch/ra.c b/lib/src/phy/phch/ra.c index a7fef1e42..00713e6c1 100644 --- a/lib/src/phy/phch/ra.c +++ b/lib/src/phy/phch/ra.c @@ -528,6 +528,7 @@ static int dl_dci_to_grant_mcs(srslte_ra_dl_dci_t *dci, srslte_ra_dl_grant_t *gr grant->nof_tb++; } } + grant->pinfo = dci->pinfo; if (tbs < 0) { return SRSLTE_ERROR; diff --git a/lib/src/phy/ue/ue_dl.c b/lib/src/phy/ue/ue_dl.c index 47337a109..c9a5dea1a 100644 --- a/lib/src/phy/ue/ue_dl.c +++ b/lib/src/phy/ue/ue_dl.c @@ -283,31 +283,23 @@ int srslte_ue_dl_decode_estimate(srslte_ue_dl_t *q, uint32_t sf_idx, uint32_t *c int srslte_ue_dl_cfg_grant(srslte_ue_dl_t *q, srslte_ra_dl_grant_t *grant, uint32_t cfi, uint32_t sf_idx, - int rvidx) { - int _rvidx [SRSLTE_MAX_CODEWORDS] = {1}; - _rvidx[0] = rvidx; - - return srslte_pdsch_cfg_multi(&q->pdsch_cfg, q->cell, grant, cfi, sf_idx, _rvidx, SRSLTE_MIMO_TYPE_SINGLE_ANTENNA, 0); -} - -int srslte_ue_dl_cfg_grant_multi(srslte_ue_dl_t *q, srslte_ra_dl_grant_t *grant, uint32_t cfi, uint32_t sf_idx, - int rvidx[SRSLTE_MAX_CODEWORDS], srslte_mimo_type_t mimo_type, uint32_t pinfo) { + int rvidx[SRSLTE_MAX_CODEWORDS], srslte_mimo_type_t mimo_type) { uint32_t pmi = 0; /* Translates Precoding Information (pinfo) to Precoding matrix Index (pmi) as 3GPP 36.212 Table 5.3.3.1.5-4 */ if (mimo_type == SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX) { if (grant->nof_tb == 1) { - if (pinfo > 0 && pinfo < 5) { - pmi = pinfo - 1; + if (grant->pinfo > 0 && grant->pinfo < 5) { + pmi = grant->pinfo - 1; } else { - ERROR("Not Implemented (nof_tb=%d, pinfo=%d)", q->pdsch_cfg.grant.nof_tb, pinfo); + ERROR("Not Implemented (nof_tb=%d, pinfo=%d)", q->pdsch_cfg.grant.nof_tb, grant->pinfo); return SRSLTE_ERROR; } } else { - if (pinfo < 2) { - pmi = pinfo; + if (grant->pinfo < 2) { + pmi = grant->pinfo; } else { - ERROR("Not Implemented (nof_tb=%d, pinfo=%d)", q->pdsch_cfg.grant.nof_tb, pinfo); + ERROR("Not Implemented (nof_tb=%d, pinfo=%d)", q->pdsch_cfg.grant.nof_tb, grant->pinfo); return SRSLTE_ERROR; } } @@ -415,7 +407,7 @@ int srslte_ue_dl_decode_rnti_multi(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_POR return SRSLTE_ERROR; } - if (srslte_ue_dl_cfg_grant_multi(q, &grant, cfi, sf_idx, rvidx, mimo_type, dci_unpacked.pinfo)) { + if (srslte_ue_dl_cfg_grant(q, &grant, cfi, sf_idx, rvidx, mimo_type)) { ERROR("Configuing PDSCH"); return SRSLTE_ERROR; } diff --git a/srsue/src/phy/phch_worker.cc b/srsue/src/phy/phch_worker.cc index 231190fb1..6dabbbf01 100644 --- a/srsue/src/phy/phch_worker.cc +++ b/srsue/src/phy/phch_worker.cc @@ -431,6 +431,7 @@ bool phch_worker::decode_pdsch_multi(srslte_ra_dl_grant_t *grant, uint8_t *paylo } switch(phy->config->dedicated.antenna_info_explicit_value.tx_mode) { + /* Implemented Tx Modes */ case LIBLTE_RRC_TRANSMISSION_MODE_1: mimo_type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA; break; @@ -447,9 +448,18 @@ bool phch_worker::decode_pdsch_multi(srslte_ra_dl_grant_t *grant, uint8_t *paylo valid_config = false; } break; + case LIBLTE_RRC_TRANSMISSION_MODE_4: + if (grant->nof_tb == 1) { + mimo_type = (grant->pinfo == 0) ? SRSLTE_MIMO_TYPE_TX_DIVERSITY : SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX; + } else if (grant->nof_tb == 2) { + mimo_type = SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX; + } else { + Error("Wrong number of transport blocks (%d) for TM4\n", grant->nof_tb); + valid_config = false; + } + break; /* Not implemented cases */ - case LIBLTE_RRC_TRANSMISSION_MODE_4: case LIBLTE_RRC_TRANSMISSION_MODE_5: case LIBLTE_RRC_TRANSMISSION_MODE_6: case LIBLTE_RRC_TRANSMISSION_MODE_7: @@ -468,7 +478,7 @@ bool phch_worker::decode_pdsch_multi(srslte_ra_dl_grant_t *grant, uint8_t *paylo /* Setup PDSCH configuration for this CFI, SFIDX and RVIDX */ if (valid_config) { - if (!srslte_ue_dl_cfg_grant_multi(&ue_dl, grant, cfi, tti%10, rv, mimo_type, 0)) { + if (!srslte_ue_dl_cfg_grant(&ue_dl, grant, cfi, tti%10, rv, mimo_type)) { if (ue_dl.pdsch_cfg.grant.mcs[0].mod > 0 && ue_dl.pdsch_cfg.grant.mcs[0].tbs >= 0) { float noise_estimate = srslte_chest_dl_get_noise_estimate(&ue_dl.chest); From 8e814003296b5b217d0ed18ff8d71cd52df3e23e Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Wed, 23 Aug 2017 15:34:40 +0200 Subject: [PATCH 18/60] Solved bug: UE DL was not getting into TxDiversity on DCI formats 1 and 1A --- lib/src/phy/ue/ue_dl.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/lib/src/phy/ue/ue_dl.c b/lib/src/phy/ue/ue_dl.c index c9a5dea1a..26dc0b908 100644 --- a/lib/src/phy/ue/ue_dl.c +++ b/lib/src/phy/ue/ue_dl.c @@ -379,7 +379,11 @@ int srslte_ue_dl_decode_rnti_multi(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_POR switch(dci_msg.format) { case SRSLTE_DCI_FORMAT1: case SRSLTE_DCI_FORMAT1A: - mimo_type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA; + if (q->cell.nof_ports == 1) { + mimo_type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA; + } else { + mimo_type = SRSLTE_MIMO_TYPE_TX_DIVERSITY; + } break; case SRSLTE_DCI_FORMAT2: if (grant.nof_tb == 1 && dci_unpacked.pinfo == 0) { @@ -456,7 +460,10 @@ int srslte_ue_dl_ri_pmi_select(srslte_ue_dl_t *q, uint32_t *ri, uint32_t *pmi, f float best_sinr = -INFINITY; uint32_t best_pmi = 0, best_ri = 0; - if (q->cell.nof_ports == 2 && q->nof_rx_antennas == 2) { + if (q->cell.nof_ports < 2 || q->nof_rx_antennas < 2) { + /* Do nothing */ + return SRSLTE_SUCCESS; + } else if (q->cell.nof_ports == 2 && q->nof_rx_antennas == 2) { if (srslte_pdsch_pmi_select(&q->pdsch, &q->pdsch_cfg, q->ce_m, noise_estimate, SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp), q->pmi, q->sinr)) { ERROR("SINR calculation error"); @@ -489,7 +496,7 @@ int srslte_ue_dl_ri_pmi_select(srslte_ue_dl_t *q, uint32_t *ri, uint32_t *pmi, f } else if (q->pdsch_cfg.nof_layers == 2) { *current_sinr = q->sinr[1][q->pdsch_cfg.codebook_idx - 1]; } else { - ERROR("Not implemented number of layers"); + ERROR("Not implemented number of layers (%d)", q->pdsch_cfg.nof_layers); return SRSLTE_ERROR; } } From 02a4bb6bddca224d5d17c6eb606e5e24d208ac8e Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Wed, 23 Aug 2017 15:35:48 +0200 Subject: [PATCH 19/60] Improved PDSCH UE debug --- lib/examples/pdsch_ue.c | 45 ++++++++++++++++++++++++++++++++--------- 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/lib/examples/pdsch_ue.c b/lib/examples/pdsch_ue.c index 60cc0a4db..8c4d57484 100644 --- a/lib/examples/pdsch_ue.c +++ b/lib/examples/pdsch_ue.c @@ -101,6 +101,7 @@ typedef struct { int net_port_signal; char *net_address_signal; int decimate; + int verbose; }prog_args_t; void args_default(prog_args_t *args) { @@ -131,6 +132,7 @@ void args_default(prog_args_t *args) { args->net_address_signal = "127.0.0.1"; args->decimate = 0; args->cpu_affinity = -1; + args->verbose = 0; } void usage(prog_args_t *args, char *prog) { @@ -187,6 +189,8 @@ void parse_args(prog_args_t *args, int argc, char **argv) { break; case 'o': args->file_offset_freq = atof(argv[optind]); + argv++; + argc--; break; case 'O': args->file_offset_time = atoi(argv[optind]); @@ -240,7 +244,8 @@ void parse_args(prog_args_t *args, int argc, char **argv) { args->disable_plots_except_constellation = true; break; case 'v': - srslte_verbose++; + args->verbose++; + srslte_verbose = args->verbose; break; case 'Z': args->decimate = atoi(argv[optind]); @@ -392,8 +397,8 @@ int main(int argc, char **argv) { srslte_rf_set_master_clock_rate(&rf, 30.72e6); /* set receiver frequency */ - printf("Tunning receiver to %.3f MHz\n", prog_args.rf_freq/1000000); - srslte_rf_set_rx_freq(&rf, prog_args.rf_freq); + printf("Tunning receiver to %.3f MHz\n", (prog_args.rf_freq + prog_args.file_offset_freq)/1000000); + srslte_rf_set_rx_freq(&rf, prog_args.rf_freq + prog_args.file_offset_freq); srslte_rf_rx_wait_lo_locked(&rf); uint32_t ntrial=0; @@ -416,7 +421,7 @@ int main(int argc, char **argv) { srslte_rf_flush_buffer(&rf); /* set sampling frequency */ - int srate = srslte_sampling_freq_hz(cell.nof_prb); + int srate = srslte_sampling_freq_hz(cell.nof_prb)*(1 + prog_args.file_offset_freq/prog_args.rf_freq); if (srate != -1) { if (srate < 10e6) { srslte_rf_set_master_clock_rate(&rf, 4*srate); @@ -540,7 +545,27 @@ int main(int argc, char **argv) { INFO("\nEntering main loop...\n\n", 0); /* Main loop */ while (!go_exit && (sf_cnt < prog_args.nof_subframes || prog_args.nof_subframes == -1)) { - + char input[128]; + + fd_set set; + FD_ZERO(&set); + FD_SET(0, &set); + + struct timeval to; + to.tv_sec = 0; + to.tv_usec = 0; + + /* Set default verbose level */ + srslte_verbose = prog_args.verbose; + int n = select(1, &set, NULL, NULL, &to); + if (n == 1) { + /* If a new line is detected set verbose level to Debug */ + if (fgets(input, sizeof(input), stdin)) { + srslte_verbose = SRSLTE_VERBOSE_DEBUG; + } + } + + ret = srslte_ue_sync_zerocopy_multi(&ue_sync, sf_buffer); if (ret < 0) { fprintf(stderr, "Error calling srslte_ue_sync_work()\n"); @@ -673,7 +698,9 @@ int main(int argc, char **argv) { printf("\033[K Rb: %6.2f / %6.2f Mbps (net/maximum)\n", uerate, enodebrate); printf("\033[K PDCCH-Miss: %5.2f%%\n", 100 * (1 - (float) ue_dl.nof_detected / nof_trials)); printf("\033[K PDSCH-BLER: %5.2f%%\n", (float) 100 * ue_dl.pkt_errors / ue_dl.pkts_total); - printf("\033[K PDSCH-BLER: %5.2f%%\n\n", (float) 100 * ue_dl.pkt_errors / ue_dl.pkts_total); + printf("\033[K PDSCH-BLER: %5.2f%%\n", (float) 100 * ue_dl.pkt_errors / ue_dl.pkts_total); + printf("\033[K TB 0: mcs=%d; tbs=%d\n", ue_dl.pdsch_cfg.grant.mcs[0].idx, ue_dl.pdsch_cfg.grant.mcs[0].tbs); + printf("\033[K TB 1: mcs=%d; tbs=%d\n", ue_dl.pdsch_cfg.grant.mcs[1].idx, ue_dl.pdsch_cfg.grant.mcs[1].tbs); printf("\033[K\n"); printf("\033[KSINR (dB) Vs RI and PMI:\n"); printf("\033[K | RI | 1 | 2 |\n"); @@ -683,7 +710,7 @@ int main(int argc, char **argv) { printf("\033[K I | 2 | %5.2f%c|-------+ \n", 10 * log10(sinr[0][2]), (ri == 1 && pmi == 2)?'*':' '); printf("\033[K | 3 | %5.2f%c| \n", 10 * log10(sinr[0][3]), (ri == 1 && pmi == 3)?'*':' '); printf("\033[K\n\n"); - printf("\033[20A"); + printf("\033[21A"); } } break; @@ -692,7 +719,7 @@ int main(int argc, char **argv) { sfn++; if (sfn == 1024) { sfn = 0; - printf("\033[20B"); + printf("\033[21B"); ue_dl.pkt_errors = 0; ue_dl.pkts_total = 0; ue_dl.nof_detected = 0; @@ -724,7 +751,7 @@ int main(int argc, char **argv) { sf_cnt++; } // Main loop - printf("\033[20B"); + printf("\033[21B\n"); #ifndef DISABLE_GRAPHICS if (!prog_args.disable_plots) { From ecaf84de5193f4f453c0ec5fafa27e55f4b03c1c Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Wed, 23 Aug 2017 15:30:13 +0200 Subject: [PATCH 20/60] pdsch_test can load MIMO files --- lib/src/phy/phch/test/pdsch_test.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/phy/phch/test/pdsch_test.c b/lib/src/phy/phch/test/pdsch_test.c index 777481d6a..41b05f229 100644 --- a/lib/src/phy/phch/test/pdsch_test.c +++ b/lib/src/phy/phch/test/pdsch_test.c @@ -317,7 +317,7 @@ int main(int argc, char **argv) { #ifdef DO_OFDM srslte_filesource_read(&fsrc, rx_slot_symbols, SRSLTE_SF_LEN_PRB(cell.nof_prb)); #else - srslte_filesource_read(&fsrc, rx_slot_symbols[0], SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp)); + srslte_filesource_read_multi(&fsrc, (void*) rx_slot_symbols, SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp), pdsch_cfg.nof_layers); #endif srslte_chest_dl_t chest; @@ -325,7 +325,7 @@ int main(int argc, char **argv) { fprintf(stderr, "Error initializing equalizer\n"); exit(-1); } - srslte_chest_dl_estimate(&chest, rx_slot_symbols[0], ce[0], subframe); + srslte_chest_dl_estimate_multi(&chest, rx_slot_symbols, ce, subframe, nof_rx_antennas); srslte_chest_dl_free(&chest); srslte_filesource_free(&fsrc); From a1060c067af960cab53b969170cfbdc51ad8f559 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Wed, 23 Aug 2017 15:35:48 +0200 Subject: [PATCH 22/60] Improved PDSCH UE debug (cherry picked from commit cef312c) --- lib/examples/pdsch_ue.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/examples/pdsch_ue.c b/lib/examples/pdsch_ue.c index 8c4d57484..4b7a3f24b 100644 --- a/lib/examples/pdsch_ue.c +++ b/lib/examples/pdsch_ue.c @@ -318,7 +318,6 @@ int main(int argc, char **argv) { srslte_rf_t rf; #endif uint32_t nof_trials = 0; - int n; uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN]; int sfn_offset; float cfo = 0; @@ -690,7 +689,12 @@ int main(int argc, char **argv) { } /* Print Results */ - printf("\033[K Tx scheme: %-10s\n", srslte_mimotype2str(ue_dl.pdsch_cfg.mimo_type)); + if (ue_dl.pdsch_cfg.mimo_type == SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX) { + printf("\033[K Tx scheme: %s (codebook_idx=%d)\n", srslte_mimotype2str(ue_dl.pdsch_cfg.mimo_type), + ue_dl.pdsch_cfg.codebook_idx); + } else { + printf("\033[K Tx scheme: %s\n", srslte_mimotype2str(ue_dl.pdsch_cfg.mimo_type)); + } printf("\033[K nof layers: %d \n", ue_dl.pdsch_cfg.nof_layers); printf("\033[Knof codewords: %d \n", ue_dl.pdsch_cfg.grant.nof_tb); printf("\033[K CFO: %+5.2f kHz\n", srslte_ue_sync_get_cfo(&ue_sync) / 1000); @@ -702,7 +706,7 @@ int main(int argc, char **argv) { printf("\033[K TB 0: mcs=%d; tbs=%d\n", ue_dl.pdsch_cfg.grant.mcs[0].idx, ue_dl.pdsch_cfg.grant.mcs[0].tbs); printf("\033[K TB 1: mcs=%d; tbs=%d\n", ue_dl.pdsch_cfg.grant.mcs[1].idx, ue_dl.pdsch_cfg.grant.mcs[1].tbs); printf("\033[K\n"); - printf("\033[KSINR (dB) Vs RI and PMI:\n"); + printf("\033[KSINR (dB) Vs RI and PMI (for TM4, close loop MIMO only):\n"); printf("\033[K | RI | 1 | 2 |\n"); printf("\033[K -------+-------+-------+\n"); printf("\033[K P | 0 | %5.2f%c| %5.2f%c|\n", 10 * log10(sinr[0][0]), (ri == 1 && pmi == 0)?'*':' ', 10 * log10(sinr[1][0]), (ri == 2 && pmi == 0)?'*':' '); From e22a526350c8c095ba0f8d0b55d4e37c76cb6708 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Mon, 28 Aug 2017 13:05:27 +0200 Subject: [PATCH 23/60] Correction RF module for supporting Rx diversity in the UE --- lib/include/srslte/phy/rf/rf.h | 15 +++++++++------ lib/src/phy/rf/rf_blade_imp.c | 2 +- lib/src/phy/rf/rf_blade_imp.h | 2 +- lib/src/phy/rf/rf_dev.h | 2 +- lib/src/phy/rf/rf_imp.c | 32 ++++++++++++++++++-------------- lib/src/phy/rf/rf_uhd_imp.c | 12 ++++++------ lib/src/phy/rf/rf_uhd_imp.h | 3 +-- lib/src/radio/radio.cc | 9 ++++++--- 8 files changed, 43 insertions(+), 34 deletions(-) diff --git a/lib/include/srslte/phy/rf/rf.h b/lib/include/srslte/phy/rf/rf.h index 42b2a691d..50ced76d9 100644 --- a/lib/include/srslte/phy/rf/rf.h +++ b/lib/include/srslte/phy/rf/rf.h @@ -99,12 +99,6 @@ SRSLTE_API int srslte_rf_open_devname_multi(srslte_rf_t *h, char *args, uint32_t nof_rx_antennas); -SRSLTE_API int srslte_rf_open_devname_multi2(srslte_rf_t *rf, - char *devname, - char *args, - uint32_t nof_tx_antennas, - uint32_t nof_rx_antennas); - SRSLTE_API const char *srslte_rf_name(srslte_rf_t *h); SRSLTE_API int srslte_rf_start_gain_thread(srslte_rf_t *rf, @@ -221,6 +215,15 @@ SRSLTE_API int srslte_rf_send_timed2(srslte_rf_t *h, bool is_start_of_burst, bool is_end_of_burst); +SRSLTE_API int srslte_rf_send_timed_multi(srslte_rf_t *rf, + void *data[4], + int nsamples, + time_t secs, + double frac_secs, + bool blocking, + bool is_start_of_burst, + bool is_end_of_burst); + SRSLTE_API int srslte_rf_send_multi(srslte_rf_t *rf, void *data[4], int nsamples, diff --git a/lib/src/phy/rf/rf_blade_imp.c b/lib/src/phy/rf/rf_blade_imp.c index c48a2ad5b..d8996925f 100644 --- a/lib/src/phy/rf/rf_blade_imp.c +++ b/lib/src/phy/rf/rf_blade_imp.c @@ -178,7 +178,7 @@ float rf_blade_get_rssi(void *h) return 0; } -int rf_blade_open_multi(char *args, void **h, uint32_t nof_tx_antennas, uint32_t nof_rx_antennas) +int rf_blade_open_multi(char *args, void **h, uint32_t nof_channels) { return rf_blade_open(args, h); } diff --git a/lib/src/phy/rf/rf_blade_imp.h b/lib/src/phy/rf/rf_blade_imp.h index 2876a5404..fbaeab1df 100644 --- a/lib/src/phy/rf/rf_blade_imp.h +++ b/lib/src/phy/rf/rf_blade_imp.h @@ -34,7 +34,7 @@ SRSLTE_API int rf_blade_open(char *args, void **handler); SRSLTE_API int rf_blade_open_multi(char *args, - void **handler, uint32_t nof_tx_antennas, uint32_t nof_rx_antennas); + void **handler, uint32_t nof_channels); SRSLTE_API char* rf_blade_devname(void *h); diff --git a/lib/src/phy/rf/rf_dev.h b/lib/src/phy/rf/rf_dev.h index 4e3f2681b..00f157b6b 100644 --- a/lib/src/phy/rf/rf_dev.h +++ b/lib/src/phy/rf/rf_dev.h @@ -38,7 +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_tx_antennas, uint32_t nof_rx_antennas); + int (*srslte_rf_open_multi)(char *args, void **h, uint32_t nof_channels); 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); diff --git a/lib/src/phy/rf/rf_imp.c b/lib/src/phy/rf/rf_imp.c index 0ae771043..cb22b301b 100644 --- a/lib/src/phy/rf/rf_imp.c +++ b/lib/src/phy/rf/rf_imp.c @@ -102,11 +102,7 @@ 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) { - return srslte_rf_open_devname_multi2(rf, devname, args, 1, nof_rx_antennas); -} - -int srslte_rf_open_devname_multi2(srslte_rf_t *rf, char *devname, char *args, uint32_t nof_tx_antennas, uint32_t nof_rx_antennas) { +int srslte_rf_open_devname_multi(srslte_rf_t *rf, char *devname, char *args, uint32_t nof_channels) { /* Try to open the device if name is provided */ if (devname) { if (devname[0] != '\0') { @@ -114,7 +110,7 @@ int srslte_rf_open_devname_multi2(srslte_rf_t *rf, char *devname, char *args, ui while(available_devices[i] != NULL) { if (!strcmp(available_devices[i]->name, devname)) { rf->dev = available_devices[i]; - return available_devices[i]->srslte_rf_open_multi(args, &rf->handler, nof_tx_antennas, nof_rx_antennas); + return available_devices[i]->srslte_rf_open_multi(args, &rf->handler, nof_channels); } i++; } @@ -125,7 +121,7 @@ int srslte_rf_open_devname_multi2(srslte_rf_t *rf, char *devname, char *args, ui /* 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_multi(args, &rf->handler, nof_tx_antennas, nof_rx_antennas)) { + if (!available_devices[i]->srslte_rf_open_multi(args, &rf->handler, nof_channels)) { rf->dev = available_devices[i]; return 0; } @@ -198,11 +194,6 @@ 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_open_multi2(srslte_rf_t *h, char *args, uint32_t nof_tx_antennas, uint32_t nof_rx_antennas) -{ - return srslte_rf_open_devname_multi2(h, NULL, args, nof_tx_antennas, nof_rx_antennas); -} - int srslte_rf_close(srslte_rf_t *rf) { return ((rf_dev_t*) rf->dev)->srslte_rf_close(rf->handler); @@ -310,6 +301,20 @@ int srslte_rf_send_timed3(srslte_rf_t *rf, has_time_spec, blocking, is_start_of_burst, is_end_of_burst); } +int srslte_rf_send_timed_multi(srslte_rf_t *rf, + void *data[4], + int nsamples, + time_t secs, + double frac_secs, + bool blocking, + bool is_start_of_burst, + bool is_end_of_burst) +{ + + return ((rf_dev_t*) rf->dev)->srslte_rf_send_timed_multi(rf->handler, data, nsamples, secs, frac_secs, + true, blocking, is_start_of_burst, is_end_of_burst); +} + int srslte_rf_send_multi(srslte_rf_t *rf, void *data[4], int nsamples, @@ -318,8 +323,7 @@ int srslte_rf_send_multi(srslte_rf_t *rf, bool is_end_of_burst) { - return ((rf_dev_t*) rf->dev)->srslte_rf_send_timed_multi(rf->handler, data, nsamples, 0, 0, - false, blocking, is_start_of_burst, is_end_of_burst); + return srslte_rf_send_timed_multi(rf, data, nsamples, 0, 0, blocking, is_start_of_burst, is_end_of_burst); } int srslte_rf_send(srslte_rf_t *rf, void *data, uint32_t nsamples, bool blocking) diff --git a/lib/src/phy/rf/rf_uhd_imp.c b/lib/src/phy/rf/rf_uhd_imp.c index e0f3ac573..8819b706c 100644 --- a/lib/src/phy/rf/rf_uhd_imp.c +++ b/lib/src/phy/rf/rf_uhd_imp.c @@ -286,10 +286,10 @@ float rf_uhd_get_rssi(void *h) { int rf_uhd_open(char *args, void **h) { - return rf_uhd_open_multi(args, h, 1, 1); + return rf_uhd_open_multi(args, h, 1); } -int rf_uhd_open_multi(char *args, void **h, uint32_t nof_tx_antennas, uint32_t nof_rx_antennas) +int rf_uhd_open_multi(char *args, void **h, uint32_t nof_channels) { if (h) { *h = NULL; @@ -395,11 +395,11 @@ int rf_uhd_open_multi(char *args, void **h, uint32_t nof_tx_antennas, uint32_t n .otw_format = "sc16", .args = "", .channel_list = channel, - .n_channels = (nof_tx_antennas > nof_rx_antennas)?nof_tx_antennas:nof_rx_antennas, + .n_channels = nof_channels, }; - handler->nof_rx_channels = nof_rx_antennas; - handler->nof_tx_channels = nof_tx_antennas; + handler->nof_rx_channels = nof_channels; + handler->nof_tx_channels = nof_channels; /* Initialize rx and tx stremers */ uhd_rx_streamer_make(&handler->rx_stream); error = uhd_usrp_get_rx_stream(handler->usrp, &stream_args, handler->rx_stream); @@ -664,7 +664,7 @@ int rf_uhd_send_timed_multi(void *h, rf_uhd_handler_t* handler = (rf_uhd_handler_t*) h; /* Resets the USRP time FIXME: this might cause problems for burst transmissions */ - if (is_start_of_burst && handler->nof_tx_channels > 1) { + if (!has_time_spec && is_start_of_burst && handler->nof_tx_channels > 1) { uhd_usrp_set_time_now(handler->usrp, 0, 0, 0); uhd_tx_metadata_set_time_spec(&handler->tx_md, 0, 0.1); } diff --git a/lib/src/phy/rf/rf_uhd_imp.h b/lib/src/phy/rf/rf_uhd_imp.h index 6c0ab7dc7..2be799333 100644 --- a/lib/src/phy/rf/rf_uhd_imp.h +++ b/lib/src/phy/rf/rf_uhd_imp.h @@ -39,8 +39,7 @@ SRSLTE_API int rf_uhd_open(char *args, SRSLTE_API int rf_uhd_open_multi(char *args, void **handler, - uint32_t nof_tx_antennas, - uint32_t nof_rx_antennas); + uint32_t nof_channels); SRSLTE_API char* rf_uhd_devname(void *h); diff --git a/lib/src/radio/radio.cc b/lib/src/radio/radio.cc index bc74660b0..f508dc046 100644 --- a/lib/src/radio/radio.cc +++ b/lib/src/radio/radio.cc @@ -169,6 +169,8 @@ bool radio::has_rssi() bool radio::tx(void* buffer, uint32_t nof_samples, srslte_timestamp_t tx_time) { + void *iq_samples[4] = {(void *) zeros, (void *) zeros, (void *) zeros, (void *) zeros}; + if (!tx_adv_negative) { srslte_timestamp_sub(&tx_time, 0, tx_adv_sec); } else { @@ -177,11 +179,11 @@ bool radio::tx(void* buffer, uint32_t nof_samples, srslte_timestamp_t tx_time) if (is_start_of_burst) { if (burst_preamble_samples != 0) { - srslte_timestamp_t tx_time_pad; + srslte_timestamp_t tx_time_pad; srslte_timestamp_copy(&tx_time_pad, &tx_time); srslte_timestamp_sub(&tx_time_pad, 0, burst_preamble_time_rounded); save_trace(1, &tx_time_pad); - srslte_rf_send_timed2(&rf_device, zeros, burst_preamble_samples, tx_time_pad.full_secs, tx_time_pad.frac_secs, true, false); + srslte_rf_send_timed_multi(&rf_device, iq_samples, burst_preamble_samples, tx_time_pad.full_secs, tx_time_pad.frac_secs, true, true, false); is_start_of_burst = false; } } @@ -191,7 +193,8 @@ bool radio::tx(void* buffer, uint32_t nof_samples, srslte_timestamp_t tx_time) srslte_timestamp_add(&end_of_burst_time, 0, (double) nof_samples/cur_tx_srate); save_trace(0, &tx_time); - int ret = srslte_rf_send_timed2(&rf_device, buffer, nof_samples+offset, tx_time.full_secs, tx_time.frac_secs, is_start_of_burst, false); + iq_samples[0] = buffer; + int ret = srslte_rf_send_timed_multi(&rf_device, (void**) iq_samples, nof_samples+offset, tx_time.full_secs, tx_time.frac_secs, true, is_start_of_burst, false); offset = 0; is_start_of_burst = false; if (ret > 0) { From 8c71c716c94ad3c72ab00f853994efd7c584c04d Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Mon, 28 Aug 2017 13:06:54 +0200 Subject: [PATCH 24/60] PDSCH decoder acknowledges TBs/CWs per sepparate and softbuffers are arrays of pointers --- lib/examples/cell_measurement.c | 5 +- lib/examples/pdsch_enodeb.c | 13 ++++-- lib/examples/pdsch_ue.c | 7 +-- lib/include/srslte/phy/common/phy_common.h | 13 +++--- lib/include/srslte/phy/phch/pdsch.h | 7 +-- lib/include/srslte/phy/ue/ue_dl.h | 7 +-- lib/src/phy/phch/pdsch.c | 30 ++++++------ lib/src/phy/phch/test/pdsch_test.c | 54 ++++++++++++++++------ lib/src/phy/ue/ue_dl.c | 48 +++++++++++-------- 9 files changed, 117 insertions(+), 67 deletions(-) diff --git a/lib/examples/cell_measurement.c b/lib/examples/cell_measurement.c index 90b963db8..c6135984c 100644 --- a/lib/examples/cell_measurement.c +++ b/lib/examples/cell_measurement.c @@ -160,7 +160,8 @@ int main(int argc, char **argv) { int sfn_offset; float rssi_utra=0,rssi=0, rsrp=0, rsrq=0, snr=0; cf_t *ce[SRSLTE_MAX_PORTS]; - float cfo = 0; + float cfo = 0; + bool acks[SRSLTE_MAX_CODEWORDS] = {false}; if (parse_args(&prog_args, argc, argv)) { exit(-1); @@ -313,7 +314,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_multi(&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), acks); if (n < 0) { fprintf(stderr, "Error decoding UE DL\n");fflush(stdout); return -1; diff --git a/lib/examples/pdsch_enodeb.c b/lib/examples/pdsch_enodeb.c index 1bc2d5230..a4558ff30 100644 --- a/lib/examples/pdsch_enodeb.c +++ b/lib/examples/pdsch_enodeb.c @@ -84,7 +84,7 @@ srslte_pcfich_t pcfich; srslte_pdcch_t pdcch; srslte_pdsch_t pdsch; srslte_pdsch_cfg_t pdsch_cfg; -srslte_softbuffer_tx_t softbuffers[SRSLTE_MAX_CODEWORDS]; +srslte_softbuffer_tx_t *softbuffers[SRSLTE_MAX_CODEWORDS]; srslte_regs_t regs; srslte_ra_dl_dci_t ra_dl; int rvidx[SRSLTE_MAX_CODEWORDS] = {0, 0}; @@ -267,7 +267,7 @@ void base_init() { } else { #ifndef DISABLE_RF printf("Opening RF device...\n"); - if (srslte_rf_open_multi2(&rf, rf_args, cell.nof_ports, 1)) { + if (srslte_rf_open_multi(&rf, rf_args, cell.nof_ports)) { fprintf(stderr, "Error opening rf\n"); exit(-1); } @@ -334,7 +334,7 @@ void base_init() { srslte_pdsch_set_rnti(&pdsch, UE_CRNTI); for (i = 0; i < nof_tb; i++) { - if (srslte_softbuffer_tx_init(&softbuffers[i], cell.nof_prb)) { + if (srslte_softbuffer_tx_init(softbuffers[i], cell.nof_prb)) { fprintf(stderr, "Error initiating soft buffer\n"); exit(-1); } @@ -344,7 +344,10 @@ void base_init() { void base_free() { int i; for (i = 0; i < nof_tb; i++) { - srslte_softbuffer_tx_free(&softbuffers[i]); + if (softbuffers[i]) { + free(softbuffers[i]); + } + srslte_softbuffer_tx_free(softbuffers[i]); } srslte_pdsch_free(&pdsch); srslte_pdcch_free(&pdcch); @@ -649,7 +652,7 @@ int main(int argc, char **argv) { bool send_data = false; for (i = 0; i < nof_tb; i++) { - srslte_softbuffer_tx_reset(&softbuffers[i]); + srslte_softbuffer_tx_reset(softbuffers[i]); } #ifndef DISABLE_RF diff --git a/lib/examples/pdsch_ue.c b/lib/examples/pdsch_ue.c index 60cc0a4db..4ce537bdd 100644 --- a/lib/examples/pdsch_ue.c +++ b/lib/examples/pdsch_ue.c @@ -540,7 +540,8 @@ int main(int argc, char **argv) { INFO("\nEntering main loop...\n\n", 0); /* Main loop */ while (!go_exit && (sf_cnt < prog_args.nof_subframes || prog_args.nof_subframes == -1)) { - + bool acks [SRSLTE_MAX_CODEWORDS] = {false}; + ret = srslte_ue_sync_zerocopy_multi(&ue_sync, sf_buffer); if (ret < 0) { fprintf(stderr, "Error calling srslte_ue_sync_work()\n"); @@ -585,7 +586,7 @@ int main(int argc, char **argv) { n = srslte_ue_dl_decode_multi(&ue_dl, sf_buffer, data, - sfn*10+srslte_ue_sync_get_sfidx(&ue_sync)); + sfn*10+srslte_ue_sync_get_sfidx(&ue_sync), acks); if (n < 0) { // fprintf(stderr, "Error decoding UE DL\n");fflush(stdout); @@ -623,7 +624,7 @@ int main(int argc, char **argv) { rsrp1 = SRSLTE_VEC_EMA(srslte_chest_dl_get_rsrp_port(&ue_dl.chest, 1), rsrp1, 0.05f); noise = SRSLTE_VEC_EMA(srslte_chest_dl_get_noise_estimate(&ue_dl.chest), noise, 0.05f); enodebrate = SRSLTE_VEC_EMA((ue_dl.pdsch_cfg.grant.mcs[0].tbs + ue_dl.pdsch_cfg.grant.mcs[1].tbs)/1000.0f, enodebrate, 0.05f); - uerate = SRSLTE_VEC_EMA((n>0)?(ue_dl.pdsch_cfg.grant.mcs[0].tbs + ue_dl.pdsch_cfg.grant.mcs[1].tbs)/1000.0f:0.0f, uerate, 0.01f); + uerate = SRSLTE_VEC_EMA(((acks[0]?ue_dl.pdsch_cfg.grant.mcs[0].tbs:0) + (acks[1]?ue_dl.pdsch_cfg.grant.mcs[1].tbs:0))/1000.0f, uerate, 0.01f); nframes++; if (isnan(rsrq)) { diff --git a/lib/include/srslte/phy/common/phy_common.h b/lib/include/srslte/phy/common/phy_common.h index ad9be3e0f..821908fcb 100644 --- a/lib/include/srslte/phy/common/phy_common.h +++ b/lib/include/srslte/phy/common/phy_common.h @@ -52,6 +52,7 @@ #define SRSLTE_MAX_PORTS 4 #define SRSLTE_MAX_LAYERS 4 #define SRSLTE_MAX_CODEWORDS 2 +#define SRSLTE_MAX_TB SRSLTE_MAX_CODEWORDS #define SRSLTE_MAX_CODEBLOCKS 32 @@ -150,12 +151,12 @@ typedef enum SRSLTE_API { } srslte_phich_resources_t; typedef enum { - SRSLTE_RNTI_USER = 0, - SRSLTE_RNTI_SI, - SRSLTE_RNTI_RAR, - SRSLTE_RNTI_TEMP, - SRSLTE_RNTI_SPS, - SRSLTE_RNTI_PCH, + SRSLTE_RNTI_USER = 0, /* Cell RNTI */ + SRSLTE_RNTI_SI, /* System Information RNTI */ + SRSLTE_RNTI_RAR, /* Random Access RNTI */ + SRSLTE_RNTI_TEMP, /* Temporary C-RNTI */ + SRSLTE_RNTI_SPS, /* Semi-Persistent Scheduling C-RNTI */ + SRSLTE_RNTI_PCH, /* Paging RNTI */ SRSLTE_RNTI_NOF_TYPES } srslte_rnti_type_t; diff --git a/lib/include/srslte/phy/phch/pdsch.h b/lib/include/srslte/phy/phch/pdsch.h index 99710b965..7cfa1b616 100644 --- a/lib/include/srslte/phy/phch/pdsch.h +++ b/lib/include/srslte/phy/phch/pdsch.h @@ -124,7 +124,7 @@ SRSLTE_API int srslte_pdsch_encode(srslte_pdsch_t *q, SRSLTE_API int srslte_pdsch_encode_multi(srslte_pdsch_t *q, srslte_pdsch_cfg_t *cfg, - srslte_softbuffer_tx_t softbuffers[SRSLTE_MAX_CODEWORDS], + srslte_softbuffer_tx_t *softbuffers[SRSLTE_MAX_CODEWORDS], uint8_t *data[SRSLTE_MAX_CODEWORDS], uint16_t rnti, cf_t *sf_symbols[SRSLTE_MAX_PORTS]); @@ -140,12 +140,13 @@ SRSLTE_API int srslte_pdsch_decode(srslte_pdsch_t *q, SRSLTE_API int srslte_pdsch_decode_multi(srslte_pdsch_t *q, srslte_pdsch_cfg_t *cfg, - srslte_softbuffer_rx_t softbuffers[SRSLTE_MAX_CODEWORDS], + srslte_softbuffer_rx_t *softbuffers[SRSLTE_MAX_CODEWORDS], 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[SRSLTE_MAX_CODEWORDS]); + uint8_t *data[SRSLTE_MAX_CODEWORDS], + bool acks[SRSLTE_MAX_CODEWORDS]); SRSLTE_API int srslte_pdsch_pmi_select(srslte_pdsch_t *q, srslte_pdsch_cfg_t *cfg, diff --git a/lib/include/srslte/phy/ue/ue_dl.h b/lib/include/srslte/phy/ue/ue_dl.h index 4101fadd9..97b2344f5 100644 --- a/lib/include/srslte/phy/ue/ue_dl.h +++ b/lib/include/srslte/phy/ue/ue_dl.h @@ -84,7 +84,7 @@ typedef struct SRSLTE_API { srslte_cfo_t sfo_correct; srslte_pdsch_cfg_t pdsch_cfg; - srslte_softbuffer_rx_t softbuffers[SRSLTE_MAX_CODEWORDS]; + srslte_softbuffer_rx_t *softbuffers[SRSLTE_MAX_CODEWORDS]; srslte_ra_dl_dci_t dl_dci; srslte_cell_t cell; @@ -180,7 +180,7 @@ SRSLTE_API int srslte_ue_dl_decode(srslte_ue_dl_t * q, SRSLTE_API int srslte_ue_dl_decode_multi(srslte_ue_dl_t * q, cf_t *input[SRSLTE_MAX_PORTS], uint8_t *data[SRSLTE_MAX_CODEWORDS], - uint32_t tti); + uint32_t tti, bool acks[SRSLTE_MAX_CODEWORDS]); SRSLTE_API int srslte_ue_dl_decode_rnti(srslte_ue_dl_t * q, cf_t *input, @@ -192,7 +192,8 @@ SRSLTE_API int srslte_ue_dl_decode_rnti_multi(srslte_ue_dl_t * q, cf_t *input[SRSLTE_MAX_PORTS], uint8_t *data[SRSLTE_MAX_CODEWORDS], uint32_t tti, - uint16_t rnti); + uint16_t rnti, + bool acks[SRSLTE_MAX_CODEWORDS]); SRSLTE_API int srslte_ue_dl_ri_pmi_select(srslte_ue_dl_t *q, uint32_t *ri, diff --git a/lib/src/phy/phch/pdsch.c b/lib/src/phy/phch/pdsch.c index 35e10fedb..0e824aaa7 100644 --- a/lib/src/phy/phch/pdsch.c +++ b/lib/src/phy/phch/pdsch.c @@ -553,30 +553,33 @@ void srslte_pdsch_free_rnti(srslte_pdsch_t* q, uint16_t rnti) 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) -{ + uint16_t rnti, uint8_t *data) { cf_t *_sf_symbols[SRSLTE_MAX_PORTS]; cf_t *_ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; + bool acks[SRSLTE_MAX_CODEWORDS]; + srslte_softbuffer_rx_t *softbuffers[SRSLTE_MAX_TB] = {NULL}; _sf_symbols[0] = sf_symbols; - for (int i=0;icell.nof_ports;i++) { + for (int i = 0; i < q->cell.nof_ports; i++) { _ce[i][0] = ce[i]; } - return srslte_pdsch_decode_multi(q, cfg, softbuffer, _sf_symbols, _ce, noise_estimate, rnti, &data); + + softbuffers[0] = softbuffer; + + return srslte_pdsch_decode_multi(q, cfg, softbuffers, _sf_symbols, _ce, noise_estimate, rnti, &data, acks); } /** 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 softbuffers[SRSLTE_MAX_CODEWORDS], - 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[SRSLTE_MAX_CODEWORDS]) -{ + srslte_pdsch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffers[SRSLTE_MAX_CODEWORDS], + 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[SRSLTE_MAX_CODEWORDS], + bool acks[SRSLTE_MAX_CODEWORDS]) { /* Set pointers for layermapping & precoding */ uint32_t i; cf_t *x[SRSLTE_MAX_LAYERS]; - int ret = 0; if (q != NULL && sf_symbols != NULL && @@ -658,7 +661,8 @@ int srslte_pdsch_decode_multi(srslte_pdsch_t *q, } for (uint32_t tb = 0; tb < cfg->grant.nof_tb; tb ++) { - ret |= srslte_pdsch_codeword_decode(q, cfg, &softbuffers[tb], rnti, data[tb], tb); + int ret = srslte_pdsch_codeword_decode(q, cfg, softbuffers[tb], rnti, data[tb], tb); + acks[tb] = (ret == SRSLTE_SUCCESS); } if (SRSLTE_VERBOSE_ISDEBUG()) { @@ -666,7 +670,7 @@ int srslte_pdsch_decode_multi(srslte_pdsch_t *q, srslte_vec_save_file("llr.dat", q->e, cfg->nbits[0].nof_bits*sizeof(int16_t)); } - return ret; + return SRSLTE_SUCCESS; } else { return SRSLTE_ERROR_INVALID_INPUTS; @@ -776,7 +780,7 @@ int srslte_pdsch_encode(srslte_pdsch_t *q, } int srslte_pdsch_encode_multi(srslte_pdsch_t *q, - srslte_pdsch_cfg_t *cfg, srslte_softbuffer_tx_t softbuffers[SRSLTE_MAX_CODEWORDS], + srslte_pdsch_cfg_t *cfg, srslte_softbuffer_tx_t *softbuffers[SRSLTE_MAX_CODEWORDS], uint8_t *data[SRSLTE_MAX_CODEWORDS], uint16_t rnti, cf_t *sf_symbols[SRSLTE_MAX_PORTS]) { int i; @@ -806,7 +810,7 @@ int srslte_pdsch_encode_multi(srslte_pdsch_t *q, } for (uint32_t tb = 0; tb < cfg->grant.nof_tb; tb ++) { - ret |= srslte_pdsch_codeword_encode(q, cfg, &softbuffers[tb], rnti, data[tb], tb); + ret |= srslte_pdsch_codeword_encode(q, cfg, softbuffers[tb], rnti, data[tb], tb); } if (q->cell.nof_ports > 1) { diff --git a/lib/src/phy/phch/test/pdsch_test.c b/lib/src/phy/phch/test/pdsch_test.c index 777481d6a..afc53d326 100644 --- a/lib/src/phy/phch/test/pdsch_test.c +++ b/lib/src/phy/phch/test/pdsch_test.c @@ -135,7 +135,7 @@ void parse_args(int argc, char **argv) { uint8_t *data[SRSLTE_MAX_CODEWORDS] = {NULL}; cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; -srslte_softbuffer_rx_t softbuffers_rx[SRSLTE_MAX_CODEWORDS]; +srslte_softbuffer_rx_t *softbuffers_rx[SRSLTE_MAX_CODEWORDS]; srslte_ra_dl_grant_t grant; srslte_pdsch_cfg_t pdsch_cfg; #ifdef DO_OFDM @@ -151,8 +151,9 @@ int main(int argc, char **argv) { uint32_t i, j, k; int ret = -1; struct timeval t[3]; - srslte_softbuffer_tx_t softbuffers_tx[SRSLTE_MAX_CODEWORDS]; + srslte_softbuffer_tx_t *softbuffers_tx[SRSLTE_MAX_CODEWORDS]; int M=10; + bool acks[SRSLTE_MAX_CODEWORDS] = {false}; parse_args(argc,argv); @@ -163,8 +164,6 @@ int main(int argc, char **argv) { bzero(ce, sizeof(cf_t*)*SRSLTE_MAX_PORTS); bzero(tx_slot_symbols, sizeof(cf_t*)*SRSLTE_MAX_PORTS); bzero(rx_slot_symbols, sizeof(cf_t*)*SRSLTE_MAX_PORTS); - bzero(softbuffers_tx, sizeof(srslte_softbuffer_tx_t)*SRSLTE_MAX_CODEWORDS); - bzero(softbuffers_rx, sizeof(srslte_softbuffer_rx_t)*SRSLTE_MAX_CODEWORDS); /* Parse transmission mode */ if (srslte_str2mimotype(mimo_type_str, &mimo_type)) { @@ -275,8 +274,14 @@ int main(int argc, char **argv) { srslte_pdsch_set_rnti(&pdsch_rx, rnti); - for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { - if (srslte_softbuffer_rx_init(&softbuffers_rx[i], cell.nof_prb)) { + for (i = 0; i < SRSLTE_MAX_TB; i++) { + softbuffers_rx[i] = calloc(sizeof(srslte_softbuffer_rx_t), 1); + if (!softbuffers_rx[i]) { + fprintf(stderr, "Error allocating RX soft buffer\n"); + goto quit; + } + + if (srslte_softbuffer_rx_init(softbuffers_rx[i], cell.nof_prb)) { fprintf(stderr, "Error initiating RX soft buffer\n"); goto quit; } @@ -339,7 +344,13 @@ int main(int argc, char **argv) { srslte_pdsch_set_rnti(&pdsch_tx, rnti); for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { - if (srslte_softbuffer_tx_init(&softbuffers_tx[i], cell.nof_prb)) { + softbuffers_tx[i] = calloc(sizeof(srslte_softbuffer_tx_t), 1); + + if (!softbuffers_tx[i]) { + fprintf(stderr, "Error allocating TX soft buffer\n"); + } + + if (srslte_softbuffer_tx_init(softbuffers_tx[i], cell.nof_prb)) { fprintf(stderr, "Error initiating TX soft buffer\n"); goto quit; } @@ -427,29 +438,44 @@ int main(int argc, char **argv) { #endif for (i = 0; i < grant.nof_tb; i++) { if (grant.mcs[i].tbs) { - srslte_softbuffer_rx_reset_tbs(&softbuffers_rx[i], (uint32_t) grant.mcs[i].tbs); + srslte_softbuffer_rx_reset_tbs(softbuffers_rx[i], (uint32_t) grant.mcs[i].tbs); } } - r = srslte_pdsch_decode_multi(&pdsch_rx, &pdsch_cfg, softbuffers_rx, rx_slot_symbols, ce, 0, rnti, data); + r = srslte_pdsch_decode_multi(&pdsch_rx, &pdsch_cfg, softbuffers_rx, rx_slot_symbols, ce, 0, rnti, data, acks); } gettimeofday(&t[2], NULL); get_time_interval(t); printf("DECODED %s in %.2f (PHY bitrate=%.2f Mbps. Processing bitrate=%.2f Mbps)\n", r?"Error":"OK", (float) t[0].tv_usec/M, (float) (grant.mcs[0].tbs + grant.mcs[1].tbs)/1000.0f, (float) (grant.mcs[0].tbs + grant.mcs[1].tbs)*M/t[0].tv_usec); + + /* If there is an error in PDSCH decode */ if (r) { - ret = -1; + ERROR("PDSCH decode"); + ret = SRSLTE_ERROR; goto quit; - } + } + + /* Check all transport blocks have been decoded OK */ + for (int tb = 0; tb < grant.nof_tb; tb++) { + ret |= (acks[tb]) ? SRSLTE_SUCCESS : SRSLTE_ERROR; + } - ret = 0; + ret = SRSLTE_SUCCESS; quit: srslte_pdsch_free(&pdsch_tx); srslte_pdsch_free(&pdsch_rx); for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { - srslte_softbuffer_tx_free(&softbuffers_tx[i]); - srslte_softbuffer_rx_free(&softbuffers_rx[i]); + srslte_softbuffer_tx_free(softbuffers_tx[i]); + if (softbuffers_tx[i]) { + free(softbuffers_tx[i]); + } + + srslte_softbuffer_rx_free(softbuffers_rx[i]); + if (softbuffers_rx[i]) { + free(softbuffers_rx[i]); + } if (data[i]) { free(data[i]); diff --git a/lib/src/phy/ue/ue_dl.c b/lib/src/phy/ue/ue_dl.c index c9a5dea1a..7e40876ec 100644 --- a/lib/src/phy/ue/ue_dl.c +++ b/lib/src/phy/ue/ue_dl.c @@ -102,8 +102,14 @@ int srslte_ue_dl_init_multi(srslte_ue_dl_t *q, goto clean_exit; } - for (int i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { - if (srslte_softbuffer_rx_init(&q->softbuffers[i], q->cell.nof_prb)) { + for (int i = 0; i < SRSLTE_MAX_TB; i++) { + q->softbuffers[i] = srslte_vec_malloc(sizeof(srslte_softbuffer_rx_t)); + if (!q->softbuffers[i]) { + fprintf(stderr, "Error allocating soft buffer\n"); + goto clean_exit; + } + + if (srslte_softbuffer_rx_init(q->softbuffers[i], q->cell.nof_prb)) { fprintf(stderr, "Error initiating soft buffer\n"); goto clean_exit; } @@ -157,8 +163,11 @@ void srslte_ue_dl_free(srslte_ue_dl_t *q) { srslte_pdcch_free(&q->pdcch); srslte_pdsch_free(&q->pdsch); srslte_cfo_free(&q->sfo_correct); - for (int i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { - srslte_softbuffer_rx_free(&q->softbuffers[i]); + for (int i = 0; i < SRSLTE_MAX_TB; i++) { + srslte_softbuffer_rx_free(q->softbuffers[i]); + if (q->softbuffers[i]) { + free(q->softbuffers[i]); + } } for (int j=0;jnof_rx_antennas;j++) { if (q->sf_symbols_m[j]) { @@ -194,7 +203,7 @@ void srslte_ue_dl_set_rnti(srslte_ue_dl_t *q, uint16_t rnti) { void srslte_ue_dl_reset(srslte_ue_dl_t *q) { for(int i = 0; i < SRSLTE_MAX_CODEWORDS; i++){ - srslte_softbuffer_rx_reset(&q->softbuffers[i]); + srslte_softbuffer_rx_reset(q->softbuffers[i]); } bzero(&q->pdsch_cfg, sizeof(srslte_pdsch_cfg_t)); } @@ -212,14 +221,16 @@ void srslte_ue_dl_set_sample_offset(srslte_ue_dl_t * q, float sample_offset) { */ int srslte_ue_dl_decode(srslte_ue_dl_t *q, cf_t *input, uint8_t *data, uint32_t tti) { uint8_t *_data[SRSLTE_MAX_CODEWORDS]; - cf_t *_input[SRSLTE_MAX_PORTS]; + cf_t *_input[SRSLTE_MAX_PORTS]; + bool acks[SRSLTE_MAX_CODEWORDS] = {false}; _data[0] = data; _input[0] = input; - return srslte_ue_dl_decode_rnti_multi(q, _input, _data, tti, q->current_rnti); + return srslte_ue_dl_decode_rnti_multi(q, _input, _data, tti, q->current_rnti, acks); } -int srslte_ue_dl_decode_multi(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint8_t *data[SRSLTE_MAX_CODEWORDS], uint32_t tti) { - return srslte_ue_dl_decode_rnti_multi(q, input, data, tti, q->current_rnti); +int srslte_ue_dl_decode_multi(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint8_t *data[SRSLTE_MAX_CODEWORDS], + uint32_t tti, bool acks[SRSLTE_MAX_CODEWORDS]) { + return srslte_ue_dl_decode_rnti_multi(q, input, data, tti, q->current_rnti, acks); } int srslte_ue_dl_decode_fft_estimate(srslte_ue_dl_t *q, cf_t *input, uint32_t sf_idx, uint32_t *cfi) @@ -307,16 +318,18 @@ int srslte_ue_dl_cfg_grant(srslte_ue_dl_t *q, srslte_ra_dl_grant_t *grant, uint3 return srslte_pdsch_cfg_multi(&q->pdsch_cfg, q->cell, grant, cfi, sf_idx, rvidx, mimo_type, pmi); } -int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, cf_t *input, uint8_t *data, uint32_t tti, uint16_t rnti) -{ +int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, cf_t *input, uint8_t *data, uint32_t tti, uint16_t rnti) { uint8_t *_data[SRSLTE_MAX_CODEWORDS]; cf_t *_input[SRSLTE_MAX_PORTS]; + bool acks[SRSLTE_MAX_CODEWORDS] = {false}; _input[0] = input; _data[0] = data; - return srslte_ue_dl_decode_rnti_multi(q, _input, _data, tti, rnti); + return srslte_ue_dl_decode_rnti_multi(q, _input, _data, tti, rnti, acks); } -int srslte_ue_dl_decode_rnti_multi(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint8_t *data[SRSLTE_MAX_CODEWORDS], uint32_t tti, uint16_t rnti) +int srslte_ue_dl_decode_rnti_multi(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], + uint8_t *data[SRSLTE_MAX_CODEWORDS], uint32_t tti, uint16_t rnti, + bool acks[SRSLTE_MAX_CODEWORDS]) { srslte_mimo_type_t mimo_type; srslte_dci_msg_t dci_msg; @@ -324,8 +337,7 @@ int srslte_ue_dl_decode_rnti_multi(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_POR srslte_ra_dl_grant_t grant; int ret = SRSLTE_ERROR; uint32_t cfi; - - uint32_t sf_idx = tti%10; + uint32_t sf_idx = tti%10; if ((ret = srslte_ue_dl_decode_fft_estimate_multi(q, input, sf_idx, &cfi)) < 0) { return ret; @@ -357,7 +369,7 @@ int srslte_ue_dl_decode_rnti_multi(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_POR uint32_t k = (sfn/2)%4; for (int i = 0; i < grant.nof_tb; i++) { rvidx[i] = ((uint32_t) ceilf((float) 1.5 * k)) % 4; - srslte_softbuffer_rx_reset_tbs(&q->softbuffers[i], (uint32_t) grant.mcs[i].tbs); + srslte_softbuffer_rx_reset_tbs(q->softbuffers[i], (uint32_t) grant.mcs[i].tbs); } } else { for (int i = 0; i < grant.nof_tb; i++) { @@ -372,7 +384,7 @@ int srslte_ue_dl_decode_rnti_multi(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_POR ERROR("Wrong number of transport blocks"); return SRSLTE_ERROR; } - srslte_softbuffer_rx_reset_tbs(&q->softbuffers[i], (uint32_t) grant.mcs[i].tbs); + srslte_softbuffer_rx_reset_tbs(q->softbuffers[i], (uint32_t) grant.mcs[i].tbs); } } @@ -421,7 +433,7 @@ int srslte_ue_dl_decode_rnti_multi(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_POR ret = srslte_pdsch_decode_multi(&q->pdsch, &q->pdsch_cfg, q->softbuffers, q->sf_symbols_m, q->ce_m, noise_estimate, - rnti, data); + rnti, data, acks); if (ret == SRSLTE_ERROR) { q->pkt_errors++; From be0c6ebd203196930357b9e13733a6347dcb2a51 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Mon, 28 Aug 2017 13:07:44 +0200 Subject: [PATCH 25/60] Added multiple codeword architecture to MAC layer --- lib/include/srslte/interfaces/ue_interfaces.h | 22 +- srsue/hdr/mac/dl_harq.h | 379 ++++++++++-------- srsue/hdr/mac/mac.h | 2 +- srsue/hdr/mac/ul_harq.h | 26 +- srsue/hdr/phy/phch_worker.h | 14 +- srsue/src/mac/mac.cc | 15 +- srsue/src/mac/proc_ra.cc | 12 +- srsue/src/phy/phch_worker.cc | 131 +++--- srsue/test/phy/ue_itf_test_prach.cc | 76 ++-- srsue/test/phy/ue_itf_test_sib1.cc | 29 +- 10 files changed, 392 insertions(+), 314 deletions(-) diff --git a/lib/include/srslte/interfaces/ue_interfaces.h b/lib/include/srslte/interfaces/ue_interfaces.h index 81ed67b74..879118021 100644 --- a/lib/include/srslte/interfaces/ue_interfaces.h +++ b/lib/include/srslte/interfaces/ue_interfaces.h @@ -277,10 +277,10 @@ public: uint32_t pid; uint32_t tti; uint32_t last_tti; - bool ndi; - bool last_ndi; - uint32_t n_bytes; - int rv; + bool ndi[SRSLTE_MAX_CODEWORDS]; + bool last_ndi[SRSLTE_MAX_CODEWORDS]; + uint32_t n_bytes[SRSLTE_MAX_CODEWORDS]; + int rv[SRSLTE_MAX_CODEWORDS]; uint16_t rnti; bool is_from_rar; bool is_sps_release; @@ -291,28 +291,28 @@ public: typedef struct { bool decode_enabled; - int rv; + int rv[SRSLTE_MAX_TB]; uint16_t rnti; bool generate_ack; bool default_ack; // If non-null, called after tb_decoded_ok to determine if ack needs to be sent bool (*generate_ack_callback)(void*); void *generate_ack_callback_arg; - uint8_t *payload_ptr; - srslte_softbuffer_rx_t *softbuffer; + uint8_t *payload_ptr[SRSLTE_MAX_TB]; + srslte_softbuffer_rx_t *softbuffers[SRSLTE_MAX_TB]; srslte_phy_grant_t phy_grant; } tb_action_dl_t; typedef struct { bool tx_enabled; bool expect_ack; - uint32_t rv; + uint32_t rv[SRSLTE_MAX_TB]; uint16_t rnti; uint32_t current_tx_nb; int32_t tti_offset; // relative offset between grant and UL tx/HARQ rx - srslte_softbuffer_tx_t *softbuffer; + srslte_softbuffer_tx_t *softbuffers; srslte_phy_grant_t phy_grant; - uint8_t *payload_ptr; + uint8_t *payload_ptr[SRSLTE_MAX_TB]; } tb_action_ul_t; /* Indicate reception of UL grant. @@ -329,7 +329,7 @@ public: virtual void new_grant_dl(mac_grant_t grant, tb_action_dl_t *action) = 0; /* Indicate successfull decoding of PDSCH TB. */ - virtual void tb_decoded(bool ack, srslte_rnti_type_t rnti_type, uint32_t harq_pid) = 0; + virtual void tb_decoded(bool ack, uint32_t tb_idx, srslte_rnti_type_t rnti_type, uint32_t harq_pid) = 0; /* Indicate successfull decoding of BCH TB through PBCH */ virtual void bch_decoded_ok(uint8_t *payload, uint32_t len) = 0; diff --git a/srsue/hdr/mac/dl_harq.h b/srsue/hdr/mac/dl_harq.h index 809ecd151..4f6df9b51 100644 --- a/srsue/hdr/mac/dl_harq.h +++ b/srsue/hdr/mac/dl_harq.h @@ -84,20 +84,20 @@ public: harq_pid = grant.pid%N; } if (grant.rnti_type == SRSLTE_RNTI_TEMP && last_temporal_crnti != grant.rnti) { - grant.ndi = true; + grant.ndi[0] = true; Info("Set NDI=1 for Temp-RNTI DL grant\n"); last_temporal_crnti = grant.rnti; } if (grant.rnti_type == SRSLTE_RNTI_USER && proc[harq_pid].is_sps()) { - grant.ndi = true; + grant.ndi[0] = true; Info("Set NDI=1 for C-RNTI DL grant\n"); } proc[harq_pid].new_grant_dl(grant, action); } else { /* This is for SPS scheduling */ uint32_t harq_pid = get_harq_sps_pid(grant.tti)%N; - if (grant.ndi) { - grant.ndi = false; + if (grant.ndi[0]) { + grant.ndi[0] = false; proc[harq_pid].new_grant_dl(grant, action); } else { if (grant.is_sps_release) { @@ -117,12 +117,12 @@ public: } - void tb_decoded(bool ack, srslte_rnti_type_t rnti_type, uint32_t harq_pid) + void tb_decoded(bool ack, uint32_t tb_idx, srslte_rnti_type_t rnti_type, uint32_t harq_pid) { if (rnti_type == SRSLTE_RNTI_SI) { - proc[N].tb_decoded(ack); + proc[N].tb_decoded(ack, 0); } else { - proc[harq_pid%N].tb_decoded(ack); + proc[harq_pid%N].tb_decoded(ack, tb_idx); } } @@ -137,200 +137,239 @@ public: void start_pcap(srslte::mac_pcap* pcap_) { pcap = pcap_; } - int get_current_tbs(uint32_t harq_pid) { return proc[harq_pid%N].get_current_tbs(); } + int get_current_tbs(uint32_t harq_pid, uint32_t tb_idx) { return proc[harq_pid%N].get_current_tbs(tb_idx); } void set_si_window_start(int si_window_start_) { si_window_start = si_window_start_; } float get_average_retx() { return average_retx; } -private: +private: class dl_harq_process { public: - dl_harq_process() - { - is_initiated = false; - ack = false; - bzero(&cur_grant, sizeof(Tgrant)); + dl_harq_process() : subproc(SRSLTE_MAX_TB) { + } - bool init(uint32_t pid_, dl_harq_entity *parent) - { - if (srslte_softbuffer_rx_init(&softbuffer, 110)) { - Error("Error initiating soft buffer\n"); - return false; - } else { - pid = pid_; - is_initiated = true; - harq_entity = parent; - log_h = harq_entity->log_h; - return true; + bool init(uint32_t pid_, dl_harq_entity *parent) { + bool ret = true; + + for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { + ret &= subproc[tb].init(pid_, parent, tb); } + return ret; } - void reset() - { - ack = false; - payload_buffer_ptr = NULL; - bzero(&cur_grant, sizeof(Tgrant)); - if (is_initiated) { - srslte_softbuffer_rx_reset(&softbuffer); + void reset(void) { + for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { + subproc[tb].reset(); } } - - void new_grant_dl(Tgrant grant, Taction *action) - { - // Compute RV for BCCH when not specified in PDCCH format - if (pid == HARQ_BCCH_PID && grant.rv == -1) { - uint32_t k; - if ((grant.tti/10)%2 == 0 && grant.tti%10 == 5) { // This is SIB1, k is different - k = (grant.tti/20)%4; - grant.rv = ((uint32_t) ceilf((float)1.5*k))%4; - } else if (grant.rv == -1) { - k = (grant.tti-harq_entity->si_window_start)%4; - grant.rv = ((uint32_t) ceilf((float)1.5*k))%4; - } - } - calc_is_new_transmission(grant); - if (is_new_transmission) { - ack = false; - srslte_softbuffer_rx_reset_tbs(&softbuffer, cur_grant.n_bytes*8); - n_retx = 0; + + void new_grant_dl(Tgrant grant, Taction *action) { + for (uint32_t tb = 0; tb < grant.phy_grant.dl.nof_tb; tb++) { + subproc[tb].new_grant_dl(grant, action); } - - // Save grant - grant.last_ndi = cur_grant.ndi; - grant.last_tti = cur_grant.tti; - memcpy(&cur_grant, &grant, sizeof(Tgrant)); - - // Fill action structure - bzero(action, sizeof(Taction)); - action->default_ack = ack; - action->generate_ack = true; - action->decode_enabled = false; - - // If data has not yet been successfully decoded - if (ack == false) { - - // Instruct the PHY To combine the received data and attempt to decode it - payload_buffer_ptr = harq_entity->demux_unit->request_buffer(pid, cur_grant.n_bytes); - action->payload_ptr = payload_buffer_ptr; - if (!action->payload_ptr) { - action->decode_enabled = false; - Error("Can't get a buffer for TBS=%d\n", cur_grant.n_bytes); - return; - } - action->decode_enabled = true; - action->rv = cur_grant.rv; - action->rnti = cur_grant.rnti; - action->softbuffer = &softbuffer; - memcpy(&action->phy_grant, &cur_grant.phy_grant, sizeof(Tphygrant)); - n_retx++; - - } else { - Warning("DL PID %d: Received duplicate TB. Discarting and retransmitting ACK\n", pid); + } + + int get_current_tbs(uint32_t tb_idx) { return subproc[tb_idx].get_current_tbs(); } + + bool is_sps() { return false; } + + void tb_decoded(bool ack_, uint32_t tb_idx) { + subproc[tb_idx].tb_decoded(ack_); + } + + private: + class dl_tb_process { + public: + dl_tb_process(void) { + is_initiated = false; + ack = false; + bzero(&cur_grant, sizeof(Tgrant)); } - - if (pid == HARQ_BCCH_PID || harq_entity->timers_db->get(TIME_ALIGNMENT)->is_expired()) { - // Do not generate ACK - Debug("Not generating ACK\n"); - action->generate_ack = false; - } else { - if (cur_grant.rnti_type == SRSLTE_RNTI_TEMP && ack == false) { - // Postpone ACK after contention resolution is resolved - action->generate_ack_callback = harq_entity->generate_ack_callback; - action->generate_ack_callback_arg = harq_entity->demux_unit; - Debug("ACK pending contention resolution\n"); + + bool init(uint32_t pid_, dl_harq_entity *parent, uint32_t tb_idx) { + tid = tb_idx; + if (srslte_softbuffer_rx_init(&softbuffer, 110)) { + Error("Error initiating soft buffer\n"); + return false; } else { - Debug("Generating ACK\n"); + pid = pid_; + is_initiated = true; + harq_entity = parent; + log_h = harq_entity->log_h; + return true; } } - } - - void tb_decoded(bool ack_) - { - ack = ack_; - if (ack == true) { - if (pid == HARQ_BCCH_PID) { - if (harq_entity->pcap) { - harq_entity->pcap->write_dl_sirnti(payload_buffer_ptr, cur_grant.n_bytes, ack, cur_grant.tti); + + void reset(void) { + ack = false; + payload_buffer_ptr = NULL; + bzero(&cur_grant, sizeof(Tgrant)); + if (is_initiated) { + srslte_softbuffer_rx_reset(&softbuffer); + } + } + + void new_grant_dl(Tgrant grant, Taction *action) { + // Compute RV for BCCH when not specified in PDCCH format + if (pid == HARQ_BCCH_PID && grant.rv[tid] == -1) { + uint32_t k; + if ((grant.tti / 10) % 2 == 0 && grant.tti % 10 == 5) { // This is SIB1, k is different + k = (grant.tti / 20) % 4; + grant.rv[tid] = ((uint32_t) ceilf((float) 1.5 * k)) % 4; + } else if (grant.rv[tid] == -1) { + k = (grant.tti - harq_entity->si_window_start) % 4; + grant.rv[tid] = ((uint32_t) ceilf((float) 1.5 * k)) % 4; } - Debug("Delivering PDU=%d bytes to Dissassemble and Demux unit (BCCH)\n", cur_grant.n_bytes); - harq_entity->demux_unit->push_pdu(pid, payload_buffer_ptr, cur_grant.n_bytes, cur_grant.tti); - } else { - if (harq_entity->pcap) { - harq_entity->pcap->write_dl_crnti(payload_buffer_ptr, cur_grant.n_bytes, cur_grant.rnti, ack, cur_grant.tti); + } + calc_is_new_transmission(grant); + if (is_new_transmission) { + ack = false; + srslte_softbuffer_rx_reset_tbs(&softbuffer, cur_grant.n_bytes[tid] * 8); + n_retx = 0; + } + + // Save grant + grant.last_ndi[tid] = cur_grant.ndi[tid]; + grant.last_tti = cur_grant.tti; + memcpy(&cur_grant, &grant, sizeof(Tgrant)); + + // Fill action structure + bzero(action, sizeof(Taction)); + action->default_ack = ack; + action->generate_ack = true; + action->decode_enabled = false; + + // If data has not yet been successfully decoded + if (!ack) { + + // Instruct the PHY To combine the received data and attempt to decode it + payload_buffer_ptr = harq_entity->demux_unit->request_buffer(pid * SRSLTE_MAX_TB + tid, + cur_grant.n_bytes[tid]); + action->payload_ptr[tid] = payload_buffer_ptr; + if (!action->payload_ptr) { + action->decode_enabled = false; + Error("Can't get a buffer for TBS=%d\n", cur_grant.n_bytes[tid]); + return; } - if (ack) { - if (cur_grant.rnti_type == SRSLTE_RNTI_TEMP) { - Debug("Delivering PDU=%d bytes to Dissassemble and Demux unit (Temporal C-RNTI)\n", cur_grant.n_bytes); - harq_entity->demux_unit->push_pdu_temp_crnti(payload_buffer_ptr, cur_grant.n_bytes); - } else { - Debug("Delivering PDU=%d bytes to Dissassemble and Demux unit\n", cur_grant.n_bytes); - harq_entity->demux_unit->push_pdu(pid, payload_buffer_ptr, cur_grant.n_bytes, cur_grant.tti); - - // Compute average number of retransmissions per packet - harq_entity->average_retx = SRSLTE_VEC_CMA((float) n_retx, harq_entity->average_retx, harq_entity->nof_pkts++); - } + action->decode_enabled = true; + action->rv[tid] = cur_grant.rv[tid]; + action->rnti = cur_grant.rnti; + action->softbuffers[tid] = &softbuffer; + memcpy(&action->phy_grant, &cur_grant.phy_grant, sizeof(Tphygrant)); + n_retx++; + + } else { + Warning("DL PID %d: Received duplicate TB. Discarting and retransmitting ACK\n", pid); + } + + if (pid == HARQ_BCCH_PID || harq_entity->timers_db->get(TIME_ALIGNMENT)->is_expired()) { + // Do not generate ACK + Debug("Not generating ACK\n"); + action->generate_ack = false; + } else { + if (cur_grant.rnti_type == SRSLTE_RNTI_TEMP && !ack) { + // Postpone ACK after contention resolution is resolved + action->generate_ack_callback = harq_entity->generate_ack_callback; + action->generate_ack_callback_arg = harq_entity->demux_unit; + Debug("ACK pending contention resolution\n"); + } else { + Debug("Generating ACK\n"); } } - } else { - harq_entity->demux_unit->deallocate(payload_buffer_ptr); - } - - Info("DL %d: %s tbs=%d, rv=%d, ack=%s, ndi=%d (%d), tti=%d (%d)\n", - pid, is_new_transmission?"newTX":"reTX ", - cur_grant.n_bytes, cur_grant.rv, ack?"OK":"KO", - cur_grant.ndi, cur_grant.last_ndi, cur_grant.tti, cur_grant.last_tti); - - if (ack && pid == HARQ_BCCH_PID) { - reset(); } - } - bool is_sps() { return false; } - int get_current_tbs() { return cur_grant.n_bytes*8; } - - private: - bool calc_is_new_transmission(Tgrant grant) - { - bool is_new_tb = true; - if ((srslte_tti_interval(grant.tti, cur_grant.tti) <= 8 && (grant.n_bytes == cur_grant.n_bytes)) || - pid == HARQ_BCCH_PID) - { - is_new_tb = false; + void tb_decoded(bool ack_) { + ack = ack_; + if (ack) { + if (pid == HARQ_BCCH_PID) { + if (harq_entity->pcap) { + harq_entity->pcap->write_dl_sirnti(payload_buffer_ptr, cur_grant.n_bytes[tid], ack, cur_grant.tti); + } + Debug("Delivering PDU=%d bytes to Dissassemble and Demux unit (BCCH)\n", cur_grant.n_bytes[tid]); + harq_entity->demux_unit->push_pdu(pid * SRSLTE_MAX_TB + tid, payload_buffer_ptr, cur_grant.n_bytes[tid], + cur_grant.tti); + } else { + if (harq_entity->pcap) { + harq_entity->pcap->write_dl_crnti(payload_buffer_ptr, cur_grant.n_bytes[tid], cur_grant.rnti, ack, + cur_grant.tti); + } + if (ack) { + if (cur_grant.rnti_type == SRSLTE_RNTI_TEMP) { + Debug("Delivering PDU=%d bytes to Dissassemble and Demux unit (Temporal C-RNTI)\n", + cur_grant.n_bytes[tid]); + harq_entity->demux_unit->push_pdu_temp_crnti(payload_buffer_ptr, cur_grant.n_bytes[tid]); + } else { + Debug("Delivering PDU=%d bytes to Dissassemble and Demux unit\n", cur_grant.n_bytes[tid]); + harq_entity->demux_unit->push_pdu(pid * SRSLTE_MAX_TB + tid, payload_buffer_ptr, cur_grant.n_bytes[tid], + cur_grant.tti); + + // Compute average number of retransmissions per packet + harq_entity->average_retx = SRSLTE_VEC_CMA((float) n_retx, harq_entity->average_retx, + harq_entity->nof_pkts++); + } + } + } + } else { + harq_entity->demux_unit->deallocate(payload_buffer_ptr); + } + + Info("DL %d (TB %d): %s tbs=%d, rv=%d, ack=%s, ndi=%d (%d), tti=%d (%d)\n", + pid, tid, is_new_transmission ? "newTX" : "reTX ", + cur_grant.n_bytes[tid], cur_grant.rv[tid], ack ? "OK" : "KO", + cur_grant.ndi[tid], cur_grant.last_ndi, cur_grant.tti, cur_grant.last_tti); + + if (ack && pid == HARQ_BCCH_PID) { + reset(); + } } - - if ((grant.ndi != cur_grant.ndi && !is_new_tb) || // NDI toggled for same TB - is_new_tb || // is new TB - (pid == HARQ_BCCH_PID && grant.rv == 0)) // Broadcast PID and 1st TX (RV=0) - { - is_new_transmission = true; - Debug("Set HARQ for new transmission\n"); - } else { - is_new_transmission = false; - Debug("Set HARQ for retransmission\n"); + + int get_current_tbs(void) { return cur_grant.n_bytes[tid] * 8; } + + private: + bool calc_is_new_transmission(Tgrant grant) { + bool is_new_tb = true; + if ((srslte_tti_interval(grant.tti, cur_grant.tti) <= 8 && (grant.n_bytes[tid] == cur_grant.n_bytes[tid])) || + pid == HARQ_BCCH_PID) { + is_new_tb = false; + } + + if ((grant.ndi[tid] != cur_grant.ndi[tid] && !is_new_tb) || // NDI toggled for same TB + is_new_tb || // is new TB + (pid == HARQ_BCCH_PID && grant.rv[tid] == 0)) // Broadcast PID and 1st TX (RV=0) + { + is_new_transmission = true; + Debug("Set HARQ for new transmission\n"); + } else { + is_new_transmission = false; + Debug("Set HARQ for retransmission\n"); + } + + return is_new_transmission; } - return is_new_transmission; - } + bool is_initiated; + dl_harq_entity *harq_entity; + srslte::log *log_h; - bool is_initiated; - dl_harq_entity *harq_entity; - srslte::log *log_h; - - bool is_new_transmission; - - uint32_t pid; - uint8_t *payload_buffer_ptr; - bool ack; - - uint32_t n_retx; - - Tgrant cur_grant; - srslte_softbuffer_rx_t softbuffer; + bool is_new_transmission; + + uint32_t pid; /* HARQ Proccess ID */ + uint32_t tid; /* Transport block ID */ + uint8_t *payload_buffer_ptr; + bool ack; + + uint32_t n_retx; + + Tgrant cur_grant; + srslte_softbuffer_rx_t softbuffer; + }; + + /* Transport blocks */ + std::vector subproc; }; - // Private members of dl_harq_entity static bool generate_ack_callback(void *arg) diff --git a/srsue/hdr/mac/mac.h b/srsue/hdr/mac/mac.h index 660f7fbba..f2785e288 100644 --- a/srsue/hdr/mac/mac.h +++ b/srsue/hdr/mac/mac.h @@ -65,7 +65,7 @@ public: void new_grant_ul_ack(mac_grant_t grant, bool ack, tb_action_ul_t *action); void harq_recv(uint32_t tti, bool ack, tb_action_ul_t *action); void new_grant_dl(mac_grant_t grant, tb_action_dl_t *action); - void tb_decoded(bool ack, srslte_rnti_type_t rnti_type, uint32_t harq_pid); + void tb_decoded(bool ack, uint32_t tb_idx, srslte_rnti_type_t rnti_type, uint32_t harq_pid); void bch_decoded_ok(uint8_t *payload, uint32_t len); void pch_decoded_ok(uint32_t len); void tti_clock(uint32_t tti); diff --git a/srsue/hdr/mac/ul_harq.h b/srsue/hdr/mac/ul_harq.h index 2ef1ed2b6..13ec0b9b3 100644 --- a/srsue/hdr/mac/ul_harq.h +++ b/srsue/hdr/mac/ul_harq.h @@ -113,12 +113,12 @@ public: grant.rnti_type == SRSLTE_RNTI_RAR) { if (grant.rnti_type == SRSLTE_RNTI_USER && proc[pidof(grant.tti)].is_sps()) { - grant.ndi = true; + grant.ndi[0] = true; } run_tti(grant.tti, &grant, action); } else if (grant.rnti_type == SRSLTE_RNTI_SPS) { - if (grant.ndi) { - grant.ndi = proc[pidof(grant.tti)].get_ndi(); + if (grant.ndi[0]) { + grant.ndi[0] = proc[pidof(grant.tti)].get_ndi(); run_tti(grant.tti, &grant, action); } else { Info("Not implemented\n"); @@ -208,7 +208,7 @@ private: // Receive and route HARQ feedbacks if (grant) { - if ((!(grant->rnti_type == SRSLTE_RNTI_TEMP) && grant->ndi != get_ndi()) || + if ((!(grant->rnti_type == SRSLTE_RNTI_TEMP) && grant->ndi[0] != get_ndi()) || (grant->rnti_type == SRSLTE_RNTI_USER && !has_grant()) || grant->is_from_rar) { @@ -216,8 +216,8 @@ private: // Uplink grant in a RAR if (grant->is_from_rar) { - Debug("Getting Msg3 buffer payload, grant size=%d bytes\n", grant->n_bytes); - pdu_ptr = harq_entity->mux_unit->msg3_get(payload_buffer, grant->n_bytes); + Debug("Getting Msg3 buffer payload, grant size=%d bytes\n", grant->n_bytes[0]); + pdu_ptr = harq_entity->mux_unit->msg3_get(payload_buffer, grant->n_bytes[0]); if (pdu_ptr) { generate_new_tx(tti_tx, true, grant, action); } else { @@ -227,7 +227,7 @@ private: // Normal UL grant } else { // Request a MAC PDU from the Multiplexing & Assemble Unit - pdu_ptr = harq_entity->mux_unit->pdu_get(payload_buffer, grant->n_bytes, tti_tx, pid); + pdu_ptr = harq_entity->mux_unit->pdu_get(payload_buffer, grant->n_bytes[0], tti_tx, pid); if (pdu_ptr) { generate_new_tx(tti_tx, false, grant, action); } else { @@ -258,7 +258,7 @@ private: if (grant->is_from_rar) { grant->rnti = harq_entity->rntis->temp_rnti; } - harq_entity->pcap->write_ul_crnti(pdu_ptr, grant->n_bytes, grant->rnti, get_nof_retx(), tti_tx); + harq_entity->pcap->write_ul_crnti(pdu_ptr, grant->n_bytes[0], grant->rnti, get_nof_retx(), tti_tx); } } @@ -285,7 +285,7 @@ private: bool is_sps() { return false; } uint32_t last_tx_tti() { return tti_last_tx; } uint32_t get_nof_retx() { return current_tx_nb; } - int get_current_tbs() { return cur_grant.n_bytes*8; } + int get_current_tbs() { return cur_grant.n_bytes[0]*8; } private: Tgrant cur_grant; @@ -321,7 +321,7 @@ private: if (grant) { // HARQ entity requests an adaptive transmission if (grant->rv) { - current_irv = irv_of_rv[grant->rv%4]; + current_irv = irv_of_rv[grant->rv[0]%4]; } memcpy(&cur_grant, grant, sizeof(Tgrant)); harq_feedback = false; @@ -370,10 +370,10 @@ private: current_tx_nb++; action->expect_ack = true; action->rnti = is_msg3?harq_entity->rntis->temp_rnti:cur_grant.rnti; - action->rv = cur_grant.rv>0?cur_grant.rv:get_rv(); - action->softbuffer = &softbuffer; + action->rv[0] = cur_grant.rv[0]>0?cur_grant.rv[0]:get_rv(); + action->softbuffers = &softbuffer; action->tx_enabled = true; - action->payload_ptr = pdu_ptr; + action->payload_ptr[0] = pdu_ptr; memcpy(&action->phy_grant, &cur_grant.phy_grant, sizeof(Tphygrant)); current_irv = (current_irv+1)%4; diff --git a/srsue/hdr/phy/phch_worker.h b/srsue/hdr/phy/phch_worker.h index ed1d7af26..a47008629 100644 --- a/srsue/hdr/phy/phch_worker.h +++ b/srsue/hdr/phy/phch_worker.h @@ -78,18 +78,20 @@ private: bool decode_pdcch_dl(mac_interface_phy::mac_grant_t *grant); bool decode_phich(bool *ack); - bool decode_pdsch(srslte_ra_dl_grant_t *grant, + int decode_pdsch(srslte_ra_dl_grant_t *grant, uint8_t *payload, srslte_softbuffer_rx_t *softbuffer, int rv, uint16_t rnti, - uint32_t pid); + uint32_t pid, + bool acks[SRSLTE_MAX_CODEWORDS]); - bool decode_pdsch_multi(srslte_ra_dl_grant_t *grant, + int decode_pdsch_multi(srslte_ra_dl_grant_t *grant, uint8_t *payload[SRSLTE_MAX_CODEWORDS], - srslte_softbuffer_rx_t softbuffers[SRSLTE_MAX_CODEWORDS], + srslte_softbuffer_rx_t *softbuffers[SRSLTE_MAX_CODEWORDS], int rv[SRSLTE_MAX_CODEWORDS], uint16_t rnti, - uint32_t pid); + uint32_t pid, + bool acks[SRSLTE_MAX_CODEWORDS]); /* ... for UL */ void encode_pusch(srslte_ra_ul_grant_t *grant, uint8_t *payload, uint32_t current_tx_nb, srslte_softbuffer_tx_t *softbuffer, @@ -100,7 +102,7 @@ private: void set_uci_sr(); void set_uci_periodic_cqi(); void set_uci_aperiodic_cqi(); - void set_uci_ack(bool ack); + void set_uci_ack(bool ack[SRSLTE_MAX_CODEWORDS], uint32_t nof_tb); bool srs_is_ready_to_send(); float set_power(float tx_power); void setup_tx_gain(); diff --git a/srsue/src/mac/mac.cc b/srsue/src/mac/mac.cc index e1426780e..1bc335bb1 100644 --- a/srsue/src/mac/mac.cc +++ b/srsue/src/mac/mac.cc @@ -44,7 +44,7 @@ namespace srsue { mac::mac() : ttisync(10240), timers_db((uint32_t) NOF_MAC_TIMERS), mux_unit(MAC_NOF_HARQ_PROC), - demux_unit(MAC_NOF_HARQ_PROC), + demux_unit(SRSLTE_MAX_TB*MAC_NOF_HARQ_PROC), pdu_process_thread(&demux_unit) { started = false; @@ -255,17 +255,17 @@ void mac::pch_decoded_ok(uint32_t len) } } -void mac::tb_decoded(bool ack, srslte_rnti_type_t rnti_type, uint32_t harq_pid) +void mac::tb_decoded(bool ack, uint32_t tb_idx, srslte_rnti_type_t rnti_type, uint32_t harq_pid) { if (rnti_type == SRSLTE_RNTI_RAR) { if (ack) { ra_procedure.tb_decoded_ok(); } } else { - dl_harq.tb_decoded(ack, rnti_type, harq_pid); + dl_harq.tb_decoded(ack, tb_idx, rnti_type, harq_pid); if (ack) { pdu_process_thread.notify(); - metrics.rx_brate += dl_harq.get_current_tbs(harq_pid); + metrics.rx_brate += dl_harq.get_current_tbs(harq_pid, tb_idx); } else { metrics.rx_errors++; } @@ -282,12 +282,9 @@ void mac::new_grant_dl(mac_interface_phy::mac_grant_t grant, mac_interface_phy:: memcpy(&action->phy_grant, &grant.phy_grant, sizeof(srslte_phy_grant_t)); action->generate_ack = false; action->decode_enabled = true; - srslte_softbuffer_rx_reset_cb(&pch_softbuffer, 1); - action->payload_ptr = pch_payload_buffer; - action->softbuffer = &pch_softbuffer; action->rnti = grant.rnti; - action->rv = grant.rv; - if (grant.n_bytes > pch_payload_buffer_sz) { + action->rv[0] = grant.rv[0]; + if (grant.n_bytes[0] > pch_payload_buffer_sz) { Error("Received grant for PCH (%d bytes) exceeds buffer (%d bytes)\n", grant.n_bytes, pch_payload_buffer_sz); action->decode_enabled = false; } diff --git a/srsue/src/mac/proc_ra.cc b/srsue/src/mac/proc_ra.cc index 73b51d61c..213042018 100644 --- a/srsue/src/mac/proc_ra.cc +++ b/srsue/src/mac/proc_ra.cc @@ -269,19 +269,19 @@ void ra_proc::step_pdcch_setup() { void ra_proc::new_grant_dl(mac_interface_phy::mac_grant_t grant, mac_interface_phy::tb_action_dl_t* action) { - if (grant.n_bytes < MAX_RAR_PDU_LEN) { + if (grant.n_bytes[0] < MAX_RAR_PDU_LEN) { rDebug("DL grant found RA-RNTI=%d\n", ra_rnti); action->decode_enabled = true; action->default_ack = false; action->generate_ack = false; - action->payload_ptr = rar_pdu_buffer; + action->payload_ptr[0] = rar_pdu_buffer; action->rnti = grant.rnti; memcpy(&action->phy_grant, &grant.phy_grant, sizeof(srslte_phy_grant_t)); - action->rv = grant.rv; - action->softbuffer = &softbuffer_rar; - rar_grant_nbytes = grant.n_bytes; + action->rv[0] = grant.rv[0]; + action->softbuffers[0] = &softbuffer_rar; + rar_grant_nbytes = grant.n_bytes[0]; rar_grant_tti = grant.tti; - if (action->rv == 0) { + if (action->rv[0] == 0) { srslte_softbuffer_rx_reset(&softbuffer_rar); } } else { diff --git a/srsue/src/phy/phch_worker.cc b/srsue/src/phy/phch_worker.cc index 6dabbbf01..78c5b2f71 100644 --- a/srsue/src/phy/phch_worker.cc +++ b/srsue/src/phy/phch_worker.cc @@ -178,8 +178,8 @@ void phch_worker::work_imp() reset_uci(); bool dl_grant_available = false; - bool ul_grant_available = false; - bool dl_ack = false; + bool ul_grant_available = false; + bool dl_ack[SRSLTE_MAX_CODEWORDS] = {false}; mac_interface_phy::mac_grant_t dl_mac_grant; mac_interface_phy::tb_action_dl_t dl_action; @@ -200,22 +200,28 @@ void phch_worker::work_imp() if(dl_grant_available) { /* Send grant to MAC and get action for this TB */ phy->mac->new_grant_dl(dl_mac_grant, &dl_action); - + + /* Set DL ACKs to default */ + for (uint32_t tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb++) { + dl_ack[tb] = dl_action.default_ack; + } + /* Decode PDSCH if instructed to do so */ - dl_ack = dl_action.default_ack; if (dl_action.decode_enabled) { - dl_ack = decode_pdsch(&dl_action.phy_grant.dl, dl_action.payload_ptr, - dl_action.softbuffer, dl_action.rv, dl_action.rnti, - dl_mac_grant.pid); + decode_pdsch_multi(&dl_action.phy_grant.dl, dl_action.payload_ptr, + dl_action.softbuffers, dl_action.rv, dl_action.rnti, + dl_mac_grant.pid, dl_ack); } if (dl_action.generate_ack_callback && dl_action.decode_enabled) { - phy->mac->tb_decoded(dl_ack, dl_mac_grant.rnti_type, dl_mac_grant.pid); - dl_ack = dl_action.generate_ack_callback(dl_action.generate_ack_callback_arg); - Debug("Calling generate ACK callback returned=%d\n", dl_ack); + for (uint32_t tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb++) { + phy->mac->tb_decoded(dl_ack[tb], tb, dl_mac_grant.rnti_type, dl_mac_grant.pid); + dl_ack[tb] = dl_action.generate_ack_callback(dl_action.generate_ack_callback_arg); + Debug("Calling generate ACK callback for TB %d returned=%d\n", tb, dl_ack); + } } - Debug("dl_ack=%d, generate_ack=%d\n", dl_ack, dl_action.generate_ack); + Debug("dl_ack={%d, %d}, generate_ack=%d\n", dl_ack[0], dl_ack[1], dl_action.generate_ack); if (dl_action.generate_ack) { - set_uci_ack(dl_ack); + set_uci_ack(dl_ack, dl_mac_grant.phy_grant.dl.nof_tb); } } } @@ -258,8 +264,8 @@ void phch_worker::work_imp() /* Transmit PUSCH, PUCCH or SRS */ bool signal_ready = false; if (ul_action.tx_enabled) { - encode_pusch(&ul_action.phy_grant.ul, ul_action.payload_ptr, ul_action.current_tx_nb, - ul_action.softbuffer, ul_action.rv, ul_action.rnti, ul_mac_grant.is_from_rar); + encode_pusch(&ul_action.phy_grant.ul, ul_action.payload_ptr[0], ul_action.current_tx_nb, + &ul_action.softbuffers[0], ul_action.rv[0], ul_action.rnti, ul_mac_grant.is_from_rar); signal_ready = true; if (ul_action.expect_ack) { phy->set_pending_ack(tti + 8, ue_ul.pusch_cfg.grant.n_prb_tilde[0], ul_action.phy_grant.ul.ncs_dmrs); @@ -279,9 +285,11 @@ void phch_worker::work_imp() if (dl_action.decode_enabled && !dl_action.generate_ack_callback) { if (dl_mac_grant.rnti_type == SRSLTE_RNTI_PCH) { - phy->mac->pch_decoded_ok(dl_mac_grant.n_bytes); + phy->mac->pch_decoded_ok(dl_mac_grant.n_bytes[0]); } else { - phy->mac->tb_decoded(dl_ack, dl_mac_grant.rnti_type, dl_mac_grant.pid); + for (uint32_t tb = 0; tb < dl_mac_grant.phy_grant.dl.nof_tb; tb++) { + phy->mac->tb_decoded(dl_ack[tb], tb, dl_mac_grant.rnti_type, dl_mac_grant.pid); + } } } @@ -380,13 +388,16 @@ bool phch_worker::decode_pdcch_dl(srsue::mac_interface_phy::mac_grant_t* grant) } /* Fill MAC grant structure */ - grant->ndi = dci_unpacked.ndi; + grant->ndi[0] = dci_unpacked.ndi; + grant->ndi[1] = dci_unpacked.ndi_1; grant->pid = dci_unpacked.harq_process; - grant->n_bytes = grant->phy_grant.dl.mcs[0].tbs/8; - grant->tti = tti; - grant->rv = dci_unpacked.rv_idx; - grant->rnti = dl_rnti; - grant->rnti_type = type; + grant->n_bytes[0] = grant->phy_grant.dl.mcs[0].tbs / (uint32_t) 8; + grant->n_bytes[1] = grant->phy_grant.dl.mcs[1].tbs / (uint32_t) 8; + grant->tti = tti; + grant->rv[0] = dci_unpacked.rv_idx; + grant->rv[1] = dci_unpacked.rv_idx_1; + grant->rnti = dl_rnti; + grant->rnti_type = type; grant->last_tti = 0; last_dl_pdcch_ncce = srslte_ue_dl_get_ncce(&ue_dl); @@ -405,23 +416,27 @@ bool phch_worker::decode_pdcch_dl(srsue::mac_interface_phy::mac_grant_t* grant) } } -bool phch_worker::decode_pdsch(srslte_ra_dl_grant_t *grant, uint8_t *payload, +int phch_worker::decode_pdsch(srslte_ra_dl_grant_t *grant, uint8_t *payload, srslte_softbuffer_rx_t *softbuffer, int rv, - uint16_t rnti, uint32_t harq_pid) { - int _rv [SRSLTE_MAX_CODEWORDS] = {1}; + uint16_t rnti, uint32_t harq_pid, bool acks[SRSLTE_MAX_CODEWORDS]) { + int _rv [SRSLTE_MAX_TB] = {1}; + srslte_softbuffer_rx_t *softbuffers[SRSLTE_MAX_TB] = {NULL}; + _rv[0] = rv; + softbuffers[0] = softbuffer; - return decode_pdsch_multi(grant, &payload, softbuffer, _rv, rnti, harq_pid); + return decode_pdsch_multi(grant, &payload, softbuffers, _rv, rnti, harq_pid, acks); } -bool phch_worker::decode_pdsch_multi(srslte_ra_dl_grant_t *grant, uint8_t *payload[SRSLTE_MAX_CODEWORDS], - srslte_softbuffer_rx_t softbuffers[SRSLTE_MAX_CODEWORDS], +int phch_worker::decode_pdsch_multi(srslte_ra_dl_grant_t *grant, uint8_t *payload[SRSLTE_MAX_CODEWORDS], + srslte_softbuffer_rx_t *softbuffers[SRSLTE_MAX_CODEWORDS], int rv[SRSLTE_MAX_CODEWORDS], - uint16_t rnti, uint32_t harq_pid) { + uint16_t rnti, uint32_t harq_pid, bool acks[SRSLTE_MAX_CODEWORDS]) { char timestr[64]; bool valid_config = true; timestr[0]='\0'; srslte_mimo_type_t mimo_type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA; + int ret = SRSLTE_SUCCESS; for (uint32_t tb = 0; tb < grant->nof_tb; tb++) { if (rv[tb] < 0 || rv[tb] > 3) { @@ -497,38 +512,39 @@ bool phch_worker::decode_pdsch_multi(srslte_ra_dl_grant_t *grant, uint8_t *paylo struct timeval t[3]; gettimeofday(&t[1], NULL); #endif - - bool ack = srslte_pdsch_decode_multi(&ue_dl.pdsch, &ue_dl.pdsch_cfg, softbuffers, ue_dl.sf_symbols_m, - ue_dl.ce_m, noise_estimate, rnti, payload) == 0; + ret = srslte_pdsch_decode_multi(&ue_dl.pdsch, &ue_dl.pdsch_cfg, softbuffers, ue_dl.sf_symbols_m, + ue_dl.ce_m, noise_estimate, rnti, payload, acks); + if (ret) { + Error("Decoding PDSCH"); + } #ifdef LOG_EXECTIME gettimeofday(&t[2], NULL); get_time_interval(t); snprintf(timestr, 64, ", dec_time=%4d us", (int) t[0].tv_usec); #endif - - Info("PDSCH: l_crb=%2d, harq=%d, tbs=%d, mcs=%d, rv=%d, crc=%s, snr=%.1f dB, n_iter=%d%s\n", - grant->nof_prb, harq_pid, - grant->mcs[0].tbs/8, grant->mcs[0].idx, rv, - ack?"OK":"KO", - 10*log10(srslte_chest_dl_get_snr(&ue_dl.chest)), - srslte_pdsch_last_noi(&ue_dl.pdsch), - timestr); + + Info("PDSCH: l_crb=%2d, harq=%d, nof_tb=%d, tbs={%d, %d}, mcs={%d, %d}, rv={%d, %d}, crc={%s, %s}, snr=%.1f dB, n_iter=%d%s\n", + grant->nof_prb, harq_pid, + grant->nof_tb, grant->mcs[0].tbs / 8, grant->mcs[1].tbs / 8, grant->mcs[0].idx, grant->mcs[1].idx, + rv[0], rv[1], acks[0] ? "OK" : "KO", acks[1] ? "OK" : "KO", + 10 * log10(srslte_chest_dl_get_snr(&ue_dl.chest)), + srslte_pdsch_last_noi(&ue_dl.pdsch), + timestr); //printf("tti=%d, cfo=%f\n", tti, cfo*15000); //srslte_vec_save_file("pdsch", signal_buffer, sizeof(cf_t)*SRSLTE_SF_LEN_PRB(cell.nof_prb)); // Store metrics dl_metrics.mcs = grant->mcs[0].idx; - - return ack; } else { Warning("Received grant for TBS=0\n"); } } else { - Error("Error configuring DL grant\n"); + Error("Error configuring DL grant\n"); + ret = SRSLTE_ERROR; } } - return true; + return ret; } bool phch_worker::decode_phich(bool *ack) @@ -625,12 +641,12 @@ bool phch_worker::decode_pdcch_ul(mac_interface_phy::mac_grant_t* grant) } if (ret) { - grant->ndi = dci_unpacked.ndi; + grant->ndi[0] = dci_unpacked.ndi; grant->pid = 0; // This is computed by MAC from TTI - grant->n_bytes = grant->phy_grant.ul.mcs.tbs/8; + grant->n_bytes[0] = grant->phy_grant.ul.mcs.tbs / (uint32_t) 8; grant->tti = tti; grant->rnti = ul_rnti; - grant->rv = dci_unpacked.rv_idx; + grant->rv[0] = dci_unpacked.rv_idx; if (SRSLTE_VERBOSE_ISINFO()) { srslte_ra_pusch_fprint(stdout, &dci_unpacked, cell.nof_prb); } @@ -646,11 +662,22 @@ void phch_worker::reset_uci() bzero(&uci_data, sizeof(srslte_uci_data_t)); } -void phch_worker::set_uci_ack(bool ack) -{ - uci_data.uci_ack = ack?1:0; - uci_data.uci_ack_len = 1; -} + void phch_worker::set_uci_ack(bool ack[SRSLTE_MAX_CODEWORDS], uint32_t nof_tb) { + if (nof_tb > 0) { + uci_data.uci_ack = (uint8_t) ((ack[0]) ? 1 : 0); + } + + if (nof_tb > 1) { + uci_data.uci_ack_2 = (uint8_t) ((ack[1]) ? 1 : 0); + } + + if (nof_tb > 2) { + Error("Number of transport blocks is not supported"); + } + + uci_data.uci_ack_len = nof_tb; + + } void phch_worker::set_uci_sr() { diff --git a/srsue/test/phy/ue_itf_test_prach.cc b/srsue/test/phy/ue_itf_test_prach.cc index 30d3e9f3d..c2d78470d 100644 --- a/srsue/test/phy/ue_itf_test_prach.cc +++ b/srsue/test/phy/ue_itf_test_prach.cc @@ -158,8 +158,8 @@ int rar_unpack(uint8_t *buffer, rar_msg_t *msg) srsue::phy my_phy; bool bch_decoded = false; -uint8_t payload[10240]; -uint8_t payload_bits[10240]; +uint8_t payload[SRSLTE_MAX_TB][10240]; +uint8_t payload_bits[SRSLTE_MAX_TB][10240]; const uint8_t conn_request_msg[] = {0x20, 0x06, 0x1F, 0x5C, 0x2C, 0x04, 0xB2, 0xAC, 0xF6, 0x00, 0x00, 0x00}; enum mac_state {RA, RAR, CONNREQUEST, CONNSETUP} state = RA; @@ -168,7 +168,7 @@ uint32_t preamble_idx = 0; rar_msg_t rar_msg; uint32_t nof_rtx_connsetup = 0; -uint32_t rv_value[4] = {0, 2, 3, 1}; +uint32_t rv_value[4] = {0, 2, 3, 1}; void config_phy() { srsue::phy_interface_rrc::phy_cfg_t config; @@ -194,8 +194,8 @@ void config_phy() { my_phy.configure_prach_params(); } -srslte_softbuffer_rx_t softbuffer_rx; -srslte_softbuffer_tx_t softbuffer_tx; +srslte_softbuffer_rx_t softbuffers_rx[SRSLTE_MAX_TB]; +srslte_softbuffer_tx_t softbuffers_tx[SRSLTE_MAX_TB]; uint16_t temp_c_rnti; @@ -218,7 +218,7 @@ public: bool rar_rnti_set; - void pch_decoded_ok(uint32_t len) {} + void pch_decoded_ok(uint32_t len) {} void tti_clock(uint32_t tti) { @@ -233,19 +233,21 @@ public: void new_grant_ul(mac_grant_t grant, tb_action_ul_t *action) { printf("New grant UL\n"); - memcpy(payload, conn_request_msg, grant.n_bytes*sizeof(uint8_t)); + for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb ++) { + memcpy(payload[tb], conn_request_msg, grant.n_bytes[tb]*sizeof(uint8_t)); + action->rv[tb] = rv_value[nof_rtx_connsetup%4]; + action->payload_ptr[tb] = payload[tb]; + if (action->rv[tb] == 0) { + srslte_softbuffer_tx_reset(&softbuffers_tx[tb]); + } + } action->current_tx_nb = nof_rtx_connsetup; - action->rv = rv_value[nof_rtx_connsetup%4]; - action->softbuffer = &softbuffer_tx; + action->softbuffers = softbuffers_tx; action->rnti = temp_c_rnti; action->expect_ack = (nof_rtx_connsetup < 5)?true:false; - action->payload_ptr = payload; memcpy(&action->phy_grant, &grant.phy_grant, sizeof(srslte_phy_grant_t)); memcpy(&last_grant, &grant, sizeof(mac_grant_t)); action->tx_enabled = true; - if (action->rv == 0) { - srslte_softbuffer_tx_reset(&softbuffer_tx); - } my_phy.pdcch_dl_search(SRSLTE_RNTI_USER, temp_c_rnti); } @@ -258,17 +260,20 @@ public: if (!ack) { nof_rtx_connsetup++; action->current_tx_nb = nof_rtx_connsetup; - action->rv = rv_value[nof_rtx_connsetup%4]; - action->softbuffer = &softbuffer_tx; + action->softbuffers = softbuffers_tx; action->rnti = temp_c_rnti; action->expect_ack = true; memcpy(&action->phy_grant, &last_grant.phy_grant, sizeof(srslte_phy_grant_t)); - action->tx_enabled = true; - if (action->rv == 0) { - srslte_softbuffer_tx_reset(&softbuffer_tx); + action->tx_enabled = true; + for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb ++) { + action->rv[tb] = rv_value[nof_rtx_connsetup%4]; + if (action->rv[tb] == 0) { + srslte_softbuffer_tx_reset(&softbuffers_tx[tb]); + } + printf("Retransmission %d (TB %d), rv=%d\n", nof_rtx_connsetup, tb, action->rv[tb]); + } - printf("Retransmission %d, rv=%d\n", nof_rtx_connsetup, action->rv); - } + } } void new_grant_dl(mac_grant_t grant, tb_action_dl_t *action) { @@ -279,24 +284,25 @@ public: } else { action->generate_ack = true; } - action->payload_ptr = payload; - action->rnti = grant.rnti; + action->rnti = grant.rnti; memcpy(&action->phy_grant, &grant.phy_grant, sizeof(srslte_phy_grant_t)); memcpy(&last_grant, &grant, sizeof(mac_grant_t)); - action->rv = grant.rv; - action->softbuffer = &softbuffer_rx; - - if (action->rv == 0) { - srslte_softbuffer_rx_reset(&softbuffer_rx); + for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb ++) { + action->softbuffers[tb] = &softbuffers_rx[tb]; + action->rv[tb] = grant.rv[tb]; + action->payload_ptr[tb] = payload[tb]; + if (action->rv[tb] == 0) { + srslte_softbuffer_rx_reset(&softbuffers_rx[tb]); + } } } - void tb_decoded(bool ack, srslte_rnti_type_t rnti_type, uint32_t harq_pid) { + void tb_decoded(bool ack, uint32_t tb_idx, srslte_rnti_type_t rnti_type, uint32_t harq_pid) { if (ack) { if (rnti_type == SRSLTE_RNTI_RAR) { my_phy.pdcch_dl_search_reset(); - srslte_bit_unpack_vector(payload, payload_bits, last_grant.n_bytes*8); - rar_unpack(payload_bits, &rar_msg); + srslte_bit_unpack_vector(payload[tb_idx], payload_bits[tb_idx], last_grant.n_bytes[tb_idx]*8); + rar_unpack(payload_bits[tb_idx], &rar_msg); if (rar_msg.RAPID == preamble_idx) { printf("Received RAR at TTI: %d\n", last_grant.tti); @@ -304,7 +310,7 @@ public: temp_c_rnti = rar_msg.temp_c_rnti; - if (last_grant.n_bytes*8 > 20 + SRSLTE_RAR_GRANT_LEN) { + if (last_grant.n_bytes[0]*8 > 20 + SRSLTE_RAR_GRANT_LEN) { uint8_t rar_grant[SRSLTE_RAR_GRANT_LEN]; memcpy(rar_grant, &payload_bits[20], sizeof(uint8_t)*SRSLTE_RAR_GRANT_LEN); my_phy.set_rar_grant(last_grant.tti, rar_grant); @@ -323,9 +329,11 @@ public: printf("BCH decoded\n"); bch_decoded = true; srslte_cell_t cell; - my_phy.get_current_cell(&cell); - srslte_softbuffer_rx_init(&softbuffer_rx, cell.nof_prb); - srslte_softbuffer_tx_init(&softbuffer_tx, cell.nof_prb); + my_phy.get_current_cell(&cell); + for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { + srslte_softbuffer_rx_init(&softbuffers_rx[tb], cell.nof_prb); + srslte_softbuffer_tx_init(&softbuffers_tx[tb], cell.nof_prb); + } } private: diff --git a/srsue/test/phy/ue_itf_test_sib1.cc b/srsue/test/phy/ue_itf_test_sib1.cc index 803c5ff11..be3cb18e8 100644 --- a/srsue/test/phy/ue_itf_test_sib1.cc +++ b/srsue/test/phy/ue_itf_test_sib1.cc @@ -87,8 +87,8 @@ bool bch_decoded = false; uint32_t total_pkts=0; uint32_t total_dci=0; uint32_t total_oks=0; -uint8_t payload[1024]; -srslte_softbuffer_rx_t softbuffer; +uint8_t payload[SRSLTE_MAX_TB][1024]; +srslte_softbuffer_rx_t softbuffers[SRSLTE_MAX_TB]; class rrc_dummy : public srsue::rrc_interface_phy { @@ -118,20 +118,23 @@ public: action->decode_enabled = true; action->default_ack = false; - action->generate_ack = false; - action->payload_ptr = payload; - memcpy(&action->phy_grant, &grant.phy_grant, sizeof(srslte_phy_grant_t)); - action->rv = ((uint32_t) ceilf((float)3*((my_phy.tti_to_SFN(grant.tti)/2)%4)/2))%4; - action->softbuffer = &softbuffer; - action->rnti = grant.rnti; - if (action->rv == 0) { - srslte_softbuffer_rx_reset(&softbuffer); + action->generate_ack = false; + for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { + action->payload_ptr[tb] = payload[tb]; + action->rv[tb] = ((uint32_t) ceilf((float) 3 * ((my_phy.tti_to_SFN(grant.tti) / 2) % 4) / 2)) % 4; + if (action->rv == 0) { + srslte_softbuffer_rx_reset(&softbuffers[tb]); + } + action->softbuffers[0] = &softbuffers[tb]; } + memcpy(&action->phy_grant, &grant.phy_grant, sizeof(srslte_phy_grant_t)); + + action->rnti = grant.rnti; } - void tb_decoded(bool ack, srslte_rnti_type_t rnti, uint32_t harq_pid) { + void tb_decoded(bool ack, uint32_t tb_idx, srslte_rnti_type_t rnti_type, uint32_t harq_pid) { if (ack) { total_oks++; } @@ -144,7 +147,9 @@ public: bch_decoded = true; srslte_cell_t cell; my_phy.get_current_cell(&cell); - srslte_softbuffer_rx_init(&softbuffer, cell.nof_prb); + for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { + srslte_softbuffer_rx_init(&softbuffers[tb], cell.nof_prb); + } } void tti_clock(uint32_t tti) { From cedc32fbb04093b8cbca13ab8aa6ff91255fb74a Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Mon, 28 Aug 2017 14:12:56 +0200 Subject: [PATCH 26/60] Added RI (CQI periodic reporting) send condition function --- lib/include/srslte/phy/phch/cqi.h | 9 ++- lib/src/phy/phch/cqi.c | 103 ++++++++++++++++++++++-------- 2 files changed, 83 insertions(+), 29 deletions(-) diff --git a/lib/include/srslte/phy/phch/cqi.h b/lib/include/srslte/phy/phch/cqi.h index f6857dfa0..593592f1c 100644 --- a/lib/include/srslte/phy/phch/cqi.h +++ b/lib/include/srslte/phy/phch/cqi.h @@ -45,7 +45,8 @@ typedef struct { bool configured; uint32_t pmi_idx; - bool simul_cqi_ack; + uint32_t ri_idx; + bool simul_cqi_ack; bool format_is_subband; uint32_t subband_size; } srslte_cqi_periodic_cfg_t; @@ -137,7 +138,11 @@ SRSLTE_API int srslte_cqi_format2_subband_unpack(uint8_t buff[SRSLTE_CQI_MAX_BIT srslte_cqi_format2_subband_t *msg); SRSLTE_API bool srslte_cqi_send(uint32_t I_cqi_pmi, - uint32_t tti); + uint32_t tti); + +SRSLTE_API bool srslte_ri_send(uint32_t I_cqi_pmi, + uint32_t I_ri, + uint32_t tti); SRSLTE_API uint8_t srslte_cqi_from_snr(float snr); diff --git a/lib/src/phy/phch/cqi.c b/lib/src/phy/phch/cqi.c index a684db8c9..0041c3fcb 100644 --- a/lib/src/phy/phch/cqi.c +++ b/lib/src/phy/phch/cqi.c @@ -159,46 +159,54 @@ int srslte_cqi_size(srslte_cqi_value_t *value) { return -1; } -bool srslte_cqi_send(uint32_t I_cqi_pmi, uint32_t tti) { - - uint32_t N_p = 0; - uint32_t N_offset = 0; - +static bool srslte_cqi_get_N(uint32_t I_cqi_pmi, uint32_t *N_p, uint32_t *N_offset) { if (I_cqi_pmi <= 1) { - N_p = 2; - N_offset = I_cqi_pmi; + *N_p = 2; + *N_offset = I_cqi_pmi; } else if (I_cqi_pmi <= 6) { - N_p = 5; - N_offset = I_cqi_pmi - 2; + *N_p = 5; + *N_offset = I_cqi_pmi - 2; } else if (I_cqi_pmi <= 16) { - N_p = 10; - N_offset = I_cqi_pmi - 7; + *N_p = 10; + *N_offset = I_cqi_pmi - 7; } else if (I_cqi_pmi <= 36) { - N_p = 20; - N_offset = I_cqi_pmi - 17; + *N_p = 20; + *N_offset = I_cqi_pmi - 17; } else if (I_cqi_pmi <= 76) { - N_p = 40; - N_offset = I_cqi_pmi - 37; + *N_p = 40; + *N_offset = I_cqi_pmi - 37; } else if (I_cqi_pmi <= 156) { - N_p = 80; - N_offset = I_cqi_pmi - 77; + *N_p = 80; + *N_offset = I_cqi_pmi - 77; } else if (I_cqi_pmi <= 316) { - N_p = 160; - N_offset = I_cqi_pmi - 157; + *N_p = 160; + *N_offset = I_cqi_pmi - 157; } else if (I_cqi_pmi == 317) { - return false; + return false; } else if (I_cqi_pmi <= 349) { - N_p = 32; - N_offset = I_cqi_pmi - 318; + *N_p = 32; + *N_offset = I_cqi_pmi - 318; } else if (I_cqi_pmi <= 413) { - N_p = 64; - N_offset = I_cqi_pmi - 350; + *N_p = 64; + *N_offset = I_cqi_pmi - 350; } else if (I_cqi_pmi <= 541) { - N_p = 128; - N_offset = I_cqi_pmi - 414; + *N_p = 128; + *N_offset = I_cqi_pmi - 414; } else if (I_cqi_pmi <= 1023) { - return false; + return false; + } + return true; +} + +bool srslte_cqi_send(uint32_t I_cqi_pmi, uint32_t tti) { + + uint32_t N_p = 0; + uint32_t N_offset = 0; + + if (!srslte_cqi_get_N(I_cqi_pmi, &N_p, &N_offset)) { + return false; } + if (N_p) { if ((tti-N_offset)%N_p == 0) { return true; @@ -207,6 +215,47 @@ bool srslte_cqi_send(uint32_t I_cqi_pmi, uint32_t tti) { return false; } +bool srslte_ri_send(uint32_t I_cqi_pmi, uint32_t I_ri, uint32_t tti) { + + uint32_t M_ri = 0; + uint32_t N_offset_ri = 0; + uint32_t N_p = 0; + uint32_t N_offset_p = 0; + + if (!srslte_cqi_get_N(I_cqi_pmi, &N_p, &N_offset_p)) { + return false; + } + + if (I_ri <= 160) { + M_ri = 1; + N_offset_ri = I_ri; + } else if (I_ri <= 161) { + M_ri = 2; + N_offset_ri = I_ri - 161; + } else if (I_ri <= 322) { + M_ri = 4; + N_offset_ri = I_ri - 322; + } else if (I_ri <= 483) { + M_ri = 8; + N_offset_ri = I_ri - 483; + } else if (I_ri <= 644) { + M_ri = 16; + N_offset_ri = I_ri - 644; + } else if (I_ri <= 805) { + M_ri = 32; + N_offset_ri = I_ri - 805; + } else if (I_ri <= 966) { + return false; + } + + if (M_ri) { + if ((tti - N_offset_p + N_offset_ri) % (N_p * M_ri) == 0) { + return true; + } + } + return false; +} + // CQI-to-Spectral Efficiency: 36.213 Table 7.2.3-1 */ static float cqi_to_coderate[16] = {0, 0.1523, 0.2344, 0.3770, 0.6016, 0.8770, 1.1758, 1.4766, 1.9141, 2.4063, 2.7305, 3.3223, 3.9023, 4.5234, 5.1152, 5.5547}; From bbf7ffffa21050ed58b7778ab074132f6ae11cb8 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Tue, 29 Aug 2017 09:59:06 +0200 Subject: [PATCH 27/60] Added Condition number calculation for Rank Indicator in TM3 (cherry picked from commit f8a4472) --- lib/examples/pdsch_ue.c | 8 +- lib/include/srslte/phy/mimo/precoding.h | 7 + lib/include/srslte/phy/phch/pdsch.h | 5 + lib/include/srslte/phy/ue/ue_dl.h | 4 + lib/include/srslte/phy/utils/algebra.h | 6 + lib/src/phy/mimo/precoding.c | 34 ++++ lib/src/phy/mimo/test/pmi_select_test.c | 14 ++ lib/src/phy/mimo/test/pmi_select_test.h | 232 ++++++++++++++---------- lib/src/phy/phch/pdsch.c | 5 + lib/src/phy/ue/ue_dl.c | 26 ++- lib/src/phy/utils/algebra.c | 23 +++ 11 files changed, 261 insertions(+), 103 deletions(-) diff --git a/lib/examples/pdsch_ue.c b/lib/examples/pdsch_ue.c index 7fc020118..be271049e 100644 --- a/lib/examples/pdsch_ue.c +++ b/lib/examples/pdsch_ue.c @@ -513,7 +513,7 @@ int main(int argc, char **argv) { uint32_t nframes=0; uint32_t ri = 0, pmi = 0; float rsrp0=0.0, rsrp1=0.0, rsrq=0.0, noise=0.0, enodebrate = 0.0, uerate = 0.0, - sinr[SRSLTE_MAX_LAYERS][SRSLTE_MAX_CODEBOOKS]; + sinr[SRSLTE_MAX_LAYERS][SRSLTE_MAX_CODEBOOKS], cn = 0.0; bool decode_pdsch = false; for (int i = 0; i < SRSLTE_MAX_LAYERS; i++) { @@ -678,11 +678,14 @@ int main(int argc, char **argv) { 100 * (1 - (float) ue_dl.nof_detected / nof_trials), (float) 100 * ue_dl.pkt_errors / ue_dl.pkts_total); } else { + /* Compute condition number */ + srslte_ue_dl_ri_select(&ue_dl, NULL, &cn); + /* Compute Rank Indicator (RI) and Precoding Matrix Indicator (PMI) */ srslte_ue_dl_ri_pmi_select(&ue_dl, &ri, &pmi, NULL); for (uint32_t nl = 0; nl < SRSLTE_MAX_LAYERS; nl++) { for (uint32_t cb = 0; cb < SRSLTE_MAX_CODEBOOKS; cb ++) { - sinr[nl][cb] = SRSLTE_VEC_EMA(ue_dl.sinr[nl][cb], sinr[nl][cb], 0.05f); + sinr[nl][cb] = SRSLTE_VEC_EMA(ue_dl.sinr[nl][cb], sinr[nl][cb], 0.5f); } } @@ -703,6 +706,7 @@ int main(int argc, char **argv) { printf("\033[K PDSCH-BLER: %5.2f%%\n", (float) 100 * ue_dl.pkt_errors / ue_dl.pkts_total); printf("\033[K TB 0: mcs=%d; tbs=%d\n", ue_dl.pdsch_cfg.grant.mcs[0].idx, ue_dl.pdsch_cfg.grant.mcs[0].tbs); printf("\033[K TB 1: mcs=%d; tbs=%d\n", ue_dl.pdsch_cfg.grant.mcs[1].idx, ue_dl.pdsch_cfg.grant.mcs[1].tbs); + printf("\033[K κ: %.1f dB (Condition number, 0 dB => Best)\n", cn); printf("\033[K\n"); printf("\033[KSINR (dB) Vs RI and PMI (for TM4, close loop MIMO only):\n"); printf("\033[K | RI | 1 | 2 |\n"); diff --git a/lib/include/srslte/phy/mimo/precoding.h b/lib/include/srslte/phy/mimo/precoding.h index b32b975d2..58fe22a40 100644 --- a/lib/include/srslte/phy/mimo/precoding.h +++ b/lib/include/srslte/phy/mimo/precoding.h @@ -127,4 +127,11 @@ SRSLTE_API int srslte_precoding_pmi_select(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_ uint32_t *pmi, float sinr[SRSLTE_MAX_CODEBOOKS]); +SRSLTE_API int srslte_precoding_cn(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], + uint32_t nof_tx_antennas, + uint32_t nof_rx_antennas, + uint32_t nof_symbols, + float *cn); + + #endif /* PRECODING_H_ */ diff --git a/lib/include/srslte/phy/phch/pdsch.h b/lib/include/srslte/phy/phch/pdsch.h index 7cfa1b616..ca6ce3478 100644 --- a/lib/include/srslte/phy/phch/pdsch.h +++ b/lib/include/srslte/phy/phch/pdsch.h @@ -156,6 +156,11 @@ SRSLTE_API int srslte_pdsch_pmi_select(srslte_pdsch_t *q, uint32_t pmi[SRSLTE_MAX_LAYERS], float sinr[SRSLTE_MAX_LAYERS][SRSLTE_MAX_CODEBOOKS]); +SRSLTE_API int srslte_pdsch_cn_compute(srslte_pdsch_t *q, + cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], + uint32_t nof_ce, + float *cn); + SRSLTE_API void srslte_pdsch_set_max_noi(srslte_pdsch_t *q, uint32_t max_iter); SRSLTE_API float srslte_pdsch_average_noi(srslte_pdsch_t *q); diff --git a/lib/include/srslte/phy/ue/ue_dl.h b/lib/include/srslte/phy/ue/ue_dl.h index 97b2344f5..416d467f8 100644 --- a/lib/include/srslte/phy/ue/ue_dl.h +++ b/lib/include/srslte/phy/ue/ue_dl.h @@ -200,6 +200,10 @@ SRSLTE_API int srslte_ue_dl_ri_pmi_select(srslte_ue_dl_t *q, uint32_t *pmi, float *current_sinr); +SRSLTE_API int srslte_ue_dl_ri_select(srslte_ue_dl_t *q, + uint32_t *ri, + float *cn); + SRSLTE_API bool srslte_ue_dl_decode_phich(srslte_ue_dl_t *q, uint32_t sf_idx, uint32_t n_prb_lowest, diff --git a/lib/include/srslte/phy/utils/algebra.h b/lib/include/srslte/phy/utils/algebra.h index 8e731a29f..ee681d558 100644 --- a/lib/include/srslte/phy/utils/algebra.h +++ b/lib/include/srslte/phy/utils/algebra.h @@ -108,6 +108,12 @@ SRSLTE_API void srslte_algebra_2x2_mmse_gen(cf_t y0, cf_t y1, float noise_estimate, float norm); +SRSLTE_API float srslte_algebra_2x2_cn(cf_t h00, + cf_t h01, + cf_t h10, + cf_t h11); + + #ifdef LV_HAVE_SSE /* SSE implementation for complex reciprocal */ diff --git a/lib/src/phy/mimo/precoding.c b/lib/src/phy/mimo/precoding.c index a79b75b0a..94b60c033 100644 --- a/lib/src/phy/mimo/precoding.c +++ b/lib/src/phy/mimo/precoding.c @@ -2517,3 +2517,37 @@ int srslte_precoding_pmi_select(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], uin return ret; } + +/* PMI Select for 1 layer */ +float srslte_precoding_2x2_cn_gen(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], uint32_t nof_symbols) { + uint32_t count = 0; + float cn_avg = 0.0f; + + for (uint32_t i = 0; i < nof_symbols; i += PMI_SEL_PRECISION) { + /* 0. Load channel matrix */ + cf_t h00 = h[0][0][i]; + cf_t h01 = h[1][0][i]; + cf_t h10 = h[0][1][i]; + cf_t h11 = h[1][1][i]; + + cn_avg += srslte_algebra_2x2_cn(h00, h01, h10, h11); + + count++; + } + + return cn_avg/count; +} + +/* Computes the condition number for a given number of antennas, + * stores in the parameter *cn the Condition Number in dB */ +int srslte_precoding_cn(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], uint32_t nof_tx_antennas, + uint32_t nof_rx_antennas, uint32_t nof_symbols, float *cn) { + if (nof_tx_antennas == 2 && nof_rx_antennas == 2) { + *cn = srslte_precoding_2x2_cn_gen(h, nof_symbols); + return SRSLTE_SUCCESS; + } else { + ERROR("MIMO Condition Number calculation not implemented for %d×%d", nof_tx_antennas, nof_rx_antennas); + return SRSLTE_ERROR; + } +} + diff --git a/lib/src/phy/mimo/test/pmi_select_test.c b/lib/src/phy/mimo/test/pmi_select_test.c index 30d358e37..9ac45f008 100644 --- a/lib/src/phy/mimo/test/pmi_select_test.c +++ b/lib/src/phy/mimo/test/pmi_select_test.c @@ -45,6 +45,7 @@ int main(int argc, char **argv) { float noise_estimate; float sinr_1l[SRSLTE_MAX_CODEBOOKS]; float sinr_2l[SRSLTE_MAX_CODEBOOKS]; + float cn; uint32_t pmi[2]; uint32_t nof_symbols = (uint32_t) SRSLTE_SF_LEN_RE(6, SRSLTE_CP_NORM); int ret = SRSLTE_ERROR; @@ -120,6 +121,19 @@ int main(int argc, char **argv) { ERROR("Test case %d failed computing 2 layer PMI (test=%d; gold=%d)\n", c + 1, pmi[1], gold->pmi[1]); goto clean; } + + /* Condition number */ + if (srslte_precoding_cn(h, 2, 2, nof_symbols, &cn)) { + ERROR("Test case %d condition number returned error\n"); + goto clean; + } + + /* Check condition number */ + if (fabsf(gold->k - cn) > 0.1) { + ERROR("Test case %d failed computing condition number (test=%.2f; gold=%.2f)\n", + c + 1, cn, gold->k); + goto clean; + } } /* Test passed */ diff --git a/lib/src/phy/mimo/test/pmi_select_test.h b/lib/src/phy/mimo/test/pmi_select_test.h index a55869a8b..14c72c266 100644 --- a/lib/src/phy/mimo/test/pmi_select_test.h +++ b/lib/src/phy/mimo/test/pmi_select_test.h @@ -30,173 +30,207 @@ #define PMI_SELECT_TEST_NOF_CASES 16 typedef struct { - cf_t h[2][2]; - float n; - float snri_1l[4]; - float snri_2l[2]; - uint32_t pmi[2]; + cf_t h[2][2]; /* Channel estimate */ + float n; /* Noise estimation */ + float snri_1l[4]; /* SINR Approximation for 1 layer (linear) */ + float snri_2l[2]; /* SINR Approximation for 2 layers (linear) */ + uint32_t pmi[2]; /* Precoding Matrix Indicator for 1 and 2 layers */ + uint32_t ri; /* Rank indicator */ + float k; /* Condition number (κ) in dB */ } pmi_select_test_case_gold_t; static pmi_select_test_case_gold_t pmi_select_test_case_gold [PMI_SELECT_TEST_NOF_CASES] = { { /* Test case 1 */ .h = { - {+0.103430f+0.455920f*_Complex_I, +0.042050f+0.751883f*_Complex_I}, - {-0.641951f-0.053356f*_Complex_I, +0.217847f+0.504428f*_Complex_I} + {+0.861552f+0.205546f*_Complex_I, +0.955538f-0.052364f*_Complex_I}, + {-0.812807f-0.287487f*_Complex_I, +0.323470f-0.048843f*_Complex_I} }, - .n = 0.181048, - .snri_1l = {5.793827f, 2.505115f, 3.350922f, 4.948020f}, - .snri_2l = {2.015732f, 1.848130f}, - .pmi = {0, 0}, + .n = 0.671022, + .snri_1l = {1.233339f, 2.567786f, 2.065012f, 1.736113f}, + .snri_2l = {0.893739f, 0.841600f}, + .pmi = {1, 0}, + .ri = 2, + .k = 4.6758, }, { /* Test case 2 */ .h = { - {-0.957328f-0.624816f*_Complex_I, -0.741457f-0.657570f*_Complex_I}, - {+0.720104f+0.351137f*_Complex_I, +0.593419f-0.200211f*_Complex_I} + {+0.919290f+0.824394f*_Complex_I, -0.821831f-0.797741f*_Complex_I}, + {+0.595485f-0.413411f*_Complex_I, +0.181551f-0.896824f*_Complex_I} }, - .n = 0.935527, - .snri_1l = {0.475069f, 3.077055f, 1.078656f, 2.473467f}, - .snri_2l = {0.747362f, 0.594324f}, - .pmi = {1, 0}, + .n = 0.504128, + .snri_1l = {5.697916f, 2.631874f, 4.143253f, 4.186538f}, + .snri_2l = {1.897704f, 1.718554f}, + .pmi = {0, 0}, + .ri = 2, + .k = 4.8715, }, { /* Test case 3 */ .h = { - {-0.047530f-0.118039f*_Complex_I, -0.195528f-0.724032f*_Complex_I}, - {-0.619953f+0.960678f*_Complex_I, -0.325868f-0.120700f*_Complex_I} + {+0.536752f-0.093497f*_Complex_I, -0.434029f+0.474769f*_Complex_I}, + {-0.549280f+0.019771f*_Complex_I, -0.337421f-0.234972f*_Complex_I} }, - .n = 0.803842, - .snri_1l = {1.331730f, 1.164592f, 1.660155f, 0.836167f}, - .snri_2l = {0.554942f, 0.579321f}, - .pmi = {2, 1}, + .n = 0.905483, + .snri_1l = {0.363469f, 0.941684f, 0.408025f, 0.897129f}, + .snri_2l = {0.311544f, 0.307074f}, + .pmi = {1, 0}, + .ri = 1, + .k = 6.2219, }, { /* Test case 4 */ .h = { - {+0.635330f-0.751786f*_Complex_I, -0.536944f-0.185884f*_Complex_I}, - {+0.282517f-0.864615f*_Complex_I, -0.484380f-0.780479f*_Complex_I} + {+0.930515f-0.233960f*_Complex_I, +0.256535f+0.982387f*_Complex_I}, + {-0.735938f-0.426345f*_Complex_I, +0.236604f+0.412383f*_Complex_I} }, - .n = 0.529556, - .snri_1l = {5.128973f, 0.465969f, 2.812367f, 2.782574f}, - .snri_2l = {1.381190f, 0.818813f}, - .pmi = {0, 0}, + .n = 0.535206, + .snri_1l = {2.487298f, 2.932872f, 4.009672f, 1.410498f}, + .snri_2l = {1.082110f, 1.248639f}, + .pmi = {2, 1}, + .ri = 2, + .k = 5.9758, }, { /* Test case 5 */ .h = { - {-0.576996f+0.964470f*_Complex_I, -0.948065f+0.902764f*_Complex_I}, - {+0.988240f-0.056784f*_Complex_I, +0.489282f+0.975071f*_Complex_I} + {-0.613578f-0.908683f*_Complex_I, +0.378870f+0.770083f*_Complex_I}, + {-0.899090f+0.679589f*_Complex_I, -0.631132f-0.763690f*_Complex_I} }, - .n = 0.852921, - .snri_1l = {2.772684f, 3.261802f, 5.698031f, 0.336455f}, - .snri_2l = {0.768370f, 1.469069f}, + .n = 0.410415, + .snri_1l = {2.929140f, 7.281276f, 7.632612f, 2.577804f}, + .snri_2l = {2.045272f, 2.159393f}, .pmi = {2, 1}, + .ri = 2, + .k = 6.8485, }, { /* Test case 6 */ .h = { - {-0.381846f-0.998609f*_Complex_I, +0.903472f-0.393687f*_Complex_I}, - {-0.772703f-0.261637f*_Complex_I, -0.765452f-0.759318f*_Complex_I} + {-0.759543f+0.979731f*_Complex_I, +0.144185f-0.300384f*_Complex_I}, + {+0.898780f-0.582955f*_Complex_I, -0.487230f+0.331654f*_Complex_I} }, - .n = 0.711912, - .snri_1l = {2.998736f, 2.538860f, 5.099274f, 0.438323f}, - .snri_2l = {0.809381f, 1.371548f}, - .pmi = {2, 1}, + .n = 0.973345, + .snri_1l = {0.151784f, 3.077111f, 2.165454f, 1.063441f}, + .snri_2l = {0.755981f, 0.503361f}, + .pmi = {1, 0}, + .ri = 1, + .k = 18.0800, }, { /* Test case 7 */ .h = { - {+0.915028f-0.780771f*_Complex_I, -0.355424f+0.447925f*_Complex_I}, - {+0.577968f+0.765204f*_Complex_I, +0.342972f-0.999014f*_Complex_I} + {+0.245400f-0.537444f*_Complex_I, -0.872924f-0.895583f*_Complex_I}, + {-0.252981f+0.803513f*_Complex_I, -0.667497f+0.586583f*_Complex_I} }, - .n = 0.101944, - .snri_1l = {12.424177f, 24.940449f, 5.411339f, 31.953288f}, - .snri_2l = {4.610588f, 7.664146f}, - .pmi = {3, 1}, + .n = 0.373014, + .snri_1l = {3.403660f, 5.744504f, 7.385295f, 1.762868f}, + .snri_2l = {1.642126f, 2.130892f}, + .pmi = {2, 1}, + .ri = 2, + .k = 7.1484, }, { /* Test case 8 */ .h = { - {-0.259232f-0.654765f*_Complex_I, +0.829378f-0.793859f*_Complex_I}, - {+0.997978f+0.212295f*_Complex_I, -0.659012f-0.176220f*_Complex_I} + {+0.664109f-0.281444f*_Complex_I, +0.507669f-0.822295f*_Complex_I}, + {+0.243726f-0.316646f*_Complex_I, -0.211814f+0.097341f*_Complex_I} }, - .n = 0.255783, - .snri_1l = {3.345813f, 9.635433f, 6.767844f, 6.213402f}, - .snri_2l = {3.215386f, 2.640976f}, - .pmi = {1, 0}, + .n = 0.460547, + .snri_1l = {1.948731f, 1.673386f, 2.389606f, 1.232511f}, + .snri_2l = {0.623422f, 0.659548f}, + .pmi = {2, 1}, + .ri = 1, + .k = 9.8582, }, { /* Test case 9 */ .h = { - {-0.596630f+0.244853f*_Complex_I, -0.624622f+0.316537f*_Complex_I}, - {+0.767545f-0.645831f*_Complex_I, +0.262828f+0.251697f*_Complex_I} + {+0.290905f-0.072573f*_Complex_I, +0.027042f+0.179635f*_Complex_I}, + {+0.628853f-0.625656f*_Complex_I, -0.805634f+0.222660f*_Complex_I} }, - .n = 0.876456, - .snri_1l = {0.367264f, 1.965908f, 1.215674f, 1.117498f}, - .snri_2l = {0.579923f, 0.479609f}, - .pmi = {1, 0}, + .n = 0.051942, + .snri_1l = {20.229536f, 10.736104f, 15.206118f, 15.759523f}, + .snri_2l = {2.426844f, 2.175025f}, + .pmi = {0, 0}, + .ri = 1, + .k = 12.8396, }, { /* Test case 10 */ .h = { - {-0.643594f+0.172442f*_Complex_I, +0.291148f-0.026254f*_Complex_I}, - {+0.768244f+0.678173f*_Complex_I, -0.498968f-0.896649f*_Complex_I} + {+0.151454f-0.701886f*_Complex_I, +0.684689f-0.943441f*_Complex_I}, + {-0.000548f+0.513340f*_Complex_I, -0.121950f+0.592212f*_Complex_I} }, - .n = 0.739473, - .snri_1l = {1.104856f, 2.455074f, 2.920106f, 0.639825f}, - .snri_2l = {0.557672f, 0.658911f}, - .pmi = {2, 1}, + .n = 0.293556, + .snri_1l = {0.848833f, 7.679596f, 3.011330f, 5.517099f}, + .snri_2l = {1.442768f, 0.788147f}, + .pmi = {1, 0}, + .ri = 1, + .k = 22.0345, }, { /* Test case 11 */ .h = { - {+0.109032f-0.285542f*_Complex_I, -0.141055f+0.318945f*_Complex_I}, - {+0.559445f-0.211656f*_Complex_I, -0.206665f-0.643045f*_Complex_I} + {-0.769587f+0.330477f*_Complex_I, -0.249817f+0.920280f*_Complex_I}, + {+0.657787f+0.886236f*_Complex_I, +0.683553f-0.774601f*_Complex_I} }, - .n = 0.054295, - .snri_1l = {8.472397f, 10.480333f, 4.074631f, 14.878099f}, - .snri_2l = {2.121444f, 2.979095f}, - .pmi = {3, 1}, + .n = 0.648287, + .snri_1l = {1.312873f, 4.697041f, 5.064183f, 0.945731f}, + .snri_2l = {0.993660f, 1.125611f}, + .pmi = {2, 1}, + .ri = 1, + .k = 12.9593, }, { /* Test case 12 */ .h = { - {-0.505758f-0.710501f*_Complex_I, +0.803627f+0.023333f*_Complex_I}, - {+0.964886f+0.987055f*_Complex_I, -0.031782f+0.525138f*_Complex_I} + {-0.038392f+0.542607f*_Complex_I, -0.866959f-0.879276f*_Complex_I}, + {+0.795542f-0.475085f*_Complex_I, -0.005540f+0.302139f*_Complex_I} }, - .n = 0.966024, - .snri_1l = {0.612742f, 3.102514f, 1.227107f, 2.488149f}, - .snri_2l = {0.848010f, 0.701000f}, - .pmi = {1, 0}, + .n = 0.133604, + .snri_1l = {6.257962f, 14.479088f, 15.459994f, 5.277056f}, + .snri_2l = {3.523645f, 3.845011f}, + .pmi = {2, 1}, + .ri = 1, + .k = 7.6196, }, { /* Test case 13 */ .h = { - {+0.859761f-0.737655f*_Complex_I, -0.527019f+0.509133f*_Complex_I}, - {-0.804956f-0.303794f*_Complex_I, -0.180451f-0.100433f*_Complex_I} + {+0.277091f-0.237022f*_Complex_I, -0.230114f-0.399963f*_Complex_I}, + {+0.531396f-0.319721f*_Complex_I, +0.305831f+0.837853f*_Complex_I} }, - .n = 0.199335, - .snri_1l = {4.402551f, 8.656756f, 10.092319f, 2.966987f}, - .snri_2l = {2.048224f, 2.462759f}, - .pmi = {2, 1}, + .n = 0.456267, + .snri_1l = {1.272387f, 2.072182f, 1.744873f, 1.599696f}, + .snri_2l = {0.720254f, 0.700519f}, + .pmi = {1, 0}, + .ri = 2, + .k = 5.9972, }, { /* Test case 14 */ .h = { - {+0.473036f+0.227467f*_Complex_I, -0.593265f-0.308456f*_Complex_I}, - {+0.536321f+0.445264f*_Complex_I, -0.517440f-0.765554f*_Complex_I} + {-0.115006f+0.764806f*_Complex_I, -0.091628f-0.960249f*_Complex_I}, + {+0.890564f-0.316470f*_Complex_I, -0.561762f+0.532055f*_Complex_I} }, - .n = 0.180788, - .snri_1l = {10.671400f, 0.736020f, 3.584109f, 7.823311f}, - .snri_2l = {2.029078f, 0.914443f}, - .pmi = {0, 0}, + .n = 0.342804, + .snri_1l = {2.060602f, 6.750694f, 8.002153f, 0.809143f}, + .snri_2l = {1.036665f, 1.575640f}, + .pmi = {2, 1}, + .ri = 1, + .k = 18.9097, }, { /* Test case 15 */ .h = { - {-0.612271f+0.338114f*_Complex_I, -0.278903f+0.914426f*_Complex_I}, - {-0.191213f-0.136670f*_Complex_I, -0.548440f+0.607628f*_Complex_I} + {+0.237613f+0.203137f*_Complex_I, -0.093958f+0.298835f*_Complex_I}, + {-0.979675f-0.314559f*_Complex_I, +0.198162f-0.013401f*_Complex_I} }, - .n = 0.798189, - .snri_1l = {2.309797f, 0.356735f, 0.731443f, 1.935089f}, - .snri_2l = {0.577612f, 0.490806f}, - .pmi = {0, 0}, + .n = 0.701774, + .snri_1l = {0.466961f, 1.376956f, 0.827475f, 1.016442f}, + .snri_2l = {0.386935f, 0.354722f}, + .pmi = {1, 0}, + .ri = 1, + .k = 11.2469, }, { /* Test case 16 */ .h = { - {+0.990482f+0.513519f*_Complex_I, -0.576391f+0.922553f*_Complex_I}, - {-0.341962f+0.139785f*_Complex_I, +0.524684f+0.217012f*_Complex_I} + {+0.775605f+0.528142f*_Complex_I, -0.889884f+0.975918f*_Complex_I}, + {-0.803276f-0.749350f*_Complex_I, +0.299566f-0.271046f*_Complex_I} }, - .n = 0.365092, - .snri_1l = {2.942635f, 4.964827f, 4.761949f, 3.145513f}, - .snri_2l = {1.291431f, 1.267123f}, + .n = 0.676230, + .snri_1l = {0.661772f, 5.245671f, 3.261470f, 2.645973f}, + .snri_2l = {1.354145f, 0.857372f}, .pmi = {1, 0}, + .ri = 1, + .k = 10.7137, }, }; diff --git a/lib/src/phy/phch/pdsch.c b/lib/src/phy/phch/pdsch.c index 0e824aaa7..bf50cb6ec 100644 --- a/lib/src/phy/phch/pdsch.c +++ b/lib/src/phy/phch/pdsch.c @@ -700,6 +700,11 @@ int srslte_pdsch_pmi_select(srslte_pdsch_t *q, return SRSLTE_SUCCESS; } +int srslte_pdsch_cn_compute(srslte_pdsch_t *q, + cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], uint32_t nof_ce, float *cn) { + return srslte_precoding_cn(ce, q->cell.nof_ports, q->nof_rx_antennas, nof_ce, cn); +} + int srslte_pdsch_encode(srslte_pdsch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbuffer_tx_t *softbuffer, uint8_t *data, uint16_t rnti, cf_t *sf_symbols[SRSLTE_MAX_PORTS]) diff --git a/lib/src/phy/ue/ue_dl.c b/lib/src/phy/ue/ue_dl.c index 219325c1d..91116ab70 100644 --- a/lib/src/phy/ue/ue_dl.c +++ b/lib/src/phy/ue/ue_dl.c @@ -467,6 +467,8 @@ int srslte_ue_dl_decode_rnti_multi(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_POR } } +/* Compute the Rank Indicator (RI) and Precoder Matrix Indicator (PMI) by computing the Signal to Interference plus + * Noise Ratio (SINR), valid for TM4 */ int srslte_ue_dl_ri_pmi_select(srslte_ue_dl_t *q, uint32_t *ri, uint32_t *pmi, float *current_sinr) { float noise_estimate = srslte_chest_dl_get_noise_estimate(&q->chest); float best_sinr = -INFINITY; @@ -484,8 +486,8 @@ int srslte_ue_dl_ri_pmi_select(srslte_ue_dl_t *q, uint32_t *ri, uint32_t *pmi, f /* Select the best Rank indicator (RI) and Precoding Matrix Indicator (PMI) */ for (uint32_t nof_layers = 1; nof_layers <= q->pdsch_cfg.nof_layers; nof_layers++ ) { - if (q->sinr[nof_layers][q->pmi[nof_layers]] > best_sinr) { - best_sinr = q->sinr[nof_layers][q->pmi[nof_layers]]; + if (q->sinr[nof_layers][q->pmi[nof_layers]] > best_sinr + 0.1) { + best_sinr = q->sinr[nof_layers][q->pmi[nof_layers]]*nof_layers; best_pmi = q->pmi[nof_layers]; best_ri = nof_layers; } @@ -526,6 +528,26 @@ int srslte_ue_dl_ri_pmi_select(srslte_ue_dl_t *q, uint32_t *ri, uint32_t *pmi, f return SRSLTE_SUCCESS; } + +/* Compute the Rank Indicator (RI) by computing the condition number, valid for TM3 */ +int srslte_ue_dl_ri_select(srslte_ue_dl_t *q, uint32_t *ri, float *cn) { + float _cn; + int ret = srslte_pdsch_cn_compute(&q->pdsch, q->ce_m, SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp), &_cn); + + /* Set Condition number */ + if (cn) { + *cn = _cn; + } + + /* Set rank indicator */ + if (!ret && ri) { + *ri = (_cn > 3.0f)? 1:0; + } + + return ret; +} + + uint32_t srslte_ue_dl_get_ncce(srslte_ue_dl_t *q) { return q->last_location.ncce; } diff --git a/lib/src/phy/utils/algebra.c b/lib/src/phy/utils/algebra.c index 3d1de2ffa..943ae57dd 100644 --- a/lib/src/phy/utils/algebra.c +++ b/lib/src/phy/utils/algebra.c @@ -26,6 +26,7 @@ #include #include +#include #include "srslte/phy/utils/algebra.h" @@ -92,6 +93,28 @@ inline void srslte_algebra_2x2_mmse_gen(cf_t y0, cf_t y1, cf_t h00, cf_t h01, cf *x1 = (y0 * w10 + y1 * w11) * _norm; } +inline float srslte_algebra_2x2_cn(cf_t h00, cf_t h01, cf_t h10, cf_t h11) { + /* 1. A = H * H' (A = A') */ + float a00 = + crealf(h00) * crealf(h00) + crealf(h01) * crealf(h01) + cimagf(h00) * cimagf(h00) + cimagf(h01) * cimagf(h01); + cf_t a01 = h00 * conjf(h10) + h01 * conjf(h11); + //cf_t a10 = h10*conjf(h00) + h11*conjf(h01) = conjf(a01); + float a11 = + crealf(h10) * crealf(h10) + crealf(h11) * crealf(h11) + cimagf(h10) * cimagf(h10) + cimagf(h11) * cimagf(h11); + + /* 2. |H * H' - {λ0, λ1}| = 0 -> aλ² + bλ + c = 0 */ + float b = a00 + a11; + float c = a00 * a11 - (crealf(a01) * crealf(a01) + cimagf(a01) * cimagf(a01)); + + /* 3. λ = (-b ± sqrt(b² - 4 * c))/2 */ + float sqr = sqrtf(b * b - 4.0f * c); + float xmax = b + sqr; + float xmin = b - sqr; + + /* 4. κ = sqrt(λ_max / λ_min) */ + return 10 * log10f(xmax / xmin); +} + #ifdef LV_HAVE_SSE /* SSE implementation for complex reciprocal */ From 9deadc13dc79c44d7cdebc0e699ca889d0299cc3 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Tue, 29 Aug 2017 12:00:52 +0200 Subject: [PATCH 28/60] Tx and Rx data check in PDSCH test (cherry picked from commit 6679a160c6f39876aa8d5930a1c8d6bc58a551d3) (cherry picked from commit 8ae673d) --- lib/src/phy/phch/test/pdsch_test.c | 58 ++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 18 deletions(-) diff --git a/lib/src/phy/phch/test/pdsch_test.c b/lib/src/phy/phch/test/pdsch_test.c index 228cb5eb5..ea40ce824 100644 --- a/lib/src/phy/phch/test/pdsch_test.c +++ b/lib/src/phy/phch/test/pdsch_test.c @@ -133,7 +133,8 @@ void parse_args(int argc, char **argv) { } } -uint8_t *data[SRSLTE_MAX_CODEWORDS] = {NULL}; +static uint8_t *data_tx[SRSLTE_MAX_CODEWORDS] = {NULL}; +static uint8_t *data_rx[SRSLTE_MAX_CODEWORDS] = {NULL}; cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; srslte_softbuffer_rx_t *softbuffers_rx[SRSLTE_MAX_CODEWORDS]; srslte_ra_dl_grant_t grant; @@ -258,12 +259,20 @@ int main(int argc, char **argv) { for (int i = 0; i < grant.nof_tb; i++) { if (grant.mcs[i].tbs) { - data[i] = srslte_vec_malloc(sizeof(uint8_t) * grant.mcs[i].tbs); - if (!data[i]) { + data_tx[i] = srslte_vec_malloc(sizeof(uint8_t) * grant.mcs[i].tbs); + if (!data_tx[i]) { perror("srslte_vec_malloc"); goto quit; } - bzero(data[i], sizeof(uint8_t) * grant.mcs[i].tbs); + bzero(data_tx[i], sizeof(uint8_t) * grant.mcs[i].tbs); + + data_rx[i] = srslte_vec_malloc(sizeof(uint8_t) * grant.mcs[i].tbs); + if (!data_rx[i]) { + perror("srslte_vec_malloc"); + goto quit; + } + bzero(data_rx[i], sizeof(uint8_t) * grant.mcs[i].tbs); + } } @@ -274,7 +283,7 @@ int main(int argc, char **argv) { srslte_pdsch_set_rnti(&pdsch_rx, rnti); - for (i = 0; i < SRSLTE_MAX_TB; i++) { + for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { softbuffers_rx[i] = calloc(sizeof(srslte_softbuffer_rx_t), 1); if (!softbuffers_rx[i]) { fprintf(stderr, "Error allocating RX soft buffer\n"); @@ -322,7 +331,7 @@ int main(int argc, char **argv) { #ifdef DO_OFDM srslte_filesource_read(&fsrc, rx_slot_symbols, SRSLTE_SF_LEN_PRB(cell.nof_prb)); #else - srslte_filesource_read_multi(&fsrc, (void*) rx_slot_symbols, SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp), pdsch_cfg.nof_layers); + srslte_filesource_read(&fsrc, rx_slot_symbols[0], SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp)); #endif srslte_chest_dl_t chest; @@ -330,7 +339,7 @@ int main(int argc, char **argv) { fprintf(stderr, "Error initializing equalizer\n"); exit(-1); } - srslte_chest_dl_estimate_multi(&chest, rx_slot_symbols, ce, subframe, nof_rx_antennas); + srslte_chest_dl_estimate(&chest, rx_slot_symbols[0], ce[0], subframe); srslte_chest_dl_free(&chest); srslte_filesource_free(&fsrc); @@ -345,7 +354,6 @@ int main(int argc, char **argv) { for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { softbuffers_tx[i] = calloc(sizeof(srslte_softbuffer_tx_t), 1); - if (!softbuffers_tx[i]) { fprintf(stderr, "Error allocating TX soft buffer\n"); } @@ -364,9 +372,9 @@ int main(int argc, char **argv) { } } - for (i = 0; i< grant.nof_tb; i++) { - for (i = 0; i < grant.mcs[i].tbs / 8; i++) { - data[i][i] = (uint8_t) (rand() % 256); + for (int tb = 0; tb < grant.nof_tb; tb++) { + for (int byte = 0; byte < grant.mcs[tb].tbs / 8; byte++) { + data_tx[tb][byte] = (uint8_t)(rand() % 256); } } @@ -377,7 +385,7 @@ int main(int argc, char **argv) { if (rv_idx[0] != 0 || rv_idx[1] != 0) { /* Do 1st transmission for rv_idx!=0 */ bzero(pdsch_cfg.rv, sizeof(uint32_t)*SRSLTE_MAX_CODEWORDS); - if (srslte_pdsch_encode_multi(&pdsch_tx, &pdsch_cfg, softbuffers_tx, data, rnti, tx_slot_symbols)) { + if (srslte_pdsch_encode_multi(&pdsch_tx, &pdsch_cfg, softbuffers_tx, data_tx, rnti, tx_slot_symbols)) { fprintf(stderr, "Error encoding PDSCH\n"); goto quit; } @@ -385,7 +393,7 @@ int main(int argc, char **argv) { memcpy(pdsch_cfg.rv, rv_idx, sizeof(uint32_t)*SRSLTE_MAX_CODEWORDS); gettimeofday(&t[1], NULL); for (k = 0; k < M; k++) { - if (srslte_pdsch_encode_multi(&pdsch_tx, &pdsch_cfg, softbuffers_tx, data, rnti, tx_slot_symbols)) { + if (srslte_pdsch_encode_multi(&pdsch_tx, &pdsch_cfg, softbuffers_tx, data_tx, rnti, tx_slot_symbols)) { ERROR("Error encoding PDSCH"); goto quit; } @@ -441,7 +449,7 @@ int main(int argc, char **argv) { srslte_softbuffer_rx_reset_tbs(softbuffers_rx[i], (uint32_t) grant.mcs[i].tbs); } } - r = srslte_pdsch_decode_multi(&pdsch_rx, &pdsch_cfg, softbuffers_rx, rx_slot_symbols, ce, 0, rnti, data, acks); + r = srslte_pdsch_decode_multi(&pdsch_rx, &pdsch_cfg, softbuffers_rx, rx_slot_symbols, ce, 0, rnti, data_rx, acks); } gettimeofday(&t[2], NULL); get_time_interval(t); @@ -451,11 +459,21 @@ int main(int argc, char **argv) { /* If there is an error in PDSCH decode */ if (r) { - ERROR("PDSCH decode"); - ret = SRSLTE_ERROR; + ret = -1; goto quit; } + /* Check Tx and Rx bytes */ + for (int tb = 0; tb < grant.nof_tb; tb++) { + for (int byte = 0; byte < grant.mcs[tb].tbs / 8; byte++) { + if (data_tx[tb][byte] != data_rx[tb][byte]) { + ERROR("Found BYTE error in TB %d (%02X != %02X), quiting...", tb, data_tx[tb][byte], data_rx[tb][byte]); + ret = SRSLTE_ERROR; + goto quit; + } + } + } + /* Check all transport blocks have been decoded OK */ for (int tb = 0; tb < grant.nof_tb; tb++) { ret |= (acks[tb]) ? SRSLTE_SUCCESS : SRSLTE_ERROR; @@ -477,8 +495,12 @@ quit: free(softbuffers_rx[i]); } - if (data[i]) { - free(data[i]); + if (data_tx[i]) { + free(data_tx[i]); + } + + if (data_rx[i]) { + free(data_rx[i]); } } From 38b38ee82f3fce7baf84d1414ad556c04c5eb4a6 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Tue, 29 Aug 2017 13:01:15 +0200 Subject: [PATCH 29/60] Solved bug in RF Send call (cherry picked from commit cc8a10e) --- lib/src/phy/rf/rf_imp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/src/phy/rf/rf_imp.c b/lib/src/phy/rf/rf_imp.c index cb22b301b..c1074ebc5 100644 --- a/lib/src/phy/rf/rf_imp.c +++ b/lib/src/phy/rf/rf_imp.c @@ -323,7 +323,8 @@ int srslte_rf_send_multi(srslte_rf_t *rf, bool is_end_of_burst) { - return srslte_rf_send_timed_multi(rf, data, nsamples, 0, 0, blocking, is_start_of_burst, is_end_of_burst); + return ((rf_dev_t*) rf->dev)->srslte_rf_send_timed_multi(rf->handler, data, nsamples, 0, 0, + false, blocking, is_start_of_burst, is_end_of_burst); } int srslte_rf_send(srslte_rf_t *rf, void *data, uint32_t nsamples, bool blocking) From d9d72e8f7b3d20542400d4f7df887868d3f535ba Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Tue, 29 Aug 2017 16:53:39 +0200 Subject: [PATCH 30/60] SINR calculation for PMI selection improvement for 2 layers; test golden values updated (cherry picked from commit 59b26dd) --- lib/src/phy/mimo/precoding.c | 6 +- lib/src/phy/mimo/test/pmi_select_test.c | 2 +- lib/src/phy/mimo/test/pmi_select_test.h | 236 ++++++++++++------------ 3 files changed, 122 insertions(+), 122 deletions(-) diff --git a/lib/src/phy/mimo/precoding.c b/lib/src/phy/mimo/precoding.c index 94b60c033..0e898448a 100644 --- a/lib/src/phy/mimo/precoding.c +++ b/lib/src/phy/mimo/precoding.c @@ -2195,7 +2195,7 @@ int srslte_precoding_pmi_select_2l_gen(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORT } /* Divide average by noise */ - sinr_list[i] /= (2 * count); + sinr_list[i] /= count; if (sinr_list[i] > max_sinr) { max_sinr = sinr_list[i]; @@ -2316,7 +2316,7 @@ int srslte_precoding_pmi_select_2l_sse(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORT } /* Divide average by noise */ - sinr_list[i] /= 2 * count; + sinr_list[i] /= count; if (sinr_list[i] > max_sinr) { max_sinr = sinr_list[i]; @@ -2463,7 +2463,7 @@ int srslte_precoding_pmi_select_2l_avx(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORT } /* Divide average by noise */ - sinr_list[i] /= 2 * count; + sinr_list[i] /= count; if (sinr_list[i] > max_sinr) { max_sinr = sinr_list[i]; diff --git a/lib/src/phy/mimo/test/pmi_select_test.c b/lib/src/phy/mimo/test/pmi_select_test.c index 9ac45f008..c7e5b5c8e 100644 --- a/lib/src/phy/mimo/test/pmi_select_test.c +++ b/lib/src/phy/mimo/test/pmi_select_test.c @@ -155,4 +155,4 @@ int main(int argc, char **argv) { } return ret; -} \ No newline at end of file +} diff --git a/lib/src/phy/mimo/test/pmi_select_test.h b/lib/src/phy/mimo/test/pmi_select_test.h index 14c72c266..c9c2ef5b3 100644 --- a/lib/src/phy/mimo/test/pmi_select_test.h +++ b/lib/src/phy/mimo/test/pmi_select_test.h @@ -42,195 +42,195 @@ typedef struct { static pmi_select_test_case_gold_t pmi_select_test_case_gold [PMI_SELECT_TEST_NOF_CASES] = { { /* Test case 1 */ .h = { - {+0.861552f+0.205546f*_Complex_I, +0.955538f-0.052364f*_Complex_I}, - {-0.812807f-0.287487f*_Complex_I, +0.323470f-0.048843f*_Complex_I} + {+0.626226f+0.060103f*_Complex_I, -0.233387f-0.449860f*_Complex_I}, + {+0.234558f-0.502742f*_Complex_I, +0.150990f-0.096722f*_Complex_I} }, - .n = 0.671022, - .snri_1l = {1.233339f, 2.567786f, 2.065012f, 1.736113f}, - .snri_2l = {0.893739f, 0.841600f}, - .pmi = {1, 0}, - .ri = 2, - .k = 4.6758, + .n = 0.227713, + .snri_1l = {2.728043f, 1.630673f, 3.226421f, 1.132295f}, + .snri_2l = {1.797660f, 1.982149f}, + .pmi = {2, 1}, + .ri = 1, + .k = 6.4007, }, { /* Test case 2 */ .h = { - {+0.919290f+0.824394f*_Complex_I, -0.821831f-0.797741f*_Complex_I}, - {+0.595485f-0.413411f*_Complex_I, +0.181551f-0.896824f*_Complex_I} + {+0.608899f-0.825846f*_Complex_I, +0.972208f+0.604183f*_Complex_I}, + {-0.940016f+0.978290f*_Complex_I, +0.071328f-0.866107f*_Complex_I} }, - .n = 0.504128, - .snri_1l = {5.697916f, 2.631874f, 4.143253f, 4.186538f}, - .snri_2l = {1.897704f, 1.718554f}, - .pmi = {0, 0}, - .ri = 2, - .k = 4.8715, + .n = 0.939398, + .snri_1l = {0.686850f, 4.591972f, 3.773925f, 1.504897f}, + .snri_2l = {2.298235f, 1.761859f}, + .pmi = {1, 0}, + .ri = 1, + .k = 11.1305, }, { /* Test case 3 */ .h = { - {+0.536752f-0.093497f*_Complex_I, -0.434029f+0.474769f*_Complex_I}, - {-0.549280f+0.019771f*_Complex_I, -0.337421f-0.234972f*_Complex_I} + {-0.963645f+0.770719f*_Complex_I, +0.367677f+0.798010f*_Complex_I}, + {+0.567473f+0.251875f*_Complex_I, +0.068275f-0.724262f*_Complex_I} }, - .n = 0.905483, - .snri_1l = {0.363469f, 0.941684f, 0.408025f, 0.897129f}, - .snri_2l = {0.311544f, 0.307074f}, - .pmi = {1, 0}, + .n = 0.217802, + .snri_1l = {3.209674f, 11.525338f, 11.962786f, 2.772226f}, + .snri_2l = {3.226053f, 3.526363f}, + .pmi = {2, 1}, .ri = 1, - .k = 6.2219, + .k = 15.4589, }, { /* Test case 4 */ .h = { - {+0.930515f-0.233960f*_Complex_I, +0.256535f+0.982387f*_Complex_I}, - {-0.735938f-0.426345f*_Complex_I, +0.236604f+0.412383f*_Complex_I} + {-0.635718f+0.879322f*_Complex_I, -0.916360f-0.291089f*_Complex_I}, + {-0.786117f-0.178742f*_Complex_I, +0.232887f+0.968699f*_Complex_I} }, - .n = 0.535206, - .snri_1l = {2.487298f, 2.932872f, 4.009672f, 1.410498f}, - .snri_2l = {1.082110f, 1.248639f}, - .pmi = {2, 1}, + .n = 0.945579, + .snri_1l = {1.818313f, 2.141519f, 1.995787f, 1.964045f}, + .snri_2l = {1.965011f, 1.958537f}, + .pmi = {1, 0}, .ri = 2, - .k = 5.9758, + .k = 1.2910, }, { /* Test case 5 */ .h = { - {-0.613578f-0.908683f*_Complex_I, +0.378870f+0.770083f*_Complex_I}, - {-0.899090f+0.679589f*_Complex_I, -0.631132f-0.763690f*_Complex_I} + {+0.353289f+0.324764f*_Complex_I, +0.976605f-0.511669f*_Complex_I}, + {+0.533663f-0.408985f*_Complex_I, -0.326601f+0.360357f*_Complex_I} }, - .n = 0.410415, - .snri_1l = {2.929140f, 7.281276f, 7.632612f, 2.577804f}, - .snri_2l = {2.045272f, 2.159393f}, - .pmi = {2, 1}, + .n = 0.527847, + .snri_1l = {1.173803f, 2.869865f, 2.273783f, 1.769885f}, + .snri_2l = {1.871430f, 1.713879f}, + .pmi = {1, 0}, .ri = 2, - .k = 6.8485, + .k = 5.5388, }, { /* Test case 6 */ .h = { - {-0.759543f+0.979731f*_Complex_I, +0.144185f-0.300384f*_Complex_I}, - {+0.898780f-0.582955f*_Complex_I, -0.487230f+0.331654f*_Complex_I} + {-0.176813f+0.103585f*_Complex_I, +0.205276f+0.167141f*_Complex_I}, + {+0.501040f+0.023640f*_Complex_I, +0.167066f-0.834815f*_Complex_I} }, - .n = 0.973345, - .snri_1l = {0.151784f, 3.077111f, 2.165454f, 1.063441f}, - .snri_2l = {0.755981f, 0.503361f}, - .pmi = {1, 0}, + .n = 0.719570, + .snri_1l = {0.490387f, 1.022313f, 1.111245f, 0.401456f}, + .snri_2l = {0.578124f, 0.597176f}, + .pmi = {2, 1}, .ri = 1, - .k = 18.0800, + .k = 21.8808, }, { /* Test case 7 */ .h = { - {+0.245400f-0.537444f*_Complex_I, -0.872924f-0.895583f*_Complex_I}, - {-0.252981f+0.803513f*_Complex_I, -0.667497f+0.586583f*_Complex_I} + {+0.992312f+0.773088f*_Complex_I, -0.290931f-0.090610f*_Complex_I}, + {+0.942518f-0.173145f*_Complex_I, -0.307102f-0.564536f*_Complex_I} }, - .n = 0.373014, - .snri_1l = {3.403660f, 5.744504f, 7.385295f, 1.762868f}, - .snri_2l = {1.642126f, 2.130892f}, - .pmi = {2, 1}, - .ri = 2, - .k = 7.1484, + .n = 0.125655, + .snri_1l = {19.459529f, 4.467420f, 18.044021f, 5.882928f}, + .snri_2l = {8.055238f, 6.832247f}, + .pmi = {0, 0}, + .ri = 1, + .k = 9.9136, }, { /* Test case 8 */ .h = { - {+0.664109f-0.281444f*_Complex_I, +0.507669f-0.822295f*_Complex_I}, - {+0.243726f-0.316646f*_Complex_I, -0.211814f+0.097341f*_Complex_I} + {-0.382171f-0.980395f*_Complex_I, +0.452209f+0.686427f*_Complex_I}, + {+0.565744f+0.844664f*_Complex_I, +0.387575f+0.541908f*_Complex_I} }, - .n = 0.460547, - .snri_1l = {1.948731f, 1.673386f, 2.389606f, 1.232511f}, - .snri_2l = {0.623422f, 0.659548f}, - .pmi = {2, 1}, - .ri = 1, - .k = 9.8582, + .n = 0.042660, + .snri_1l = {26.560881f, 49.864772f, 33.269985f, 43.155668f}, + .snri_2l = {37.201526f, 34.461078f}, + .pmi = {1, 0}, + .ri = 2, + .k = 3.1172, }, { /* Test case 9 */ .h = { - {+0.290905f-0.072573f*_Complex_I, +0.027042f+0.179635f*_Complex_I}, - {+0.628853f-0.625656f*_Complex_I, -0.805634f+0.222660f*_Complex_I} + {-0.243628f-0.461891f*_Complex_I, +0.408679f+0.346062f*_Complex_I}, + {+0.459026f-0.045016f*_Complex_I, -0.551446f+0.247433f*_Complex_I} }, - .n = 0.051942, - .snri_1l = {20.229536f, 10.736104f, 15.206118f, 15.759523f}, - .snri_2l = {2.426844f, 2.175025f}, - .pmi = {0, 0}, + .n = 0.236445, + .snri_1l = {1.429443f, 3.381496f, 0.227617f, 4.583322f}, + .snri_2l = {1.272903f, 2.118832f}, + .pmi = {3, 1}, .ri = 1, - .k = 12.8396, + .k = 24.1136, }, { /* Test case 10 */ .h = { - {+0.151454f-0.701886f*_Complex_I, +0.684689f-0.943441f*_Complex_I}, - {-0.000548f+0.513340f*_Complex_I, -0.121950f+0.592212f*_Complex_I} + {-0.645752f-0.784222f*_Complex_I, +0.659287f-0.635545f*_Complex_I}, + {+0.533843f-0.801809f*_Complex_I, +0.868957f-0.020472f*_Complex_I} }, - .n = 0.293556, - .snri_1l = {0.848833f, 7.679596f, 3.011330f, 5.517099f}, - .snri_2l = {1.442768f, 0.788147f}, - .pmi = {1, 0}, + .n = 0.193245, + .snri_1l = {13.697372f, 4.693597f, 1.561737f, 16.829232f}, + .snri_2l = {2.961344f, 5.773049f}, + .pmi = {3, 1}, .ri = 1, - .k = 22.0345, + .k = 17.5194, }, { /* Test case 11 */ .h = { - {-0.769587f+0.330477f*_Complex_I, -0.249817f+0.920280f*_Complex_I}, - {+0.657787f+0.886236f*_Complex_I, +0.683553f-0.774601f*_Complex_I} + {+0.791783f+0.544990f*_Complex_I, -0.801821f-0.376120f*_Complex_I}, + {-0.911669f-0.642035f*_Complex_I, +0.114590f-0.322089f*_Complex_I} }, - .n = 0.648287, - .snri_1l = {1.312873f, 4.697041f, 5.064183f, 0.945731f}, - .snri_2l = {0.993660f, 1.125611f}, - .pmi = {2, 1}, - .ri = 1, - .k = 12.9593, + .n = 0.210146, + .snri_1l = {2.340213f, 12.261749f, 5.921675f, 8.680286f}, + .snri_2l = {6.912040f, 4.520201f}, + .pmi = {1, 0}, + .ri = 2, + .k = 7.7819, }, { /* Test case 12 */ .h = { - {-0.038392f+0.542607f*_Complex_I, -0.866959f-0.879276f*_Complex_I}, - {+0.795542f-0.475085f*_Complex_I, -0.005540f+0.302139f*_Complex_I} + {+0.020305f-0.218290f*_Complex_I, +0.812729f-0.890767f*_Complex_I}, + {+0.257848f+0.002566f*_Complex_I, -0.796932f-0.136558f*_Complex_I} }, - .n = 0.133604, - .snri_1l = {6.257962f, 14.479088f, 15.459994f, 5.277056f}, - .snri_2l = {3.523645f, 3.845011f}, + .n = 0.997560, + .snri_1l = {0.591218f, 1.636514f, 1.880263f, 0.347469f}, + .snri_2l = {0.869026f, 0.967991f}, .pmi = {2, 1}, .ri = 1, - .k = 7.6196, + .k = 12.9774, }, { /* Test case 13 */ .h = { - {+0.277091f-0.237022f*_Complex_I, -0.230114f-0.399963f*_Complex_I}, - {+0.531396f-0.319721f*_Complex_I, +0.305831f+0.837853f*_Complex_I} + {+0.623205f-0.219990f*_Complex_I, -0.028697f+0.854712f*_Complex_I}, + {+0.788896f+0.834988f*_Complex_I, -0.724907f+0.427148f*_Complex_I} }, - .n = 0.456267, - .snri_1l = {1.272387f, 2.072182f, 1.744873f, 1.599696f}, - .snri_2l = {0.720254f, 0.700519f}, - .pmi = {1, 0}, - .ri = 2, - .k = 5.9972, + .n = 0.618337, + .snri_1l = {3.706176f, 1.461946f, 0.479632f, 4.688490f}, + .snri_2l = {1.444336f, 2.102567f}, + .pmi = {3, 1}, + .ri = 1, + .k = 17.0493, }, { /* Test case 14 */ .h = { - {-0.115006f+0.764806f*_Complex_I, -0.091628f-0.960249f*_Complex_I}, - {+0.890564f-0.316470f*_Complex_I, -0.561762f+0.532055f*_Complex_I} + {-0.313424f+0.292955f*_Complex_I, +0.872055f+0.666304f*_Complex_I}, + {-0.750452f-0.203436f*_Complex_I, +0.461171f+0.499644f*_Complex_I} }, - .n = 0.342804, - .snri_1l = {2.060602f, 6.750694f, 8.002153f, 0.809143f}, - .snri_2l = {1.036665f, 1.575640f}, - .pmi = {2, 1}, + .n = 0.835221, + .snri_1l = {2.560265f, 0.379539f, 0.976562f, 1.963242f}, + .snri_2l = {1.380223f, 1.109300f}, + .pmi = {0, 0}, .ri = 1, - .k = 18.9097, + .k = 10.1729, }, { /* Test case 15 */ .h = { - {+0.237613f+0.203137f*_Complex_I, -0.093958f+0.298835f*_Complex_I}, - {-0.979675f-0.314559f*_Complex_I, +0.198162f-0.013401f*_Complex_I} + {-0.355079f-0.339153f*_Complex_I, +0.104523f+0.238943f*_Complex_I}, + {+0.958258f-0.278727f*_Complex_I, +0.098617f+0.513019f*_Complex_I} }, - .n = 0.701774, - .snri_1l = {0.466961f, 1.376956f, 0.827475f, 1.016442f}, - .snri_2l = {0.386935f, 0.354722f}, - .pmi = {1, 0}, + .n = 0.413901, + .snri_1l = {1.633620f, 2.178855f, 0.809297f, 3.003178f}, + .snri_2l = {1.250898f, 1.512017f}, + .pmi = {3, 1}, .ri = 1, - .k = 11.2469, + .k = 10.8925, }, { /* Test case 16 */ .h = { - {+0.775605f+0.528142f*_Complex_I, -0.889884f+0.975918f*_Complex_I}, - {-0.803276f-0.749350f*_Complex_I, +0.299566f-0.271046f*_Complex_I} + {-0.015310f+0.675606f*_Complex_I, +0.389486f+0.478144f*_Complex_I}, + {+0.945468f+0.908349f*_Complex_I, -0.344490f-0.936155f*_Complex_I} }, - .n = 0.676230, - .snri_1l = {0.661772f, 5.245671f, 3.261470f, 2.645973f}, - .snri_2l = {1.354145f, 0.857372f}, - .pmi = {1, 0}, - .ri = 1, - .k = 10.7137, + .n = 0.356869, + .snri_1l = {5.024121f, 4.926495f, 7.364348f, 2.586268f}, + .snri_2l = {3.165416f, 3.851590f}, + .pmi = {2, 1}, + .ri = 2, + .k = 7.7799, }, }; From b872f84255565db017657d7c38901af571b2fc75 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Tue, 29 Aug 2017 16:54:33 +0200 Subject: [PATCH 31/60] Improved RI selection (cherry picked from commit 034025d) --- lib/src/phy/phch/pdsch.c | 2 +- lib/src/phy/ue/ue_dl.c | 21 +++++++++++++-------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/lib/src/phy/phch/pdsch.c b/lib/src/phy/phch/pdsch.c index bf50cb6ec..62f2834ae 100644 --- a/lib/src/phy/phch/pdsch.c +++ b/lib/src/phy/phch/pdsch.c @@ -683,7 +683,7 @@ int srslte_pdsch_pmi_select(srslte_pdsch_t *q, uint32_t pmi[SRSLTE_MAX_LAYERS], float sinr[SRSLTE_MAX_LAYERS][SRSLTE_MAX_CODEBOOKS]) { if (q->cell.nof_ports == 2 && q->nof_rx_antennas == 2) { - for (int nof_layers = 1; nof_layers <= cfg->nof_layers; nof_layers++ ) { + for (int nof_layers = 1; nof_layers <= 2; nof_layers++ ) { if (sinr[nof_layers - 1] && pmi) { if (srslte_precoding_pmi_select(ce, nof_ce, noise_estimate, nof_layers, &pmi[nof_layers - 1], sinr[nof_layers - 1]) < 0) { diff --git a/lib/src/phy/ue/ue_dl.c b/lib/src/phy/ue/ue_dl.c index 91116ab70..55f65ad3d 100644 --- a/lib/src/phy/ue/ue_dl.c +++ b/lib/src/phy/ue/ue_dl.c @@ -438,9 +438,15 @@ int srslte_ue_dl_decode_rnti_multi(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_POR q->sf_symbols_m, q->ce_m, noise_estimate, rnti, data, acks); - + + for (int tb = 0; tb < q->pdsch_cfg.grant.nof_tb; tb++) { + if (!acks[tb]) { + q->pkt_errors++; + } + q->pkts_total++; + } + if (ret == SRSLTE_ERROR) { - q->pkt_errors++; } else if (ret == SRSLTE_ERROR_INVALID_INPUTS) { fprintf(stderr, "Error calling srslte_pdsch_decode()\n"); } @@ -458,8 +464,6 @@ int srslte_ue_dl_decode_rnti_multi(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_POR } - q->pkts_total++; - if (found_dci == 1 && ret == SRSLTE_SUCCESS) { return q->pdsch_cfg.grant.mcs[0].tbs; } else { @@ -485,10 +489,11 @@ int srslte_ue_dl_ri_pmi_select(srslte_ue_dl_t *q, uint32_t *ri, uint32_t *pmi, f } /* Select the best Rank indicator (RI) and Precoding Matrix Indicator (PMI) */ - for (uint32_t nof_layers = 1; nof_layers <= q->pdsch_cfg.nof_layers; nof_layers++ ) { - if (q->sinr[nof_layers][q->pmi[nof_layers]] > best_sinr + 0.1) { - best_sinr = q->sinr[nof_layers][q->pmi[nof_layers]]*nof_layers; - best_pmi = q->pmi[nof_layers]; + for (uint32_t nof_layers = 1; nof_layers <= 2; nof_layers++) { + float _sinr = q->sinr[nof_layers - 1][q->pmi[nof_layers - 1]] * nof_layers; + if (_sinr > best_sinr + 0.1) { + best_sinr = _sinr; + best_pmi = q->pmi[nof_layers - 1]; best_ri = nof_layers; } } From cf4a601ea385ce382569766dbc51eb9e1bfa6b03 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Tue, 29 Aug 2017 16:56:55 +0200 Subject: [PATCH 32/60] pdsch_ue can change the Tx mode dynamically (cherry picked from commit fb36014) --- lib/examples/pdsch_enodeb.c | 111 ++++++++++++++++++++++++++++++------ 1 file changed, 92 insertions(+), 19 deletions(-) diff --git a/lib/examples/pdsch_enodeb.c b/lib/examples/pdsch_enodeb.c index a4558ff30..4ded08fdf 100644 --- a/lib/examples/pdsch_enodeb.c +++ b/lib/examples/pdsch_enodeb.c @@ -202,23 +202,15 @@ void base_init() { switch(pdsch_cfg.mimo_type) { case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA: cell.nof_ports = 1; - pdsch_cfg.nof_layers = 1; - nof_tb = 1; break; case SRSLTE_MIMO_TYPE_TX_DIVERSITY: cell.nof_ports = 2; - pdsch_cfg.nof_layers = 2; - nof_tb = 1; break; case SRSLTE_MIMO_TYPE_CDD: cell.nof_ports = 2; - pdsch_cfg.nof_layers = 2; - nof_tb = 2; break; case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX: cell.nof_ports = 2; - pdsch_cfg.nof_layers = multiplex_nof_layers; - nof_tb = multiplex_nof_layers; break; default: ERROR("Transmission mode not implemented."); @@ -226,7 +218,7 @@ void base_init() { } /* Allocate memory */ - for(i = 0; i < nof_tb; i++) { + for(i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { data[i] = srslte_vec_malloc(sizeof(uint8_t) * SOFTBUFFER_SIZE); if (!data[i]) { perror("malloc"); @@ -236,7 +228,7 @@ void base_init() { } /* init memory */ - for (i = 0; i < cell.nof_ports; i++) { + for (i = 0; i < SRSLTE_MAX_PORTS; i++) { sf_buffer[i] = srslte_vec_malloc(sizeof(cf_t) * sf_n_re); if (!sf_buffer[i]) { perror("malloc"); @@ -333,7 +325,13 @@ void base_init() { srslte_pdsch_set_rnti(&pdsch, UE_CRNTI); - for (i = 0; i < nof_tb; i++) { + for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { + softbuffers[i] = calloc(sizeof(srslte_softbuffer_tx_t), 1); + if (!softbuffers[i]) { + fprintf(stderr, "Error allocating soft buffer\n"); + exit(-1); + } + if (srslte_softbuffer_tx_init(softbuffers[i], cell.nof_prb)) { fprintf(stderr, "Error initiating soft buffer\n"); exit(-1); @@ -343,11 +341,11 @@ void base_init() { void base_free() { int i; - for (i = 0; i < nof_tb; i++) { + for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { + srslte_softbuffer_tx_free(softbuffers[i]); if (softbuffers[i]) { free(softbuffers[i]); } - srslte_softbuffer_tx_free(softbuffers[i]); } srslte_pdsch_free(&pdsch); srslte_pdcch_free(&pdcch); @@ -422,7 +420,30 @@ uint32_t prbset_to_bitmask() { } int update_radl() { - + + /* Configure cell and PDSCH in function of the transmission mode */ + switch(pdsch_cfg.mimo_type) { + case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA: + pdsch_cfg.nof_layers = 1; + nof_tb = 1; + break; + case SRSLTE_MIMO_TYPE_TX_DIVERSITY: + pdsch_cfg.nof_layers = 2; + nof_tb = 1; + break; + case SRSLTE_MIMO_TYPE_CDD: + pdsch_cfg.nof_layers = 2; + nof_tb = 2; + break; + case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX: + pdsch_cfg.nof_layers = multiplex_nof_layers; + nof_tb = multiplex_nof_layers; + break; + default: + ERROR("Transmission mode not implemented."); + exit(-1); + } + bzero(&ra_dl, sizeof(srslte_ra_dl_dci_t)); ra_dl.harq_process = 0; ra_dl.mcs_idx = mcs_idx; @@ -445,8 +466,21 @@ int update_radl() { srslte_ra_dl_dci_to_grant(&ra_dl, cell.nof_prb, UE_CRNTI, &dummy_grant); srslte_ra_dl_grant_to_nbits(&dummy_grant, cfi, cell, 0, &dummy_nbits); srslte_ra_dl_grant_fprint(stdout, &dummy_grant); - printf("Type new MCS index and press Enter: "); fflush(stdout); - + + if (pdsch_cfg.mimo_type != SRSLTE_MIMO_TYPE_SINGLE_ANTENNA) { + printf("\nTransmission mode key table:\n"); + printf(" Mode | 1TB | 2TB |\n"); + printf("----------+---------+-----+\n"); + printf("Diversity | x | |\n"); + printf(" CDD | | z |\n"); + printf("Multiplex | q,w,e,r | a,s |\n"); + printf("\n"); + printf("Type new MCS index (0-28) or mode key and press Enter: "); + } else { + printf("Type new MCS index (0-28) and press Enter: "); + } + fflush(stdout); + return 0; } @@ -487,8 +521,47 @@ int update_control() { break; } } else { - last_mcs_idx = mcs_idx; - mcs_idx = atoi(input); + switch (input[0]) { + case 'q': + pdsch_cfg.mimo_type = SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX; + multiplex_pmi = 0; + multiplex_nof_layers = 1; + break; + case 'w': + pdsch_cfg.mimo_type = SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX; + multiplex_pmi = 1; + multiplex_nof_layers = 1; + break; + case 'e': + pdsch_cfg.mimo_type = SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX; + multiplex_pmi = 2; + multiplex_nof_layers = 1; + break; + case 'r': + pdsch_cfg.mimo_type = SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX; + multiplex_pmi = 3; + multiplex_nof_layers = 1; + break; + case 'a': + pdsch_cfg.mimo_type = SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX; + multiplex_pmi = 0; + multiplex_nof_layers = 2; + break; + case 's': + pdsch_cfg.mimo_type = SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX; + multiplex_pmi = 1; + multiplex_nof_layers = 2; + break; + case 'z': + pdsch_cfg.mimo_type = SRSLTE_MIMO_TYPE_CDD; + break; + case 'x': + pdsch_cfg.mimo_type = SRSLTE_MIMO_TYPE_TX_DIVERSITY; + break; + default: + last_mcs_idx = mcs_idx; + mcs_idx = atoi(input); + } } bzero(input,sizeof(input)); if (update_radl()) { @@ -651,7 +724,7 @@ int main(int argc, char **argv) { nf = 0; bool send_data = false; - for (i = 0; i < nof_tb; i++) { + for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { srslte_softbuffer_tx_reset(softbuffers[i]); } From 92882e64479f0c74a2d5a35d73d33cab8de9f794 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Tue, 29 Aug 2017 16:57:56 +0200 Subject: [PATCH 33/60] Improved MIMO stats display (cherry picked from commit 877ea6a) --- lib/examples/pdsch_ue.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/examples/pdsch_ue.c b/lib/examples/pdsch_ue.c index be271049e..1a9f77c6f 100644 --- a/lib/examples/pdsch_ue.c +++ b/lib/examples/pdsch_ue.c @@ -663,7 +663,7 @@ int main(int argc, char **argv) { } // Plot and Printf - if (srslte_ue_sync_get_sfidx(&ue_sync) == 5) { + if (srslte_ue_sync_get_sfidx(&ue_sync) == 5 && sfn % 20 == 0) { float gain = prog_args.rf_gain; if (gain < 0) { gain = 10*log10(srslte_agc_get_gain(&ue_sync.agc)); @@ -703,7 +703,6 @@ int main(int argc, char **argv) { printf("\033[K Rb: %6.2f / %6.2f Mbps (net/maximum)\n", uerate, enodebrate); printf("\033[K PDCCH-Miss: %5.2f%%\n", 100 * (1 - (float) ue_dl.nof_detected / nof_trials)); printf("\033[K PDSCH-BLER: %5.2f%%\n", (float) 100 * ue_dl.pkt_errors / ue_dl.pkts_total); - printf("\033[K PDSCH-BLER: %5.2f%%\n", (float) 100 * ue_dl.pkt_errors / ue_dl.pkts_total); printf("\033[K TB 0: mcs=%d; tbs=%d\n", ue_dl.pdsch_cfg.grant.mcs[0].idx, ue_dl.pdsch_cfg.grant.mcs[0].tbs); printf("\033[K TB 1: mcs=%d; tbs=%d\n", ue_dl.pdsch_cfg.grant.mcs[1].idx, ue_dl.pdsch_cfg.grant.mcs[1].tbs); printf("\033[K κ: %.1f dB (Condition number, 0 dB => Best)\n", cn); @@ -715,7 +714,7 @@ int main(int argc, char **argv) { printf("\033[K M | 1 | %5.2f%c| %5.2f%c|\n", 10 * log10(sinr[0][1]), (ri == 1 && pmi == 1)?'*':' ', 10 * log10(sinr[1][1]), (ri == 2 && pmi == 1)?'*':' '); printf("\033[K I | 2 | %5.2f%c|-------+ \n", 10 * log10(sinr[0][2]), (ri == 1 && pmi == 2)?'*':' '); printf("\033[K | 3 | %5.2f%c| \n", 10 * log10(sinr[0][3]), (ri == 1 && pmi == 3)?'*':' '); - printf("\033[K\n\n"); + printf("\033[K\nPress enter maximum printing debug log of 1 subframe.\n"); printf("\033[21A"); } } From d933f1b8175e00f2330b8052138a9eae79ae365b Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Thu, 31 Aug 2017 12:24:26 +0200 Subject: [PATCH 34/60] Renamed module algebra (it is now named mat) and moved usefl math SIMD macros to simd.h --- lib/include/srslte/phy/utils/algebra.h | 161 ------------------ lib/include/srslte/phy/utils/mat.h | 111 ++++++++++++ lib/include/srslte/phy/utils/simd.h | 81 +++++++++ lib/src/phy/mimo/precoding.c | 36 ++-- lib/src/phy/utils/{algebra.c => mat.c} | 46 ++--- lib/src/phy/utils/test/CMakeLists.txt | 2 +- .../utils/test/{algebra_test.c => mat_test.c} | 14 +- 7 files changed, 241 insertions(+), 210 deletions(-) delete mode 100644 lib/include/srslte/phy/utils/algebra.h create mode 100644 lib/include/srslte/phy/utils/mat.h create mode 100644 lib/include/srslte/phy/utils/simd.h rename lib/src/phy/utils/{algebra.c => mat.c} (82%) rename lib/src/phy/utils/test/{algebra_test.c => mat_test.c} (96%) diff --git a/lib/include/srslte/phy/utils/algebra.h b/lib/include/srslte/phy/utils/algebra.h deleted file mode 100644 index ee681d558..000000000 --- a/lib/include/srslte/phy/utils/algebra.h +++ /dev/null @@ -1,161 +0,0 @@ -/** - * - * \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/. - * - */ - -#ifndef SRSLTE_ALGEBRA_H -#define SRSLTE_ALGEBRA_H - -#include "srslte/config.h" - -/* - * Generic Macros - */ -#define RANDOM_CF() (((float)rand())/((float)RAND_MAX) + _Complex_I*((float)rand())/((float)RAND_MAX)) - -/* - * SSE Macros - */ -#ifdef LV_HAVE_SSE -#define _MM_SWAP(X) ((__m128)_mm_shuffle_ps(X, X, _MM_SHUFFLE(2,3,0,1))) -#define _MM_PERM(X) ((__m128)_mm_shuffle_ps(X, X, _MM_SHUFFLE(2,1,3,0))) -#define _MM_MULJ_PS(X) _MM_SWAP(_MM_CONJ_PS(X)) -#define _MM_CONJ_PS(X) (_mm_xor_ps(X, _mm_set_ps(-0.0f, 0.0f, -0.0f, 0.0f))) -#define _MM_SQMOD_PS(X) _MM_PERM(_mm_hadd_ps(_mm_mul_ps(X,X), _mm_set_ps(0.0f, 0.0f, 0.0f, 0.0f))) -#define _MM_PROD_PS(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))) - -#endif /* LV_HAVE_SSE */ - - -/* - * AVX Macros - */ -#ifdef LV_HAVE_AVX - -#define _MM256_MULJ_PS(X) _mm256_permute_ps(_MM256_CONJ_PS(X), 0b10110001) -#define _MM256_CONJ_PS(X) (_mm256_xor_ps(X, _mm256_set_ps(-0.0f, 0.0f, -0.0f, 0.0f, -0.0f, 0.0f, -0.0f, 0.0f))) - -#ifdef LV_HAVE_FMA -#define _MM256_SQMOD_PS(A, B) _mm256_permute_ps(_mm256_hadd_ps(_mm256_fmadd_ps(A, A, _mm256_mul_ps(B,B)), \ - _mm256_set_ps(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), 0b11011100) -#define _MM256_PROD_PS(a, b) _mm256_fmaddsub_ps(a,_mm256_moveldup_ps(b),\ - _mm256_mul_ps(_mm256_shuffle_ps(a,a,0xB1),_mm256_movehdup_ps(b))) -#else -#define _MM256_SQMOD_PS(A, B) _mm256_permute_ps(_mm256_hadd_ps(_mm256_add_ps(_mm256_mul_ps(A,A), _mm256_mul_ps(B,B)), \ - _mm256_set_ps(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), 0b11011100) -#define _MM256_PROD_PS(a, b) _mm256_addsub_ps(_mm256_mul_ps(a,_mm256_moveldup_ps(b)),\ - _mm256_mul_ps(_mm256_shuffle_ps(a,a,0xB1),_mm256_movehdup_ps(b))) -#endif /* LV_HAVE_FMA */ -#endif /* LV_HAVE_AVX */ - -/* - * AVX extension with FMA Macros - */ -#ifdef LV_HAVE_FMA - -#define _MM256_SQMOD_ADD_PS(A, B, C) _mm256_permute_ps(_mm256_hadd_ps(_mm256_fmadd_ps(A, A, _mm256_fmadd_ps(B, B, C)),\ - _mm256_set_ps(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), 0b11011100) - -#define _MM256_PROD_ADD_PS(A, B, C) _mm256_fmaddsub_ps(A,_mm256_moveldup_ps(B),\ - _mm256_fmaddsub_ps(_mm256_shuffle_ps(A,A,0xB1),_mm256_movehdup_ps(B), C)) - -#define _MM256_PROD_SUB_PS(A, B, C) _mm256_fmaddsub_ps(A,_mm256_moveldup_ps(B),\ - _mm256_fmsubadd_ps(_mm256_shuffle_ps(A,A,0xB1),_mm256_movehdup_ps(B), C)) -#endif /* LV_HAVE_FMA */ - -/* Generic implementation for complex reciprocal */ -SRSLTE_API cf_t srslte_algebra_cf_recip_gen(cf_t a); - -/* Generic implementation for 2x2 determinant */ -SRSLTE_API cf_t srslte_algebra_2x2_det_gen(cf_t a00, cf_t a01, cf_t a10, cf_t a11); - -/* Generic implementation for 2x2 Matrix Inversion */ -SRSLTE_API void srslte_algebra_2x2_inv_gen(cf_t a00, cf_t a01, cf_t a10, cf_t a11, - cf_t *r00, cf_t *r01, cf_t *r10, cf_t *r11); - -/* Generic implementation for Zero Forcing (ZF) solver */ -SRSLTE_API void srslte_algebra_2x2_zf_gen(cf_t y0, cf_t y1, - cf_t h00, cf_t h01, cf_t h10, cf_t h11, - cf_t *x0, cf_t *x1, - float norm); - -/* Generic implementation for Minimum Mean Squared Error (MMSE) solver */ -SRSLTE_API void srslte_algebra_2x2_mmse_gen(cf_t y0, cf_t y1, - cf_t h00, cf_t h01, cf_t h10, cf_t h11, - cf_t *x0, cf_t *x1, - float noise_estimate, - float norm); - -SRSLTE_API float srslte_algebra_2x2_cn(cf_t h00, - cf_t h01, - cf_t h10, - cf_t h11); - - -#ifdef LV_HAVE_SSE - -/* SSE implementation for complex reciprocal */ -SRSLTE_API __m128 srslte_algebra_cf_recip_sse(__m128 a); - -/* SSE implementation for 2x2 determinant */ -SRSLTE_API __m128 srslte_algebra_2x2_det_sse(__m128 a00, __m128 a01, __m128 a10, __m128 a11); - -/* SSE implementation for Zero Forcing (ZF) solver */ -SRSLTE_API void srslte_algebra_2x2_zf_sse(__m128 y0, __m128 y1, - __m128 h00, __m128 h01, __m128 h10, __m128 h11, - __m128 *x0, __m128 *x1, - float norm); - -/* SSE implementation for Minimum Mean Squared Error (MMSE) solver */ -SRSLTE_API void srslte_algebra_2x2_mmse_sse(__m128 y0, __m128 y1, - __m128 h00, __m128 h01, __m128 h10, __m128 h11, - __m128 *x0, __m128 *x1, - float noise_estimate, float norm); - -#endif /* LV_HAVE_SSE */ - -#ifdef LV_HAVE_AVX - -/* AVX implementation for complex reciprocal */ -SRSLTE_API __m256 srslte_algebra_cf_recip_avx(__m256 a); - -/* AVX implementation for 2x2 determinant */ -SRSLTE_API __m256 srslte_algebra_2x2_det_avx(__m256 a00, __m256 a01, __m256 a10, __m256 a11); - -/* AVX implementation for Zero Forcing (ZF) solver */ -SRSLTE_API void srslte_algebra_2x2_zf_avx(__m256 y0, __m256 y1, - __m256 h00, __m256 h01, __m256 h10, __m256 h11, - __m256 *x0, __m256 *x1, - float norm); - -/* AVX implementation for Minimum Mean Squared Error (MMSE) solver */ -SRSLTE_API void srslte_algebra_2x2_mmse_avx(__m256 y0, __m256 y1, - __m256 h00, __m256 h01, __m256 h10, __m256 h11, - __m256 *x0, __m256 *x1, - float noise_estimate, float norm); - -#endif /* LV_HAVE_AVX */ - -#endif //SRSLTE_ALGEBRA_H diff --git a/lib/include/srslte/phy/utils/mat.h b/lib/include/srslte/phy/utils/mat.h new file mode 100644 index 000000000..48d3b776d --- /dev/null +++ b/lib/include/srslte/phy/utils/mat.h @@ -0,0 +1,111 @@ +/** + * + * \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/. + * + */ + +#ifndef SRSLTE_MAT_H +#define SRSLTE_MAT_H + +#include "srslte/phy/utils/simd.h" +#include "srslte/config.h" + +/* + * Generic Macros + */ +#define RANDOM_CF() (((float)rand())/((float)RAND_MAX) + _Complex_I*((float)rand())/((float)RAND_MAX)) + +/* Generic implementation for complex reciprocal */ +SRSLTE_API cf_t srslte_mat_cf_recip_gen(cf_t a); + +/* Generic implementation for 2x2 determinant */ +SRSLTE_API cf_t srslte_mat_2x2_det_gen(cf_t a00, cf_t a01, cf_t a10, cf_t a11); + +/* Generic implementation for 2x2 Matrix Inversion */ +SRSLTE_API void srslte_mat_2x2_inv_gen(cf_t a00, cf_t a01, cf_t a10, cf_t a11, + cf_t *r00, cf_t *r01, cf_t *r10, cf_t *r11); + +/* Generic implementation for Zero Forcing (ZF) solver */ +SRSLTE_API void srslte_mat_2x2_zf_gen(cf_t y0, cf_t y1, + cf_t h00, cf_t h01, cf_t h10, cf_t h11, + cf_t *x0, cf_t *x1, + float norm); + +/* Generic implementation for Minimum Mean Squared Error (MMSE) solver */ +SRSLTE_API void srslte_mat_2x2_mmse_gen(cf_t y0, cf_t y1, + cf_t h00, cf_t h01, cf_t h10, cf_t h11, + cf_t *x0, cf_t *x1, + float noise_estimate, + float norm); + +SRSLTE_API float srslte_mat_2x2_cn(cf_t h00, + cf_t h01, + cf_t h10, + cf_t h11); + + +#ifdef LV_HAVE_SSE + +/* SSE implementation for complex reciprocal */ +SRSLTE_API __m128 srslte_mat_cf_recip_sse(__m128 a); + +/* SSE implementation for 2x2 determinant */ +SRSLTE_API __m128 srslte_mat_2x2_det_sse(__m128 a00, __m128 a01, __m128 a10, __m128 a11); + +/* SSE implementation for Zero Forcing (ZF) solver */ +SRSLTE_API void srslte_mat_2x2_zf_sse(__m128 y0, __m128 y1, + __m128 h00, __m128 h01, __m128 h10, __m128 h11, + __m128 *x0, __m128 *x1, + float norm); + +/* SSE implementation for Minimum Mean Squared Error (MMSE) solver */ +SRSLTE_API void srslte_mat_2x2_mmse_sse(__m128 y0, __m128 y1, + __m128 h00, __m128 h01, __m128 h10, __m128 h11, + __m128 *x0, __m128 *x1, + float noise_estimate, float norm); + +#endif /* LV_HAVE_SSE */ + +#ifdef LV_HAVE_AVX + +/* AVX implementation for complex reciprocal */ +SRSLTE_API __m256 srslte_mat_cf_recip_avx(__m256 a); + +/* AVX implementation for 2x2 determinant */ +SRSLTE_API __m256 srslte_mat_2x2_det_avx(__m256 a00, __m256 a01, __m256 a10, __m256 a11); + +/* AVX implementation for Zero Forcing (ZF) solver */ +SRSLTE_API void srslte_mat_2x2_zf_avx(__m256 y0, __m256 y1, + __m256 h00, __m256 h01, __m256 h10, __m256 h11, + __m256 *x0, __m256 *x1, + float norm); + +/* AVX implementation for Minimum Mean Squared Error (MMSE) solver */ +SRSLTE_API void srslte_mat_2x2_mmse_avx(__m256 y0, __m256 y1, + __m256 h00, __m256 h01, __m256 h10, __m256 h11, + __m256 *x0, __m256 *x1, + float noise_estimate, float norm); + +#endif /* LV_HAVE_AVX */ + +#endif /* SRSLTE_MAT_H */ diff --git a/lib/include/srslte/phy/utils/simd.h b/lib/include/srslte/phy/utils/simd.h new file mode 100644 index 000000000..420d07213 --- /dev/null +++ b/lib/include/srslte/phy/utils/simd.h @@ -0,0 +1,81 @@ +/** + * + * \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/. + * + */ + +#ifndef SRSLTE_SIMD_H_H +#define SRSLTE_SIMD_H_H + +/* + * SSE Macros + */ +#ifdef LV_HAVE_SSE +#define _MM_SWAP(X) ((__m128)_mm_shuffle_ps(X, X, _MM_SHUFFLE(2,3,0,1))) +#define _MM_PERM(X) ((__m128)_mm_shuffle_ps(X, X, _MM_SHUFFLE(2,1,3,0))) +#define _MM_MULJ_PS(X) _MM_SWAP(_MM_CONJ_PS(X)) +#define _MM_CONJ_PS(X) (_mm_xor_ps(X, _mm_set_ps(-0.0f, 0.0f, -0.0f, 0.0f))) +#define _MM_SQMOD_PS(X) _MM_PERM(_mm_hadd_ps(_mm_mul_ps(X,X), _mm_set_ps(0.0f, 0.0f, 0.0f, 0.0f))) +#define _MM_PROD_PS(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))) + +#endif /* LV_HAVE_SSE */ + +/* + * AVX Macros + */ +#ifdef LV_HAVE_AVX + +#define _MM256_MULJ_PS(X) _mm256_permute_ps(_MM256_CONJ_PS(X), 0b10110001) +#define _MM256_CONJ_PS(X) (_mm256_xor_ps(X, _mm256_set_ps(-0.0f, 0.0f, -0.0f, 0.0f, -0.0f, 0.0f, -0.0f, 0.0f))) + +#ifdef LV_HAVE_FMA +#define _MM256_SQMOD_PS(A, B) _mm256_permute_ps(_mm256_hadd_ps(_mm256_fmadd_ps(A, A, _mm256_mul_ps(B,B)), \ + _mm256_set_ps(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), 0b11011100) +#define _MM256_PROD_PS(a, b) _mm256_fmaddsub_ps(a,_mm256_moveldup_ps(b),\ + _mm256_mul_ps(_mm256_shuffle_ps(a,a,0xB1),_mm256_movehdup_ps(b))) +#else +#define _MM256_SQMOD_PS(A, B) _mm256_permute_ps(_mm256_hadd_ps(_mm256_add_ps(_mm256_mul_ps(A,A), _mm256_mul_ps(B,B)), \ + _mm256_set_ps(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), 0b11011100) +#define _MM256_PROD_PS(a, b) _mm256_addsub_ps(_mm256_mul_ps(a,_mm256_moveldup_ps(b)),\ + _mm256_mul_ps(_mm256_shuffle_ps(a,a,0xB1),_mm256_movehdup_ps(b))) +#endif /* LV_HAVE_FMA */ +#endif /* LV_HAVE_AVX */ + + +/* + * AVX extension with FMA Macros + */ +#ifdef LV_HAVE_FMA + +#define _MM256_SQMOD_ADD_PS(A, B, C) _mm256_permute_ps(_mm256_hadd_ps(_mm256_fmadd_ps(A, A, _mm256_fmadd_ps(B, B, C)),\ + _mm256_set_ps(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), 0b11011100) + +#define _MM256_PROD_ADD_PS(A, B, C) _mm256_fmaddsub_ps(A,_mm256_moveldup_ps(B),\ + _mm256_fmaddsub_ps(_mm256_shuffle_ps(A,A,0xB1),_mm256_movehdup_ps(B), C)) + +#define _MM256_PROD_SUB_PS(A, B, C) _mm256_fmaddsub_ps(A,_mm256_moveldup_ps(B),\ + _mm256_fmsubadd_ps(_mm256_shuffle_ps(A,A,0xB1),_mm256_movehdup_ps(B), C)) +#endif /* LV_HAVE_FMA */ + +#endif //SRSLTE_SIMD_H_H diff --git a/lib/src/phy/mimo/precoding.c b/lib/src/phy/mimo/precoding.c index 0e898448a..02faa6e1c 100644 --- a/lib/src/phy/mimo/precoding.c +++ b/lib/src/phy/mimo/precoding.c @@ -36,14 +36,14 @@ #ifdef LV_HAVE_SSE #include -#include "srslte/phy/utils/algebra.h" +#include "srslte/phy/utils/mat.h" 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 -#include "srslte/phy/utils/algebra.h" +#include "srslte/phy/utils/mat.h" 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 @@ -597,7 +597,7 @@ int srslte_predecoding_ccd_2x2_zf_avx(cf_t *y[SRSLTE_MAX_PORTS], __m256 x0, x1; - srslte_algebra_2x2_zf_avx(y0, y1, h00, h01, h10, h11, &x0, &x1, 2.0f); + srslte_mat_2x2_zf_avx(y0, y1, h00, h01, h10, h11, &x0, &x1, 2.0f); _mm256_store_ps((float *) &x[0][i], x0); _mm256_store_ps((float *) &x[1][i], x1); @@ -634,7 +634,7 @@ int srslte_predecoding_ccd_2x2_zf_sse(cf_t *y[SRSLTE_MAX_PORTS], __m128 x0, x1; - srslte_algebra_2x2_zf_sse(y0, y1, h00, h01, h10, h11, &x0, &x1, 2.0f); + srslte_mat_2x2_zf_sse(y0, y1, h00, h01, h10, h11, &x0, &x1, 2.0f); _mm_store_ps((float *) &x[0][i], x0); _mm_store_ps((float *) &x[1][i], x1); @@ -731,7 +731,7 @@ int srslte_predecoding_ccd_2x2_mmse_avx(cf_t *y[SRSLTE_MAX_PORTS], __m256 x0, x1; - srslte_algebra_2x2_mmse_avx(y0, y1, h00, h01, h10, h11, &x0, &x1, noise_estimate, 2.0f); + srslte_mat_2x2_mmse_avx(y0, y1, h00, h01, h10, h11, &x0, &x1, noise_estimate, 2.0f); _mm256_store_ps((float *) &x[0][i], x0); _mm256_store_ps((float *) &x[1][i], x1); @@ -768,7 +768,7 @@ int srslte_predecoding_ccd_2x2_mmse_sse(cf_t *y[SRSLTE_MAX_PORTS], __m128 x0, x1; - srslte_algebra_2x2_mmse_sse(y0, y1, h00, h01, h10, h11, &x0, &x1, noise_estimate, 2.0f); + srslte_mat_2x2_mmse_sse(y0, y1, h00, h01, h10, h11, &x0, &x1, noise_estimate, 2.0f); _mm_store_ps((float *) &x[0][i], x0); _mm_store_ps((float *) &x[1][i], x1); @@ -789,7 +789,7 @@ int srslte_predecoding_ccd_2x2_mmse_gen(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLT h10 = +h[0][1][i] + h[1][1][i]; h01 = +h[0][0][i] - h[1][0][i]; h11 = +h[0][1][i] - h[1][1][i]; - srslte_algebra_2x2_mmse_gen(y[0][i], y[1][i], h00, h01, h10, h11, &x[0][i], &x[1][i], noise_estimate, 2.0f); + srslte_mat_2x2_mmse_gen(y[0][i], y[1][i], h00, h01, h10, h11, &x[0][i], &x[1][i], noise_estimate, 2.0f); i++; @@ -798,7 +798,7 @@ int srslte_predecoding_ccd_2x2_mmse_gen(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLT h10 = h[0][1][i] - h[1][1][i]; h01 = h[0][0][i] + h[1][0][i]; h11 = h[0][1][i] + h[1][1][i]; - srslte_algebra_2x2_mmse_gen(y[0][i], y[1][i], h00, h01, h10, h11, &x[0][i], &x[1][i], noise_estimate, 2.0f); + srslte_mat_2x2_mmse_gen(y[0][i], y[1][i], h00, h01, h10, h11, &x[0][i], &x[1][i], noise_estimate, 2.0f); } return SRSLTE_SUCCESS; } @@ -886,7 +886,7 @@ int srslte_predecoding_multiplex_2x2_zf_avx(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[S __m256 x0, x1; - srslte_algebra_2x2_zf_avx(y0, y1, h00, h01, h10, h11, &x0, &x1, norm); + srslte_mat_2x2_zf_avx(y0, y1, h00, h01, h10, h11, &x0, &x1, norm); _mm256_store_ps((float *) &x[0][i], x0); _mm256_store_ps((float *) &x[1][i], x1); @@ -954,7 +954,7 @@ int srslte_predecoding_multiplex_2x2_zf_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[S __m128 x0, x1; - srslte_algebra_2x2_zf_sse(y0, y1, h00, h01, h10, h11, &x0, &x1, norm); + srslte_mat_2x2_zf_sse(y0, y1, h00, h01, h10, h11, &x0, &x1, norm); _mm_store_ps((float *) &x[0][i], x0); _mm_store_ps((float *) &x[1][i], x1); @@ -1078,7 +1078,7 @@ int srslte_predecoding_multiplex_2x2_mmse_avx(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h __m256 x0, x1; - srslte_algebra_2x2_mmse_avx(y0, y1, h00, h01, h10, h11, &x0, &x1, noise_estimate, norm); + srslte_mat_2x2_mmse_avx(y0, y1, h00, h01, h10, h11, &x0, &x1, noise_estimate, norm); _mm256_store_ps((float *) &x[0][i], x0); _mm256_store_ps((float *) &x[1][i], x1); @@ -1148,7 +1148,7 @@ int srslte_predecoding_multiplex_2x2_mmse_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h __m128 x0, x1; - srslte_algebra_2x2_mmse_sse(y0, y1, h00, h01, h10, h11, &x0, &x1, noise_estimate, norm); + srslte_mat_2x2_mmse_sse(y0, y1, h00, h01, h10, h11, &x0, &x1, noise_estimate, norm); _mm_store_ps((float *) &x[0][i], x0); _mm_store_ps((float *) &x[1][i], x1); @@ -1205,7 +1205,7 @@ int srslte_predecoding_multiplex_2x2_mmse_gen(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h return SRSLTE_ERROR; } - srslte_algebra_2x2_mmse_gen(y[0][i], y[1][i], h00, h01, h10, h11, &x[0][i], &x[1][i], noise_estimate, norm); + srslte_mat_2x2_mmse_gen(y[0][i], y[1][i], h00, h01, h10, h11, &x[0][i], &x[1][i], noise_estimate, norm); } return SRSLTE_SUCCESS; } @@ -2295,8 +2295,8 @@ int srslte_precoding_pmi_select_2l_sse(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORT c11 = _mm_add_ps(c11, sse_noise_estimate); /* 5. detC */ - __m128 detC = srslte_algebra_2x2_det_sse(c00, c01, c10, c11); - __m128 inv_detC = srslte_algebra_cf_recip_sse(detC); + __m128 detC = srslte_mat_2x2_det_sse(c00, c01, c10, c11); + __m128 inv_detC = srslte_mat_cf_recip_sse(detC); inv_detC = _mm_mul_ps(sse_noise_estimate, inv_detC); __m128 den0 = _MM_PROD_PS(c00, inv_detC); @@ -2442,8 +2442,8 @@ int srslte_precoding_pmi_select_2l_avx(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORT c11 = _mm256_add_ps(c11, avx_noise_estimate); /* 5. detC */ - __m256 detC = srslte_algebra_2x2_det_avx(c00, c01, c10, c11); - __m256 inv_detC = srslte_algebra_cf_recip_avx(detC); + __m256 detC = srslte_mat_2x2_det_avx(c00, c01, c10, c11); + __m256 inv_detC = srslte_mat_cf_recip_avx(detC); inv_detC = _mm256_mul_ps(avx_noise_estimate, inv_detC); __m256 den0 = _MM256_PROD_PS(c00, inv_detC); @@ -2530,7 +2530,7 @@ float srslte_precoding_2x2_cn_gen(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], u cf_t h10 = h[0][1][i]; cf_t h11 = h[1][1][i]; - cn_avg += srslte_algebra_2x2_cn(h00, h01, h10, h11); + cn_avg += srslte_mat_2x2_cn(h00, h01, h10, h11); count++; } diff --git a/lib/src/phy/utils/algebra.c b/lib/src/phy/utils/mat.c similarity index 82% rename from lib/src/phy/utils/algebra.c rename to lib/src/phy/utils/mat.c index 943ae57dd..3c81d4a13 100644 --- a/lib/src/phy/utils/algebra.c +++ b/lib/src/phy/utils/mat.c @@ -28,23 +28,23 @@ #include #include -#include "srslte/phy/utils/algebra.h" +#include "srslte/phy/utils/mat.h" /* Generic implementation for complex reciprocal */ -inline cf_t srslte_algebra_cf_recip_gen(cf_t a) { +inline cf_t srslte_mat_cf_recip_gen(cf_t a) { return conjf(a) / (crealf(a) * crealf(a) + cimagf(a) * cimagf(a)); } /* Generic implementation for 2x2 determinant */ -inline cf_t srslte_algebra_2x2_det_gen(cf_t a00, cf_t a01, cf_t a10, cf_t a11) { +inline cf_t srslte_mat_2x2_det_gen(cf_t a00, cf_t a01, cf_t a10, cf_t a11) { return a00 * a11 - a01 * a10; } /* 2x2 Matrix inversion, generic implementation */ -inline void srslte_algebra_2x2_inv_gen(cf_t a00, cf_t a01, cf_t a10, cf_t a11, +inline void srslte_mat_2x2_inv_gen(cf_t a00, cf_t a01, cf_t a10, cf_t a11, cf_t *r00, cf_t *r01, cf_t *r10, cf_t *r11) { - cf_t div = srslte_algebra_cf_recip_gen(srslte_algebra_2x2_det_gen(a00, a01, a10, a11)); + cf_t div = srslte_mat_cf_recip_gen(srslte_mat_2x2_det_gen(a00, a01, a10, a11)); *r00 = a11 * div; *r01 = -a01 * div; *r10 = -a10 * div; @@ -52,15 +52,15 @@ inline void srslte_algebra_2x2_inv_gen(cf_t a00, cf_t a01, cf_t a10, cf_t a11, } /* Generic implementation for Zero Forcing (ZF) solver */ -inline void srslte_algebra_2x2_zf_gen(cf_t y0, cf_t y1, cf_t h00, cf_t h01, cf_t h10, cf_t h11, +inline void srslte_mat_2x2_zf_gen(cf_t y0, cf_t y1, cf_t h00, cf_t h01, cf_t h10, cf_t h11, cf_t *x0, cf_t *x1, float norm) { - cf_t _norm = srslte_algebra_cf_recip_gen(srslte_algebra_2x2_det_gen(h00, h01, h10, h11)) * norm; + cf_t _norm = srslte_mat_cf_recip_gen(srslte_mat_2x2_det_gen(h00, h01, h10, h11)) * norm; *x0 = (y0 * h11 - h01 * y1) * _norm; *x1 = (y1 * h00 - h10 * y0) * _norm; } /* Generic implementation for Minimum Mean Squared Error (MMSE) solver */ -inline void srslte_algebra_2x2_mmse_gen(cf_t y0, cf_t y1, cf_t h00, cf_t h01, cf_t h10, cf_t h11, +inline void srslte_mat_2x2_mmse_gen(cf_t y0, cf_t y1, cf_t h00, cf_t h01, cf_t h10, cf_t h11, cf_t *x0, cf_t *x1, float noise_estimate, float norm) { /* Create conjugated matrix */ cf_t _h00 = conjf(h00); @@ -79,7 +79,7 @@ inline void srslte_algebra_2x2_mmse_gen(cf_t y0, cf_t y1, cf_t h00, cf_t h01, cf cf_t b01 = -a01; cf_t b10 = -a10; cf_t b11 = a00; - cf_t _norm = norm * srslte_algebra_cf_recip_gen(srslte_algebra_2x2_det_gen(a00, a01, a10, a11)); + cf_t _norm = norm * srslte_mat_cf_recip_gen(srslte_mat_2x2_det_gen(a00, a01, a10, a11)); /* 3. W = inv(H' x H + No) x H' = B x H' */ @@ -93,7 +93,7 @@ inline void srslte_algebra_2x2_mmse_gen(cf_t y0, cf_t y1, cf_t h00, cf_t h01, cf *x1 = (y0 * w10 + y1 * w11) * _norm; } -inline float srslte_algebra_2x2_cn(cf_t h00, cf_t h01, cf_t h10, cf_t h11) { +inline float srslte_mat_2x2_cn(cf_t h00, cf_t h01, cf_t h10, cf_t h11) { /* 1. A = H * H' (A = A') */ float a00 = crealf(h00) * crealf(h00) + crealf(h01) * crealf(h01) + cimagf(h00) * cimagf(h00) + cimagf(h01) * cimagf(h01); @@ -118,7 +118,7 @@ inline float srslte_algebra_2x2_cn(cf_t h00, cf_t h01, cf_t h10, cf_t h11) { #ifdef LV_HAVE_SSE /* SSE implementation for complex reciprocal */ -inline __m128 srslte_algebra_cf_recip_sse(__m128 a) { +inline __m128 srslte_mat_cf_recip_sse(__m128 a) { __m128 conj = _MM_CONJ_PS(a); __m128 sqabs = _mm_mul_ps(a, a); sqabs = _mm_add_ps(_mm_movehdup_ps(sqabs), _mm_moveldup_ps(sqabs)); @@ -129,25 +129,25 @@ inline __m128 srslte_algebra_cf_recip_sse(__m128 a) { } /* SSE implementation for 2x2 determinant */ -inline __m128 srslte_algebra_2x2_det_sse(__m128 a00, __m128 a01, __m128 a10, __m128 a11) { +inline __m128 srslte_mat_2x2_det_sse(__m128 a00, __m128 a01, __m128 a10, __m128 a11) { return _mm_sub_ps(_MM_PROD_PS(a00, a11), _MM_PROD_PS(a01, a10)); } /* SSE implementation for Zero Forcing (ZF) solver */ -inline void srslte_algebra_2x2_zf_sse(__m128 y0, __m128 y1, __m128 h00, __m128 h01, __m128 h10, __m128 h11, +inline void srslte_mat_2x2_zf_sse(__m128 y0, __m128 y1, __m128 h00, __m128 h01, __m128 h10, __m128 h11, __m128 *x0, __m128 *x1, float norm) { __m128 detmult1 = _MM_PROD_PS(h00, h11); __m128 detmult2 = _MM_PROD_PS(h01, h10); __m128 det = _mm_sub_ps(detmult1, detmult2); - __m128 detrec = _mm_mul_ps(srslte_algebra_cf_recip_sse(det), _mm_set1_ps(norm)); + __m128 detrec = _mm_mul_ps(srslte_mat_cf_recip_sse(det), _mm_set1_ps(norm)); *x0 = _MM_PROD_PS(_mm_sub_ps(_MM_PROD_PS(h11, y0), _MM_PROD_PS(h01, y1)), detrec); *x1 = _MM_PROD_PS(_mm_sub_ps(_MM_PROD_PS(h00, y1), _MM_PROD_PS(h10, y0)), detrec); } /* SSE implementation for Minimum Mean Squared Error (MMSE) solver */ -inline void srslte_algebra_2x2_mmse_sse(__m128 y0, __m128 y1, __m128 h00, __m128 h01, __m128 h10, __m128 h11, +inline void srslte_mat_2x2_mmse_sse(__m128 y0, __m128 y1, __m128 h00, __m128 h01, __m128 h10, __m128 h11, __m128 *x0, __m128 *x1, float noise_estimate, float norm) { __m128 _noise_estimate = _mm_set_ps(0.0f, noise_estimate, 0.0f, noise_estimate); __m128 _norm = _mm_set1_ps(norm); @@ -169,7 +169,7 @@ inline void srslte_algebra_2x2_mmse_sse(__m128 y0, __m128 y1, __m128 h00, __m128 __m128 b01 = _mm_xor_ps(a01, _mm_set1_ps(-0.0f)); __m128 b10 = _mm_xor_ps(a10, _mm_set1_ps(-0.0f)); __m128 b11 = a00; - _norm = _mm_mul_ps(_norm, srslte_algebra_cf_recip_sse(srslte_algebra_2x2_det_sse(a00, a01, a10, a11))); + _norm = _mm_mul_ps(_norm, srslte_mat_cf_recip_sse(srslte_mat_2x2_det_sse(a00, a01, a10, a11))); /* 3. W = inv(H' x H + No) x H' = B x H' */ @@ -188,7 +188,7 @@ inline void srslte_algebra_2x2_mmse_sse(__m128 y0, __m128 y1, __m128 h00, __m128 #ifdef LV_HAVE_AVX /* AVX implementation for complex reciprocal */ -inline __m256 srslte_algebra_cf_recip_avx(__m256 a) { +inline __m256 srslte_mat_cf_recip_avx(__m256 a) { __m256 conj = _MM256_CONJ_PS(a); __m256 sqabs = _mm256_mul_ps(a, a); sqabs = _mm256_add_ps(_mm256_movehdup_ps(sqabs), _mm256_moveldup_ps(sqabs)); @@ -199,7 +199,7 @@ inline __m256 srslte_algebra_cf_recip_avx(__m256 a) { } /* AVX implementation for 2x2 determinant */ -inline __m256 srslte_algebra_2x2_det_avx(__m256 a00, __m256 a01, __m256 a10, __m256 a11) { +inline __m256 srslte_mat_2x2_det_avx(__m256 a00, __m256 a01, __m256 a10, __m256 a11) { #ifdef LV_HAVE_FMA return _MM256_PROD_SUB_PS(a00, a11, _MM256_PROD_PS(a01, a10)); #else @@ -208,11 +208,11 @@ inline __m256 srslte_algebra_2x2_det_avx(__m256 a00, __m256 a01, __m256 a10, __m } /* AVX implementation for Zero Forcing (ZF) solver */ -inline void srslte_algebra_2x2_zf_avx(__m256 y0, __m256 y1, __m256 h00, __m256 h01, __m256 h10, __m256 h11, +inline void srslte_mat_2x2_zf_avx(__m256 y0, __m256 y1, __m256 h00, __m256 h01, __m256 h10, __m256 h11, __m256 *x0, __m256 *x1, float norm) { - __m256 det = srslte_algebra_2x2_det_avx(h00, h01, h10, h11); - __m256 detrec = _mm256_mul_ps(srslte_algebra_cf_recip_avx(det), _mm256_set1_ps(norm)); + __m256 det = srslte_mat_2x2_det_avx(h00, h01, h10, h11); + __m256 detrec = _mm256_mul_ps(srslte_mat_cf_recip_avx(det), _mm256_set1_ps(norm)); #ifdef LV_HAVE_FMA *x0 = _MM256_PROD_PS(_MM256_PROD_SUB_PS(h11, y0, _MM256_PROD_PS(h01, y1)), detrec); @@ -224,7 +224,7 @@ inline void srslte_algebra_2x2_zf_avx(__m256 y0, __m256 y1, __m256 h00, __m256 h } /* AVX implementation for Minimum Mean Squared Error (MMSE) solver */ -inline void srslte_algebra_2x2_mmse_avx(__m256 y0, __m256 y1, __m256 h00, __m256 h01, __m256 h10, __m256 h11, +inline void srslte_mat_2x2_mmse_avx(__m256 y0, __m256 y1, __m256 h00, __m256 h01, __m256 h10, __m256 h11, __m256 *x0, __m256 *x1, float noise_estimate, float norm) { __m256 _noise_estimate = _mm256_set_ps(0.0f, noise_estimate, 0.0f, noise_estimate, 0.0f, noise_estimate, 0.0f, noise_estimate); @@ -254,7 +254,7 @@ inline void srslte_algebra_2x2_mmse_avx(__m256 y0, __m256 y1, __m256 h00, __m256 __m256 b01 = _mm256_xor_ps(a01, _mm256_set1_ps(-0.0f)); __m256 b10 = _mm256_xor_ps(a10, _mm256_set1_ps(-0.0f)); __m256 b11 = a00; - _norm = _mm256_mul_ps(_norm, srslte_algebra_cf_recip_avx(srslte_algebra_2x2_det_avx(a00, a01, a10, a11))); + _norm = _mm256_mul_ps(_norm, srslte_mat_cf_recip_avx(srslte_mat_2x2_det_avx(a00, a01, a10, a11))); /* 3. W = inv(H' x H + No) x H' = B x H' */ diff --git a/lib/src/phy/utils/test/CMakeLists.txt b/lib/src/phy/utils/test/CMakeLists.txt index 1f516da8f..4dccbf2a0 100644 --- a/lib/src/phy/utils/test/CMakeLists.txt +++ b/lib/src/phy/utils/test/CMakeLists.txt @@ -37,7 +37,7 @@ add_test(dft_odd_dc dft_test -N 255 -b -d) # Odd-length, backwards first, handle # Algebra TEST ######################################################################## -add_executable(algebra_test algebra_test.c) +add_executable(algebra_test mat_test.c) target_link_libraries(algebra_test srslte_phy) add_test(algebra_2x2_zf_solver_test algebra_test -z) diff --git a/lib/src/phy/utils/test/algebra_test.c b/lib/src/phy/utils/test/mat_test.c similarity index 96% rename from lib/src/phy/utils/test/algebra_test.c rename to lib/src/phy/utils/test/mat_test.c index a5bc7e773..49be5c9ae 100644 --- a/lib/src/phy/utils/test/algebra_test.c +++ b/lib/src/phy/utils/test/mat_test.c @@ -32,7 +32,7 @@ #include #include -#include "srslte/phy/utils/algebra.h" +#include "srslte/phy/utils/mat.h" bool zf_solver = false; @@ -104,7 +104,7 @@ bool test_zf_solver_gen(void) { cf_t y0 = x0_gold * h00 + x1_gold * h01; cf_t y1 = x0_gold * h10 + x1_gold * h11; - srslte_algebra_2x2_zf_gen(y0, y1, h00, h01, h10, h11, &x0, &x1, 1.0f); + srslte_mat_2x2_zf_gen(y0, y1, h00, h01, h10, h11, &x0, &x1, 1.0f); cf_error0 = x0 - x0_gold; cf_error1 = x1 - x1_gold; @@ -127,7 +127,7 @@ bool test_mmse_solver_gen(void) { cf_t y0 = x0_gold * h00 + x1_gold * h01; cf_t y1 = x0_gold * h10 + x1_gold * h11; - srslte_algebra_2x2_mmse_gen(y0, y1, h00, h01, h10, h11, &x0, &x1, 0.0f, 1.0f); + srslte_mat_2x2_mmse_gen(y0, y1, h00, h01, h10, h11, &x0, &x1, 0.0f, 1.0f); cf_error0 = x0 - x0_gold; cf_error1 = x1 - x1_gold; @@ -171,7 +171,7 @@ bool test_zf_solver_sse(void) { __m128 _x0, _x1; - srslte_algebra_2x2_zf_sse(_y0, _y1, _h00, _h01, _h10, _h11, &_x0, &_x1, 1.0f); + srslte_mat_2x2_zf_sse(_y0, _y1, _h00, _h01, _h10, _h11, &_x0, &_x1, 1.0f); __attribute__((aligned(128))) cf_t x0[2]; @@ -225,7 +225,7 @@ bool test_mmse_solver_sse(void) { __m128 _x0, _x1; - srslte_algebra_2x2_mmse_sse(_y0, _y1, _h00, _h01, _h10, _h11, &_x0, &_x1, 0.0f, 1.0f); + srslte_mat_2x2_mmse_sse(_y0, _y1, _h00, _h01, _h10, _h11, &_x0, &_x1, 0.0f, 1.0f); __attribute__((aligned(128))) cf_t x0[2]; @@ -289,7 +289,7 @@ bool test_zf_solver_avx(void) { __m256 _x0, _x1; - srslte_algebra_2x2_zf_avx(_y0, _y1, _h00, _h01, _h10, _h11, &_x0, &_x1, 1.0f); + srslte_mat_2x2_zf_avx(_y0, _y1, _h00, _h01, _h10, _h11, &_x0, &_x1, 1.0f); __attribute__((aligned(256))) cf_t x0[4]; @@ -349,7 +349,7 @@ bool test_mmse_solver_avx(void) { __m256 _x0, _x1; - srslte_algebra_2x2_mmse_avx(_y0, _y1, _h00, _h01, _h10, _h11, &_x0, &_x1, 0.0f, 1.0f); + srslte_mat_2x2_mmse_avx(_y0, _y1, _h00, _h01, _h10, _h11, &_x0, &_x1, 0.0f, 1.0f); __attribute__((aligned(256))) cf_t x0[4]; From c2b5499284e00087e2faa1d6cc58a9604e01996a Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Thu, 31 Aug 2017 12:35:27 +0200 Subject: [PATCH 35/60] Removed SCH object vector from PDSCH object (only SCH object from now on) --- lib/include/srslte/phy/phch/pdsch.h | 2 +- lib/src/phy/phch/pdsch.c | 33 ++++++++++++----------------- 2 files changed, 15 insertions(+), 20 deletions(-) diff --git a/lib/include/srslte/phy/phch/pdsch.h b/lib/include/srslte/phy/phch/pdsch.h index a1016aaf5..a30851648 100644 --- a/lib/include/srslte/phy/phch/pdsch.h +++ b/lib/include/srslte/phy/phch/pdsch.h @@ -74,7 +74,7 @@ typedef struct SRSLTE_API { // This is to generate the scrambling seq for multiple CRNTIs srslte_pdsch_user_t **users; - srslte_sch_t dl_sch[SRSLTE_MAX_CODEWORDS]; + srslte_sch_t dl_sch; } srslte_pdsch_t; diff --git a/lib/src/phy/phch/pdsch.c b/lib/src/phy/phch/pdsch.c index 8a1d66be1..018fb96e5 100644 --- a/lib/src/phy/phch/pdsch.c +++ b/lib/src/phy/phch/pdsch.c @@ -227,12 +227,12 @@ int srslte_pdsch_init_multi(srslte_pdsch_t *q, srslte_cell_t cell, uint32_t nof_ srslte_modem_table_bytes(&q->mod[i]); } - for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { - if (srslte_sch_init(&q->dl_sch[i])) { - ERROR("Initiating DL SCH"); - goto clean; - } + if (srslte_sch_init(&q->dl_sch)) { + ERROR("Initiating DL SCH"); + goto clean; + } + for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { // Allocate int16_t for reception (LLRs) q->e[i] = srslte_vec_malloc(sizeof(int16_t) * q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM)); if (!q->e[i]) { @@ -313,12 +313,11 @@ void srslte_pdsch_free(srslte_pdsch_t *q) { if (q->d[i]) { free(q->d[i]); } - - /* Free sch objects */ - srslte_sch_free(&q->dl_sch[i]); - } + /* Free sch objects */ + srslte_sch_free(&q->dl_sch); + for (i = 0; i < q->cell.nof_ports; i++) { if (q->x[i]) { free(q->x[i]); @@ -452,7 +451,6 @@ int srslte_pdsch_set_rnti(srslte_pdsch_t *q, uint16_t rnti) { static int srslte_pdsch_codeword_encode(srslte_pdsch_t *pdsch, srslte_pdsch_cfg_t *cfg, srslte_softbuffer_tx_t *softbuffer, uint16_t rnti, uint8_t *data, uint32_t codeword_idx) { - srslte_sch_t *dl_sch = &pdsch->dl_sch[codeword_idx]; srslte_ra_nbits_t *nbits = &cfg->nbits[codeword_idx]; srslte_ra_mcs_t *mcs = &cfg->grant.mcs[codeword_idx]; uint32_t rv = cfg->rv[codeword_idx]; @@ -463,7 +461,7 @@ static int srslte_pdsch_codeword_encode(srslte_pdsch_t *pdsch, srslte_pdsch_cfg_ nbits->nof_re, nbits->nof_bits, rv); /* Channel coding */ - if (srslte_dlsch_encode2(dl_sch, cfg, softbuffer, data, pdsch->e[codeword_idx], codeword_idx)) { + if (srslte_dlsch_encode2(&pdsch->dl_sch, cfg, softbuffer, data, pdsch->e[codeword_idx], codeword_idx)) { ERROR("Error encoding TB %d", codeword_idx); return SRSLTE_ERROR; } @@ -497,7 +495,6 @@ static int srslte_pdsch_codeword_encode(srslte_pdsch_t *pdsch, srslte_pdsch_cfg_ static int srslte_pdsch_codeword_decode(srslte_pdsch_t *pdsch, srslte_pdsch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffer, uint16_t rnti, uint8_t *data, uint32_t codeword_idx) { - srslte_sch_t *dl_sch = &pdsch->dl_sch[codeword_idx]; srslte_ra_nbits_t *nbits = &cfg->nbits[codeword_idx]; srslte_ra_mcs_t *mcs = &cfg->grant.mcs[codeword_idx]; uint32_t rv = cfg->rv[codeword_idx]; @@ -526,7 +523,7 @@ static int srslte_pdsch_codeword_decode(srslte_pdsch_t *pdsch, srslte_pdsch_cfg_ srslte_sequence_free(&seq); } - return srslte_dlsch_decode2(dl_sch, cfg, softbuffer, pdsch->e[codeword_idx], data, codeword_idx); + return srslte_dlsch_decode2(&pdsch->dl_sch, cfg, softbuffer, pdsch->e[codeword_idx], data, codeword_idx); } return SRSLTE_SUCCESS; @@ -741,7 +738,7 @@ int srslte_pdsch_encode(srslte_pdsch_t *q, } memset(&x[q->cell.nof_ports], 0, sizeof(cf_t*) * (SRSLTE_MAX_LAYERS - q->cell.nof_ports)); - if (srslte_dlsch_encode(&q->dl_sch[0], cfg, softbuffer, data, q->e[0])) { + if (srslte_dlsch_encode(&q->dl_sch, cfg, softbuffer, data, q->e[0])) { fprintf(stderr, "Error encoding TB\n"); return SRSLTE_ERROR; } @@ -852,17 +849,15 @@ int srslte_pdsch_encode_multi(srslte_pdsch_t *q, } void srslte_pdsch_set_max_noi(srslte_pdsch_t *q, uint32_t max_iter) { - for (int cw = 0; cw < SRSLTE_MAX_CODEWORDS; cw++) { - srslte_sch_set_max_noi(&q->dl_sch[cw], max_iter); - } + srslte_sch_set_max_noi(&q->dl_sch, max_iter); } float srslte_pdsch_average_noi(srslte_pdsch_t *q) { - return q->dl_sch[0].average_nof_iterations; + return q->dl_sch.average_nof_iterations; } uint32_t srslte_pdsch_last_noi(srslte_pdsch_t *q) { - return q->dl_sch[0].nof_iterations; + return q->dl_sch.nof_iterations; } From fee8337c67ff57cabfdfce6ee01a3748f96e124e Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Thu, 31 Aug 2017 14:22:42 +0200 Subject: [PATCH 36/60] Removed unused function entries --- lib/include/srslte/phy/phch/ra.h | 23 +---------------------- lib/include/srslte/phy/rf/rf.h | 17 +---------------- 2 files changed, 2 insertions(+), 38 deletions(-) diff --git a/lib/include/srslte/phy/phch/ra.h b/lib/include/srslte/phy/phch/ra.h index 58e9585a5..9f31a0218 100644 --- a/lib/include/srslte/phy/phch/ra.h +++ b/lib/include/srslte/phy/phch/ra.h @@ -208,28 +208,7 @@ SRSLTE_API void srslte_ra_dl_grant_to_nbits(srslte_ra_dl_grant_t *grant, uint32_t sf_idx, srslte_ra_nbits_t nbits[SRSLTE_MAX_CODEWORDS]); -SRSLTE_API void srslte_ra_dl_grant_to_nbits_multi(srslte_ra_dl_grant_t *grant, - uint32_t cfi, - srslte_cell_t cell, - uint32_t sf_idx, - srslte_ra_nbits_t *nbits, - srslte_ra_nbits_t *nbits2); - -SRSLTE_API void srslte_ra_dl_grant_to_nbits_multi(srslte_ra_dl_grant_t *grant, - uint32_t cfi, - srslte_cell_t cell, - uint32_t sf_idx, - srslte_ra_nbits_t *nbits, - srslte_ra_nbits_t *nbits2); - -SRSLTE_API void srslte_ra_dl_grant_to_nbits_multi(srslte_ra_dl_grant_t *grant, - uint32_t cfi, - srslte_cell_t cell, - uint32_t sf_idx, - srslte_ra_nbits_t *nbits, - srslte_ra_nbits_t *nbits2); - -SRSLTE_API uint32_t srslte_ra_dl_approx_nof_re(srslte_cell_t cell, +SRSLTE_API uint32_t srslte_ra_dl_approx_nof_re(srslte_cell_t cell, uint32_t nof_prb, uint32_t nof_ctrl_symbols); diff --git a/lib/include/srslte/phy/rf/rf.h b/lib/include/srslte/phy/rf/rf.h index 50ced76d9..860e0a257 100644 --- a/lib/include/srslte/phy/rf/rf.h +++ b/lib/include/srslte/phy/rf/rf.h @@ -75,22 +75,7 @@ SRSLTE_API int srslte_rf_open_multi(srslte_rf_t *h, char *args, uint32_t nof_rx_antennas); -SRSLTE_API int srslte_rf_open_multi2(srslte_rf_t *h, - char *args, - uint32_t nof_tx_antennas, - uint32_t nof_rx_antennas); - -SRSLTE_API int srslte_rf_open_multi2(srslte_rf_t *h, - char *args, - uint32_t nof_tx_antennas, - uint32_t nof_rx_antennas); - -SRSLTE_API int srslte_rf_open_multi2(srslte_rf_t *h, - char *args, - uint32_t nof_tx_antennas, - uint32_t nof_rx_antennas); - -SRSLTE_API int srslte_rf_open_devname(srslte_rf_t *h, +SRSLTE_API int srslte_rf_open_devname(srslte_rf_t *h, char *devname, char *args); From 25a239753438decd2534a1a49e899a0a57d23820 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Thu, 31 Aug 2017 14:23:59 +0200 Subject: [PATCH 37/60] Removed .gitignore --- .gitignore | 21 --------------------- 1 file changed, 21 deletions(-) delete mode 100644 .gitignore diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 694c93182..000000000 --- a/.gitignore +++ /dev/null @@ -1,21 +0,0 @@ -# Ignore build directories -build -debug -cmake-build-debug - -# Ignore CLion IDE project files -.idea - -# Generated data files -*.dat - -# Temporal files -*~ - -# Internal development -matlab -mex -cmake/modules/BuildMex.cmake -cmake/modules/FindMATLAB.cmake -cmake/modules/FindOCTAVE.cmake - From b027ec3bda16182da9b0fab88a8b12fff6209dfc Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Thu, 31 Aug 2017 14:32:50 +0200 Subject: [PATCH 38/60] srslte_str2 functions convert to lower or capital letters --- lib/src/phy/common/phy_common.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/lib/src/phy/common/phy_common.c b/lib/src/phy/common/phy_common.c index cfb6d717b..977ebc5b1 100644 --- a/lib/src/phy/common/phy_common.c +++ b/lib/src/phy/common/phy_common.c @@ -125,6 +125,11 @@ bool srslte_N_id_1_isvalid(uint32_t N_id_1) { } srslte_mod_t srslte_str2mod (char * mod_str) { + int i = 0; + + /* Upper case */ + while (mod_str[i] &= (~' '), mod_str[++i]); + if (!strcmp(mod_str, "QPSK")) { return SRSLTE_MOD_QPSK; } else if (!strcmp(mod_str, "16QAM")) { @@ -437,13 +442,18 @@ struct lte_band lte_bands[SRSLTE_NOF_LTE_BANDS] = { int srslte_str2mimotype(char *mimo_type_str, srslte_mimo_type_t *type) { - if (!strcmp(mimo_type_str, "single") || !strcmp(mimo_type_str, "Port0")) { + int i = 0; + + /* Low case */ + while (mimo_type_str[i] |= ' ', mimo_type_str[++i]); + + if (!strcmp(mimo_type_str, "single") || !strcmp(mimo_type_str, "port0")) { *type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA; - } else if (!strcmp(mimo_type_str, "diversity") || !strcmp(mimo_type_str, "TxDiversity")) { + } else if (!strcmp(mimo_type_str, "diversity") || !strcmp(mimo_type_str, "txdiversity")) { *type = SRSLTE_MIMO_TYPE_TX_DIVERSITY; - } else if (!strcmp(mimo_type_str, "multiplex") || !strcmp(mimo_type_str, "SpatialMux")) { + } else if (!strcmp(mimo_type_str, "multiplex") || !strcmp(mimo_type_str, "spatialmux")) { *type = SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX; - } else if (!strcmp(mimo_type_str, "cdd") || !strcmp(mimo_type_str, "CDD")) { + } else if (!strcmp(mimo_type_str, "cdd")) { *type = SRSLTE_MIMO_TYPE_CDD; } else { return SRSLTE_ERROR; From c52023e4cc1e5a83077e91d97699d6f98be58899 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Thu, 31 Aug 2017 16:40:49 +0200 Subject: [PATCH 39/60] Solved PCH downlink bug --- srsue/src/mac/mac.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/srsue/src/mac/mac.cc b/srsue/src/mac/mac.cc index 1bc335bb1..7c569358a 100644 --- a/srsue/src/mac/mac.cc +++ b/srsue/src/mac/mac.cc @@ -282,6 +282,9 @@ void mac::new_grant_dl(mac_interface_phy::mac_grant_t grant, mac_interface_phy:: memcpy(&action->phy_grant, &grant.phy_grant, sizeof(srslte_phy_grant_t)); action->generate_ack = false; action->decode_enabled = true; + srslte_softbuffer_rx_reset_cb(&pch_softbuffer, 1); + action->payload_ptr[0] = pch_payload_buffer; + action->softbuffers[0] = &pch_softbuffer; action->rnti = grant.rnti; action->rv[0] = grant.rv[0]; if (grant.n_bytes[0] > pch_payload_buffer_sz) { From 02439f291d7b8ccfd6d9576e7fef2a192f65b39e Mon Sep 17 00:00:00 2001 From: Paul Sutton Date: Thu, 31 Aug 2017 19:25:22 +0100 Subject: [PATCH 40/60] Add n_prb description --- srsenb/enb.conf.example | 1 + 1 file changed, 1 insertion(+) diff --git a/srsenb/enb.conf.example b/srsenb/enb.conf.example index 7446df122..1c54cfc45 100644 --- a/srsenb/enb.conf.example +++ b/srsenb/enb.conf.example @@ -12,6 +12,7 @@ # mnc: Mobile Network Code # mme_addr: IP address of MME for S1 connnection # gtp_bind_addr: Local IP address to bind for GTP connection +# n_prb: Number of Physical Resource Blocks (6,15,25,50,75,100) # ##################################################################### [enb] From 409d81f43c82edf80c5298bdde2e0eb47d9ad107 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Fri, 1 Sep 2017 12:19:38 +0200 Subject: [PATCH 41/60] Corrected comments and a few lines refactor in pdsch --- lib/src/phy/mimo/precoding.c | 4 ++-- lib/src/phy/phch/pdsch.c | 18 ++++++++---------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/lib/src/phy/mimo/precoding.c b/lib/src/phy/mimo/precoding.c index 02faa6e1c..f1aab3b5d 100644 --- a/lib/src/phy/mimo/precoding.c +++ b/lib/src/phy/mimo/precoding.c @@ -1406,9 +1406,9 @@ int srslte_predecoding_multiplex(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_P #endif /* LV_HAVE_AVX */ } } else if (nof_ports == 4) { - ERROR("Error predecoding CCD: Only 2 ports supported"); + ERROR("Error predecoding multiplex: not implemented for %d Tx ports", nof_ports); } else { - fprintf(stderr, "Error predecoding CCD: Invalid combination of ports %d and rx antennax %d\n", nof_ports, nof_rxant); + ERROR("Error predecoding multiplex: Invalid combination of ports %d and rx antennax %d\n", nof_ports, nof_rxant); } return SRSLTE_ERROR; } diff --git a/lib/src/phy/phch/pdsch.c b/lib/src/phy/phch/pdsch.c index 018fb96e5..9f0e4ed12 100644 --- a/lib/src/phy/phch/pdsch.c +++ b/lib/src/phy/phch/pdsch.c @@ -611,21 +611,19 @@ int srslte_pdsch_decode_multi(srslte_pdsch_t *q, for (i = 0; i < cfg->nof_layers; i++) { x[i] = q->d[i]; } - - srslte_predecoding_type_multi(q->symbols, q->ce, x, q->nof_rx_antennas, q->cell.nof_ports, cfg->nof_layers, - cfg->codebook_idx, cfg->nbits[0].nof_re, cfg->mimo_type, noise_estimate); - } else { - /* number of layers equals number of ports */ - for (i = 0; i < cfg->nof_layers; i++) { - x[i] = q->x[i]; - } - memset(&x[cfg->nof_layers], 0, sizeof(cf_t*) * (SRSLTE_MAX_LAYERS - cfg->nof_layers)); + /* number of layers equals number of ports */ + for (i = 0; i < cfg->nof_layers; i++) { + x[i] = q->x[i]; + } + memset(&x[cfg->nof_layers], 0, sizeof(cf_t*) * (SRSLTE_MAX_LAYERS - cfg->nof_layers)); + } srslte_predecoding_type_multi(q->symbols, q->ce, x, q->nof_rx_antennas, q->cell.nof_ports, cfg->nof_layers, cfg->codebook_idx, cfg->nbits[0].nof_re, cfg->mimo_type, noise_estimate); - srslte_layerdemap_type(x, q->d, cfg->nof_layers, cfg->grant.nof_tb, + if (cfg->nof_layers != cfg->grant.nof_tb) { + srslte_layerdemap_type(x, q->d, cfg->nof_layers, cfg->grant.nof_tb, nof_symbols[0], nof_symbols, cfg->mimo_type); } From 2979833364308a947f3e2f618013ea3f97802943 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Fri, 1 Sep 2017 13:30:28 +0200 Subject: [PATCH 42/60] Improved how data is displayed in pdsch_ue --- lib/examples/pdsch_ue.c | 94 ++++++++++++++++++++++++----------------- 1 file changed, 55 insertions(+), 39 deletions(-) diff --git a/lib/examples/pdsch_ue.c b/lib/examples/pdsch_ue.c index 1a9f77c6f..0a5d2d81d 100644 --- a/lib/examples/pdsch_ue.c +++ b/lib/examples/pdsch_ue.c @@ -304,6 +304,12 @@ prog_args_t prog_args; uint32_t sfn = 0; // system frame number srslte_netsink_t net_sink, net_sink_signal; +/* Useful macros for printing lines which will disappear */ +#define PRINT_LINE_INIT() int this_nof_lines = 0; static int prev_nof_lines = 0 +#define PRINT_LINE(_fmt, ...) printf("\033[K" _fmt "\n", ##__VA_ARGS__); this_nof_lines++ +#define PRINT_LINE_RESET_CURSOR() printf("\033[%dA", this_nof_lines); prev_nof_lines = this_nof_lines +#define PRINT_LINE_ADVANCE_CURSOR() printf("\033[%dB", prev_nof_lines + 1) + int main(int argc, char **argv) { int ret; int decimate = 1; @@ -542,6 +548,7 @@ int main(int argc, char **argv) { while (!go_exit && (sf_cnt < prog_args.nof_subframes || prog_args.nof_subframes == -1)) { bool acks [SRSLTE_MAX_CODEWORDS] = {false}; char input[128]; + PRINT_LINE_INIT(); fd_set set; FD_ZERO(&set); @@ -668,55 +675,64 @@ int main(int argc, char **argv) { if (gain < 0) { gain = 10*log10(srslte_agc_get_gain(&ue_sync.agc)); } - if (cell.nof_ports == 1) { - printf("CFO: %+6.2f kHz, " - "SNR: %4.1f dB, " - "PDCCH-Miss: %5.2f%%, PDSCH-BLER: %5.2f%%\r", - - srslte_ue_sync_get_cfo(&ue_sync) / 1000, - 10 * log10(rsrp0 / noise), - 100 * (1 - (float) ue_dl.nof_detected / nof_trials), - (float) 100 * ue_dl.pkt_errors / ue_dl.pkts_total); + + /* Print transmission scheme */ + if (ue_dl.pdsch_cfg.mimo_type == SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX) { + PRINT_LINE(" Tx scheme: %s (codebook_idx=%d)", srslte_mimotype2str(ue_dl.pdsch_cfg.mimo_type), + ue_dl.pdsch_cfg.codebook_idx); } else { + PRINT_LINE(" Tx scheme: %s", srslte_mimotype2str(ue_dl.pdsch_cfg.mimo_type)); + } + + /* Print basic Parameters */ + PRINT_LINE(" nof layers: %d", ue_dl.pdsch_cfg.nof_layers); + PRINT_LINE("nof codewords: %d", ue_dl.pdsch_cfg.grant.nof_tb); + PRINT_LINE(" CFO: %+5.2f kHz", srslte_ue_sync_get_cfo(&ue_sync) / 1000); + PRINT_LINE(" SNR: %+5.1f dB | %+5.1f dB", 10 * log10(rsrp0 / noise), 10 * log10(rsrp1 / noise)); + PRINT_LINE(" Rb: %6.2f / %6.2f Mbps (net/maximum)", uerate, enodebrate); + PRINT_LINE(" PDCCH-Miss: %5.2f%%", 100 * (1 - (float) ue_dl.nof_detected / nof_trials)); + PRINT_LINE(" PDSCH-BLER: %5.2f%%", (float) 100 * ue_dl.pkt_errors / ue_dl.pkts_total); + PRINT_LINE(" TB 0: mcs=%d; tbs=%d", ue_dl.pdsch_cfg.grant.mcs[0].idx, + ue_dl.pdsch_cfg.grant.mcs[0].tbs); + PRINT_LINE(" TB 1: mcs=%d; tbs=%d", ue_dl.pdsch_cfg.grant.mcs[1].idx, + ue_dl.pdsch_cfg.grant.mcs[1].tbs); + + /* MIMO: if tx and rx antennas are bigger than 1 */ + if (cell.nof_ports > 1 && ue_dl.pdsch.nof_rx_antennas > 1) { /* Compute condition number */ srslte_ue_dl_ri_select(&ue_dl, NULL, &cn); + /* Print condition number */ + PRINT_LINE(" κ: %.1f dB (Condition number, 0 dB => Best)", cn); + } + PRINT_LINE(""); + + /* Spatial multiplex only */ + if (ue_dl.pdsch_cfg.mimo_type == SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX) { + /* Compute Rank Indicator (RI) and Precoding Matrix Indicator (PMI) */ srslte_ue_dl_ri_pmi_select(&ue_dl, &ri, &pmi, NULL); for (uint32_t nl = 0; nl < SRSLTE_MAX_LAYERS; nl++) { - for (uint32_t cb = 0; cb < SRSLTE_MAX_CODEBOOKS; cb ++) { + for (uint32_t cb = 0; cb < SRSLTE_MAX_CODEBOOKS; cb++) { sinr[nl][cb] = SRSLTE_VEC_EMA(ue_dl.sinr[nl][cb], sinr[nl][cb], 0.5f); } } - /* Print Results */ - if (ue_dl.pdsch_cfg.mimo_type == SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX) { - printf("\033[K Tx scheme: %s (codebook_idx=%d)\n", srslte_mimotype2str(ue_dl.pdsch_cfg.mimo_type), - ue_dl.pdsch_cfg.codebook_idx); - } else { - printf("\033[K Tx scheme: %s\n", srslte_mimotype2str(ue_dl.pdsch_cfg.mimo_type)); - } - printf("\033[K nof layers: %d \n", ue_dl.pdsch_cfg.nof_layers); - printf("\033[Knof codewords: %d \n", ue_dl.pdsch_cfg.grant.nof_tb); - printf("\033[K CFO: %+5.2f kHz\n", srslte_ue_sync_get_cfo(&ue_sync) / 1000); - printf("\033[K SNR: %+5.1f dB | %+5.1f dB\n", 10 * log10(rsrp0 / noise), 10 * log10(rsrp1 / noise)); - printf("\033[K Rb: %6.2f / %6.2f Mbps (net/maximum)\n", uerate, enodebrate); - printf("\033[K PDCCH-Miss: %5.2f%%\n", 100 * (1 - (float) ue_dl.nof_detected / nof_trials)); - printf("\033[K PDSCH-BLER: %5.2f%%\n", (float) 100 * ue_dl.pkt_errors / ue_dl.pkts_total); - printf("\033[K TB 0: mcs=%d; tbs=%d\n", ue_dl.pdsch_cfg.grant.mcs[0].idx, ue_dl.pdsch_cfg.grant.mcs[0].tbs); - printf("\033[K TB 1: mcs=%d; tbs=%d\n", ue_dl.pdsch_cfg.grant.mcs[1].idx, ue_dl.pdsch_cfg.grant.mcs[1].tbs); - printf("\033[K κ: %.1f dB (Condition number, 0 dB => Best)\n", cn); - printf("\033[K\n"); - printf("\033[KSINR (dB) Vs RI and PMI (for TM4, close loop MIMO only):\n"); - printf("\033[K | RI | 1 | 2 |\n"); - printf("\033[K -------+-------+-------+\n"); - printf("\033[K P | 0 | %5.2f%c| %5.2f%c|\n", 10 * log10(sinr[0][0]), (ri == 1 && pmi == 0)?'*':' ', 10 * log10(sinr[1][0]), (ri == 2 && pmi == 0)?'*':' '); - printf("\033[K M | 1 | %5.2f%c| %5.2f%c|\n", 10 * log10(sinr[0][1]), (ri == 1 && pmi == 1)?'*':' ', 10 * log10(sinr[1][1]), (ri == 2 && pmi == 1)?'*':' '); - printf("\033[K I | 2 | %5.2f%c|-------+ \n", 10 * log10(sinr[0][2]), (ri == 1 && pmi == 2)?'*':' '); - printf("\033[K | 3 | %5.2f%c| \n", 10 * log10(sinr[0][3]), (ri == 1 && pmi == 3)?'*':' '); - printf("\033[K\nPress enter maximum printing debug log of 1 subframe.\n"); - printf("\033[21A"); + /* Print Multiplex stats */ + PRINT_LINE("SINR (dB) Vs RI and PMI:"); + PRINT_LINE(" | RI | 1 | 2 |"); + PRINT_LINE(" -------+-------+-------+"); + PRINT_LINE(" P | 0 | %5.2f%c| %5.2f%c|", 10 * log10(sinr[0][0]), (ri == 1 && pmi == 0) ? '*' : ' ', + 10 * log10(sinr[1][0]), (ri == 2 && pmi == 0) ? '*' : ' '); + PRINT_LINE(" M | 1 | %5.2f%c| %5.2f%c|", 10 * log10(sinr[0][1]), (ri == 1 && pmi == 1) ? '*' : ' ', + 10 * log10(sinr[1][1]), (ri == 2 && pmi == 1) ? '*' : ' '); + PRINT_LINE(" I | 2 | %5.2f%c|-------+ ", 10 * log10(sinr[0][2]), (ri == 1 && pmi == 2) ? '*' : ' '); + PRINT_LINE(" | 3 | %5.2f%c| ", 10 * log10(sinr[0][3]), (ri == 1 && pmi == 3) ? '*' : ' '); + PRINT_LINE(""); } + PRINT_LINE("Press enter maximum printing debug log of 1 subframe."); + PRINT_LINE(""); + PRINT_LINE_RESET_CURSOR(); } break; } @@ -724,7 +740,7 @@ int main(int argc, char **argv) { sfn++; if (sfn == 1024) { sfn = 0; - printf("\033[21B"); + PRINT_LINE_ADVANCE_CURSOR(); ue_dl.pkt_errors = 0; ue_dl.pkts_total = 0; ue_dl.nof_detected = 0; @@ -756,7 +772,7 @@ int main(int argc, char **argv) { sf_cnt++; } // Main loop - printf("\033[21B\n"); + printf("\033[30B\n"); #ifndef DISABLE_GRAPHICS if (!prog_args.disable_plots) { From 3dfe42099ce916503c7d19e8cd0aab67da9657e5 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Fri, 1 Sep 2017 13:49:04 +0200 Subject: [PATCH 43/60] Corrected prompt of Tx scheme selection --- lib/examples/pdsch_enodeb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/examples/pdsch_enodeb.c b/lib/examples/pdsch_enodeb.c index 4ded08fdf..a4157d872 100644 --- a/lib/examples/pdsch_enodeb.c +++ b/lib/examples/pdsch_enodeb.c @@ -194,7 +194,7 @@ void base_init() { /* Select transmission mode */ if (srslte_str2mimotype(mimo_type_str, &pdsch_cfg.mimo_type)) { - ERROR("Wrong transmission mode! Allowed modes: single, diversity, cdd"); + ERROR("Wrong transmission mode! Allowed modes: single, diversity, cdd and multiplex"); exit(-1); } From 2335d2a6447d29ee01eba2329084757577021cf2 Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Fri, 1 Sep 2017 14:24:48 +0200 Subject: [PATCH 44/60] remove boost::assign --- srsue/hdr/upper/rrc.h | 33 +++++++++++++++++++++++---------- srsue/src/upper/rrc.cc | 26 +++++--------------------- 2 files changed, 28 insertions(+), 31 deletions(-) diff --git a/srsue/hdr/upper/rrc.h b/srsue/hdr/upper/rrc.h index c758622fb..9cbdd5201 100644 --- a/srsue/hdr/upper/rrc.h +++ b/srsue/hdr/upper/rrc.h @@ -42,14 +42,20 @@ using srslte::byte_buffer_t; namespace srsue { +static std::string rb_id_str[] = {"SRB0", "SRB1", "SRB2", + "DRB1","DRB2","DRB3", + "DRB4","DRB5","DRB6", + "DRB7","DRB8"}; + + class rrc - :public rrc_interface_nas - ,public rrc_interface_phy - ,public rrc_interface_mac - ,public rrc_interface_gw - ,public rrc_interface_pdcp - ,public rrc_interface_rlc - ,public srslte::timer_callback + :public rrc_interface_nas + ,public rrc_interface_phy + ,public rrc_interface_mac + ,public rrc_interface_gw + ,public rrc_interface_pdcp + ,public rrc_interface_rlc + ,public srslte::timer_callback { public: rrc(); @@ -156,10 +162,17 @@ private: RB_ID_DRB5, RB_ID_DRB6, RB_ID_DRB7, - RB_ID_DRB8 + RB_ID_DRB8, + RB_ID_MAX } rb_id_t; - std::map bearers; - std::string get_rb_name(uint32_t lcid) { return bearers.at(lcid); } + + std::string get_rb_name(uint32_t lcid) { + if (lcid < RB_ID_MAX) { + return rb_id_str[lcid]; + } else { + return std::string("INVALID_RB"); + } + } // RLC interface void max_retx_attempted(); diff --git a/srsue/src/upper/rrc.cc b/srsue/src/upper/rrc.cc index 291024c05..8b417f40d 100644 --- a/srsue/src/upper/rrc.cc +++ b/srsue/src/upper/rrc.cc @@ -45,7 +45,6 @@ rrc::rrc() :state(RRC_STATE_IDLE) ,drb_up(false) { - set_bearers(); } static void liblte_rrc_handler(void *ctx, char *str) { @@ -127,7 +126,7 @@ void rrc::set_ue_category(int category) void rrc::write_sdu(uint32_t lcid, byte_buffer_t *sdu) { - rrc_log->info_hex(sdu->msg, sdu->N_bytes, "RX %s SDU", bearers.at(lcid).c_str()); + rrc_log->info_hex(sdu->msg, sdu->N_bytes, "RX %s SDU", rb_id_str[lcid].c_str()); switch(state) { @@ -238,7 +237,7 @@ bool rrc::have_drb() void rrc::write_pdu(uint32_t lcid, byte_buffer_t *pdu) { - rrc_log->info_hex(pdu->msg, pdu->N_bytes, "TX %s PDU", bearers.at(lcid).c_str()); + rrc_log->info_hex(pdu->msg, pdu->N_bytes, "TX %s PDU", rb_id_str[lcid].c_str()); rrc_log->info("TX PDU Stack latency: %ld us\n", pdu->get_latency_us()); switch(lcid) @@ -804,7 +803,7 @@ void rrc::parse_dl_dcch(uint32_t lcid, byte_buffer_t *pdu) liblte_rrc_unpack_dl_dcch_msg((LIBLTE_BIT_MSG_STRUCT*)&bit_buf, &dl_dcch_msg); rrc_log->info("%s - Received %s\n", - bearers.at(lcid).c_str(), + rb_id_str[lcid].c_str(), liblte_rrc_dl_dcch_msg_type_text[dl_dcch_msg.msg_type]); // Reset and reuse pdu buffer if possible @@ -1387,7 +1386,7 @@ void rrc::add_srb(LIBLTE_RRC_SRB_TO_ADD_MOD_STRUCT *srb_cnfg) } srbs[srb_cnfg->srb_id] = *srb_cnfg; - rrc_log->info("Added radio bearer %s\n", bearers.at(srb_cnfg->srb_id).c_str()); + rrc_log->info("Added radio bearer %s\n", rb_id_str[srb_cnfg->srb_id].c_str()); } void rrc::add_drb(LIBLTE_RRC_DRB_TO_ADD_MOD_STRUCT *drb_cnfg) @@ -1448,7 +1447,7 @@ void rrc::add_drb(LIBLTE_RRC_DRB_TO_ADD_MOD_STRUCT *drb_cnfg) drbs[lcid] = *drb_cnfg; drb_up = true; - rrc_log->info("Added radio bearer %s\n", bearers.at(lcid).c_str()); + rrc_log->info("Added radio bearer %s\n", rb_id_str[lcid].c_str()); } void rrc::release_drb(uint8_t lcid) @@ -1504,19 +1503,4 @@ void rrc::set_rrc_default() { mac_timers->get(safe_reset_timer)->set(this, 10); } -void rrc::set_bearers() -{ - boost::assign::insert(bearers) (RB_ID_SRB0, "SRB0") - (RB_ID_SRB1, "SRB1") - (RB_ID_SRB2, "SRB2") - (RB_ID_DRB1, "DRB1") - (RB_ID_DRB2, "DRB2") - (RB_ID_DRB3, "DRB3") - (RB_ID_DRB4, "DRB4") - (RB_ID_DRB5, "DRB5") - (RB_ID_DRB6, "DRB6") - (RB_ID_DRB7, "DRB7") - (RB_ID_DRB8, "DRB8"); -} - } // namespace srsue From a8bbc29ee6141be1bdffb603ed3551adcb5b6a53 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Fri, 1 Sep 2017 14:27:22 +0200 Subject: [PATCH 45/60] Reverted default number of rx antennas for UE config --- srsue/ue.conf.example | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/srsue/ue.conf.example b/srsue/ue.conf.example index 532bb9849..8c9ba7d3d 100644 --- a/srsue/ue.conf.example +++ b/srsue/ue.conf.example @@ -26,7 +26,7 @@ ul_freq = 2565000000 tx_gain = 80 rx_gain = 60 -nof_rx_ant = 2 +#nof_rx_ant = 1 #device_name = auto #device_args = auto #time_adv_nsamples = auto From f5e5e946819c73d97323acbde8ee6b004729f7ba Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Fri, 1 Sep 2017 14:27:37 +0200 Subject: [PATCH 46/60] if (cell.nof_ports > 1) { --- srsue/src/phy/phch_worker.cc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/srsue/src/phy/phch_worker.cc b/srsue/src/phy/phch_worker.cc index 78c5b2f71..265d3e005 100644 --- a/srsue/src/phy/phch_worker.cc +++ b/srsue/src/phy/phch_worker.cc @@ -40,6 +40,8 @@ #ifdef ENABLE_GUI #include "srsgui/srsgui.h" #include +#include + void init_plots(srsue::phch_worker *worker); pthread_t plot_thread; sem_t plot_sem; @@ -451,7 +453,11 @@ int phch_worker::decode_pdsch_multi(srslte_ra_dl_grant_t *grant, uint8_t *payloa mimo_type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA; break; case LIBLTE_RRC_TRANSMISSION_MODE_2: - mimo_type = SRSLTE_MIMO_TYPE_TX_DIVERSITY; + if (cell.nof_ports > 1) { + mimo_type = SRSLTE_MIMO_TYPE_TX_DIVERSITY; + } else { + mimo_type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA; + } break; case LIBLTE_RRC_TRANSMISSION_MODE_3: if (grant->nof_tb == 1) { From ae287dd89a29413d08fcd901ecb5d037a9de7e81 Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Fri, 1 Sep 2017 18:58:52 +0200 Subject: [PATCH 47/60] fixed incorrect printf --- srsue/hdr/mac/dl_harq.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/srsue/hdr/mac/dl_harq.h b/srsue/hdr/mac/dl_harq.h index 4f6df9b51..963551150 100644 --- a/srsue/hdr/mac/dl_harq.h +++ b/srsue/hdr/mac/dl_harq.h @@ -280,7 +280,6 @@ private: } } - void tb_decoded(bool ack_) { ack = ack_; if (ack) { @@ -319,7 +318,7 @@ private: Info("DL %d (TB %d): %s tbs=%d, rv=%d, ack=%s, ndi=%d (%d), tti=%d (%d)\n", pid, tid, is_new_transmission ? "newTX" : "reTX ", cur_grant.n_bytes[tid], cur_grant.rv[tid], ack ? "OK" : "KO", - cur_grant.ndi[tid], cur_grant.last_ndi, cur_grant.tti, cur_grant.last_tti); + cur_grant.ndi[tid], cur_grant.last_ndi[tid], cur_grant.tti, cur_grant.last_tti); if (ack && pid == HARQ_BCCH_PID) { reset(); From 8a3ff19b309a2ec146ef9abdd77dfefa1b32bf3d Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Fri, 1 Sep 2017 18:59:28 +0200 Subject: [PATCH 48/60] set all pdsch functionts to MIMO by default (removed _multi) --- lib/examples/pdsch_enodeb.c | 7 +- lib/include/srslte/phy/enb/enb_dl.h | 4 +- lib/include/srslte/phy/phch/pdsch.h | 59 ++---- lib/src/phy/enb/enb_dl.c | 6 +- lib/src/phy/phch/pdsch.c | 288 ++++++++++------------------ lib/src/phy/phch/test/pdsch_test.c | 12 +- lib/src/phy/ue/ue_dl.c | 12 +- srsenb/src/phy/phch_worker.cc | 5 +- srsue/hdr/phy/phch_worker.h | 19 +- srsue/src/phy/phch_worker.cc | 29 +-- 10 files changed, 155 insertions(+), 286 deletions(-) diff --git a/lib/examples/pdsch_enodeb.c b/lib/examples/pdsch_enodeb.c index a4157d872..35f7d3e9f 100644 --- a/lib/examples/pdsch_enodeb.c +++ b/lib/examples/pdsch_enodeb.c @@ -318,7 +318,7 @@ void base_init() { } bzero(&pdsch, sizeof(srslte_pdsch_t)); - if (srslte_pdsch_init_tx_multi(&pdsch, cell)) { + if (srslte_pdsch_init_tx(&pdsch, cell)) { fprintf(stderr, "Error creating PDSCH object\n"); exit(-1); } @@ -820,14 +820,13 @@ int main(int argc, char **argv) { /* Configure pdsch_cfg parameters */ srslte_ra_dl_grant_t grant; srslte_ra_dl_dci_to_grant(&ra_dl, cell.nof_prb, UE_CRNTI, &grant); - if (srslte_pdsch_cfg_multi(&pdsch_cfg, cell, &grant, cfi, sf_idx, rvidx, pdsch_cfg.mimo_type, multiplex_pmi)) { + if (srslte_pdsch_cfg_mimo(&pdsch_cfg, cell, &grant, cfi, sf_idx, rvidx, pdsch_cfg.mimo_type, multiplex_pmi)) { fprintf(stderr, "Error configuring PDSCH\n"); exit(-1); } /* Encode PDSCH */ - if (srslte_pdsch_encode_multi(&pdsch, &pdsch_cfg, softbuffers, data, UE_CRNTI, - sf_symbols)) { + if (srslte_pdsch_encode(&pdsch, &pdsch_cfg, softbuffers, data, UE_CRNTI, sf_symbols)) { fprintf(stderr, "Error encoding PDSCH\n"); exit(-1); } diff --git a/lib/include/srslte/phy/enb/enb_dl.h b/lib/include/srslte/phy/enb/enb_dl.h index 08cb5da4f..d39eed1e1 100644 --- a/lib/include/srslte/phy/enb/enb_dl.h +++ b/lib/include/srslte/phy/enb/enb_dl.h @@ -152,11 +152,11 @@ SRSLTE_API void srslte_enb_dl_rem_rnti(srslte_enb_dl_t *q, SRSLTE_API int srslte_enb_dl_put_pdsch(srslte_enb_dl_t *q, srslte_ra_dl_grant_t *grant, - srslte_softbuffer_tx_t *softbuffer, + srslte_softbuffer_tx_t *softbuffer[SRSLTE_MAX_CODEWORDS], uint16_t rnti, uint32_t rv_idx, uint32_t sf_idx, - uint8_t *data); + uint8_t *data[SRSLTE_MAX_CODEWORDS]); SRSLTE_API int srslte_enb_dl_put_pdcch_dl(srslte_enb_dl_t *q, srslte_ra_dl_dci_t *grant, diff --git a/lib/include/srslte/phy/phch/pdsch.h b/lib/include/srslte/phy/phch/pdsch.h index a30851648..44ed161e8 100644 --- a/lib/include/srslte/phy/phch/pdsch.h +++ b/lib/include/srslte/phy/phch/pdsch.h @@ -78,15 +78,12 @@ typedef struct SRSLTE_API { } srslte_pdsch_t; -SRSLTE_API int srslte_pdsch_init(srslte_pdsch_t *q, - srslte_cell_t cell); +SRSLTE_API int srslte_pdsch_init_tx(srslte_pdsch_t *q, + srslte_cell_t cell); -SRSLTE_API int srslte_pdsch_init_tx_multi(srslte_pdsch_t *q, - srslte_cell_t cell); - -SRSLTE_API int srslte_pdsch_init_rx_multi(srslte_pdsch_t *q, - srslte_cell_t cell, - uint32_t nof_antennas); +SRSLTE_API int srslte_pdsch_init_rx(srslte_pdsch_t *q, + srslte_cell_t cell, + uint32_t nof_antennas); SRSLTE_API void srslte_pdsch_free(srslte_pdsch_t *q); @@ -103,23 +100,16 @@ SRSLTE_API int srslte_pdsch_cfg(srslte_pdsch_cfg_t *cfg, uint32_t sf_idx, int rvidx); -SRSLTE_API int srslte_pdsch_cfg_multi(srslte_pdsch_cfg_t *cfg, - srslte_cell_t cell, - srslte_ra_dl_grant_t *grant, - uint32_t cfi, - uint32_t sf_idx, - int rvidx[SRSLTE_MAX_CODEWORDS], - srslte_mimo_type_t mimo_type, - uint32_t pmi); +SRSLTE_API int srslte_pdsch_cfg_mimo(srslte_pdsch_cfg_t *cfg, + srslte_cell_t cell, + srslte_ra_dl_grant_t *grant, + uint32_t cfi, + uint32_t sf_idx, + int rvidx[SRSLTE_MAX_CODEWORDS], + srslte_mimo_type_t mimo_type, + uint32_t pmi); SRSLTE_API int srslte_pdsch_encode(srslte_pdsch_t *q, - srslte_pdsch_cfg_t *cfg, - srslte_softbuffer_tx_t *softbuffer, - uint8_t *data, - uint16_t rnti, - cf_t *sf_symbols[SRSLTE_MAX_PORTS]); - -SRSLTE_API int srslte_pdsch_encode_multi(srslte_pdsch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbuffer_tx_t *softbuffers[SRSLTE_MAX_CODEWORDS], uint8_t *data[SRSLTE_MAX_CODEWORDS], @@ -127,23 +117,14 @@ SRSLTE_API int srslte_pdsch_encode_multi(srslte_pdsch_t *q, cf_t *sf_symbols[SRSLTE_MAX_PORTS]); SRSLTE_API 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, + srslte_pdsch_cfg_t *cfg, + srslte_softbuffer_rx_t *softbuffers[SRSLTE_MAX_CODEWORDS], + 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); - -SRSLTE_API int srslte_pdsch_decode_multi(srslte_pdsch_t *q, - srslte_pdsch_cfg_t *cfg, - srslte_softbuffer_rx_t *softbuffers[SRSLTE_MAX_CODEWORDS], - 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[SRSLTE_MAX_CODEWORDS], - bool acks[SRSLTE_MAX_CODEWORDS]); + uint8_t *data[SRSLTE_MAX_CODEWORDS], + bool acks[SRSLTE_MAX_CODEWORDS]); SRSLTE_API int srslte_pdsch_pmi_select(srslte_pdsch_t *q, srslte_pdsch_cfg_t *cfg, diff --git a/lib/src/phy/enb/enb_dl.c b/lib/src/phy/enb/enb_dl.c index 4cc33d3b8..39606ff7f 100644 --- a/lib/src/phy/enb/enb_dl.c +++ b/lib/src/phy/enb/enb_dl.c @@ -83,7 +83,7 @@ int srslte_enb_dl_init(srslte_enb_dl_t *q, srslte_cell_t cell) goto clean_exit; } - if (srslte_pdsch_init(&q->pdsch, q->cell)) { + if (srslte_pdsch_init_tx(&q->pdsch, q->cell)) { fprintf(stderr, "Error creating PDSCH object\n"); goto clean_exit; } @@ -262,9 +262,9 @@ int srslte_enb_dl_put_pdcch_ul(srslte_enb_dl_t *q, srslte_ra_ul_dci_t *grant, return SRSLTE_SUCCESS; } -int srslte_enb_dl_put_pdsch(srslte_enb_dl_t *q, srslte_ra_dl_grant_t *grant, srslte_softbuffer_tx_t *softbuffer, +int srslte_enb_dl_put_pdsch(srslte_enb_dl_t *q, srslte_ra_dl_grant_t *grant, srslte_softbuffer_tx_t *softbuffer[SRSLTE_MAX_CODEWORDS], uint16_t rnti, uint32_t rv_idx, uint32_t sf_idx, - uint8_t *data) + uint8_t *data[SRSLTE_MAX_CODEWORDS]) { /* Configure pdsch_cfg parameters */ if (srslte_pdsch_cfg(&q->pdsch_cfg, q->cell, grant, q->cfi, sf_idx, rv_idx)) { diff --git a/lib/src/phy/phch/pdsch.c b/lib/src/phy/phch/pdsch.c index 9f0e4ed12..bc62df7fd 100644 --- a/lib/src/phy/phch/pdsch.c +++ b/lib/src/phy/phch/pdsch.c @@ -198,7 +198,7 @@ int srslte_pdsch_get(srslte_pdsch_t *q, cf_t *sf_symbols, cf_t *symbols, } /** Initializes the PDCCH transmitter or receiver */ -int srslte_pdsch_init_multi(srslte_pdsch_t *q, srslte_cell_t cell, uint32_t nof_antennas, bool is_receiver) +int srslte_pdsch_init(srslte_pdsch_t *q, srslte_cell_t cell, uint32_t nof_antennas, bool is_receiver) { int ret = SRSLTE_ERROR_INVALID_INPUTS; int i; @@ -243,7 +243,6 @@ int srslte_pdsch_init_multi(srslte_pdsch_t *q, srslte_cell_t cell, uint32_t nof_ if (!q->d[i]) { goto clean; } - } /* Layer mapped symbols memory allocation */ @@ -289,16 +288,12 @@ int srslte_pdsch_init_multi(srslte_pdsch_t *q, srslte_cell_t cell, uint32_t nof_ return ret; } -int srslte_pdsch_init(srslte_pdsch_t *q, srslte_cell_t cell) { - return srslte_pdsch_init_multi(q, cell, 1, true); -} - -int srslte_pdsch_init_tx_multi(srslte_pdsch_t *q, srslte_cell_t cell) { - return srslte_pdsch_init_multi(q, cell, 0, false); +int srslte_pdsch_init_tx(srslte_pdsch_t *q, srslte_cell_t cell) { + return srslte_pdsch_init(q, cell, 0, false); } -int srslte_pdsch_init_rx_multi(srslte_pdsch_t *q, srslte_cell_t cell, uint32_t nof_antennas) { - return srslte_pdsch_init_multi(q, cell, nof_antennas, true); +int srslte_pdsch_init_rx(srslte_pdsch_t *q, srslte_cell_t cell, uint32_t nof_antennas) { + return srslte_pdsch_init(q, cell, nof_antennas, true); } void srslte_pdsch_free(srslte_pdsch_t *q) { @@ -346,9 +341,75 @@ void srslte_pdsch_free(srslte_pdsch_t *q) { } bzero(q, sizeof(srslte_pdsch_t)); +} +/* Precalculate the PDSCH scramble sequences for a given RNTI. This function takes a while + * to execute, so shall be called once the final C-RNTI has been allocated for the session. + */ +int srslte_pdsch_set_rnti(srslte_pdsch_t *q, uint16_t rnti) { + uint32_t i, j; + if (!q->users[rnti]) { + q->users[rnti] = calloc(1, sizeof(srslte_pdsch_user_t)); + if (q->users[rnti]) { + for (i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) { + for (j = 0; j < SRSLTE_MAX_CODEWORDS; j++) { + if (srslte_sequence_pdsch(&q->users[rnti]->seq[j][i], rnti, j, 2 * i, q->cell.id, + q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM))) { + ERROR("Generating scrambling sequence"); + return SRSLTE_ERROR; + } + } + } + q->users[rnti]->sequence_generated = true; + } + } + return SRSLTE_SUCCESS; +} + +void srslte_pdsch_free_rnti(srslte_pdsch_t* q, uint16_t rnti) +{ + if (q->users[rnti]) { + for (int i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) { + for (int j = 0; j < SRSLTE_MAX_CODEWORDS; j++) { + srslte_sequence_free(&q->users[rnti]->seq[j][i]); + } + } + free(q->users[rnti]); + q->users[rnti] = NULL; + } } +static void pdsch_decode_debug(srslte_pdsch_t *q, srslte_pdsch_cfg_t *cfg, + cf_t *sf_symbols[SRSLTE_MAX_PORTS], cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]) +{ + if (SRSLTE_VERBOSE_ISDEBUG()) { + char filename[FILENAME_MAX]; + for (int j = 0; j < q->nof_rx_antennas; j++) { + if (snprintf(filename, FILENAME_MAX, "subframe_p%d.dat", j) < 0) { + ERROR("Generating file name"); + break; + } + DEBUG("SAVED FILE %s: received subframe symbols\n", filename); + srslte_vec_save_file(filename, sf_symbols, SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t)); + + for (int i = 0; i < q->cell.nof_ports; i++) { + if (snprintf(filename, FILENAME_MAX, "hest_%d%d.dat", i, j) < 0) { + ERROR("Generating file name"); + break; + } + DEBUG("SAVED FILE %s: channel estimates for Tx %d and Rx %d\n", filename, j, i); + srslte_vec_save_file(filename, ce[i][j], SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t)); + } + } + DEBUG("SAVED FILE pdsch_symbols.dat: symbols after equalization\n",0); + srslte_vec_save_file("pdsch_symbols.dat", q->d, cfg->nbits[0].nof_re*sizeof(cf_t)); + + DEBUG("SAVED FILE llr.dat: LLR estimates after demodulation and descrambling\n",0); + srslte_vec_save_file("llr.dat", q->e, cfg->nbits[0].nof_bits*sizeof(int16_t)); + } +} + + /* Configures the structure srslte_pdsch_cfg_t from the DL DCI allocation dci_msg. * If dci_msg is NULL, the grant is assumed to be already stored in cfg->grant */ @@ -357,13 +418,13 @@ int srslte_pdsch_cfg(srslte_pdsch_cfg_t *cfg, srslte_cell_t cell, srslte_ra_dl_g int _rvids[SRSLTE_MAX_CODEWORDS] = {1}; _rvids[0] = rvidx; - return srslte_pdsch_cfg_multi(cfg, cell, grant, cfi, sf_idx, _rvids, SRSLTE_MIMO_TYPE_SINGLE_ANTENNA, 0); + return srslte_pdsch_cfg_mimo(cfg, cell, grant, cfi, sf_idx, _rvids, SRSLTE_MIMO_TYPE_SINGLE_ANTENNA, 0); } /* Configures the structure srslte_pdsch_cfg_t from the DL DCI allocation dci_msg. * If dci_msg is NULL, the grant is assumed to be already stored in cfg->grant */ -int srslte_pdsch_cfg_multi(srslte_pdsch_cfg_t *cfg, srslte_cell_t cell, srslte_ra_dl_grant_t *grant, uint32_t cfi, +int srslte_pdsch_cfg_mimo(srslte_pdsch_cfg_t *cfg, srslte_cell_t cell, srslte_ra_dl_grant_t *grant, uint32_t cfi, uint32_t sf_idx, int rvidx[SRSLTE_MAX_CODEWORDS], srslte_mimo_type_t mimo_type, uint32_t pmi) { if (cfg) { @@ -425,29 +486,6 @@ int srslte_pdsch_cfg_multi(srslte_pdsch_cfg_t *cfg, srslte_cell_t cell, srslte_r } } -/* Precalculate the PDSCH scramble sequences for a given RNTI. This function takes a while - * to execute, so shall be called once the final C-RNTI has been allocated for the session. - */ -int srslte_pdsch_set_rnti(srslte_pdsch_t *q, uint16_t rnti) { - uint32_t i, j; - if (!q->users[rnti]) { - q->users[rnti] = calloc(1, sizeof(srslte_pdsch_user_t)); - if (q->users[rnti]) { - for (i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) { - for (j = 0; j < SRSLTE_MAX_CODEWORDS; j++) { - if (srslte_sequence_pdsch(&q->users[rnti]->seq[j][i], rnti, j, 2 * i, q->cell.id, - q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM))) { - ERROR("Generating scrambling sequence"); - return SRSLTE_ERROR; - } - } - } - q->users[rnti]->sequence_generated = true; - } - } - return SRSLTE_SUCCESS; -} - static int srslte_pdsch_codeword_encode(srslte_pdsch_t *pdsch, srslte_pdsch_cfg_t *cfg, srslte_softbuffer_tx_t *softbuffer, uint16_t rnti, uint8_t *data, uint32_t codeword_idx) { @@ -529,45 +567,14 @@ static int srslte_pdsch_codeword_decode(srslte_pdsch_t *pdsch, srslte_pdsch_cfg_ return SRSLTE_SUCCESS; } -void srslte_pdsch_free_rnti(srslte_pdsch_t* q, uint16_t rnti) -{ - if (q->users[rnti]) { - for (int i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) { - for (int j = 0; j < SRSLTE_MAX_CODEWORDS; j++) { - srslte_sequence_free(&q->users[rnti]->seq[j][i]); - } - } - free(q->users[rnti]); - q->users[rnti] = NULL; - } -} - -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]; - bool acks[SRSLTE_MAX_CODEWORDS]; - srslte_softbuffer_rx_t *softbuffers[SRSLTE_MAX_TB] = {NULL}; - - _sf_symbols[0] = sf_symbols; - for (int i = 0; i < q->cell.nof_ports; i++) { - _ce[i][0] = ce[i]; - } - - softbuffers[0] = softbuffer; - - return srslte_pdsch_decode_multi(q, cfg, softbuffers, _sf_symbols, _ce, noise_estimate, rnti, &data, acks); -} - /** 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 *softbuffers[SRSLTE_MAX_CODEWORDS], - 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[SRSLTE_MAX_CODEWORDS], - bool acks[SRSLTE_MAX_CODEWORDS]) { +int srslte_pdsch_decode(srslte_pdsch_t *q, + srslte_pdsch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffers[SRSLTE_MAX_CODEWORDS], + 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[SRSLTE_MAX_CODEWORDS], + bool acks[SRSLTE_MAX_CODEWORDS]) +{ /* Set pointers for layermapping & precoding */ uint32_t i; @@ -579,18 +586,17 @@ int srslte_pdsch_decode_multi(srslte_pdsch_t *q, cfg != NULL) { - INFO("Decoding PDSCH SF: %d, RNTI: 0x%x, NofSymbols: %d, C_prb=%d\n", - cfg->sf_idx, rnti, cfg->nbits[0].nof_re, cfg->grant.nof_prb); + INFO("Decoding PDSCH SF: %d, RNTI: 0x%x, NofSymbols: %d, C_prb=%d, mimo_type=%d, nof_layers=%d, nof_tb=%d\n", + cfg->sf_idx, rnti, cfg->nbits[0].nof_re, cfg->grant.nof_prb, cfg->nof_layers, cfg->grant.nof_tb); + // Extract Symbols and Channel Estimates for (int j=0;jnof_rx_antennas;j++) { - /* extract symbols */ int n = srslte_pdsch_get(q, sf_symbols[j], q->symbols[j], &cfg->grant, cfg->nbits[0].lstart, cfg->sf_idx); if (n != cfg->nbits[0].nof_re) { fprintf(stderr, "Error expecting %d symbols but got %d\n", cfg->nbits[0].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[0].lstart, cfg->sf_idx); if (n != cfg->nbits[0].nof_re) { @@ -600,8 +606,7 @@ int srslte_pdsch_decode_multi(srslte_pdsch_t *q, } } - INFO("PDSCH Layer demapper and predecode: mimo_type=%d, nof_layers=%d, nof_tb=%d\n", cfg->mimo_type, - cfg->nof_layers, cfg->grant.nof_tb); + // Prepare layers int nof_symbols [SRSLTE_MAX_CODEWORDS]; nof_symbols[0] = cfg->nbits[0].nof_re * cfg->grant.nof_tb / cfg->nof_layers; nof_symbols[1] = cfg->nbits[1].nof_re * cfg->grant.nof_tb / cfg->nof_layers; @@ -612,53 +617,30 @@ int srslte_pdsch_decode_multi(srslte_pdsch_t *q, x[i] = q->d[i]; } } else { - /* number of layers equals number of ports */ - for (i = 0; i < cfg->nof_layers; i++) { - x[i] = q->x[i]; - } - memset(&x[cfg->nof_layers], 0, sizeof(cf_t*) * (SRSLTE_MAX_LAYERS - cfg->nof_layers)); + /* number of layers equals number of ports */ + for (i = 0; i < cfg->nof_layers; i++) { + x[i] = q->x[i]; + } + memset(&x[cfg->nof_layers], 0, sizeof(cf_t*) * (SRSLTE_MAX_LAYERS - cfg->nof_layers)); } - srslte_predecoding_type_multi(q->symbols, q->ce, x, q->nof_rx_antennas, q->cell.nof_ports, cfg->nof_layers, + // Pre-decoder + srslte_predecoding_type_multi(q->symbols, q->ce, x, q->nof_rx_antennas, q->cell.nof_ports, cfg->nof_layers, cfg->codebook_idx, cfg->nbits[0].nof_re, cfg->mimo_type, noise_estimate); + // Layer demapping only if necessary if (cfg->nof_layers != cfg->grant.nof_tb) { srslte_layerdemap_type(x, q->d, cfg->nof_layers, cfg->grant.nof_tb, nof_symbols[0], nof_symbols, cfg->mimo_type); } - if (SRSLTE_VERBOSE_ISDEBUG()) { - char filename[FILENAME_MAX]; - for (int j = 0; j < q->nof_rx_antennas; j++) { - if (snprintf(filename, FILENAME_MAX, "subframe_p%d.dat", j) < 0) { - ERROR("Generating file name"); - break; - } - DEBUG("SAVED FILE %s: received subframe symbols\n", filename); - srslte_vec_save_file(filename, sf_symbols, SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t)); - - for (i = 0; i < q->cell.nof_ports; i++) { - if (snprintf(filename, FILENAME_MAX, "hest_%d%d.dat", i, j) < 0) { - ERROR("Generating file name"); - break; - } - DEBUG("SAVED FILE %s: channel estimates for Tx %d and Rx %d\n", filename, j, i); - srslte_vec_save_file(filename, ce[i][j], SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t)); - } - } - DEBUG("SAVED FILE pdsch_symbols.dat: symbols after equalization\n",0); - srslte_vec_save_file("pdsch_symbols.dat", q->d, cfg->nbits[0].nof_re*sizeof(cf_t)); - } - + // Codeword decoding for (uint32_t tb = 0; tb < cfg->grant.nof_tb; tb ++) { int ret = srslte_pdsch_codeword_decode(q, cfg, softbuffers[tb], rnti, data[tb], tb); acks[tb] = (ret == SRSLTE_SUCCESS); } - if (SRSLTE_VERBOSE_ISDEBUG()) { - DEBUG("SAVED FILE llr.dat: LLR estimates after demodulation and descrambling\n",0); - srslte_vec_save_file("llr.dat", q->e, cfg->nbits[0].nof_bits*sizeof(int16_t)); - } + pdsch_decode_debug(q, cfg, sf_symbols, ce); return SRSLTE_SUCCESS; @@ -696,88 +678,10 @@ int srslte_pdsch_cn_compute(srslte_pdsch_t *q, } int srslte_pdsch_encode(srslte_pdsch_t *q, - srslte_pdsch_cfg_t *cfg, srslte_softbuffer_tx_t *softbuffer, - uint8_t *data, uint16_t rnti, cf_t *sf_symbols[SRSLTE_MAX_PORTS]) + srslte_pdsch_cfg_t *cfg, srslte_softbuffer_tx_t *softbuffers[SRSLTE_MAX_CODEWORDS], + uint8_t *data[SRSLTE_MAX_CODEWORDS], uint16_t rnti, cf_t *sf_symbols[SRSLTE_MAX_PORTS]) { - int i; - /* Set pointers for layermapping & precoding */ - cf_t *x[SRSLTE_MAX_LAYERS]; - int ret = SRSLTE_ERROR_INVALID_INPUTS; - - if (q != NULL && - cfg != NULL) - { - - for (i=0;icell.nof_ports;i++) { - if (sf_symbols[i] == NULL) { - return SRSLTE_ERROR_INVALID_INPUTS; - } - } - - if (cfg->grant.mcs[0].tbs == 0) { - return SRSLTE_ERROR_INVALID_INPUTS; - } - - if (cfg->nbits[0].nof_re > q->max_re) { - fprintf(stderr, - "Error too many RE per subframe (%d). PDSCH configured for %d RE (%d PRB)\n", - cfg->nbits[0].nof_re, q->max_re, q->cell.nof_prb); - return SRSLTE_ERROR_INVALID_INPUTS; - } - - INFO("Encoding PDSCH SF: %d, Mod %s, NofBits: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d\n", - cfg->sf_idx, srslte_mod_string(cfg->grant.mcs[0].mod), cfg->grant.mcs[0].tbs, - cfg->nbits[0].nof_re, cfg->nbits[0].nof_bits, cfg->rv[0]); - - /* number of layers equals number of ports */ - for (i = 0; i < q->cell.nof_ports; i++) { - x[i] = q->x[i]; - } - memset(&x[q->cell.nof_ports], 0, sizeof(cf_t*) * (SRSLTE_MAX_LAYERS - q->cell.nof_ports)); - - if (srslte_dlsch_encode(&q->dl_sch, cfg, softbuffer, data, q->e[0])) { - fprintf(stderr, "Error encoding TB\n"); - return SRSLTE_ERROR; - } - - /* scramble */ - if (q->users[rnti] && q->users[rnti]->sequence_generated) { - srslte_scrambling_bytes(&q->users[rnti]->seq[0][cfg->sf_idx], (uint8_t*) q->e[0], cfg->nbits[0].nof_bits); - } else { - srslte_sequence_t seq; - if (srslte_sequence_pdsch(&seq, rnti, 0, 2 * cfg->sf_idx, q->cell.id, cfg->nbits[0].nof_bits)) { - return SRSLTE_ERROR; - } - srslte_scrambling_bytes(&seq, (uint8_t*) q->e[0], cfg->nbits[0].nof_bits); - srslte_sequence_free(&seq); - } - - srslte_mod_modulate_bytes(&q->mod[cfg->grant.mcs[0].mod], (uint8_t*) q->e[0], q->d[0], cfg->nbits[0].nof_bits); - - /* TODO: only diversity supported */ - if (q->cell.nof_ports > 1) { - srslte_layermap_diversity(q->d[0], x, q->cell.nof_ports, cfg->nbits[0].nof_re); - srslte_precoding_diversity(x, q->symbols, q->cell.nof_ports, - cfg->nbits[0].nof_re / q->cell.nof_ports); - } else { - memcpy(q->symbols[0], q->d, cfg->nbits[0].nof_re * sizeof(cf_t)); - } - - /* mapping to resource elements */ - for (i = 0; i < q->cell.nof_ports; i++) { - srslte_pdsch_put(q, q->symbols[i], sf_symbols[i], &cfg->grant, cfg->nbits[0].lstart, cfg->sf_idx); - } - - ret = SRSLTE_SUCCESS; - } - return ret; -} - -int srslte_pdsch_encode_multi(srslte_pdsch_t *q, - srslte_pdsch_cfg_t *cfg, srslte_softbuffer_tx_t *softbuffers[SRSLTE_MAX_CODEWORDS], - uint8_t *data[SRSLTE_MAX_CODEWORDS], uint16_t rnti, cf_t *sf_symbols[SRSLTE_MAX_PORTS]) { - int i; /* Set pointers for layermapping & precoding */ cf_t *x[SRSLTE_MAX_LAYERS]; @@ -808,6 +712,7 @@ int srslte_pdsch_encode_multi(srslte_pdsch_t *q, ret |= srslte_pdsch_codeword_encode(q, cfg, softbuffers[tb], rnti, data[tb], tb); } + // Layer mapping & precode if necessary if (q->cell.nof_ports > 1) { int nof_symbols; /* If number of layers is equal to transport blocks (codewords) skip layer mapping */ @@ -836,7 +741,6 @@ int srslte_pdsch_encode_multi(srslte_pdsch_t *q, } /* mapping to resource elements */ - for (i = 0; i < q->cell.nof_ports; i++) { srslte_pdsch_put(q, q->symbols[i], sf_symbols[i], &cfg->grant, cfg->nbits[0].lstart, cfg->sf_idx); } diff --git a/lib/src/phy/phch/test/pdsch_test.c b/lib/src/phy/phch/test/pdsch_test.c index ea40ce824..b98d75c22 100644 --- a/lib/src/phy/phch/test/pdsch_test.c +++ b/lib/src/phy/phch/test/pdsch_test.c @@ -232,7 +232,7 @@ int main(int argc, char **argv) { #endif /* DO_OFDM */ /* Configure PDSCH */ - if (srslte_pdsch_cfg_multi(&pdsch_cfg, cell, &grant, cfi, subframe, rv_idx, mimo_type, pmi)) { + if (srslte_pdsch_cfg_mimo(&pdsch_cfg, cell, &grant, cfi, subframe, rv_idx, mimo_type, pmi)) { fprintf(stderr, "Error configuring PDSCH\n"); goto quit; } @@ -276,7 +276,7 @@ int main(int argc, char **argv) { } } - if (srslte_pdsch_init_rx_multi(&pdsch_rx, cell, nof_rx_antennas)) { + if (srslte_pdsch_init_rx(&pdsch_rx, cell, nof_rx_antennas)) { fprintf(stderr, "Error creating PDSCH object\n"); goto quit; } @@ -345,7 +345,7 @@ int main(int argc, char **argv) { srslte_filesource_free(&fsrc); } else { - if (srslte_pdsch_init_tx_multi(&pdsch_tx, cell)) { + if (srslte_pdsch_init_tx(&pdsch_tx, cell)) { fprintf(stderr, "Error creating PDSCH object\n"); goto quit; } @@ -385,7 +385,7 @@ int main(int argc, char **argv) { if (rv_idx[0] != 0 || rv_idx[1] != 0) { /* Do 1st transmission for rv_idx!=0 */ bzero(pdsch_cfg.rv, sizeof(uint32_t)*SRSLTE_MAX_CODEWORDS); - if (srslte_pdsch_encode_multi(&pdsch_tx, &pdsch_cfg, softbuffers_tx, data_tx, rnti, tx_slot_symbols)) { + if (srslte_pdsch_encode(&pdsch_tx, &pdsch_cfg, softbuffers_tx, data_tx, rnti, tx_slot_symbols)) { fprintf(stderr, "Error encoding PDSCH\n"); goto quit; } @@ -393,7 +393,7 @@ int main(int argc, char **argv) { memcpy(pdsch_cfg.rv, rv_idx, sizeof(uint32_t)*SRSLTE_MAX_CODEWORDS); gettimeofday(&t[1], NULL); for (k = 0; k < M; k++) { - if (srslte_pdsch_encode_multi(&pdsch_tx, &pdsch_cfg, softbuffers_tx, data_tx, rnti, tx_slot_symbols)) { + if (srslte_pdsch_encode(&pdsch_tx, &pdsch_cfg, softbuffers_tx, data_tx, rnti, tx_slot_symbols)) { ERROR("Error encoding PDSCH"); goto quit; } @@ -449,7 +449,7 @@ int main(int argc, char **argv) { srslte_softbuffer_rx_reset_tbs(softbuffers_rx[i], (uint32_t) grant.mcs[i].tbs); } } - r = srslte_pdsch_decode_multi(&pdsch_rx, &pdsch_cfg, softbuffers_rx, rx_slot_symbols, ce, 0, rnti, data_rx, acks); + r = srslte_pdsch_decode(&pdsch_rx, &pdsch_cfg, softbuffers_rx, rx_slot_symbols, ce, 0, rnti, data_rx, acks); } gettimeofday(&t[2], NULL); get_time_interval(t); diff --git a/lib/src/phy/ue/ue_dl.c b/lib/src/phy/ue/ue_dl.c index 55f65ad3d..dfe9a18a7 100644 --- a/lib/src/phy/ue/ue_dl.c +++ b/lib/src/phy/ue/ue_dl.c @@ -97,7 +97,7 @@ int srslte_ue_dl_init_multi(srslte_ue_dl_t *q, goto clean_exit; } - if (srslte_pdsch_init_rx_multi(&q->pdsch, q->cell, nof_rx_antennas)) { + if (srslte_pdsch_init_rx(&q->pdsch, q->cell, nof_rx_antennas)) { fprintf(stderr, "Error creating PDSCH object\n"); goto clean_exit; } @@ -315,7 +315,7 @@ int srslte_ue_dl_cfg_grant(srslte_ue_dl_t *q, srslte_ra_dl_grant_t *grant, uint3 } } } - return srslte_pdsch_cfg_multi(&q->pdsch_cfg, q->cell, grant, cfi, sf_idx, rvidx, mimo_type, pmi); + return srslte_pdsch_cfg_mimo(&q->pdsch_cfg, q->cell, grant, cfi, sf_idx, rvidx, mimo_type, pmi); } int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, cf_t *input, uint8_t *data, uint32_t tti, uint16_t rnti) { @@ -434,10 +434,10 @@ int srslte_ue_dl_decode_rnti_multi(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_POR if (q->pdsch_cfg.grant.mcs[0].mod > 0 && q->pdsch_cfg.grant.mcs[0].tbs >= 0) { - ret = srslte_pdsch_decode_multi(&q->pdsch, &q->pdsch_cfg, q->softbuffers, - q->sf_symbols_m, q->ce_m, - noise_estimate, - rnti, data, acks); + ret = srslte_pdsch_decode(&q->pdsch, &q->pdsch_cfg, q->softbuffers, + q->sf_symbols_m, q->ce_m, + noise_estimate, + rnti, data, acks); for (int tb = 0; tb < q->pdsch_cfg.grant.nof_tb; tb++) { if (!acks[tb]) { diff --git a/srsenb/src/phy/phch_worker.cc b/srsenb/src/phy/phch_worker.cc index 5c5537c61..d86bce9c9 100644 --- a/srsenb/src/phy/phch_worker.cc +++ b/srsenb/src/phy/phch_worker.cc @@ -647,8 +647,9 @@ int phch_worker::encode_pdsch(srslte_enb_dl_pdsch_t *grants, uint32_t nof_grants rnti, phy_grant.nof_prb, grant_str, grants[i].grant.harq_process, phy_grant.mcs[0].tbs/8, phy_grant.mcs[0].idx, grants[i].grant.rv_idx, tti_tx); } - if (srslte_enb_dl_put_pdsch(&enb_dl, &phy_grant, grants[i].softbuffer, rnti, grants[i].grant.rv_idx, sf_idx, - grants[i].data)) + srslte_softbuffer_tx_t *sb[SRSLTE_MAX_CODEWORDS] = {grants[i].softbuffer, NULL}; + uint8_t *d[SRSLTE_MAX_CODEWORDS] = {grants[i].data, NULL}; + if (srslte_enb_dl_put_pdsch(&enb_dl, &phy_grant, sb, rnti, grants[i].grant.rv_idx, sf_idx, d)) { fprintf(stderr, "Error putting PDSCH %d\n",i); return SRSLTE_ERROR; diff --git a/srsue/hdr/phy/phch_worker.h b/srsue/hdr/phy/phch_worker.h index a47008629..7b196f948 100644 --- a/srsue/hdr/phy/phch_worker.h +++ b/srsue/hdr/phy/phch_worker.h @@ -79,19 +79,12 @@ private: bool decode_phich(bool *ack); int decode_pdsch(srslte_ra_dl_grant_t *grant, - uint8_t *payload, srslte_softbuffer_rx_t *softbuffer, - int rv, - uint16_t rnti, - uint32_t pid, - bool acks[SRSLTE_MAX_CODEWORDS]); - - int decode_pdsch_multi(srslte_ra_dl_grant_t *grant, - uint8_t *payload[SRSLTE_MAX_CODEWORDS], - srslte_softbuffer_rx_t *softbuffers[SRSLTE_MAX_CODEWORDS], - int rv[SRSLTE_MAX_CODEWORDS], - uint16_t rnti, - uint32_t pid, - bool acks[SRSLTE_MAX_CODEWORDS]); + uint8_t *payload[SRSLTE_MAX_CODEWORDS], + srslte_softbuffer_rx_t *softbuffers[SRSLTE_MAX_CODEWORDS], + int rv[SRSLTE_MAX_CODEWORDS], + uint16_t rnti, + uint32_t pid, + bool acks[SRSLTE_MAX_CODEWORDS]); /* ... for UL */ void encode_pusch(srslte_ra_ul_grant_t *grant, uint8_t *payload, uint32_t current_tx_nb, srslte_softbuffer_tx_t *softbuffer, diff --git a/srsue/src/phy/phch_worker.cc b/srsue/src/phy/phch_worker.cc index 265d3e005..1959ba479 100644 --- a/srsue/src/phy/phch_worker.cc +++ b/srsue/src/phy/phch_worker.cc @@ -41,6 +41,7 @@ #include "srsgui/srsgui.h" #include #include +#include void init_plots(srsue::phch_worker *worker); pthread_t plot_thread; @@ -210,12 +211,14 @@ void phch_worker::work_imp() /* Decode PDSCH if instructed to do so */ if (dl_action.decode_enabled) { - decode_pdsch_multi(&dl_action.phy_grant.dl, dl_action.payload_ptr, - dl_action.softbuffers, dl_action.rv, dl_action.rnti, - dl_mac_grant.pid, dl_ack); + decode_pdsch(&dl_action.phy_grant.dl, dl_action.payload_ptr, + dl_action.softbuffers, dl_action.rv, dl_action.rnti, + dl_mac_grant.pid, dl_ack); } if (dl_action.generate_ack_callback && dl_action.decode_enabled) { - for (uint32_t tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb++) { + + // NOTE: Currently hard-coded to 1st TB only + for (uint32_t tb = 0; tb < 1; tb++) { phy->mac->tb_decoded(dl_ack[tb], tb, dl_mac_grant.rnti_type, dl_mac_grant.pid); dl_ack[tb] = dl_action.generate_ack_callback(dl_action.generate_ack_callback_arg); Debug("Calling generate ACK callback for TB %d returned=%d\n", tb, dl_ack); @@ -418,19 +421,7 @@ bool phch_worker::decode_pdcch_dl(srsue::mac_interface_phy::mac_grant_t* grant) } } -int phch_worker::decode_pdsch(srslte_ra_dl_grant_t *grant, uint8_t *payload, - srslte_softbuffer_rx_t *softbuffer, int rv, - uint16_t rnti, uint32_t harq_pid, bool acks[SRSLTE_MAX_CODEWORDS]) { - int _rv [SRSLTE_MAX_TB] = {1}; - srslte_softbuffer_rx_t *softbuffers[SRSLTE_MAX_TB] = {NULL}; - - _rv[0] = rv; - softbuffers[0] = softbuffer; - - return decode_pdsch_multi(grant, &payload, softbuffers, _rv, rnti, harq_pid, acks); -} - -int phch_worker::decode_pdsch_multi(srslte_ra_dl_grant_t *grant, uint8_t *payload[SRSLTE_MAX_CODEWORDS], +int phch_worker::decode_pdsch(srslte_ra_dl_grant_t *grant, uint8_t *payload[SRSLTE_MAX_CODEWORDS], srslte_softbuffer_rx_t *softbuffers[SRSLTE_MAX_CODEWORDS], int rv[SRSLTE_MAX_CODEWORDS], uint16_t rnti, uint32_t harq_pid, bool acks[SRSLTE_MAX_CODEWORDS]) { @@ -518,8 +509,8 @@ int phch_worker::decode_pdsch_multi(srslte_ra_dl_grant_t *grant, uint8_t *payloa struct timeval t[3]; gettimeofday(&t[1], NULL); #endif - ret = srslte_pdsch_decode_multi(&ue_dl.pdsch, &ue_dl.pdsch_cfg, softbuffers, ue_dl.sf_symbols_m, - ue_dl.ce_m, noise_estimate, rnti, payload, acks); + ret = srslte_pdsch_decode(&ue_dl.pdsch, &ue_dl.pdsch_cfg, softbuffers, ue_dl.sf_symbols_m, + ue_dl.ce_m, noise_estimate, rnti, payload, acks); if (ret) { Error("Decoding PDSCH"); } From 38c67dc410fe80e3cc0b67001554e2957fc74d06 Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Mon, 4 Sep 2017 10:45:13 +0200 Subject: [PATCH 49/60] Moved FFTW to WISDOM and save/load from file --- lib/include/srslte/phy/dft/dft.h | 6 ++++-- lib/src/phy/dft/dft_fftw.c | 16 ++++++++++++++-- srsenb/src/enb.cc | 2 ++ srsenb/src/main.cc | 1 + srsue/hdr/ue_base.h | 2 +- srsue/src/ue_base.cc | 8 ++++++++ 6 files changed, 30 insertions(+), 5 deletions(-) diff --git a/lib/include/srslte/phy/dft/dft.h b/lib/include/srslte/phy/dft/dft.h index 12c06dd98..b90aab2e5 100644 --- a/lib/include/srslte/phy/dft/dft.h +++ b/lib/include/srslte/phy/dft/dft.h @@ -71,9 +71,11 @@ typedef struct SRSLTE_API { srslte_dft_mode_t mode; // Complex/Real }srslte_dft_plan_t; -/* Create DFT plans */ +SRSLTE_API void srslte_dft_load(); -SRSLTE_API int srslte_dft_plan(srslte_dft_plan_t *plan, +SRSLTE_API void srslte_dft_exit(); + +SRSLTE_API int srslte_dft_plan(srslte_dft_plan_t *plan, int dft_points, srslte_dft_dir_t dir, srslte_dft_mode_t type); diff --git a/lib/src/phy/dft/dft_fftw.c b/lib/src/phy/dft/dft_fftw.c index 347e04547..5fb34bb3c 100644 --- a/lib/src/phy/dft/dft_fftw.c +++ b/lib/src/phy/dft/dft_fftw.c @@ -36,6 +36,18 @@ #define dft_ceil(a,b) ((a-1)/b+1) #define dft_floor(a,b) (a/b) +#define FFTW_WISDOM_FILE ".fftw_wisdom" + +void srslte_dft_load() { + fftwf_import_wisdom_from_filename(FFTW_WISDOM_FILE); +} + +void srslte_dft_exit() { + if (!fftwf_export_wisdom_to_filename(FFTW_WISDOM_FILE)) { + fprintf(stderr, "Error saving FFTW wisdom to file %s\n", FFTW_WISDOM_FILE); + } +} + int srslte_dft_plan(srslte_dft_plan_t *plan, const int dft_points, srslte_dft_dir_t dir, srslte_dft_mode_t mode) { if(mode == SRSLTE_DFT_COMPLEX){ @@ -54,7 +66,7 @@ static void allocate(srslte_dft_plan_t *plan, int size_in, int size_out, int len int srslte_dft_plan_c(srslte_dft_plan_t *plan, const int dft_points, srslte_dft_dir_t dir) { allocate(plan,sizeof(fftwf_complex),sizeof(fftwf_complex), dft_points); int sign = (dir == SRSLTE_DFT_FORWARD) ? FFTW_FORWARD : FFTW_BACKWARD; - plan->p = fftwf_plan_dft_1d(dft_points, plan->in, plan->out, sign, 0U); + plan->p = fftwf_plan_dft_1d(dft_points, plan->in, plan->out, sign, FFTW_MEASURE); if (!plan->p) { return -1; } @@ -73,7 +85,7 @@ int srslte_dft_plan_c(srslte_dft_plan_t *plan, const int dft_points, srslte_dft_ int srslte_dft_plan_r(srslte_dft_plan_t *plan, const int dft_points, srslte_dft_dir_t dir) { allocate(plan,sizeof(float),sizeof(float), dft_points); int sign = (dir == SRSLTE_DFT_FORWARD) ? FFTW_R2HC : FFTW_HC2R; - plan->p = fftwf_plan_r2r_1d(dft_points, plan->in, plan->out, sign, 0U); + plan->p = fftwf_plan_r2r_1d(dft_points, plan->in, plan->out, sign, FFTW_MEASURE); if (!plan->p) { return -1; } diff --git a/srsenb/src/enb.cc b/srsenb/src/enb.cc index 9a747dba6..1bd7240a2 100644 --- a/srsenb/src/enb.cc +++ b/srsenb/src/enb.cc @@ -44,6 +44,7 @@ enb* enb::get_instance(void) } void enb::cleanup(void) { + srslte_dft_exit(); boost::mutex::scoped_lock lock(enb_instance_mutex); if(NULL != instance) { delete instance; @@ -54,6 +55,7 @@ void enb::cleanup(void) enb::enb() :started(false) { + srslte_dft_load(); pool = srslte::byte_buffer_pool::get_instance(); } diff --git a/srsenb/src/main.cc b/srsenb/src/main.cc index 1e337b3ba..528878388 100644 --- a/srsenb/src/main.cc +++ b/srsenb/src/main.cc @@ -373,6 +373,7 @@ int main(int argc, char *argv[]) pthread_cancel(input); metrics.stop(); enb->stop(); + enb->cleanup(); cout << "--- exiting ---" << endl; exit(0); } diff --git a/srsue/hdr/ue_base.h b/srsue/hdr/ue_base.h index 06c3f3e24..4720d8062 100644 --- a/srsue/hdr/ue_base.h +++ b/srsue/hdr/ue_base.h @@ -134,7 +134,7 @@ class ue_base ,public ue_metrics_interface { public: - ue_base() {} + ue_base(); virtual ~ue_base() {} static ue_base* get_instance(srsue_instance_type_t type); diff --git a/srsue/src/ue_base.cc b/srsue/src/ue_base.cc index 61cbafb2c..c84393ae4 100644 --- a/srsue/src/ue_base.cc +++ b/srsue/src/ue_base.cc @@ -57,8 +57,16 @@ ue_base* ue_base::get_instance(srsue_instance_type_t type) return(instance); } +ue_base::ue_base() { + // load FFTW wisdom + srslte_dft_load(); +} + void ue_base::cleanup(void) { + // save FFTW wisdom + srslte_dft_exit(); + pthread_mutex_lock(&ue_instance_mutex); if(NULL != instance) { delete instance; From 741f5b7a0af4cd920f318a8b2ad189e41764f5a8 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Mon, 4 Sep 2017 11:24:52 +0200 Subject: [PATCH 50/60] Corrected some logging messages --- srsue/hdr/mac/ul_harq.h | 6 +++--- srsue/src/mac/mac.cc | 2 +- srsue/src/mac/proc_ra.cc | 2 +- srsue/src/phy/phch_worker.cc | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/srsue/hdr/mac/ul_harq.h b/srsue/hdr/mac/ul_harq.h index 13ec0b9b3..952b9f002 100644 --- a/srsue/hdr/mac/ul_harq.h +++ b/srsue/hdr/mac/ul_harq.h @@ -326,11 +326,11 @@ private: memcpy(&cur_grant, grant, sizeof(Tgrant)); harq_feedback = false; Info("UL %d: Adaptive retx=%d, RV=%d, TBS=%d\n", - pid, current_tx_nb, get_rv(), grant->n_bytes); + pid, current_tx_nb, get_rv(), grant->n_bytes[0]); generate_tx(tti_tx, action); } else { Info("UL %d: Non-Adaptive retx=%d, RV=%d, TBS=%d\n", - pid, current_tx_nb, get_rv(), cur_grant.n_bytes); + pid, current_tx_nb, get_rv(), cur_grant.n_bytes[0]); // HARQ entity requests a non-adaptive transmission if (!harq_feedback) { generate_tx(tti_tx, action); @@ -358,7 +358,7 @@ private: current_irv = 0; is_msg3 = is_msg3_; Info("UL %d: New TX%s, RV=%d, TBS=%d, RNTI=%d\n", - pid, is_msg3?" for Msg3":"", get_rv(), cur_grant.n_bytes, cur_grant.rnti); + pid, is_msg3?" for Msg3":"", get_rv(), cur_grant.n_bytes[0], cur_grant.rnti); generate_tx(tti_tx, action); } } diff --git a/srsue/src/mac/mac.cc b/srsue/src/mac/mac.cc index 7c569358a..6028ce7e8 100644 --- a/srsue/src/mac/mac.cc +++ b/srsue/src/mac/mac.cc @@ -288,7 +288,7 @@ void mac::new_grant_dl(mac_interface_phy::mac_grant_t grant, mac_interface_phy:: action->rnti = grant.rnti; action->rv[0] = grant.rv[0]; if (grant.n_bytes[0] > pch_payload_buffer_sz) { - Error("Received grant for PCH (%d bytes) exceeds buffer (%d bytes)\n", grant.n_bytes, pch_payload_buffer_sz); + Error("Received grant for PCH (%d bytes) exceeds buffer (%d bytes)\n", grant.n_bytes[0], pch_payload_buffer_sz); action->decode_enabled = false; } } else { diff --git a/srsue/src/mac/proc_ra.cc b/srsue/src/mac/proc_ra.cc index 213042018..98fed02fc 100644 --- a/srsue/src/mac/proc_ra.cc +++ b/srsue/src/mac/proc_ra.cc @@ -285,7 +285,7 @@ void ra_proc::new_grant_dl(mac_interface_phy::mac_grant_t grant, mac_interface_p srslte_softbuffer_rx_reset(&softbuffer_rar); } } else { - rError("Received RAR grant exceeds buffer length (%d>%d)\n", grant.n_bytes, MAX_RAR_PDU_LEN); + rError("Received RAR grant exceeds buffer length (%d>%d)\n", grant.n_bytes[0], MAX_RAR_PDU_LEN); action->decode_enabled = false; state = RESPONSE_ERROR; } diff --git a/srsue/src/phy/phch_worker.cc b/srsue/src/phy/phch_worker.cc index 1959ba479..3c05cc463 100644 --- a/srsue/src/phy/phch_worker.cc +++ b/srsue/src/phy/phch_worker.cc @@ -221,7 +221,7 @@ void phch_worker::work_imp() for (uint32_t tb = 0; tb < 1; tb++) { phy->mac->tb_decoded(dl_ack[tb], tb, dl_mac_grant.rnti_type, dl_mac_grant.pid); dl_ack[tb] = dl_action.generate_ack_callback(dl_action.generate_ack_callback_arg); - Debug("Calling generate ACK callback for TB %d returned=%d\n", tb, dl_ack); + Debug("Calling generate ACK callback for TB %d returned=%d\n", tb, dl_ack[tb]); } } Debug("dl_ack={%d, %d}, generate_ack=%d\n", dl_ack[0], dl_ack[1], dl_action.generate_ack); From 1486911e32e3a0c88ca2140544bc1bdeb1682c54 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Mon, 4 Sep 2017 15:28:18 +0200 Subject: [PATCH 51/60] DCI blind search takes Transmission mode in consideration and some _multi functions removed --- lib/examples/cell_measurement.c | 4 +- lib/examples/pdsch_ue.c | 34 ++++-- lib/include/srslte/phy/ue/ue_dl.h | 52 ++++----- lib/src/phy/phch/test/pdsch_pdcch_file_test.c | 20 ++-- lib/src/phy/ue/ue_dl.c | 105 ++++++++---------- srsue/src/phy/phch_worker.cc | 7 +- 6 files changed, 106 insertions(+), 116 deletions(-) diff --git a/lib/examples/cell_measurement.c b/lib/examples/cell_measurement.c index c6135984c..cb6a9b78d 100644 --- a/lib/examples/cell_measurement.c +++ b/lib/examples/cell_measurement.c @@ -245,7 +245,7 @@ int main(int argc, char **argv) { fprintf(stderr, "Error initiating ue_sync\n"); return -1; } - if (srslte_ue_dl_init_multi(&ue_dl, cell, 1)) { + if (srslte_ue_dl_init(&ue_dl, cell, 1)) { fprintf(stderr, "Error initiating UE downlink processing module\n"); return -1; } @@ -314,7 +314,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_multi(&ue_dl, sf_buffer, data, sfn*10+srslte_ue_sync_get_sfidx(&ue_sync), acks); + n = srslte_ue_dl_decode(&ue_dl, sf_buffer, data, 0, sfn*10+srslte_ue_sync_get_sfidx(&ue_sync), acks); if (n < 0) { fprintf(stderr, "Error decoding UE DL\n");fflush(stdout); return -1; diff --git a/lib/examples/pdsch_ue.c b/lib/examples/pdsch_ue.c index 0a5d2d81d..2ace49d6d 100644 --- a/lib/examples/pdsch_ue.c +++ b/lib/examples/pdsch_ue.c @@ -242,6 +242,7 @@ void parse_args(prog_args_t *args, int argc, char **argv) { break; case 'v': srslte_verbose++; + args->verbose = srslte_verbose; break; case 'Z': args->decimate = atoi(argv[optind]); @@ -323,7 +324,7 @@ int main(int argc, char **argv) { uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN]; int sfn_offset; float cfo = 0; - + parse_args(&prog_args, argc, argv); for (int i = 0; i< SRSLTE_MAX_CODEWORDS; i++) { @@ -486,7 +487,7 @@ int main(int argc, char **argv) { exit(-1); } - if (srslte_ue_dl_init_multi(&ue_dl, cell, prog_args.rf_nof_rx_ant)) { // This is the User RNTI + if (srslte_ue_dl_init(&ue_dl, cell, prog_args.rf_nof_rx_ant)) { // This is the User RNTI fprintf(stderr, "Error initiating UE downlink processing module\n"); exit(-1); } @@ -608,13 +609,30 @@ int main(int argc, char **argv) { decode_pdsch = false; } } - if (decode_pdsch) { - INFO("Attempting DL decode SFN=%d\n", sfn); - n = srslte_ue_dl_decode_multi(&ue_dl, - sf_buffer, - data, - sfn*10+srslte_ue_sync_get_sfidx(&ue_sync), + + INFO("Attempting DL decode SFN=%d\n", sfn); + if (decode_pdsch) { + if (cell.nof_ports == 1) { + /* Transmission mode 1 */ + n = srslte_ue_dl_decode(&ue_dl, sf_buffer, data, 0, sfn*10+srslte_ue_sync_get_sfidx(&ue_sync), acks); + } else { + if (prog_args.rf_nof_rx_ant == 1) { + /* Transmission mode 2 */ + n = srslte_ue_dl_decode(&ue_dl, sf_buffer, data, 1, sfn * 10 + srslte_ue_sync_get_sfidx(&ue_sync), + acks); + } else { + /* Transmission mode 3 */ + n = srslte_ue_dl_decode(&ue_dl, sf_buffer, data, 2, sfn * 10 + srslte_ue_sync_get_sfidx(&ue_sync), + acks); + if (n < 1) { + /* Transmission mode 4 */ + n = srslte_ue_dl_decode(&ue_dl, sf_buffer, data, 3, sfn * 10 + srslte_ue_sync_get_sfidx(&ue_sync), acks); + } + } + } + + if (n < 0) { // fprintf(stderr, "Error decoding UE DL\n");fflush(stdout); diff --git a/lib/include/srslte/phy/ue/ue_dl.h b/lib/include/srslte/phy/ue/ue_dl.h index 416d467f8..d0723fae7 100644 --- a/lib/include/srslte/phy/ue/ue_dl.h +++ b/lib/include/srslte/phy/ue/ue_dl.h @@ -118,21 +118,13 @@ typedef struct SRSLTE_API { }srslte_ue_dl_t; /* This function shall be called just after the initial synchronization */ -SRSLTE_API int srslte_ue_dl_init(srslte_ue_dl_t *q, - srslte_cell_t cell); - -SRSLTE_API int srslte_ue_dl_init_multi(srslte_ue_dl_t *q, - srslte_cell_t cell, - uint32_t nof_rx_antennas); +SRSLTE_API int srslte_ue_dl_init(srslte_ue_dl_t *q, + srslte_cell_t cell, + uint32_t nof_rx_antennas); SRSLTE_API void srslte_ue_dl_free(srslte_ue_dl_t *q); -SRSLTE_API int srslte_ue_dl_decode_fft_estimate(srslte_ue_dl_t *q, - cf_t *input, - uint32_t sf_idx, - uint32_t *cfi); - -SRSLTE_API int srslte_ue_dl_decode_fft_estimate_multi(srslte_ue_dl_t *q, +SRSLTE_API int srslte_ue_dl_decode_fft_estimate(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint32_t sf_idx, uint32_t *cfi); @@ -155,12 +147,14 @@ SRSLTE_API int srslte_ue_dl_find_ul_dci(srslte_ue_dl_t *q, srslte_dci_msg_t *dci_msg); SRSLTE_API int srslte_ue_dl_find_dl_dci(srslte_ue_dl_t *q, + uint32_t tm, uint32_t cfi, uint32_t sf_idx, uint16_t rnti, srslte_dci_msg_t *dci_msg); SRSLTE_API int srslte_ue_dl_find_dl_dci_type(srslte_ue_dl_t *q, + uint32_t tm, uint32_t cfi, uint32_t sf_idx, uint16_t rnti, @@ -172,28 +166,20 @@ SRSLTE_API uint32_t srslte_ue_dl_get_ncce(srslte_ue_dl_t *q); SRSLTE_API void srslte_ue_dl_set_sample_offset(srslte_ue_dl_t * q, float sample_offset); -SRSLTE_API int srslte_ue_dl_decode(srslte_ue_dl_t * q, - cf_t *input, - uint8_t *data, - uint32_t tti); - -SRSLTE_API int srslte_ue_dl_decode_multi(srslte_ue_dl_t * q, - cf_t *input[SRSLTE_MAX_PORTS], - uint8_t *data[SRSLTE_MAX_CODEWORDS], - uint32_t tti, bool acks[SRSLTE_MAX_CODEWORDS]); - -SRSLTE_API int srslte_ue_dl_decode_rnti(srslte_ue_dl_t * q, - cf_t *input, - uint8_t *data, +SRSLTE_API int srslte_ue_dl_decode(srslte_ue_dl_t *q, + cf_t *input[SRSLTE_MAX_PORTS], + uint8_t *data[SRSLTE_MAX_CODEWORDS], + uint32_t tm, + uint32_t tti, + bool acks[SRSLTE_MAX_CODEWORDS]); + +SRSLTE_API int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, + cf_t *input[SRSLTE_MAX_PORTS], + uint8_t *data[SRSLTE_MAX_CODEWORDS], + uint32_t tm, uint32_t tti, - uint16_t rnti); - -SRSLTE_API int srslte_ue_dl_decode_rnti_multi(srslte_ue_dl_t * q, - cf_t *input[SRSLTE_MAX_PORTS], - uint8_t *data[SRSLTE_MAX_CODEWORDS], - uint32_t tti, - uint16_t rnti, - bool acks[SRSLTE_MAX_CODEWORDS]); + uint16_t rnti, + bool acks[SRSLTE_MAX_CODEWORDS]); SRSLTE_API int srslte_ue_dl_ri_pmi_select(srslte_ue_dl_t *q, uint32_t *ri, diff --git a/lib/src/phy/phch/test/pdsch_pdcch_file_test.c b/lib/src/phy/phch/test/pdsch_pdcch_file_test.c index 0d19d689e..c32f6ac76 100644 --- a/lib/src/phy/phch/test/pdsch_pdcch_file_test.c +++ b/lib/src/phy/phch/test/pdsch_pdcch_file_test.c @@ -54,7 +54,7 @@ uint32_t sf_idx = 0; srslte_dci_format_t dci_format = SRSLTE_DCI_FORMAT1A; srslte_filesource_t fsrc; srslte_ue_dl_t ue_dl; -cf_t *input_buffer; +cf_t *input_buffer[SRSLTE_MAX_PORTS]; void usage(char *prog) { printf("Usage: %s [rovfcenmps] -i input_file\n", prog); @@ -131,13 +131,13 @@ int base_init() { flen = 2 * (SRSLTE_SLOT_LEN(srslte_symbol_sz(cell.nof_prb))); - input_buffer = malloc(flen * sizeof(cf_t)); - if (!input_buffer) { + input_buffer[0] = malloc(flen * sizeof(cf_t)); + if (!input_buffer[0]) { perror("malloc"); exit(-1); } - if (srslte_ue_dl_init_multi(&ue_dl, cell, 1)) { + if (srslte_ue_dl_init(&ue_dl, cell, 1)) { fprintf(stderr, "Error initializing UE DL\n"); return -1; } @@ -151,12 +151,13 @@ int base_init() { void base_free() { srslte_filesource_free(&fsrc); srslte_ue_dl_free(&ue_dl); - free(input_buffer); + free(input_buffer[0]); } int main(int argc, char **argv) { int nof_frames; int ret; + bool acks[SRSLTE_MAX_TB]; if (argc < 3) { usage(argv[0]); @@ -169,15 +170,15 @@ int main(int argc, char **argv) { exit(-1); } - uint8_t *data = malloc(100000); + uint8_t *data[] = {malloc(100000)}; ret = -1; nof_frames = 0; do { - srslte_filesource_read(&fsrc, input_buffer, flen); + srslte_filesource_read(&fsrc, input_buffer[0], flen); INFO("Reading %d samples sub-frame %d\n", flen, sf_idx); - ret = srslte_ue_dl_decode(&ue_dl, input_buffer, data, sf_idx); + ret = srslte_ue_dl_decode(&ue_dl, input_buffer, data, 0, sf_idx, acks); if(ret > 0) { printf("PDSCH Decoded OK!\n"); } else if (ret == 0) { @@ -190,7 +191,8 @@ int main(int argc, char **argv) { } while (nof_frames <= max_frames && ret == 0); base_free(); - if (ret > 0) { + free(data[0]); + if (ret > 0) { exit(0); } else { exit(-1); diff --git a/lib/src/phy/ue/ue_dl.c b/lib/src/phy/ue/ue_dl.c index dfe9a18a7..888b0d9b3 100644 --- a/lib/src/phy/ue/ue_dl.c +++ b/lib/src/phy/ue/ue_dl.c @@ -26,8 +26,6 @@ #include "srslte/phy/ue/ue_dl.h" -#include -#include #include @@ -38,21 +36,23 @@ #define CURRENT_SFLEN_RE SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp) -static srslte_dci_format_t ue_formats[] = {SRSLTE_DCI_FORMAT1A, SRSLTE_DCI_FORMAT1, SRSLTE_DCI_FORMAT2A, SRSLTE_DCI_FORMAT2}; // Only TM1, TM2, TM3 and TM4 are currently supported -const uint32_t nof_ue_formats = 4; +const static srslte_dci_format_t ue_dci_formats[8][2] = { + /* Mode 1 */ {SRSLTE_DCI_FORMAT1A, SRSLTE_DCI_FORMAT1}, + /* Mode 2 */ {SRSLTE_DCI_FORMAT1A, SRSLTE_DCI_FORMAT1}, + /* Mode 3 */ {SRSLTE_DCI_FORMAT1A, SRSLTE_DCI_FORMAT2A}, + /* Mode 4 */ {SRSLTE_DCI_FORMAT1A, SRSLTE_DCI_FORMAT2}, + /* Mode 5 */ {SRSLTE_DCI_FORMAT1A, SRSLTE_DCI_FORMAT1D}, + /* Mode 6 */ {SRSLTE_DCI_FORMAT1A, SRSLTE_DCI_FORMAT1B}, + /* Mode 7 */ {SRSLTE_DCI_FORMAT1A, SRSLTE_DCI_FORMAT1}, + /* Mode 8 */ {SRSLTE_DCI_FORMAT1A, SRSLTE_DCI_FORMAT2B} +}; 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) -{ - 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 srslte_ue_dl_init(srslte_ue_dl_t *q, + srslte_cell_t cell, + uint32_t nof_rx_antennas) { int ret = SRSLTE_ERROR_INVALID_INPUTS; @@ -118,7 +118,7 @@ int srslte_ue_dl_init_multi(srslte_ue_dl_t *q, fprintf(stderr, "Error initiating SFO correct\n"); goto clean_exit; } - srslte_cfo_set_tol(&q->sfo_correct, 1e-5/q->fft.symbol_sz); + srslte_cfo_set_tol(&q->sfo_correct, 1e-5f/q->fft.symbol_sz); for (int j=0;jsf_symbols_m[j] = srslte_vec_malloc(CURRENT_SFLEN_RE * sizeof(cf_t)); @@ -219,28 +219,12 @@ void srslte_ue_dl_set_sample_offset(srslte_ue_dl_t * q, float sample_offset) { * - PDCCH decoding: Find DCI for RNTI given by previous call to srslte_ue_dl_set_rnti() * - 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) { - uint8_t *_data[SRSLTE_MAX_CODEWORDS]; - cf_t *_input[SRSLTE_MAX_PORTS]; - bool acks[SRSLTE_MAX_CODEWORDS] = {false}; - _data[0] = data; - _input[0] = input; - return srslte_ue_dl_decode_rnti_multi(q, _input, _data, tti, q->current_rnti, acks); -} - -int srslte_ue_dl_decode_multi(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint8_t *data[SRSLTE_MAX_CODEWORDS], - uint32_t tti, bool acks[SRSLTE_MAX_CODEWORDS]) { - return srslte_ue_dl_decode_rnti_multi(q, input, data, tti, q->current_rnti, acks); -} - -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(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint8_t *data[SRSLTE_MAX_CODEWORDS], + uint32_t tm, uint32_t tti, bool acks[SRSLTE_MAX_CODEWORDS]) { + return srslte_ue_dl_decode_rnti(q, input, data, tm, tti, q->current_rnti, acks); } -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) +int srslte_ue_dl_decode_fft_estimate(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) { @@ -318,19 +302,9 @@ int srslte_ue_dl_cfg_grant(srslte_ue_dl_t *q, srslte_ra_dl_grant_t *grant, uint3 return srslte_pdsch_cfg_mimo(&q->pdsch_cfg, q->cell, grant, cfi, sf_idx, rvidx, mimo_type, pmi); } -int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, cf_t *input, uint8_t *data, uint32_t tti, uint16_t rnti) { - uint8_t *_data[SRSLTE_MAX_CODEWORDS]; - cf_t *_input[SRSLTE_MAX_PORTS]; - bool acks[SRSLTE_MAX_CODEWORDS] = {false}; - _input[0] = input; - _data[0] = data; - return srslte_ue_dl_decode_rnti_multi(q, _input, _data, tti, rnti, acks); -} - -int srslte_ue_dl_decode_rnti_multi(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], - uint8_t *data[SRSLTE_MAX_CODEWORDS], uint32_t tti, uint16_t rnti, - bool acks[SRSLTE_MAX_CODEWORDS]) -{ +int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], + uint8_t *data[SRSLTE_MAX_CODEWORDS], uint32_t tm, uint32_t tti, uint16_t rnti, + bool acks[SRSLTE_MAX_CODEWORDS]) { srslte_mimo_type_t mimo_type; srslte_dci_msg_t dci_msg; srslte_ra_dl_dci_t dci_unpacked; @@ -339,7 +313,7 @@ int srslte_ue_dl_decode_rnti_multi(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_POR uint32_t cfi; uint32_t sf_idx = tti%10; - if ((ret = srslte_ue_dl_decode_fft_estimate_multi(q, input, sf_idx, &cfi)) < 0) { + if ((ret = srslte_ue_dl_decode_fft_estimate(q, input, sf_idx, &cfi)) < 0) { return ret; } @@ -352,7 +326,7 @@ int srslte_ue_dl_decode_rnti_multi(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_POR return SRSLTE_ERROR; } - int found_dci = srslte_ue_dl_find_dl_dci(q, cfi, sf_idx, rnti, &dci_msg); + int found_dci = srslte_ue_dl_find_dl_dci(q, tm, cfi, sf_idx, rnti, &dci_msg); if (found_dci == 1) { if (srslte_dci_msg_to_dl_grant(&dci_msg, rnti, q->cell.nof_prb, q->cell.nof_ports, &dci_unpacked, &grant)) { @@ -630,7 +604,7 @@ int srslte_ue_dl_find_ul_dci(srslte_ue_dl_t *q, uint32_t cfi, uint32_t sf_idx, u } } -int srslte_ue_dl_find_dl_dci(srslte_ue_dl_t *q, uint32_t cfi, uint32_t sf_idx, uint16_t rnti, srslte_dci_msg_t *dci_msg) +int srslte_ue_dl_find_dl_dci(srslte_ue_dl_t *q, uint32_t tm, uint32_t cfi, uint32_t sf_idx, uint16_t rnti, srslte_dci_msg_t *dci_msg) { srslte_rnti_type_t rnti_type; if (rnti == SRSLTE_SIRNTI) { @@ -642,7 +616,7 @@ int srslte_ue_dl_find_dl_dci(srslte_ue_dl_t *q, uint32_t cfi, uint32_t sf_idx, u } else { rnti_type = SRSLTE_RNTI_USER; } - return srslte_ue_dl_find_dl_dci_type(q, cfi, sf_idx, rnti, rnti_type, dci_msg); + return srslte_ue_dl_find_dl_dci_type(q, tm, cfi, sf_idx, rnti, rnti_type, dci_msg); } // Blind search for SI/P/RA-RNTI @@ -666,12 +640,17 @@ static int find_dl_dci_type_siprarnti(srslte_ue_dl_t *q, uint32_t cfi, uint16_t } // Blind search for C-RNTI -static int find_dl_dci_type_crnti(srslte_ue_dl_t *q, uint32_t cfi, uint32_t sf_idx, uint16_t rnti, srslte_dci_msg_t *dci_msg) -{ +static int find_dl_dci_type_crnti(srslte_ue_dl_t *q, uint32_t tm, uint32_t cfi, + uint32_t sf_idx, uint16_t rnti, srslte_dci_msg_t *dci_msg) { int ret = SRSLTE_SUCCESS; dci_blind_search_t search_space; dci_blind_search_t *current_ss = &search_space; - + + if (cfi < 1 || cfi > 3) { + ERROR("CFI must be 1 ≤ cfi ≤ 3", cfi); + return SRSLTE_ERROR; + } + // Search UE-specific search space if (q->current_rnti == rnti) { current_ss = &q->current_ss_ue[cfi-1][sf_idx]; @@ -681,15 +660,19 @@ static int find_dl_dci_type_crnti(srslte_ue_dl_t *q, uint32_t cfi, uint32_t sf_i } srslte_pdcch_set_cfi(&q->pdcch, cfi); - - INFO("Searching DL C-RNTI in %d ue locations, %d formats\n", current_ss->nof_locations, nof_ue_formats); - for (int f=0;fformat = ue_formats[f]; + + for (int f = 0; f < 2; f++) { + srslte_dci_format_t format = ue_dci_formats[tm][f]; + + INFO("Searching DL C-RNTI %s in %d ue locations\n", srslte_dci_format_string(format), + current_ss->nof_locations); + + current_ss->format = format; if ((ret = dci_blind_search(q, current_ss, rnti, dci_msg))) { return ret; } } - + // Search Format 1A in the Common SS also if (q->current_rnti == rnti) { current_ss = &q->current_ss_common[cfi-1]; @@ -709,13 +692,13 @@ static int find_dl_dci_type_crnti(srslte_ue_dl_t *q, uint32_t cfi, uint32_t sf_i return SRSLTE_SUCCESS; } -int srslte_ue_dl_find_dl_dci_type(srslte_ue_dl_t *q, uint32_t cfi, uint32_t sf_idx, +int srslte_ue_dl_find_dl_dci_type(srslte_ue_dl_t *q, uint32_t tm, uint32_t cfi, uint32_t sf_idx, uint16_t rnti, srslte_rnti_type_t rnti_type, srslte_dci_msg_t *dci_msg) { if (rnti_type == SRSLTE_RNTI_SI || rnti_type == SRSLTE_RNTI_PCH || rnti_type == SRSLTE_RNTI_RAR) { return find_dl_dci_type_siprarnti(q, cfi, rnti, dci_msg); } else { - return find_dl_dci_type_crnti(q, cfi, sf_idx, rnti, dci_msg); + return find_dl_dci_type_crnti(q, tm, cfi, sf_idx, rnti, dci_msg); } } diff --git a/srsue/src/phy/phch_worker.cc b/srsue/src/phy/phch_worker.cc index 3c05cc463..53dc232dc 100644 --- a/srsue/src/phy/phch_worker.cc +++ b/srsue/src/phy/phch_worker.cc @@ -103,7 +103,7 @@ bool phch_worker::init_cell(srslte_cell_t cell_) } } - if (srslte_ue_dl_init_multi(&ue_dl, cell, phy->args->nof_rx_ant)) { + if (srslte_ue_dl_init(&ue_dl, cell, phy->args->nof_rx_ant)) { Error("Initiating UE DL\n"); return false; } @@ -334,7 +334,7 @@ bool phch_worker::extract_fft_and_pdcch_llr() { srslte_chest_dl_set_noise_alg(&ue_dl.chest, SRSLTE_NOISE_ALG_PSS); } - if (srslte_ue_dl_decode_fft_estimate_multi(&ue_dl, signal_buffer, tti%10, &cfi) < 0) { + if (srslte_ue_dl_decode_fft_estimate(&ue_dl, signal_buffer, tti%10, &cfi) < 0) { Error("Getting PDCCH FFT estimate\n"); return false; } @@ -383,7 +383,8 @@ bool phch_worker::decode_pdcch_dl(srsue::mac_interface_phy::mac_grant_t* grant) Debug("Looking for RNTI=0x%x\n", dl_rnti); - if (srslte_ue_dl_find_dl_dci_type(&ue_dl, cfi, tti%10, dl_rnti, type, &dci_msg) != 1) { + if (srslte_ue_dl_find_dl_dci_type(&ue_dl, phy->config->dedicated.antenna_info_explicit_value.tx_mode, cfi, tti%10, + dl_rnti, type, &dci_msg) != 1) { return false; } From 9dffa10550a2435102eab2bae87aca72f4d2e71a Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Mon, 4 Sep 2017 17:56:58 +0200 Subject: [PATCH 52/60] fixed compiling issues --- lib/include/srslte/phy/utils/mat.h | 4 ++++ lib/src/phy/utils/mat.c | 3 ++- lib/src/phy/utils/vector.c | 10 ++++++++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/lib/include/srslte/phy/utils/mat.h b/lib/include/srslte/phy/utils/mat.h index 48d3b776d..d960590c4 100644 --- a/lib/include/srslte/phy/utils/mat.h +++ b/lib/include/srslte/phy/utils/mat.h @@ -30,6 +30,7 @@ #include "srslte/phy/utils/simd.h" #include "srslte/config.h" + /* * Generic Macros */ @@ -65,6 +66,7 @@ SRSLTE_API float srslte_mat_2x2_cn(cf_t h00, #ifdef LV_HAVE_SSE +#include /* SSE implementation for complex reciprocal */ SRSLTE_API __m128 srslte_mat_cf_recip_sse(__m128 a); @@ -88,6 +90,8 @@ SRSLTE_API void srslte_mat_2x2_mmse_sse(__m128 y0, __m128 y1, #ifdef LV_HAVE_AVX +#include + /* AVX implementation for complex reciprocal */ SRSLTE_API __m256 srslte_mat_cf_recip_avx(__m256 a); diff --git a/lib/src/phy/utils/mat.c b/lib/src/phy/utils/mat.c index 3c81d4a13..439daa2ce 100644 --- a/lib/src/phy/utils/mat.c +++ b/lib/src/phy/utils/mat.c @@ -25,7 +25,6 @@ */ #include -#include #include #include "srslte/phy/utils/mat.h" @@ -116,6 +115,7 @@ inline float srslte_mat_2x2_cn(cf_t h00, cf_t h01, cf_t h10, cf_t h11) { } #ifdef LV_HAVE_SSE +#include /* SSE implementation for complex reciprocal */ inline __m128 srslte_mat_cf_recip_sse(__m128 a) { @@ -186,6 +186,7 @@ inline void srslte_mat_2x2_mmse_sse(__m128 y0, __m128 y1, __m128 h00, __m128 h01 #endif /* LV_HAVE_SSE */ #ifdef LV_HAVE_AVX +#include /* AVX implementation for complex reciprocal */ inline __m256 srslte_mat_cf_recip_avx(__m256 a) { diff --git a/lib/src/phy/utils/vector.c b/lib/src/phy/utils/vector.c index 742b9573f..d78f5d707 100644 --- a/lib/src/phy/utils/vector.c +++ b/lib/src/phy/utils/vector.c @@ -35,6 +35,16 @@ #include "srslte/phy/utils/vector_simd.h" #include "srslte/phy/utils/bit.h" + +#ifdef LV_HAVE_SSE +#include +#endif + +#ifdef LV_HAVE_AVX +#include +#endif + + #ifdef HAVE_VOLK #include "volk/volk.h" #endif From 4e8f0de6dae75d76a6ed6ed035f8d26812c4c5b3 Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Mon, 4 Sep 2017 19:07:36 +0200 Subject: [PATCH 53/60] reduce PUSCH spectral efficiency if UCI is required --- srsenb/hdr/mac/scheduler_ue.h | 5 ++++- srsenb/src/mac/scheduler.cc | 15 +++++++++++---- srsenb/src/mac/scheduler_harq.cc | 2 +- srsenb/src/mac/scheduler_metric.cc | 3 ++- srsenb/src/mac/scheduler_ue.cc | 5 +++++ 5 files changed, 23 insertions(+), 7 deletions(-) diff --git a/srsenb/hdr/mac/scheduler_ue.h b/srsenb/hdr/mac/scheduler_ue.h index b95e5dda2..b59461140 100644 --- a/srsenb/hdr/mac/scheduler_ue.h +++ b/srsenb/hdr/mac/scheduler_ue.h @@ -40,7 +40,10 @@ class sched_ue { public: // used by sched_metric - uint32_t ue_idx; + uint32_t ue_idx; + + bool has_pusch; + bool has_pucch; typedef struct { uint32_t cce_start[4][6]; diff --git a/srsenb/src/mac/scheduler.cc b/srsenb/src/mac/scheduler.cc index 12a7ea1cc..73dbc2d41 100644 --- a/srsenb/src/mac/scheduler.cc +++ b/srsenb/src/mac/scheduler.cc @@ -691,7 +691,10 @@ int sched::ul_sched(uint32_t tti, srsenb::sched_interface::ul_sched_res_t* sched for(std::map::iterator iter=ue_db.begin(); iter!=ue_db.end(); ++iter) { sched_ue *user = (sched_ue*) &iter->second; uint16_t rnti = (uint16_t) iter->first; - + + user->has_pusch = false; + user->has_pucch = false; + ul_harq_proc *h = user->get_ul_harq(current_tti); /* Indicate PHICH acknowledgment if needed */ @@ -717,9 +720,13 @@ int sched::ul_sched(uint32_t tti, srsenb::sched_interface::ul_sched_res_t* sched uint32_t prb_idx[2] = {0, 0}; uint32_t L = 0; if (user->get_pucch_sched(current_tti, prb_idx, &L)) { - for (int i=0;i<2;i++) { - ul_harq_proc::ul_alloc_t pucch = {prb_idx[i], L}; - ul_metric->update_allocation(pucch); + user->has_pucch = true; + // allocate PUCCH if no PUSCH for user + if (!user->has_pusch) { + for (int i=0;i<2;i++) { + ul_harq_proc::ul_alloc_t pucch = {prb_idx[i], L}; + ul_metric->update_allocation(pucch); + } } } } diff --git a/srsenb/src/mac/scheduler_harq.cc b/srsenb/src/mac/scheduler_harq.cc index 009872153..a6ae70d19 100644 --- a/srsenb/src/mac/scheduler_harq.cc +++ b/srsenb/src/mac/scheduler_harq.cc @@ -100,7 +100,7 @@ void harq_proc::set_ack(bool ack_) ack = ack_; ack_received = true; log_h->debug("ACK=%d received pid=%d, n_rtx=%d, max_retx=%d\n", ack_, id, n_rtx, max_retx); - if (n_rtx >= max_retx) { + if (n_rtx + 1 >= max_retx) { Warning("SCHED: discarting TB pid=%d, tti=%d, maximum number of retx exceeded (%d)\n", id, tti, max_retx); active = false; } diff --git a/srsenb/src/mac/scheduler_metric.cc b/srsenb/src/mac/scheduler_metric.cc index 2a9a4432b..309eed45a 100644 --- a/srsenb/src/mac/scheduler_metric.cc +++ b/srsenb/src/mac/scheduler_metric.cc @@ -214,7 +214,8 @@ void ul_metric_rr::new_tti(std::map &ue_db, uint32_t nof_rb_, for(std::map::iterator iter=ue_db.begin(); iter!=ue_db.end(); ++iter) { sched_ue *user = (sched_ue*) &iter->second; if (user->get_pending_ul_new_data(current_tti) || !user->get_ul_harq(current_tti)->is_empty()) { - user->ue_idx = nof_users_with_data; + user->ue_idx = nof_users_with_data; + user->has_pusch = true; nof_users_with_data++; } } diff --git a/srsenb/src/mac/scheduler_ue.cc b/srsenb/src/mac/scheduler_ue.cc index 21aa61b19..4c6d467a2 100644 --- a/srsenb/src/mac/scheduler_ue.cc +++ b/srsenb/src/mac/scheduler_ue.cc @@ -813,6 +813,11 @@ int sched_ue::alloc_tbs(uint32_t nof_prb, uint32_t max_mcs = is_ul?max_mcs_ul:max_mcs_dl; uint32_t max_Qm = is_ul?4:6; // Allow 16-QAM in PUSCH Only + // TODO: Compute real spectral efficiency based on PUSCH-UCI configuration + if (has_pucch) { + cqi-=2; + } + int tbs = cqi_to_tbs(cqi, nof_prb, nof_re, max_mcs, max_Qm, &sel_mcs)/8; /* If less bytes are requested, lower the MCS */ From 14ab68e652311d0ae703a27835b1d6ba3aae12c2 Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Tue, 5 Sep 2017 10:05:53 +0200 Subject: [PATCH 54/60] added CQI to metrics --- srsenb/hdr/mac/mac_metrics.h | 1 + srsenb/hdr/mac/ue.h | 18 ++++++++++-------- srsenb/src/mac/mac.cc | 1 + srsenb/src/mac/scheduler_ue.cc | 6 +++--- srsenb/src/mac/ue.cc | 12 +++++++++--- srsenb/src/metrics_stdout.cc | 7 ++++--- 6 files changed, 28 insertions(+), 17 deletions(-) diff --git a/srsenb/hdr/mac/mac_metrics.h b/srsenb/hdr/mac/mac_metrics.h index 4e3452ae1..35a65f8ae 100644 --- a/srsenb/hdr/mac/mac_metrics.h +++ b/srsenb/hdr/mac/mac_metrics.h @@ -43,6 +43,7 @@ struct mac_metrics_t int rx_brate; int ul_buffer; int dl_buffer; + float dl_cqi; float phr; }; diff --git a/srsenb/hdr/mac/ue.h b/srsenb/hdr/mac/ue.h index b98b07f9d..5805e5472 100644 --- a/srsenb/hdr/mac/ue.h +++ b/srsenb/hdr/mac/ue.h @@ -48,8 +48,9 @@ public: log_h = NULL; rnti = 0; pcap = NULL; - nof_failures = 0; - phr_counter = 0; + nof_failures = 0; + phr_counter = 0; + dl_cqi_counter = 0; is_phy_added = false; for (int i=0;i lc_groups[4]; - + + uint32_t phr_counter; + uint32_t dl_cqi_counter; mac_metrics_t metrics; srslte::mac_pcap* pcap; diff --git a/srsenb/src/mac/mac.cc b/srsenb/src/mac/mac.cc index fb2c3110e..63d189c20 100644 --- a/srsenb/src/mac/mac.cc +++ b/srsenb/src/mac/mac.cc @@ -329,6 +329,7 @@ int mac::cqi_info(uint32_t tti, uint16_t rnti, uint32_t cqi_value) if (ue_db.count(rnti)) { scheduler.dl_cqi_info(tti, rnti, cqi_value); + ue_db[rnti]->metrics_dl_cqi(cqi_value); } else { Error("User rnti=0x%x not found\n", rnti); return -1; diff --git a/srsenb/src/mac/scheduler_ue.cc b/srsenb/src/mac/scheduler_ue.cc index 4c6d467a2..9a258a1a3 100644 --- a/srsenb/src/mac/scheduler_ue.cc +++ b/srsenb/src/mac/scheduler_ue.cc @@ -257,7 +257,7 @@ bool sched_ue::get_pucch_sched(uint32_t current_tti, uint32_t prb_idx[2], uint32 if (L) { *L = 1; } - Info("SCHED: Reserved Format1A PUCCH for rnti=0x%x, n_prb=%d,%d, n_pucch=%d\n", rnti, prb_idx[0], prb_idx[1], n_pucch); + Debug("SCHED: Reserved Format1A PUCCH for rnti=0x%x, n_prb=%d,%d, n_pucch=%d\n", rnti, prb_idx[0], prb_idx[1], n_pucch); return true; } } @@ -271,7 +271,7 @@ bool sched_ue::get_pucch_sched(uint32_t current_tti, uint32_t prb_idx[2], uint32 if (L) { *L = 1; } - Info("SCHED: Reserved Format1 PUCCH for rnti=0x%x, n_prb=%d,%d, n_pucch=%d\n", rnti, prb_idx[0], prb_idx[1], cfg.sr_N_pucch); + Debug("SCHED: Reserved Format1 PUCCH for rnti=0x%x, n_prb=%d,%d, n_pucch=%d\n", rnti, prb_idx[0], prb_idx[1], cfg.sr_N_pucch); return true; } // Finally check Format2 (periodic CQI) @@ -284,7 +284,7 @@ bool sched_ue::get_pucch_sched(uint32_t current_tti, uint32_t prb_idx[2], uint32 if(L) { *L = 2; } - Info("SCHED: Reserved Format2 PUCCH for rnti=0x%x, n_prb=%d,%d, n_pucch=%d, pmi_idx=%d\n", + Debug("SCHED: Reserved Format2 PUCCH for rnti=0x%x, n_prb=%d,%d, n_pucch=%d, pmi_idx=%d\n", rnti, prb_idx[0], prb_idx[1], cfg.cqi_pucch, cfg.cqi_idx); return true; } diff --git a/srsenb/src/mac/ue.cc b/srsenb/src/mac/ue.cc index 0b9776918..14944b6d4 100644 --- a/srsenb/src/mac/ue.cc +++ b/srsenb/src/mac/ue.cc @@ -396,14 +396,20 @@ void ue::metrics_read(mac_metrics_t* metrics_) metrics.dl_buffer = sched->get_dl_buffer(rnti); memcpy(metrics_, &metrics, sizeof(mac_metrics_t)); - - phr_counter = 0; + + phr_counter = 0; + dl_cqi_counter = 0; bzero(&metrics, sizeof(mac_metrics_t)); } void ue::metrics_phr(float phr) { metrics.phr = SRSLTE_VEC_CMA(phr, metrics.phr, phr_counter); - phr_counter++; + phr_counter++; +} + +void ue::metrics_dl_cqi(uint32_t dl_cqi) { + metrics.dl_cqi = SRSLTE_VEC_CMA((float) dl_cqi, metrics.dl_cqi, dl_cqi_counter); + dl_cqi_counter++; } void ue::metrics_rx(bool crc, uint32_t tbs) diff --git a/srsenb/src/metrics_stdout.cc b/srsenb/src/metrics_stdout.cc index dc6b6d575..6c294b96d 100644 --- a/srsenb/src/metrics_stdout.cc +++ b/srsenb/src/metrics_stdout.cc @@ -108,8 +108,8 @@ void metrics_stdout::print_metrics() { n_reports = 0; cout << endl; - cout << "------DL-------------------UL----------------" << endl; - cout << "rnti mcs brate bler snr phr turbo mcs brate bler" << endl; + cout << "------DL-------------------------UL-------------------------------" << endl; + cout << "rnti cqi mcs brate bler snr phr mcs brate bler bsr" << endl; } if (metrics.rrc.n_ues > 0) { @@ -122,6 +122,7 @@ void metrics_stdout::print_metrics() } cout << std::hex << metrics.mac[i].rnti << " "; + cout << float_to_string(metrics.mac[i].dl_cqi, 2); cout << float_to_string(metrics.phy[i].dl.mcs, 2); if (metrics.mac[i].tx_brate > 0 && metrics_report_period) { cout << float_to_eng_string((float) metrics.mac[i].tx_brate/metrics_report_period, 2); @@ -135,7 +136,6 @@ void metrics_stdout::print_metrics() } cout << float_to_string(metrics.phy[i].ul.sinr, 2); cout << float_to_string(metrics.mac[i].phr, 2); - cout << float_to_string(metrics.phy[i].ul.turbo_iters, 2); cout << float_to_string(metrics.phy[i].ul.mcs, 2); if (metrics.mac[i].rx_brate > 0 && metrics_report_period) { cout << float_to_eng_string((float) metrics.mac[i].rx_brate/metrics_report_period, 2); @@ -147,6 +147,7 @@ void metrics_stdout::print_metrics() } else { cout << float_to_string(0, 2) << "%"; } + cout << float_to_eng_string(metrics.mac[i].ul_buffer, 2); cout << endl; } } else { From 5341d79b8a0a618f7d1e3c715bdbd659554e9b25 Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Tue, 5 Sep 2017 10:54:36 +0200 Subject: [PATCH 55/60] Fix memory alignment in PUCCH processing. Fixes #94 --- lib/include/srslte/phy/phch/uci.h | 8 +++++--- lib/src/phy/phch/pucch.c | 1 + lib/src/phy/phch/uci.c | 17 ++++++++++++++++- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/lib/include/srslte/phy/phch/uci.h b/lib/include/srslte/phy/phch/uci.h index bad87866e..01eae8e89 100644 --- a/lib/include/srslte/phy/phch/uci.h +++ b/lib/include/srslte/phy/phch/uci.h @@ -57,8 +57,8 @@ typedef struct SRSLTE_API { } srslte_uci_cqi_pusch_t; typedef struct SRSLTE_API { - uint8_t cqi_table[16][32]; - int16_t cqi_table_s[16][32]; // aligned for simd + uint8_t *cqi_table[16]; + int16_t *cqi_table_s[16]; } srslte_uci_cqi_pucch_t; typedef struct SRSLTE_API { @@ -85,7 +85,9 @@ typedef struct { SRSLTE_API void srslte_uci_cqi_pucch_init(srslte_uci_cqi_pucch_t *q); -SRSLTE_API int srslte_uci_encode_cqi_pucch(uint8_t *cqi_data, +SRSLTE_API void srslte_uci_cqi_pucch_free(srslte_uci_cqi_pucch_t *q); + +SRSLTE_API int srslte_uci_encode_cqi_pucch(uint8_t *cqi_data, uint32_t cqi_len, uint8_t b_bits[SRSLTE_UCI_CQI_CODED_PUCCH_B]); diff --git a/lib/src/phy/phch/pucch.c b/lib/src/phy/phch/pucch.c index 70b500cd0..56349dee4 100644 --- a/lib/src/phy/phch/pucch.c +++ b/lib/src/phy/phch/pucch.c @@ -465,6 +465,7 @@ void srslte_pucch_free(srslte_pucch_t *q) { } free(q->users); } + srslte_uci_cqi_pucch_free(&q->cqi); if (q->z) { free(q->z); } diff --git a/lib/src/phy/phch/uci.c b/lib/src/phy/phch/uci.c index 5bf40cc17..3b22eb792 100644 --- a/lib/src/phy/phch/uci.c +++ b/lib/src/phy/phch/uci.c @@ -32,6 +32,7 @@ #include #include #include +#include #include "srslte/phy/phch/uci.h" #include "srslte/phy/fec/cbsegm.h" @@ -109,7 +110,9 @@ void srslte_uci_cqi_pucch_init(srslte_uci_cqi_pucch_t *q) { uint32_t nwords = 16; for (uint32_t w=0;wcqi_table[w] = srslte_vec_malloc(SRSLTE_UCI_CQI_CODED_PUCCH_B*sizeof(int8_t)); + q->cqi_table_s[w] = srslte_vec_malloc(SRSLTE_UCI_CQI_CODED_PUCCH_B*sizeof(int16_t)); + uint8_t *ptr = word; srslte_bit_unpack(w, &ptr, 4); srslte_uci_encode_cqi_pucch(word, 4, q->cqi_table[w]); for (int j=0;jcqi_table[w]) { + free(q->cqi_table[w]); + } + if (q->cqi_table_s[w]) { + free(q->cqi_table_s[w]); + } + } +} + /* Encode UCI CQI/PMI as described in 5.2.3.3 of 36.212 */ int srslte_uci_encode_cqi_pucch(uint8_t *cqi_data, uint32_t cqi_len, uint8_t b_bits[SRSLTE_UCI_CQI_CODED_PUCCH_B]) From a9d03ebb42d4fbdf1e63438f2bb6ed7e9f4dfa71 Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Tue, 5 Sep 2017 15:09:19 +0200 Subject: [PATCH 56/60] fixed offset length in pdsch scrambling sequence --- lib/src/phy/phch/pdsch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/phy/phch/pdsch.c b/lib/src/phy/phch/pdsch.c index bc62df7fd..f761dbc3d 100644 --- a/lib/src/phy/phch/pdsch.c +++ b/lib/src/phy/phch/pdsch.c @@ -557,7 +557,7 @@ static int srslte_pdsch_codeword_decode(srslte_pdsch_t *pdsch, srslte_pdsch_cfg_ ERROR("Initialising scrambling sequence"); return SRSLTE_ERROR; } - srslte_scrambling_s_offset(&seq, pdsch->e[codeword_idx], codeword_idx, nbits->nof_bits); + srslte_scrambling_s_offset(&seq, pdsch->e[codeword_idx], 0, nbits->nof_bits); srslte_sequence_free(&seq); } From 30c6c8d21bdb62e81e376ec683024cbc53f896a1 Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Tue, 5 Sep 2017 15:09:19 +0200 Subject: [PATCH 57/60] fixed offset length in pdsch scrambling sequence --- lib/src/phy/phch/pdsch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/phy/phch/pdsch.c b/lib/src/phy/phch/pdsch.c index bc62df7fd..f761dbc3d 100644 --- a/lib/src/phy/phch/pdsch.c +++ b/lib/src/phy/phch/pdsch.c @@ -557,7 +557,7 @@ static int srslte_pdsch_codeword_decode(srslte_pdsch_t *pdsch, srslte_pdsch_cfg_ ERROR("Initialising scrambling sequence"); return SRSLTE_ERROR; } - srslte_scrambling_s_offset(&seq, pdsch->e[codeword_idx], codeword_idx, nbits->nof_bits); + srslte_scrambling_s_offset(&seq, pdsch->e[codeword_idx], 0, nbits->nof_bits); srslte_sequence_free(&seq); } From 91a8a291009a427b33054957ebd20929f745d69b Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Tue, 5 Sep 2017 16:51:44 +0200 Subject: [PATCH 58/60] fixed memory issues --- lib/src/phy/enb/enb_ul.c | 4 ++-- srsenb/hdr/phy/phch_common.h | 1 + srsenb/src/mac/mac.cc | 10 ---------- srsenb/src/mac/scheduler.cc | 2 ++ srsenb/src/phy/phch_common.cc | 2 +- srsenb/src/phy/phch_worker.cc | 13 ++++++++++++- srsenb/src/phy/prach_worker.cc | 5 +++-- srsenb/src/upper/rrc.cc | 8 ++++---- srsenb/src/upper/s1ap.cc | 1 + 9 files changed, 26 insertions(+), 20 deletions(-) diff --git a/lib/src/phy/enb/enb_ul.c b/lib/src/phy/enb/enb_ul.c index 9d773d6d5..c399d715c 100644 --- a/lib/src/phy/enb/enb_ul.c +++ b/lib/src/phy/enb/enb_ul.c @@ -60,7 +60,7 @@ int srslte_enb_ul_init(srslte_enb_ul_t *q, srslte_cell_t cell, memcpy(&q->hopping_cfg, hopping_cfg, sizeof(srslte_pusch_hopping_cfg_t)); } - q->users = calloc(sizeof(srslte_enb_ul_user_t*), SRSLTE_SIRNTI); + q->users = calloc(sizeof(srslte_enb_ul_user_t*), (1+SRSLTE_SIRNTI)); if (!q->users) { perror("malloc"); goto clean_exit; @@ -161,7 +161,7 @@ void srslte_enb_ul_free(srslte_enb_ul_t *q) int srslte_enb_ul_add_rnti(srslte_enb_ul_t *q, uint16_t rnti) { if (!q->users[rnti]) { - q->users[rnti] = malloc(sizeof(srslte_enb_ul_user_t)); + q->users[rnti] = calloc(1, sizeof(srslte_enb_ul_user_t)); if (srslte_pucch_set_crnti(&q->pucch, rnti)) { fprintf(stderr, "Error setting PUCCH rnti\n"); diff --git a/srsenb/hdr/phy/phch_common.h b/srsenb/hdr/phy/phch_common.h index ae396ae0e..00a59d969 100644 --- a/srsenb/hdr/phy/phch_common.h +++ b/srsenb/hdr/phy/phch_common.h @@ -54,6 +54,7 @@ public: phch_common(uint32_t max_mutex_) : tx_mutex(max_mutex_) { + nof_mutex = 0; max_mutex = max_mutex_; params.max_prach_offset_us = 20; } diff --git a/srsenb/src/mac/mac.cc b/srsenb/src/mac/mac.cc index 63d189c20..a1e9fb21b 100644 --- a/srsenb/src/mac/mac.cc +++ b/srsenb/src/mac/mac.cc @@ -113,16 +113,6 @@ void mac::reset() /* Setup scheduler */ scheduler.reset(); - /* Setup SI-RNTI in PHY */ - phy_h->add_rnti(SRSLTE_SIRNTI); - - /* Setup P-RNTI in PHY */ - phy_h->add_rnti(SRSLTE_PRNTI); - - /* Setup RA-RNTI in PHY */ - for (int i=0;i<10;i++) { - phy_h->add_rnti(1+i); - } } uint32_t mac::get_unique_id() diff --git a/srsenb/src/mac/scheduler.cc b/srsenb/src/mac/scheduler.cc index 73dbc2d41..325970b83 100644 --- a/srsenb/src/mac/scheduler.cc +++ b/srsenb/src/mac/scheduler.cc @@ -20,6 +20,7 @@ namespace srsenb { *******************************************************/ sched::sched() { + current_tti = 0; log_h = NULL; pthread_mutex_init(&mutex, NULL); reset(); @@ -39,6 +40,7 @@ void sched::init(rrc_interface_mac *rrc_, srslte::log* log) int sched::reset() { + bzero(pending_msg3, sizeof(pending_msg3_t)*10); bzero(pending_rar, sizeof(sched_rar_t)*SCHED_MAX_PENDING_RAR); bzero(pending_sibs, sizeof(sched_sib_t)*MAX_SIBS); ue_db.clear(); diff --git a/srsenb/src/phy/phch_common.cc b/srsenb/src/phy/phch_common.cc index bfb0d1b0d..e4d91581e 100644 --- a/srsenb/src/phy/phch_common.cc +++ b/srsenb/src/phy/phch_common.cc @@ -60,7 +60,7 @@ bool phch_common::init(srslte_cell_t *cell_, srslte::radio* radio_h_, mac_interf is_first_of_burst = true; is_first_tx = true; - for (uint32_t i=0;iparams.pusch_max_its); srslte_enb_dl_set_amp(&enb_dl, phy->params.tx_amplitude); diff --git a/srsenb/src/phy/prach_worker.cc b/srsenb/src/phy/prach_worker.cc index 218f7cc21..15b42c374 100644 --- a/srsenb/src/phy/prach_worker.cc +++ b/srsenb/src/phy/prach_worker.cc @@ -56,8 +56,9 @@ int prach_worker::init(srslte_cell_t *cell_, srslte_prach_cfg_t *prach_cfg_, mac } start(priority); - initiated = true; - + initiated = true; + + sf_cnt = 0; pending_tti = 0; processed_tti = 0; return 0; diff --git a/srsenb/src/upper/rrc.cc b/srsenb/src/upper/rrc.cc index 03ea65f2c..44b3d9a89 100644 --- a/srsenb/src/upper/rrc.cc +++ b/srsenb/src/upper/rrc.cc @@ -61,7 +61,8 @@ void rrc::init(rrc_cfg_t *cfg_, pthread_mutex_init(&user_mutex, NULL); pthread_mutex_init(&paging_mutex, NULL); - + + act_monitor.start(RRC_THREAD_PRIO); bzero(&sr_sched, sizeof(sr_sched_t)); start(RRC_THREAD_PRIO); @@ -69,9 +70,8 @@ void rrc::init(rrc_cfg_t *cfg_, rrc::activity_monitor::activity_monitor(rrc* parent_) { - running = true; - parent = parent_; - start(RRC_THREAD_PRIO); + running = true; + parent = parent_; } void rrc::activity_monitor::stop() diff --git a/srsenb/src/upper/s1ap.cc b/srsenb/src/upper/s1ap.cc index eba9186e7..44a564d09 100644 --- a/srsenb/src/upper/s1ap.cc +++ b/srsenb/src/upper/s1ap.cc @@ -347,6 +347,7 @@ bool s1ap::setup_s1() uint16_t tmp16; srslte::byte_buffer_t msg; LIBLTE_S1AP_S1AP_PDU_STRUCT pdu; + bzero(&pdu, sizeof(LIBLTE_S1AP_S1AP_PDU_STRUCT)); pdu.choice_type = LIBLTE_S1AP_S1AP_PDU_CHOICE_INITIATINGMESSAGE; From ea368516c951aea6b8f4e37b09072e51a718b37f Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Thu, 7 Sep 2017 12:52:45 +0200 Subject: [PATCH 59/60] fixed plot for MIMO --- srsue/src/phy/phch_worker.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/srsue/src/phy/phch_worker.cc b/srsue/src/phy/phch_worker.cc index 53dc232dc..4618f2d16 100644 --- a/srsue/src/phy/phch_worker.cc +++ b/srsue/src/phy/phch_worker.cc @@ -1054,7 +1054,7 @@ int phch_worker::read_ce_abs(float *ce_abs) { int phch_worker::read_pdsch_d(cf_t* pdsch_d) { - memcpy(pdsch_d, ue_dl.pdsch.d, ue_dl.pdsch_cfg.nbits[0].nof_re*sizeof(cf_t)); + memcpy(pdsch_d, ue_dl.pdsch.d[0], ue_dl.pdsch_cfg.nbits[0].nof_re*sizeof(cf_t)); return ue_dl.pdsch_cfg.nbits[0].nof_re; } From 25e9acd0693d9f47ccca0f38d2a596b8fdb78f2e Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Thu, 7 Sep 2017 13:03:53 +0200 Subject: [PATCH 60/60] restore RX gain to 50 dB --- srsenb/enb.conf.example | 2 +- srsue/ue.conf.example | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/srsenb/enb.conf.example b/srsenb/enb.conf.example index 1c54cfc45..6847f7392 100644 --- a/srsenb/enb.conf.example +++ b/srsenb/enb.conf.example @@ -59,7 +59,7 @@ drb_config = drb.conf [rf] dl_earfcn = 3400 tx_gain = 80 -rx_gain = 60 +rx_gain = 50 #device_name = auto #device_args = auto diff --git a/srsue/ue.conf.example b/srsue/ue.conf.example index 8c9ba7d3d..ea162e337 100644 --- a/srsue/ue.conf.example +++ b/srsue/ue.conf.example @@ -24,7 +24,7 @@ dl_freq = 2685000000 ul_freq = 2565000000 tx_gain = 80 -rx_gain = 60 +rx_gain = 50 #nof_rx_ant = 1 #device_name = auto