added pucch enodeb receiver

This commit is contained in:
Ismael Gomez 2016-10-18 10:39:49 +02:00
parent 383dfa63fe
commit ea4a81c8d0
10 changed files with 465 additions and 89 deletions

View File

@ -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);

View File

@ -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;
uint32_t n_srs;
uint32_t k_tc;
uint32_t n_rrc;
// 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;
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);

View File

@ -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

View File

@ -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;

View File

@ -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]);

View File

@ -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;i<n_rs;i++) {
srslte_vec_sum_ccc(&q->pilot_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;i<SRSLTE_CP_NSYMB(q->cell.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;
}

View File

@ -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;m<N_rs;m++) {
uint32_t n_oc=0;
uint32_t l = get_pucch_dmrs_symbol(m, format, q->cell.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;i<N_rs;i++) {
uint32_t l = get_pucch_dmrs_symbol(i, format, q->cell.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);
}

View File

@ -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;
}

View File

@ -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;i<N_sf;i++) {
uint32_t l = get_pucch_symbol(i, format, q->cell.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;m<N_sf;m++) {
uint32_t l = get_pucch_symbol(m, format, q->cell.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;n<SRSLTE_PUCCH_N_SEQ;n++) {
z[(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));
}
} 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;n<SRSLTE_PUCCH_N_SEQ;n++) {
z[(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));
}
}
}
}
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,49 +576,10 @@ 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];
}
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;m<N_sf;m++) {
uint32_t l = get_pucch_symbol(m, format, q->cell.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;n<SRSLTE_PUCCH_N_SEQ;n++) {
q->z[(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));
}
} 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;n<SRSLTE_PUCCH_N_SEQ;n++) {
q->z[(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));
}
}
}
}
if (pucch_put(q, format, n_pucch, sf_symbols)) {
if (pucch_put(q, format, n_pucch, q->z, sf_symbols) < 0) {
fprintf(stderr, "Error putting PUCCH symbols\n");
return SRSLTE_ERROR;
}
@ -549,3 +590,88 @@ int srslte_pucch_encode(srslte_pucch_t* q, srslte_pucch_format_t format,
}
/* 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;
}
}
}
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 {
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("format1a b=%d, corr=%f, nof_re=%d, th=%f\n", b, corr, nof_re, q->threshold_format1);
}
bits[0] = b_max;
break;
default:
fprintf(stderr, "Error decoding PUCCH: Format %d not supported\n", format);
break;
}
ret = SRSLTE_SUCCESS;
}
return ret;
}

View File

@ -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)