diff --git a/srslte/include/srslte/ch_estimation/chest_ul.h b/srslte/include/srslte/ch_estimation/chest_ul.h index 37800d02a..90a706cc7 100644 --- a/srslte/include/srslte/ch_estimation/chest_ul.h +++ b/srslte/include/srslte/ch_estimation/chest_ul.h @@ -57,6 +57,7 @@ typedef struct { cf_t *pilot_estimates; cf_t *pilot_recv_signal; + cf_t *pilot_known_signal; cf_t *tmp_noise; #ifdef FREQ_SEL_SNR @@ -99,6 +100,13 @@ SRSLTE_API int srslte_chest_ul_estimate(srslte_chest_ul_t *q, uint32_t cyclic_shift_for_dmrs, uint32_t n_prb[2]); +SRSLTE_API int srslte_chest_ul_estimate_pucch(srslte_chest_ul_t *q, + cf_t *input, + cf_t *ce, + srslte_pucch_format_t format, + uint32_t n_pucch, + uint32_t sf_idx); + SRSLTE_API float srslte_chest_ul_get_noise_estimate(srslte_chest_ul_t *q); SRSLTE_API float srslte_chest_ul_get_snr(srslte_chest_ul_t *q); diff --git a/srslte/include/srslte/ch_estimation/refsignal_ul.h b/srslte/include/srslte/ch_estimation/refsignal_ul.h index 0d8b7f5fb..1c6814b63 100644 --- a/srslte/include/srslte/ch_estimation/refsignal_ul.h +++ b/srslte/include/srslte/ch_estimation/refsignal_ul.h @@ -46,6 +46,7 @@ #define SRSLTE_REFSIGNAL_UL_L(ns_idx, cp) ((ns_idx+1)*SRSLTE_CP_NSYMB(cp)-4) +/* PUSCH DMRS common configuration (received in SIB2) */ typedef struct SRSLTE_API { uint32_t cyclic_shift; uint32_t delta_ss; @@ -53,15 +54,19 @@ typedef struct SRSLTE_API { bool sequence_hopping_en; }srslte_refsignal_dmrs_pusch_cfg_t; + typedef struct SRSLTE_API { + // Common Configuration uint32_t subframe_config; - uint32_t I_srs; uint32_t bw_cfg; + + // Dedicated configuration + uint32_t B; + uint32_t b_hop; uint32_t n_srs; + uint32_t I_srs; uint32_t k_tc; uint32_t n_rrc; - uint32_t B; - uint32_t b_hop; bool configured; }srslte_refsignal_srs_cfg_t; @@ -101,6 +106,13 @@ SRSLTE_API void srslte_refsignal_ul_set_cfg(srslte_refsignal_ul_t *q, SRSLTE_API void srslte_refsignal_r_uv_arg_1prb(float *arg, uint32_t u); +SRSLTE_API uint32_t srslte_refsignal_dmrs_N_rs(srslte_pucch_format_t format, + srslte_cp_t cp); + +SRSLTE_API uint32_t srslte_refsignal_dmrs_pucch_symbol(uint32_t m, + srslte_pucch_format_t format, + srslte_cp_t cp); + SRSLTE_API bool srslte_refsignal_dmrs_pusch_cfg_isvalid(srslte_refsignal_ul_t *q, srslte_refsignal_dmrs_pusch_cfg_t *cfg, uint32_t nof_prb); @@ -150,6 +162,12 @@ SRSLTE_API int srslte_refsignal_dmrs_pucch_put(srslte_refsignal_ul_t* q, cf_t *r_pucch, cf_t *output); +SRSLTE_API int srslte_refsignal_dmrs_pucch_get(srslte_refsignal_ul_t* q, + srslte_pucch_format_t format, + uint32_t n_pucch, + cf_t *input, + cf_t *r_pucch); + SRSLTE_API int srslte_refsignal_srs_pregen(srslte_refsignal_ul_t *q, srslte_refsignal_srs_pregen_t *pregen); diff --git a/srslte/include/srslte/enb/enb_ul.h b/srslte/include/srslte/enb/enb_ul.h index c636c994b..59fd02065 100644 --- a/srslte/include/srslte/enb/enb_ul.h +++ b/srslte/include/srslte/enb/enb_ul.h @@ -73,7 +73,15 @@ typedef struct SRSLTE_API { srslte_prach_t prach; srslte_pusch_cfg_t pusch_cfg; - + + srslte_pusch_hopping_cfg_t hopping_cfg; + + // Configuration for each user + bool *uci_cfg_en; + bool *srs_cfg_en; + srslte_uci_cfg_t *uci_cfg; + srslte_refsignal_srs_cfg_t *srs_cfg; + } srslte_enb_ul_t; typedef struct { @@ -85,6 +93,7 @@ typedef struct { bool needs_pdcch; uint8_t *data; srslte_softbuffer_rx_t *softbuffer; + } srslte_enb_ul_pusch_t; /* This function shall be called just after the initial synchronization */ @@ -92,6 +101,7 @@ SRSLTE_API int srslte_enb_ul_init(srslte_enb_ul_t *q, srslte_cell_t cell, srslte_prach_cfg_t* prach_cfg, srslte_refsignal_dmrs_pusch_cfg_t *pusch_cfg, + srslte_pusch_hopping_cfg_t *hopping_cfg, srslte_pucch_cfg_t *pucch_cfg, uint32_t nof_rntis); @@ -101,12 +111,24 @@ SRSLTE_API int srslte_enb_ul_cfg_rnti(srslte_enb_ul_t *q, uint32_t idx, uint16_t rnti); +SRSLTE_API int srslte_enb_ul_cfg_ue(srslte_enb_ul_t *q, uint32_t idx, + srslte_uci_cfg_t *uci_cfg, + srslte_refsignal_srs_cfg_t *srs_cfg); + + SRSLTE_API int srslte_enb_ul_rem_rnti(srslte_enb_ul_t *q, uint32_t idx); SRSLTE_API void srslte_enb_ul_fft(srslte_enb_ul_t *q, cf_t *signal_buffer); +SRSLTE_API int srslte_enb_ul_get_pucch(srslte_enb_ul_t *q, + srslte_pucch_format_t format, + uint32_t n_pucch, + uint32_t rnti_idx, + srslte_uci_data_t *uci_data, + uint32_t tti); + SRSLTE_API int srslte_enb_ul_get_pusch(srslte_enb_ul_t *q, srslte_ra_ul_grant_t *grant, srslte_softbuffer_rx_t *softbuffer, @@ -123,7 +145,7 @@ SRSLTE_API int srslte_enb_ul_detect_prach(srslte_enb_ul_t *q, cf_t *signal, uint32_t *indices, float *offsets, - float *peak2avg); + float *peak2avg); #endif diff --git a/srslte/include/srslte/phch/prach.h b/srslte/include/srslte/phch/prach.h index 8221fc434..346447e8b 100644 --- a/srslte/include/srslte/phch/prach.h +++ b/srslte/include/srslte/phch/prach.h @@ -110,7 +110,8 @@ typedef enum SRSLTE_API { typedef struct { uint32_t config_idx; uint32_t root_seq_idx; - uint32_t zero_corr_zone; + uint32_t zero_corr_zone; + uint32_t freq_offset; bool hs_flag; } srslte_prach_cfg_t; diff --git a/srslte/include/srslte/phch/pucch.h b/srslte/include/srslte/phch/pucch.h index 92b493fa4..66062b057 100644 --- a/srslte/include/srslte/phch/pucch.h +++ b/srslte/include/srslte/phch/pucch.h @@ -64,15 +64,18 @@ typedef struct SRSLTE_API { }srslte_pucch_sched_t; typedef struct SRSLTE_API { + // Common configuration uint32_t delta_pucch_shift; uint32_t n_rb_2; uint32_t N_cs; + + // SRS configuration bool srs_configured; uint32_t srs_cs_subf_cfg; bool srs_simul_ack; } srslte_pucch_cfg_t; -/* PUSCH object */ +/* PUCCH object */ typedef struct SRSLTE_API { srslte_cell_t cell; srslte_pucch_cfg_t pucch_cfg; @@ -85,9 +88,15 @@ typedef struct SRSLTE_API { uint32_t f_gh[SRSLTE_NSLOTS_X_FRAME]; float tmp_arg[SRSLTE_PUCCH_N_SEQ]; cf_t z[SRSLTE_PUCCH_MAX_SYMBOLS]; + cf_t z_tmp[SRSLTE_PUCCH_MAX_SYMBOLS]; + cf_t ce[SRSLTE_PUCCH_MAX_SYMBOLS]; bool rnti_is_set; bool shortened; bool group_hopping_en; + + float threshold_format1; + float threshold_format1a; + }srslte_pucch_t; @@ -100,6 +109,10 @@ SRSLTE_API bool srslte_pucch_set_cfg(srslte_pucch_t* q, srslte_pucch_cfg_t* cfg, bool group_hopping_en); +SRSLTE_API void srslte_pucch_set_threshold(srslte_pucch_t *q, + float format1, + float format1a); + SRSLTE_API int srslte_pucch_set_crnti(srslte_pucch_t *q, uint16_t c_rnti); @@ -114,6 +127,15 @@ SRSLTE_API int srslte_pucch_encode(srslte_pucch_t *q, uint8_t bits[SRSLTE_PUCCH_MAX_BITS], cf_t *sf_symbols); +SRSLTE_API int srslte_pucch_decode(srslte_pucch_t *q, + srslte_pucch_format_t format, + uint32_t n_pucch, // n_pucch_1 or n_pucch_2 depending on format + uint32_t sf_idx, + cf_t *sf_symbols, + cf_t *ce, + float noise_estimate, + uint8_t bits[SRSLTE_PUCCH_MAX_BITS]); + SRSLTE_API float srslte_pucch_alpha_format1(uint32_t n_cs_cell[SRSLTE_NSLOTS_X_FRAME][SRSLTE_CP_NORM_NSYMB], srslte_pucch_cfg_t *cfg, uint32_t n_pucch, @@ -135,6 +157,13 @@ SRSLTE_API uint32_t srslte_pucch_m(srslte_pucch_cfg_t *cfg, uint32_t n_pucch, srslte_cp_t cp); +SRSLTE_API uint32_t srslte_pucch_n_prb(srslte_pucch_cfg_t *cfg, + srslte_pucch_format_t format, + uint32_t n_pucch, + uint32_t nof_prb, + srslte_cp_t cp, + uint32_t ns); + SRSLTE_API int srslte_pucch_n_cs_cell(srslte_cell_t cell, uint32_t n_cs_cell[SRSLTE_NSLOTS_X_FRAME][SRSLTE_CP_NORM_NSYMB]); diff --git a/srslte/lib/ch_estimation/chest_ul.c b/srslte/lib/ch_estimation/chest_ul.c index c61e88c7d..a75d2a7a3 100644 --- a/srslte/lib/ch_estimation/chest_ul.c +++ b/srslte/lib/ch_estimation/chest_ul.c @@ -84,6 +84,12 @@ int srslte_chest_ul_init(srslte_chest_ul_t *q, srslte_cell_t cell) goto clean_exit; } + q->pilot_known_signal = srslte_vec_malloc(sizeof(cf_t) * (NOF_REFS_SF+1)); + if (!q->pilot_known_signal) { + perror("malloc"); + goto clean_exit; + } + if (srslte_interp_linear_vector_init(&q->srslte_interp_linvec, NOF_REFS_SYM)) { fprintf(stderr, "Error initializing vector interpolator\n"); goto clean_exit; @@ -122,6 +128,9 @@ void srslte_chest_ul_free(srslte_chest_ul_t *q) if (q->pilot_recv_signal) { free(q->pilot_recv_signal); } + if (q->pilot_known_signal) { + free(q->pilot_known_signal); + } bzero(q, sizeof(srslte_chest_ul_t)); } @@ -252,6 +261,59 @@ int srslte_chest_ul_estimate(srslte_chest_ul_t *q, cf_t *input, cf_t *ce, return 0; } +int srslte_chest_ul_estimate_pucch(srslte_chest_ul_t *q, cf_t *input, cf_t *ce, + srslte_pucch_format_t format, uint32_t n_pucch, uint32_t sf_idx) +{ + if (!q->dmrs_signal_configured) { + fprintf(stderr, "Error must call srslte_chest_ul_set_cfg() before using the UL estimator\n"); + return SRSLTE_ERROR; + } + + int n_rs = srslte_refsignal_dmrs_N_rs(format, q->cell.cp); + int nrefs_sf = SRSLTE_NRE*n_rs*2; + + /* Get references from the input signal */ + srslte_refsignal_dmrs_pucch_get(&q->dmrs_signal, format, n_pucch, input, q->pilot_recv_signal); + + /* Generate known pilots */ + uint8_t pucch2_bits[2] = {0, 0}; + srslte_refsignal_dmrs_pucch_gen(&q->dmrs_signal, format, n_pucch, sf_idx, pucch2_bits, q->pilot_known_signal), + + /* Use the known DMRS signal to compute Least-squares estimates */ + srslte_vec_prod_conj_ccc(q->pilot_recv_signal, q->pilot_known_signal, q->pilot_estimates, nrefs_sf); + + if (ce != NULL) { + /* FIXME: Currently averaging entire slot, performance good enough? */ + for (int ns=0;ns<2;ns++) { + // Average all slot + for (int i=1;ipilot_estimates[ns*n_rs*SRSLTE_NRE], &q->pilot_estimates[(i+ns*n_rs)*SRSLTE_NRE], + &q->pilot_estimates[ns*n_rs*SRSLTE_NRE], + SRSLTE_NRE); + } + srslte_vec_sc_prod_ccc(&q->pilot_estimates[ns*n_rs*SRSLTE_NRE], (float) 1.0/n_rs, + &q->pilot_estimates[ns*n_rs*SRSLTE_NRE], + SRSLTE_NRE); + + // Average in freq domain + srslte_chest_average_pilots(&q->pilot_estimates[ns*n_rs*SRSLTE_NRE], &q->pilot_recv_signal[ns*n_rs*SRSLTE_NRE], + q->smooth_filter, SRSLTE_NRE, 1, q->smooth_filter_len); + + // Determine n_prb + uint32_t n_prb = srslte_pucch_n_prb(&q->dmrs_signal.pucch_cfg, format, n_pucch, q->cell.nof_prb, q->cell.cp, ns); + + // copy estimates to slot + for (int i=0;icell.cp);i++) { + memcpy(&ce[SRSLTE_RE_IDX(q->cell.nof_prb, i+ns*SRSLTE_CP_NSYMB(q->cell.cp), n_prb*SRSLTE_NRE)], + &q->pilot_recv_signal[ns*n_rs*SRSLTE_NRE], sizeof(cf_t)*SRSLTE_NRE); + } + } + } + + return 0; +} + + float srslte_chest_ul_get_noise_estimate(srslte_chest_ul_t *q) { return q->noise_estimate; } diff --git a/srslte/lib/ch_estimation/refsignal_ul.c b/srslte/lib/ch_estimation/refsignal_ul.c index 30aa7da08..f85b33c19 100644 --- a/srslte/lib/ch_estimation/refsignal_ul.c +++ b/srslte/lib/ch_estimation/refsignal_ul.c @@ -452,7 +452,7 @@ int srslte_refsignal_dmrs_pusch_gen(srslte_refsignal_ul_t *q, uint32_t nof_prb, } /* Number of PUCCH demodulation reference symbols per slot N_rs_pucch tABLE 5.5.2.2.1-1 36.211 */ -static uint32_t get_N_rs(srslte_pucch_format_t format, srslte_cp_t cp) { +uint32_t srslte_refsignal_dmrs_N_rs(srslte_pucch_format_t format, srslte_cp_t cp) { switch (format) { case SRSLTE_PUCCH_FORMAT_1: case SRSLTE_PUCCH_FORMAT_1A: @@ -476,7 +476,7 @@ static uint32_t get_N_rs(srslte_pucch_format_t format, srslte_cp_t cp) { } /* Table 5.5.2.2.2-1: Demodulation reference signal location for different PUCCH formats. 36.211 */ -static uint32_t get_pucch_dmrs_symbol(uint32_t m, srslte_pucch_format_t format, srslte_cp_t cp) { +uint32_t srslte_refsignal_dmrs_pucch_symbol(uint32_t m, srslte_pucch_format_t format, srslte_cp_t cp) { switch (format) { case SRSLTE_PUCCH_FORMAT_1: case SRSLTE_PUCCH_FORMAT_1A: @@ -523,7 +523,7 @@ int srslte_refsignal_dmrs_pucch_gen(srslte_refsignal_ul_t *q, srslte_pucch_forma if (q && r_pucch) { ret = SRSLTE_ERROR; - uint32_t N_rs=get_N_rs(format, q->cell.cp); + uint32_t N_rs=srslte_refsignal_dmrs_N_rs(format, q->cell.cp); cf_t z_m_1 = 1.0; if (format == SRSLTE_PUCCH_FORMAT_2A || format == SRSLTE_PUCCH_FORMAT_2B) { @@ -543,7 +543,7 @@ int srslte_refsignal_dmrs_pucch_gen(srslte_refsignal_ul_t *q, srslte_pucch_forma for (uint32_t m=0;mcell.cp); + uint32_t l = srslte_refsignal_dmrs_pucch_symbol(m, format, q->cell.cp); // Add cyclic prefix alpha float alpha = 0.0; if (format < SRSLTE_PUCCH_FORMAT_2) { @@ -594,36 +594,48 @@ int srslte_refsignal_dmrs_pucch_gen(srslte_refsignal_ul_t *q, srslte_pucch_forma return ret; } -/* Maps PUCCH DMRS to the physical resources as defined in 5.5.2.2.2 in 36.211 */ -int srslte_refsignal_dmrs_pucch_put(srslte_refsignal_ul_t *q, srslte_pucch_format_t format, uint32_t n_pucch, cf_t *r_pucch, cf_t *output) +int srslte_refsignal_dmrs_pucch_cp(srslte_refsignal_ul_t *q, srslte_pucch_format_t format, uint32_t n_pucch, cf_t *source, cf_t *dest, bool source_is_grid) { int ret = SRSLTE_ERROR_INVALID_INPUTS; - if (q && output && r_pucch) { + if (q && source && dest) { ret = SRSLTE_ERROR; uint32_t nsymbols = SRSLTE_CP_ISNORM(q->cell.cp)?SRSLTE_CP_NORM_NSYMB:SRSLTE_CP_EXT_NSYMB; - - // Determine m - uint32_t m = srslte_pucch_m(&q->pucch_cfg, format, n_pucch, q->cell.cp); - - uint32_t N_rs = get_N_rs(format, q->cell.cp); + + uint32_t N_rs = srslte_refsignal_dmrs_N_rs(format, q->cell.cp); for (uint32_t ns=0;ns<2;ns++) { - // Determine n_prb - uint32_t n_prb = m/2; - if ((m+ns)%2) { - n_prb = q->cell.nof_prb-1-m/2; - } - + + // Determine n_prb + uint32_t n_prb = srslte_pucch_n_prb(&q->pucch_cfg, format, n_pucch, q->cell.nof_prb, q->cell.cp, ns); + for (uint32_t i=0;icell.cp); - memcpy(&output[SRSLTE_RE_IDX(q->cell.nof_prb, l+ns*nsymbols, n_prb*SRSLTE_NRE)], - &r_pucch[ns*N_rs*SRSLTE_NRE+i*SRSLTE_NRE], - SRSLTE_NRE*sizeof(cf_t)); + uint32_t l = srslte_refsignal_dmrs_pucch_symbol(i, format, q->cell.cp); + if (!source_is_grid) { + memcpy(&dest[SRSLTE_RE_IDX(q->cell.nof_prb, l+ns*nsymbols, n_prb*SRSLTE_NRE)], + &source[ns*N_rs*SRSLTE_NRE+i*SRSLTE_NRE], + SRSLTE_NRE*sizeof(cf_t)); + } else { + memcpy(&dest[ns*N_rs*SRSLTE_NRE+i*SRSLTE_NRE], + &source[SRSLTE_RE_IDX(q->cell.nof_prb, l+ns*nsymbols, n_prb*SRSLTE_NRE)], + SRSLTE_NRE*sizeof(cf_t)); + } } } ret = SRSLTE_SUCCESS; } - return ret; + return ret; +} + +/* Maps PUCCH DMRS to the physical resources as defined in 5.5.2.2.2 in 36.211 */ +int srslte_refsignal_dmrs_pucch_put(srslte_refsignal_ul_t *q, srslte_pucch_format_t format, uint32_t n_pucch, cf_t *r_pucch, cf_t *output) +{ + return srslte_refsignal_dmrs_pucch_cp(q, format, n_pucch, r_pucch, output, false); +} + +/* Gets PUCCH DMRS from the physical resources as defined in 5.5.2.2.2 in 36.211 */ +int srslte_refsignal_dmrs_pucch_get(srslte_refsignal_ul_t *q, srslte_pucch_format_t format, uint32_t n_pucch, cf_t *input, cf_t *r_pucch) +{ + return srslte_refsignal_dmrs_pucch_cp(q, format, n_pucch, input, r_pucch, true); } diff --git a/srslte/lib/enb/enb_ul.c b/srslte/lib/enb/enb_ul.c index 01940f5b0..a5b16ea3f 100644 --- a/srslte/lib/enb/enb_ul.c +++ b/srslte/lib/enb/enb_ul.c @@ -42,6 +42,7 @@ int srslte_enb_ul_init(srslte_enb_ul_t *q, srslte_cell_t cell, srslte_prach_cfg_t *prach_cfg, srslte_refsignal_dmrs_pusch_cfg_t *pusch_cfg, + srslte_pusch_hopping_cfg_t *hopping_cfg, srslte_pucch_cfg_t *pucch_cfg, uint32_t nof_rnti) { @@ -57,6 +58,16 @@ int srslte_enb_ul_init(srslte_enb_ul_t *q, srslte_cell_t cell, q->cell = cell; q->nof_rnti = nof_rnti; + if (hopping_cfg) { + memcpy(&q->hopping_cfg, hopping_cfg, sizeof(srslte_pusch_hopping_cfg_t)); + } + + q->uci_cfg_en = calloc(sizeof(bool),nof_rnti); + q->srs_cfg_en = calloc(sizeof(bool),nof_rnti); + + q->uci_cfg = calloc(sizeof(srslte_uci_cfg_t),nof_rnti); + q->srs_cfg = calloc(sizeof(srslte_refsignal_srs_cfg_t),nof_rnti); + if (srslte_ofdm_rx_init(&q->fft, q->cell.cp, q->cell.nof_prb)) { fprintf(stderr, "Error initiating FFT\n"); goto clean_exit; @@ -91,6 +102,9 @@ int srslte_enb_ul_init(srslte_enb_ul_t *q, srslte_cell_t cell, goto clean_exit; } + // Configure common PUCCH configuration + srslte_pucch_set_cfg(&q->pucch, pucch_cfg, pusch_cfg->group_hopping_en); + // SRS is a dedicated configuration srslte_chest_ul_set_cfg(&q->chest, pusch_cfg, pucch_cfg, NULL); @@ -123,6 +137,20 @@ clean_exit: void srslte_enb_ul_free(srslte_enb_ul_t *q) { if (q) { + + if (q->uci_cfg) { + free(q->uci_cfg); + } + if (q->uci_cfg_en) { + free(q->uci_cfg_en); + } + if (q->srs_cfg) { + free(q->srs_cfg); + } + if (q->srs_cfg_en) { + free(q->srs_cfg_en); + } + srslte_prach_free(&q->prach); srslte_ofdm_rx_free(&q->fft); srslte_pucch_free(&q->pucch); @@ -143,6 +171,30 @@ int srslte_enb_ul_cfg_rnti(srslte_enb_ul_t *q, uint32_t idx, uint16_t rnti) return srslte_pusch_set_rnti_multi(&q->pusch, idx, rnti); } +int srslte_enb_ul_cfg_ue(srslte_enb_ul_t *q, uint32_t idx, + srslte_uci_cfg_t *uci_cfg, + srslte_refsignal_srs_cfg_t *srs_cfg) +{ + if (idx < q->nof_rnti) { + if (uci_cfg) { + memcpy(&q->uci_cfg[idx], uci_cfg, sizeof(srslte_uci_cfg_t)); + q->uci_cfg_en[idx] = true; + } else { + q->uci_cfg_en[idx] = false; + } + if (srs_cfg) { + memcpy(&q->srs_cfg[idx], srs_cfg, sizeof(srslte_refsignal_srs_cfg_t)); + q->srs_cfg_en[idx] = true; + } else { + q->srs_cfg_en[idx] = false; + } + return SRSLTE_SUCCESS; + } else { + fprintf(stderr, "Error configuring UE: Invalid idx=%d, max users=%d\n", idx, q->nof_rnti); + return SRSLTE_ERROR; + } +} + int srslte_enb_ul_rem_rnti(srslte_enb_ul_t *q, uint32_t idx) { return srslte_pusch_set_rnti_multi(&q->pusch, idx, 0); @@ -153,12 +205,58 @@ void srslte_enb_ul_fft(srslte_enb_ul_t *q, cf_t *signal_buffer) srslte_ofdm_rx_sf(&q->fft, signal_buffer, q->sf_symbols); } +int srslte_enb_ul_get_pucch(srslte_enb_ul_t *q, srslte_pucch_format_t format, uint32_t n_pucch, + uint32_t rnti_idx, srslte_uci_data_t *uci_data, uint32_t tti) +{ + + if (srslte_chest_ul_estimate_pucch(&q->chest, q->sf_symbols, q->ce, format, n_pucch, tti%10)) { + fprintf(stderr,"Error estimating PUCCH DMRS\n"); + return SRSLTE_ERROR; + } + + float noise_power = srslte_chest_ul_get_noise_estimate(&q->chest); + + uint8_t bits[SRSLTE_PUCCH_MAX_BITS]; + if (srslte_pucch_decode(&q->pucch, format, n_pucch, tti%10, q->sf_symbols, q->ce, noise_power, bits)) { + fprintf(stderr,"Error decoding PUCCH\n"); + return SRSLTE_ERROR; + } + + switch(format) { + case SRSLTE_PUCCH_FORMAT_1: + if (bits[0]) { + uci_data->scheduling_request = true; + } + break; + case SRSLTE_PUCCH_FORMAT_1A: + case SRSLTE_PUCCH_FORMAT_1B: + uci_data->uci_ack = bits[0]; + uci_data->uci_ack_len = 1; + if (format == SRSLTE_PUCCH_FORMAT_1B) { + uci_data->uci_ack_2 = bits[0]; + uci_data->uci_ack_len = 2; + } + break; + default: + fprintf(stderr, "Error getting PUCCH format %d not supported\n"); + return SRSLTE_ERROR; + } + + return SRSLTE_SUCCESS; +} + int srslte_enb_ul_get_pusch(srslte_enb_ul_t *q, srslte_ra_ul_grant_t *grant, srslte_softbuffer_rx_t *softbuffer, uint32_t rnti_idx, uint32_t rv_idx, uint32_t current_tx_nb, uint8_t *data, srslte_uci_data_t *uci_data, uint32_t tti) { - if (srslte_pusch_cfg(&q->pusch, &q->pusch_cfg, grant, NULL, NULL, NULL, tti, rv_idx, current_tx_nb)) { + if (srslte_pusch_cfg(&q->pusch, + &q->pusch_cfg, + grant, + q->uci_cfg_en[rnti_idx]?&q->uci_cfg[rnti_idx]:NULL, + &q->hopping_cfg, + q->srs_cfg_en[rnti_idx]?&q->srs_cfg[rnti_idx]:NULL, + tti, rv_idx, current_tx_nb)) { fprintf(stderr, "Error configuring PDSCH\n"); return SRSLTE_ERROR; } diff --git a/srslte/lib/phch/pucch.c b/srslte/lib/phch/pucch.c index fb2419be0..30fdb66b7 100644 --- a/srslte/lib/phch/pucch.c +++ b/srslte/lib/phch/pucch.c @@ -38,6 +38,7 @@ #include "srslte/phch/pucch.h" #include "srslte/common/sequence.h" #include "srslte/common/phy_common.h" +#include "srslte/mimo/precoding.h" #include "srslte/scrambling/scrambling.h" #include "srslte/utils/debug.h" #include "srslte/utils/vector.h" @@ -159,6 +160,17 @@ uint32_t get_pucch_symbol(uint32_t m, srslte_pucch_format_t format, srslte_cp_t return 0; } +uint32_t srslte_pucch_n_prb(srslte_pucch_cfg_t *cfg, srslte_pucch_format_t format, uint32_t n_pucch, + uint32_t nof_prb, srslte_cp_t cp, uint32_t ns) +{ + uint32_t m = srslte_pucch_m(cfg, format, n_pucch, cp); + // Determine n_prb + uint32_t n_prb = m/2; + if ((m+ns)%2) { + n_prb = nof_prb-1-m/2; + } + return n_prb; +} // Compute m according to Section 5.4.3 of 36.211 uint32_t srslte_pucch_m(srslte_pucch_cfg_t *cfg, srslte_pucch_format_t format, uint32_t n_pucch, srslte_cp_t cp) { @@ -250,6 +262,9 @@ float srslte_pucch_alpha_format1(uint32_t n_cs_cell[SRSLTE_NSLOTS_X_FRAME][SRSLT n_cs = (n_cs_cell[ns][l]+(n_prime*cfg->delta_pucch_shift+n_oc/n_oc_div)%N_prime)%SRSLTE_NRE; } + DEBUG("n_cs=%d, N_prime=%d, delta_pucch=%d, n_prime=%d, ns=%d, l=%d, ns_cs_cell=%d\n", + n_cs, N_prime, cfg->delta_pucch_shift, n_prime, ns, l, n_cs_cell[ns][l]); + return 2 * M_PI * (n_cs) / SRSLTE_NRE; } @@ -281,40 +296,55 @@ float srslte_pucch_alpha_format2(uint32_t n_cs_cell[SRSLTE_NSLOTS_X_FRAME][SRSLT } /* Map PUCCH symbols to physical resources according to 5.4.3 in 36.211 */ -static int pucch_put(srslte_pucch_t *q, srslte_pucch_format_t format, uint32_t n_pucch, cf_t *output) { +static int pucch_cp(srslte_pucch_t *q, srslte_pucch_format_t format, uint32_t n_pucch, cf_t *source, cf_t *dest, bool source_is_grid) { int ret = SRSLTE_ERROR_INVALID_INPUTS; - if (q && output) { + if (q && source && dest) { ret = SRSLTE_ERROR; uint32_t nsymbols = SRSLTE_CP_ISNORM(q->cell.cp)?SRSLTE_CP_NORM_NSYMB:SRSLTE_CP_EXT_NSYMB; - // Determine m - uint32_t m = srslte_pucch_m(&q->pucch_cfg, format, n_pucch, q->cell.cp); - + uint32_t n_re = 0; uint32_t N_sf_0 = get_N_sf(format, 0, q->shortened); for (uint32_t ns=0;ns<2;ns++) { uint32_t N_sf = get_N_sf(format, ns%2, q->shortened); - // Determine n_prb - uint32_t n_prb = m/2; - if ((m+ns)%2) { - n_prb = q->cell.nof_prb-1-m/2; - } + + // Determine n_prb + uint32_t n_prb = srslte_pucch_n_prb(&q->pucch_cfg, format, n_pucch, q->cell.nof_prb, q->cell.cp, ns); if (n_prb < q->cell.nof_prb) { for (uint32_t i=0;icell.cp); - memcpy(&output[SRSLTE_RE_IDX(q->cell.nof_prb, l+ns*nsymbols, n_prb*SRSLTE_NRE)], - &q->z[i*SRSLTE_NRE+ns*N_sf_0*SRSLTE_NRE], - SRSLTE_NRE*sizeof(cf_t)); + if (!source_is_grid) { + memcpy(&dest[SRSLTE_RE_IDX(q->cell.nof_prb, l+ns*nsymbols, n_prb*SRSLTE_NRE)], + &source[i*SRSLTE_NRE+ns*N_sf_0*SRSLTE_NRE], + SRSLTE_NRE*sizeof(cf_t)); + } else { + memcpy(&dest[i*SRSLTE_NRE+ns*N_sf_0*SRSLTE_NRE], + &source[SRSLTE_RE_IDX(q->cell.nof_prb, l+ns*nsymbols, n_prb*SRSLTE_NRE)], + SRSLTE_NRE*sizeof(cf_t)); + } + n_re += SRSLTE_NRE; } } else { return SRSLTE_ERROR; } } - ret = SRSLTE_SUCCESS; + ret = n_re; } return ret; } +static int pucch_put(srslte_pucch_t *q, srslte_pucch_format_t format, uint32_t n_pucch, cf_t *z, cf_t *output) { + return pucch_cp(q, format, n_pucch, z, output, false); +} + +static int pucch_get(srslte_pucch_t *q, srslte_pucch_format_t format, uint32_t n_pucch, cf_t *input, cf_t *z) { + return pucch_cp(q, format, n_pucch, input, z, true); +} + +void srslte_pucch_set_threshold(srslte_pucch_t *q, float format1, float format1a) { + q->threshold_format1 = format1; + q->threshold_format1a = format1a; +} /** Initializes the PDCCH transmitter and receiver */ int srslte_pucch_init(srslte_pucch_t *q, srslte_cell_t cell) { @@ -470,9 +500,59 @@ static int uci_mod_bits(srslte_pucch_t *q, srslte_pucch_format_t format, uint8_t // Declare this here, since we can not include refsignal_ul.h void srslte_refsignal_r_uv_arg_1prb(float *arg, uint32_t u); +static int pucch_encode(srslte_pucch_t* q, srslte_pucch_format_t format, + uint32_t n_pucch, uint32_t sf_idx, + uint8_t bits[SRSLTE_PUCCH_MAX_BITS], cf_t z[SRSLTE_PUCCH_MAX_SYMBOLS]) +{ + if (uci_mod_bits(q, format, bits, sf_idx)) { + fprintf(stderr, "Error encoding PUCCH bits\n"); + return SRSLTE_ERROR; + } + uint32_t N_sf_0 = get_N_sf(format, 0, q->shortened); + for (uint32_t ns=2*sf_idx;ns<2*(sf_idx+1);ns++) { + uint32_t N_sf = get_N_sf(format, ns%2, q->shortened); + DEBUG("ns=%d, N_sf=%d\n", ns, N_sf); + // Get group hopping number u + uint32_t f_gh=0; + if (q->group_hopping_en) { + f_gh = q->f_gh[ns]; + } + uint32_t u = (f_gh + (q->cell.id%30))%30; + + srslte_refsignal_r_uv_arg_1prb(q->tmp_arg, u); + uint32_t N_sf_widx = N_sf==3?1:0; + for (uint32_t m=0;mcell.cp); + float alpha=0; + if (format >= SRSLTE_PUCCH_FORMAT_2) { + alpha = srslte_pucch_alpha_format2(q->n_cs_cell, &q->pucch_cfg, n_pucch, ns, l); + for (uint32_t n=0;nd[(ns%2)*N_sf+m]*cexpf(I*(q->tmp_arg[n]+alpha*n)); + } + } else { + uint32_t n_prime_ns=0; + uint32_t n_oc=0; + alpha = srslte_pucch_alpha_format1(q->n_cs_cell, &q->pucch_cfg, n_pucch, q->cell.cp, true, ns, l, &n_oc, &n_prime_ns); + float S_ns = 0; + if (n_prime_ns%2) { + S_ns = M_PI/2; + } + DEBUG("PUCCH d_0: %.1f+%.1fi, alpha: %.1f, n_oc: %d, n_prime_ns: %d, n_rb_2=%d\n", + __real__ q->d[0], __imag__ q->d[0], alpha, n_oc, n_prime_ns, q->pucch_cfg.n_rb_2); + for (uint32_t n=0;nd[0]*cexpf(I*(w_n_oc[N_sf_widx][n_oc%3][m]+q->tmp_arg[n]+alpha*n+S_ns)); + } + } + } + } + return SRSLTE_SUCCESS; +} + /* Encode, modulate and resource mapping of PUCCH bits according to Section 5.4.1 of 36.211 */ int srslte_pucch_encode(srslte_pucch_t* q, srslte_pucch_format_t format, - uint32_t n_pucch, uint32_t sf_idx, uint8_t bits[SRSLTE_PUCCH_MAX_BITS], cf_t *sf_symbols) + uint32_t n_pucch, uint32_t sf_idx, uint8_t bits[SRSLTE_PUCCH_MAX_BITS], + cf_t *sf_symbols) { int ret = SRSLTE_ERROR_INVALID_INPUTS; if (q != NULL && @@ -496,56 +576,102 @@ int srslte_pucch_encode(srslte_pucch_t* q, srslte_pucch_format_t format, fprintf(stderr, "Error encoding PUCCH: C-RNTI must be set before encoding PUCCH Format 2/2a/2b\n"); return SRSLTE_ERROR; } - if (uci_mod_bits(q, format, bits, sf_idx)) { - fprintf(stderr, "Error encoding PUCCH bits\n"); + if (pucch_encode(q, format, n_pucch, sf_idx, bits, q->z)) { return SRSLTE_ERROR; } - uint32_t N_sf_0 = get_N_sf(format, 0, q->shortened); - for (uint32_t ns=2*sf_idx;ns<2*(sf_idx+1);ns++) { - uint32_t N_sf = get_N_sf(format, ns%2, q->shortened); - DEBUG("ns=%d, N_sf=%d\n", ns, N_sf); - // Get group hopping number u - uint32_t f_gh=0; - if (q->group_hopping_en) { - f_gh = q->f_gh[ns]; + if (pucch_put(q, format, n_pucch, q->z, sf_symbols) < 0) { + fprintf(stderr, "Error putting PUCCH symbols\n"); + return SRSLTE_ERROR; + } + ret = SRSLTE_SUCCESS; + } + + return ret; +} + + +/* Equalize, demodulate and decode PUCCH bits according to Section 5.4.1 of 36.211 */ +int srslte_pucch_decode(srslte_pucch_t* q, srslte_pucch_format_t format, + uint32_t n_pucch, uint32_t sf_idx, cf_t *sf_symbols, cf_t *ce, float noise_estimate, + uint8_t bits[SRSLTE_PUCCH_MAX_BITS]) +{ + int ret = SRSLTE_ERROR_INVALID_INPUTS; + if (q != NULL && + ce != NULL && + sf_symbols != NULL) + { + ret = SRSLTE_ERROR; + + // Shortened PUCCH happen in every cell-specific SRS subframes for Format 1/1a/1b + if (q->pucch_cfg.srs_configured && format < SRSLTE_PUCCH_FORMAT_2) { + q->shortened = false; + // If CQI is not transmitted, PUCCH will be normal unless ACK/NACK and SRS simultaneous transmission is enabled + if (q->pucch_cfg.srs_simul_ack) { + // If simultaneous ACK and SRS is enabled, PUCCH is shortened in cell-specific SRS subframes + if (srslte_refsignal_srs_send_cs(q->pucch_cfg.srs_cs_subf_cfg, sf_idx) == 1) { + q->shortened = true; + } } - uint32_t u = (f_gh + (q->cell.id%30))%30; - - srslte_refsignal_r_uv_arg_1prb(q->tmp_arg, u); - uint32_t N_sf_widx = N_sf==3?1:0; - for (uint32_t m=0;mcell.cp); - float alpha=0; - if (format >= SRSLTE_PUCCH_FORMAT_2) { - alpha = srslte_pucch_alpha_format2(q->n_cs_cell, &q->pucch_cfg, n_pucch, ns, l); - for (uint32_t n=0;nz[(ns%2)*N_sf*SRSLTE_PUCCH_N_SEQ+m*SRSLTE_PUCCH_N_SEQ+n] = q->d[(ns%2)*N_sf+m]*cexpf(I*(q->tmp_arg[n]+alpha*n)); - } + } + + if (format >= SRSLTE_PUCCH_FORMAT_2 && !q->rnti_is_set) { + fprintf(stderr, "Error decoding PUCCH: C-RNTI must be set before encoding PUCCH Format 2/2a/2b\n"); + return SRSLTE_ERROR; + } + int nof_re = pucch_get(q, format, n_pucch, sf_symbols, q->z_tmp); + if (nof_re < 0) { + fprintf(stderr, "Error getting PUCCH symbols\n"); + return SRSLTE_ERROR; + } + + if (pucch_get(q, format, n_pucch, ce, q->ce) < 0) { + fprintf(stderr, "Error getting PUCCH symbols\n"); + return SRSLTE_ERROR; + } + + // Equalization + srslte_predecoding_single(q->z_tmp, q->ce, q->z, nof_re, noise_estimate); + + // Perform ML-decoding + float corr=0, corr_max=-1e9; + int b_max = 0; // default bit value, eg. HI is NACK + switch(format) { + case SRSLTE_PUCCH_FORMAT_1: + bzero(bits, SRSLTE_PUCCH_MAX_BITS*sizeof(uint8_t)); + pucch_encode(q, format, n_pucch, sf_idx, bits, q->z_tmp); + corr = crealf(srslte_vec_dot_prod_conj_ccc(q->z, q->z_tmp, nof_re))/nof_re; + if (corr >= q->threshold_format1) { + bits[0] = 1; } else { - uint32_t n_prime_ns=0; - uint32_t n_oc=0; - alpha = srslte_pucch_alpha_format1(q->n_cs_cell, &q->pucch_cfg, n_pucch, q->cell.cp, true, ns, l, &n_oc, &n_prime_ns); - float S_ns = 0; - if (n_prime_ns%2) { - S_ns = M_PI/2; + bits[0] = 0; + } + printf("format1 corr=%f, nof_re=%d, th=%f\n", corr, nof_re, q->threshold_format1); + break; + case SRSLTE_PUCCH_FORMAT_1A: + bzero(bits, SRSLTE_PUCCH_MAX_BITS*sizeof(uint8_t)); + + for (int b=0;b<2;b++) { + bits[0] = b; + pucch_encode(q, format, n_pucch, sf_idx, bits, q->z_tmp); + corr = crealf(srslte_vec_dot_prod_conj_ccc(q->z, q->z_tmp, nof_re))/nof_re; + if (corr > corr_max && corr >= q->threshold_format1a) { + corr_max = corr; + b_max = b; } - DEBUG("PUCCH d_0: %.1f+%.1fi, alpha: %.1f, n_oc: %d, n_prime_ns: %d, n_rb_2=%d\n", - __real__ q->d[0], __imag__ q->d[0], alpha, n_oc, n_prime_ns, q->pucch_cfg.n_rb_2); - for (uint32_t n=0;nz[(ns%2)*N_sf_0*SRSLTE_PUCCH_N_SEQ+m*SRSLTE_PUCCH_N_SEQ+n] = - q->d[0]*cexpf(I*(w_n_oc[N_sf_widx][n_oc%3][m]+q->tmp_arg[n]+alpha*n+S_ns)); - } + DEBUG("format1a b=%d, corr=%f, nof_re=%d, th=%f\n", b, corr, nof_re, q->threshold_format1); } - } - } - if (pucch_put(q, format, n_pucch, sf_symbols)) { - fprintf(stderr, "Error putting PUCCH symbols\n"); - return SRSLTE_ERROR; + bits[0] = b_max; + break; + default: + fprintf(stderr, "Error decoding PUCCH: Format %d not supported\n", format); + break; } + ret = SRSLTE_SUCCESS; } return ret; } - + + \ No newline at end of file diff --git a/srslte/lib/phch/test/CMakeLists.txt b/srslte/lib/phch/test/CMakeLists.txt index 90c658e66..6675e0faf 100644 --- a/srslte/lib/phch/test/CMakeLists.txt +++ b/srslte/lib/phch/test/CMakeLists.txt @@ -146,7 +146,7 @@ target_link_libraries(pucch_test srslte) add_test(pucch_test pucch_test) BuildMex(MEXNAME pucch_encode SOURCES pucch_encode_test_mex.c LIBRARIES srslte_static srslte_mex) - +BuildMex(MEXNAME pucch SOURCES pucch_test_mex.c LIBRARIES srslte_static srslte_mex)