diff --git a/srslte/include/srslte/ch_estimation/chest_dl.h b/srslte/include/srslte/ch_estimation/chest_dl.h index 1d37b3aad..50a083dae 100644 --- a/srslte/include/srslte/ch_estimation/chest_dl.h +++ b/srslte/include/srslte/ch_estimation/chest_dl.h @@ -76,9 +76,9 @@ typedef struct { srslte_interp_linsrslte_vec_t srslte_interp_linvec; srslte_interp_lin_t srslte_interp_lin; - float rssi[SRSLTE_MAX_PORTS]; - float rsrp[SRSLTE_MAX_PORTS]; - float noise_estimate[SRSLTE_MAX_PORTS]; + float rssi[SRSLTE_MAX_RXANT][SRSLTE_MAX_PORTS]; + float rsrp[SRSLTE_MAX_RXANT][SRSLTE_MAX_PORTS]; + float noise_estimate[SRSLTE_MAX_RXANT][SRSLTE_MAX_PORTS]; /* Use PSS for noise estimation in LS linear interpolation mode */ cf_t pss_signal[SRSLTE_PSS_LEN]; @@ -86,6 +86,7 @@ typedef struct { cf_t tmp_pss_noisy[SRSLTE_PSS_LEN]; srslte_chest_dl_noise_alg_t noise_alg; + int last_nof_antennas; } srslte_chest_dl_t; @@ -120,7 +121,8 @@ SRSLTE_API int srslte_chest_dl_estimate_port(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, uint32_t sf_idx, - uint32_t port_id); + uint32_t port_id, + uint32_t rxant_id); SRSLTE_API float srslte_chest_dl_get_noise_estimate(srslte_chest_dl_t *q); diff --git a/srslte/include/srslte/phch/pdcch.h b/srslte/include/srslte/phch/pdcch.h index 5f080cbd8..ba538ba98 100644 --- a/srslte/include/srslte/phch/pdcch.h +++ b/srslte/include/srslte/phch/pdcch.h @@ -63,12 +63,13 @@ typedef struct SRSLTE_API { uint32_t nof_regs; uint32_t nof_cce; uint32_t max_bits; - + uint32_t nof_rx_antennas; + srslte_regs_t *regs; /* buffers */ - cf_t *ce[SRSLTE_MAX_PORTS]; - cf_t *symbols[SRSLTE_MAX_PORTS]; + cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_RXANT]; + cf_t *symbols[SRSLTE_MAX_RXANT]; cf_t *x[SRSLTE_MAX_PORTS]; cf_t *d; uint8_t *e; @@ -87,6 +88,11 @@ SRSLTE_API int srslte_pdcch_init(srslte_pdcch_t *q, srslte_regs_t *regs, srslte_cell_t cell); +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 void srslte_pdcch_free(srslte_pdcch_t *q); @@ -113,6 +119,13 @@ SRSLTE_API int srslte_pdcch_extract_llr(srslte_pdcch_t *q, uint32_t nsubframe, uint32_t cfi); +SRSLTE_API int srslte_pdcch_extract_llr_multi(srslte_pdcch_t *q, + cf_t *sf_symbols[SRSLTE_MAX_RXANT], + cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_RXANT], + float noise_estimate, + uint32_t nsubframe, + uint32_t cfi); + /* Decoding functions: Try to decode a DCI message after calling srslte_pdcch_extract_llr */ SRSLTE_API int srslte_pdcch_decode_msg(srslte_pdcch_t *q, srslte_dci_msg_t *msg, diff --git a/srslte/lib/ch_estimation/chest_dl.c b/srslte/lib/ch_estimation/chest_dl.c index 7145c9fd6..d6b6a0480 100644 --- a/srslte/lib/ch_estimation/chest_dl.c +++ b/srslte/lib/ch_estimation/chest_dl.c @@ -311,7 +311,7 @@ float srslte_chest_dl_rssi(srslte_chest_dl_t *q, cf_t *input, uint32_t port_id) return rssi/nsymbols; } -int srslte_chest_dl_estimate_port(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, uint32_t sf_idx, uint32_t port_id) +int srslte_chest_dl_estimate_port(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, uint32_t sf_idx, uint32_t port_id, uint32_t rxant_id) { /* Get references from the input signal */ srslte_refsignal_cs_get_sf(q->cell, port_id, input, q->pilot_recv_signal); @@ -331,24 +331,24 @@ int srslte_chest_dl_estimate_port(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, u /* Estimate noise power */ if (q->noise_alg == SRSLTE_NOISE_ALG_REFS && q->smooth_filter_len > 0) { - q->noise_estimate[port_id] = estimate_noise_pilots(q, port_id); + q->noise_estimate[rxant_id][port_id] = estimate_noise_pilots(q, port_id); } else if (q->noise_alg == SRSLTE_NOISE_ALG_PSS) { if (sf_idx == 0 || sf_idx == 5) { - q->noise_estimate[port_id] = estimate_noise_pss(q, input, ce); + q->noise_estimate[rxant_id][port_id] = estimate_noise_pss(q, input, ce); } } else { if (sf_idx == 0 || sf_idx == 5) { - q->noise_estimate[port_id] = estimate_noise_empty_sc(q, input); + q->noise_estimate[rxant_id][port_id] = estimate_noise_empty_sc(q, input); } } } /* Compute RSRP for the channel estimates in this port */ - q->rsrp[port_id] = srslte_vec_avg_power_cf(q->pilot_recv_signal, SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id)); + q->rsrp[rxant_id][port_id] = srslte_vec_avg_power_cf(q->pilot_recv_signal, SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id)); if (port_id == 0) { /* compute rssi only for port 0 */ - q->rssi[port_id] = srslte_chest_dl_rssi(q, input, port_id); + q->rssi[rxant_id][port_id] = srslte_chest_dl_rssi(q, input, port_id); } return 0; @@ -356,13 +356,14 @@ int srslte_chest_dl_estimate_port(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, u int srslte_chest_dl_estimate_multi(srslte_chest_dl_t *q, cf_t *input[SRSLTE_MAX_RXANT], cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_RXANT], uint32_t sf_idx, uint32_t nof_rx_antennas) { - for (uint32_t rxant=0;rxantcell.nof_ports;port_id++) { - if (srslte_chest_dl_estimate_port(q, input[rxant], ce[port_id][rxant], sf_idx, port_id)) { + if (srslte_chest_dl_estimate_port(q, input[rxant_id], ce[port_id][rxant_id], sf_idx, port_id, rxant_id)) { return SRSLTE_ERROR; } } } + q->last_nof_antennas = nof_rx_antennas; return SRSLTE_SUCCESS; } @@ -371,15 +372,20 @@ int srslte_chest_dl_estimate(srslte_chest_dl_t *q, cf_t *input, cf_t *ce[SRSLTE_ uint32_t port_id; for (port_id=0;port_idcell.nof_ports;port_id++) { - if (srslte_chest_dl_estimate_port(q, input, ce[port_id], sf_idx, port_id)) { + if (srslte_chest_dl_estimate_port(q, input, ce[port_id], sf_idx, port_id, 0)) { return SRSLTE_ERROR; } } + q->last_nof_antennas = 1; return SRSLTE_SUCCESS; } float srslte_chest_dl_get_noise_estimate(srslte_chest_dl_t *q) { - return srslte_vec_acc_ff(q->noise_estimate, q->cell.nof_ports)/q->cell.nof_ports; + float n = 0; + for (int i=0;ilast_nof_antennas;i++) { + n += srslte_vec_acc_ff(q->noise_estimate[i], q->cell.nof_ports)/q->cell.nof_ports; + } + return n/q->last_nof_antennas; } float srslte_chest_dl_get_snr(srslte_chest_dl_t *q) { @@ -392,20 +398,31 @@ float srslte_chest_dl_get_snr(srslte_chest_dl_t *q) { } float srslte_chest_dl_get_rssi(srslte_chest_dl_t *q) { - return 4*q->rssi[0]/q->cell.nof_prb/SRSLTE_NRE; + float n = 0; + for (int i=0;ilast_nof_antennas;i++) { + n += 4*q->rssi[i][0]/q->cell.nof_prb/SRSLTE_NRE; + } + return n/q->last_nof_antennas; } /* q->rssi[0] is the average power in all RE in all symbol containing references for port 0 . q->rssi[0]/q->cell.nof_prb is the average power per PRB * q->rsrp[0] is the average power of RE containing references only (for port 0). */ float srslte_chest_dl_get_rsrq(srslte_chest_dl_t *q) { - return q->cell.nof_prb*q->rsrp[0] / q->rssi[0]; + float n = 0; + for (int i=0;ilast_nof_antennas;i++) { + n += q->cell.nof_prb*q->rsrp[i][0] / q->rssi[i][0]; + } + return n/q->last_nof_antennas; } -float srslte_chest_dl_get_rsrp(srslte_chest_dl_t *q) { - +float srslte_chest_dl_get_rsrp(srslte_chest_dl_t *q) { // return sum of power received from all tx ports - return srslte_vec_acc_ff(q->rsrp, q->cell.nof_ports); + float n = 0; + for (int i=0;ilast_nof_antennas;i++) { + n += srslte_vec_acc_ff(q->rsrp[i], q->cell.nof_ports)/q->cell.nof_ports; + } + return n/q->last_nof_antennas; } diff --git a/srslte/lib/ch_estimation/test/chest_test_dl.c b/srslte/lib/ch_estimation/test/chest_test_dl.c index d296ccc18..c60e94d96 100644 --- a/srslte/lib/ch_estimation/test/chest_test_dl.c +++ b/srslte/lib/ch_estimation/test/chest_test_dl.c @@ -161,7 +161,7 @@ int main(int argc, char **argv) { struct timeval t[3]; gettimeofday(&t[1], NULL); for (int j=0;j<100;j++) { - srslte_chest_dl_estimate_port(&est, input, ce, sf_idx, n_port); + srslte_chest_dl_estimate_port(&est, input, ce, sf_idx, n_port, 0); } gettimeofday(&t[2], NULL); get_time_interval(t); diff --git a/srslte/lib/phch/pdcch.c b/srslte/lib/phch/pdcch.c index 9cf610c01..4b40e5a06 100644 --- a/srslte/lib/phch/pdcch.c +++ b/srslte/lib/phch/pdcch.c @@ -62,8 +62,12 @@ float srslte_pdcch_coderate(uint32_t nof_bits, uint32_t l) { /** Initializes the PDCCH transmitter and receiver */ int srslte_pdcch_init(srslte_pdcch_t *q, srslte_regs_t *regs, srslte_cell_t cell) { + return srslte_pdcch_init_multi(q, regs, cell, 1); +} + +int srslte_pdcch_init_multi(srslte_pdcch_t *q, srslte_regs_t *regs, srslte_cell_t cell, uint32_t nof_rx_antennas) +{ int ret = SRSLTE_ERROR_INVALID_INPUTS; - uint32_t i; if (q != NULL && regs != NULL && @@ -73,6 +77,7 @@ int srslte_pdcch_init(srslte_pdcch_t *q, srslte_regs_t *regs, srslte_cell_t cell bzero(q, sizeof(srslte_pdcch_t)); q->cell = cell; q->regs = regs; + q->nof_rx_antennas = nof_rx_antennas; /* Allocate memory for the maximum number of PDCCH bits (CFI=3) */ q->max_bits = (srslte_regs_pdcch_nregs(q->regs, 3) / 9) * 72; @@ -87,7 +92,7 @@ int srslte_pdcch_init(srslte_pdcch_t *q, srslte_regs_t *regs, srslte_cell_t cell goto clean; } - for (i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) { + for (int i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) { // we need to pregenerate the sequence for the maximum number of bits, which is 8 times // the maximum number of REGs (for CFI=3) if (srslte_sequence_pdcch(&q->seq[i], 2 * i, q->cell.id, 8*srslte_regs_pdcch_nregs(q->regs, 3))) { @@ -117,17 +122,21 @@ int srslte_pdcch_init(srslte_pdcch_t *q, srslte_regs_t *regs, srslte_cell_t cell goto clean; } - for (i = 0; i < SRSLTE_MAX_PORTS; i++) { - q->ce[i] = srslte_vec_malloc(sizeof(cf_t) * q->max_bits / 2); - if (!q->ce[i]) { - goto clean; + for (int i = 0; i < SRSLTE_MAX_PORTS; i++) { + for (int j=0;jnof_rx_antennas;j++) { + q->ce[i][j] = srslte_vec_malloc(sizeof(cf_t) * q->max_bits / 2); + if (!q->ce[i][j]) { + goto clean; + } } q->x[i] = srslte_vec_malloc(sizeof(cf_t) * q->max_bits / 2); if (!q->x[i]) { goto clean; } - q->symbols[i] = srslte_vec_malloc(sizeof(cf_t) * q->max_bits / 2); - if (!q->symbols[i]) { + } + for (int j=0;jnof_rx_antennas;j++) { + q->symbols[j] = srslte_vec_malloc(sizeof(cf_t) * q->max_bits / 2); + if (!q->symbols[j]) { goto clean; } } @@ -142,7 +151,6 @@ int srslte_pdcch_init(srslte_pdcch_t *q, srslte_regs_t *regs, srslte_cell_t cell } void srslte_pdcch_free(srslte_pdcch_t *q) { - int i; if (q->e) { free(q->e); @@ -153,19 +161,22 @@ void srslte_pdcch_free(srslte_pdcch_t *q) { if (q->d) { free(q->d); } - for (i = 0; i < SRSLTE_MAX_PORTS; i++) { - if (q->ce[i]) { - free(q->ce[i]); + for (int i = 0; i < SRSLTE_MAX_PORTS; i++) { + for (int j=0;jnof_rx_antennas;j++) { + if (q->ce[i][j]) { + free(q->ce[i][j]); + } } if (q->x[i]) { free(q->x[i]); } - if (q->symbols[i]) { - free(q->symbols[i]); + } + for (int j=0;jnof_rx_antennas;j++) { + if (q->symbols[j]) { + free(q->symbols[j]); } } - - for (i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) { + for (int i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) { srslte_sequence_free(&q->seq[i]); } @@ -379,13 +390,27 @@ int srslte_pdcch_decode_msg(srslte_pdcch_t *q, int cnt=0; +int srslte_pdcch_extract_llr(srslte_pdcch_t *q, cf_t *sf_symbols, cf_t *ce[SRSLTE_MAX_PORTS], float noise_estimate, + uint32_t nsubframe, uint32_t cfi) +{ + cf_t *_sf_symbols[SRSLTE_MAX_RXANT]; + cf_t *_ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_RXANT]; + + _sf_symbols[0] = sf_symbols; + for (int i=0;icell.nof_ports;i++) { + _ce[i][0] = ce[i]; + } + return srslte_pdcch_extract_llr_multi(q, _sf_symbols, _ce, noise_estimate, nsubframe, cfi); +} + /** Extracts the LLRs from srslte_dci_location_t location of the subframe and stores them in the srslte_pdcch_t structure. * DCI messages can be extracted from this location calling the function srslte_pdcch_decode_msg(). * Every time this function is called (with a different location), the last demodulated symbols are overwritten and * new messages from other locations can be decoded */ -int srslte_pdcch_extract_llr(srslte_pdcch_t *q, cf_t *sf_symbols, cf_t *ce[SRSLTE_MAX_PORTS], float noise_estimate, - uint32_t nsubframe, uint32_t cfi) { +int srslte_pdcch_extract_llr_multi(srslte_pdcch_t *q, cf_t *sf_symbols[SRSLTE_MAX_RXANT], cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_RXANT], float noise_estimate, + uint32_t nsubframe, uint32_t cfi) +{ int ret = SRSLTE_ERROR_INVALID_INPUTS; @@ -415,27 +440,29 @@ int srslte_pdcch_extract_llr(srslte_pdcch_t *q, cf_t *sf_symbols, cf_t *ce[SRSLT memset(&x[q->cell.nof_ports], 0, sizeof(cf_t*) * (SRSLTE_MAX_LAYERS - q->cell.nof_ports)); /* extract symbols */ - int n = srslte_regs_pdcch_get(q->regs, sf_symbols, q->symbols[0]); - if (nof_symbols != n) { - fprintf(stderr, "Expected %d PDCCH symbols but got %d symbols\n", nof_symbols, n); - return ret; - } - - /* extract channel estimates */ - for (i = 0; i < q->cell.nof_ports; i++) { - n = srslte_regs_pdcch_get(q->regs, ce[i], q->ce[i]); + for (int j=0;jnof_rx_antennas;j++) { + int n = srslte_regs_pdcch_get(q->regs, sf_symbols[j], q->symbols[j]); if (nof_symbols != n) { fprintf(stderr, "Expected %d PDCCH symbols but got %d symbols\n", nof_symbols, n); return ret; } - } + /* extract channel estimates */ + for (i = 0; i < q->cell.nof_ports; i++) { + n = srslte_regs_pdcch_get(q->regs, ce[i][j], q->ce[i][j]); + if (nof_symbols != n) { + fprintf(stderr, "Expected %d PDCCH symbols but got %d symbols\n", nof_symbols, n); + return ret; + } + } + } + /* in control channels, only diversity is supported */ if (q->cell.nof_ports == 1) { /* no need for layer demapping */ - srslte_predecoding_single(q->symbols[0], q->ce[0], q->d, nof_symbols, noise_estimate/2); + srslte_predecoding_single_multi(q->symbols, q->ce[0], q->d, q->nof_rx_antennas, nof_symbols, noise_estimate/2); } else { - srslte_predecoding_diversity(q->symbols[0], q->ce, x, q->cell.nof_ports, nof_symbols); + srslte_predecoding_diversity_multi(q->symbols, q->ce, x, q->nof_rx_antennas, q->cell.nof_ports, nof_symbols); srslte_layerdemap_diversity(x, q->d, q->cell.nof_ports, nof_symbols / q->cell.nof_ports); } diff --git a/srslte/lib/ue/ue_dl.c b/srslte/lib/ue/ue_dl.c index 6f326b114..c12ce8889 100644 --- a/srslte/lib/ue/ue_dl.c +++ b/srslte/lib/ue/ue_dl.c @@ -87,7 +87,7 @@ int srslte_ue_dl_init(srslte_ue_dl_t *q, goto clean_exit; } - if (srslte_pdcch_init(&q->pdcch, &q->regs, q->cell)) { + if (srslte_pdcch_init_multi(&q->pdcch, &q->regs, q->cell, nof_rx_antennas)) { fprintf(stderr, "Error creating PDCCH object\n"); goto clean_exit; } @@ -272,11 +272,11 @@ int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_RXANT], u return ret; } - cf_t *ce0[SRSLTE_MAX_PORTS]; - for (int i=0;ice[i][0]; - } - if (srslte_pdcch_extract_llr(&q->pdcch, q->sf_symbols[0], ce0, srslte_chest_dl_get_noise_estimate(&q->chest), sf_idx, cfi)) { + float noise_estimate = srslte_chest_dl_get_noise_estimate(&q->chest); + // Uncoment next line to do ZF by default in pdsch_ue example + //float noise_estimate = 0; + + if (srslte_pdcch_extract_llr_multi(&q->pdcch, q->sf_symbols, q->ce, noise_estimate, sf_idx, cfi)) { fprintf(stderr, "Error extracting LLRs\n"); return SRSLTE_ERROR; } @@ -311,9 +311,6 @@ int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_RXANT], u q->nof_detected++; - // Uncoment next line to do ZF by default in pdsch_ue example - //float noise_estimate = 0; - float noise_estimate = srslte_chest_dl_get_noise_estimate(&q->chest); if (q->pdsch_cfg.grant.mcs.mod > 0 && q->pdsch_cfg.grant.mcs.tbs >= 0) { ret = srslte_pdsch_decode_multi(&q->pdsch, &q->pdsch_cfg, &q->softbuffer,