From 7ad46244e8191787ba0c4bf3b003cbbe1135e9aa Mon Sep 17 00:00:00 2001 From: ismagom Date: Thu, 16 Apr 2015 23:38:26 +0200 Subject: [PATCH] PUCCH Formats 2/2a/2b verified with Matlab --- matlab/tests/pucch_test.m | 58 +++-- .../srslte/ch_estimation/refsignal_ul.h | 7 +- srslte/include/srslte/common/sequence.h | 4 + srslte/include/srslte/phch/pucch.h | 52 +++-- srslte/lib/ch_estimation/src/refsignal_ul.c | 30 ++- srslte/lib/phch/src/pucch.c | 207 ++++++++++++++---- srslte/lib/phch/src/sequences.c | 12 +- srslte/lib/phch/test/CMakeLists.txt | 4 +- srslte/lib/phch/test/pucch_encode_test_mex.c | 53 ++++- srslte/lib/phch/test/pucch_test.c | 90 ++++---- 10 files changed, 372 insertions(+), 145 deletions(-) diff --git a/matlab/tests/pucch_test.m b/matlab/tests/pucch_test.m index d97ffca7b..49af83b8d 100644 --- a/matlab/tests/pucch_test.m +++ b/matlab/tests/pucch_test.m @@ -1,50 +1,66 @@ clear -ueConfig=struct('NCellID',2,'NULRB',6,'NSubframe',7,'CyclicPrefixUL','Normal','NTxAnts',1,'Hopping','Off'); +ueConfig=struct('NCellID',50,'RNTI',11,'NULRB',6,'NSubframe',1,'CyclicPrefixUL','Normal','NTxAnts',1,'Hopping','Off'); pucchConfig=struct('NLayers',1,'OrthCover','Off','Shortened',0,'ResourceSize',0); addpath('../../debug/srslte/lib/phch/test') +format_str={'1','1a','1b','2','2a','2b'}; + k=1; -for f=0:2 - for n=0:130 +for f=0:5 + for n=0:7:130 for d=1:3 for ncs=0:d:7 pucchConfig.ResourceIdx= n; pucchConfig.DeltaShift = d; pucchConfig.CyclicShifts = ncs; - ack=randi(2,f,1)-1; - fprintf('Testint Format: %d, n_pucch=%d, DeltaShift=%d, CyclicShift=%d\n',f,n,d,ncs); - [sym_mat, info]=ltePUCCH1(ueConfig,pucchConfig,ack); - idx=ltePUCCH1Indices(ueConfig,pucchConfig); - [dmrs_mat, info_dmrs]=ltePUCCH1DRS(ueConfig,pucchConfig); - idx_dmrs=ltePUCCH1DRSIndices(ueConfig,pucchConfig); + if (f >= 3) + nb=20; + nb_ack=f-3; + else + nb=f; + nb_ack=0; + end + bits=randi(2,nb,1)-1; + bits_ack=randi(2,nb_ack,1)-1; + fprintf('Testing PUCCH Format: %s, n_pucch=%d, DeltaShift=%d, CyclicShift=%d\n',format_str{f+1},n,d,ncs); + if (f >= 3) + [sym_mat, info]=ltePUCCH2(ueConfig,pucchConfig,bits); + idx=ltePUCCH2Indices(ueConfig,pucchConfig); + [dmrs_mat, info_dmrs]=ltePUCCH2DRS(ueConfig,pucchConfig,bits_ack); + idx_dmrs=ltePUCCH2DRSIndices(ueConfig,pucchConfig); + else + [sym_mat, info]=ltePUCCH1(ueConfig,pucchConfig,bits); + idx=ltePUCCH1Indices(ueConfig,pucchConfig); + [dmrs_mat, info_dmrs]=ltePUCCH1DRS(ueConfig,pucchConfig); + idx_dmrs=ltePUCCH1DRSIndices(ueConfig,pucchConfig); + end subframe_mat = lteULResourceGrid(ueConfig); subframe_mat(idx)=sym_mat; subframe_mat(idx_dmrs)=dmrs_mat; - [sym, dmrs]=srslte_pucch_encode(ueConfig,pucchConfig,ack); - + [sym, dmrs, subframe]=srslte_pucch_encode(ueConfig,pucchConfig,[bits; bits_ack]); + error_sym=mean(abs(sym-sym_mat)); error_dmrs=mean(abs(dmrs-dmrs_mat)); - %error_sf=mean(abs(subframe_mat(:)-subframe_lib)); + error_sf=mean(abs(subframe_mat(:)-subframe)); k=k+1; - if (error_sym > 1e-6) + if (error_sym > 1e-5) disp(info) - plot(angle(sym)-angle(sym_mat)) + plot(abs(sym-sym_mat)) error('Error in symbols'); end - if (error_dmrs > 1e-6) + if (error_dmrs > 1e-5) disp(info_dmrs) plot(angle(dmrs)-angle(dmrs_mat)) error('Error in DMRS'); end -% if (error_sf > 1e-6) -% disp(info) -% p=1:length(subframe_lib); -% plot(p,real(subframe_lib(p)),p,real(subframe_mat(p))) -% error('Error in subframe'); -% end + if (error_sf > 1e-6) + disp(info) + plot(abs(subframe-subframe_mat(:))) + error('Error in subframe'); + end end end end diff --git a/srslte/include/srslte/ch_estimation/refsignal_ul.h b/srslte/include/srslte/ch_estimation/refsignal_ul.h index 963bf9cf3..d36832ef1 100644 --- a/srslte/include/srslte/ch_estimation/refsignal_ul.h +++ b/srslte/include/srslte/ch_estimation/refsignal_ul.h @@ -105,9 +105,10 @@ SRSLTE_API void srslte_refsignal_dmrs_pusch_put(srslte_refsignal_ul_t *q, SRSLTE_API int srslte_refsignal_dmrs_pucch_gen(srslte_refsignal_ul_t *q, srslte_pucch_format_t format, - uint32_t n_pucch, - uint32_t sf_idx, - cf_t *r_pucch); + uint8_t pucch2_bits[2], + uint32_t n_pucch, // n_pucch_1 or n_pucch_2 depending on format + uint32_t sf_idx, + cf_t *r_pucch); SRSLTE_API int srslte_refsignal_dmrs_pucch_put(srslte_refsignal_ul_t* q, srslte_pucch_format_t format, diff --git a/srslte/include/srslte/common/sequence.h b/srslte/include/srslte/common/sequence.h index 5b8fceddf..a9f8d637a 100644 --- a/srslte/include/srslte/common/sequence.h +++ b/srslte/include/srslte/common/sequence.h @@ -86,4 +86,8 @@ SRSLTE_API int srslte_sequence_pusch(srslte_sequence_t *seq, uint32_t cell_id, uint32_t len); +SRSLTE_API int srslte_sequence_pucch(srslte_sequence_t *seq, + uint16_t rnti, + uint32_t nslot, + uint32_t cell_id); #endif diff --git a/srslte/include/srslte/phch/pucch.h b/srslte/include/srslte/phch/pucch.h index 3880304be..980e3cee6 100644 --- a/srslte/include/srslte/phch/pucch.h +++ b/srslte/include/srslte/phch/pucch.h @@ -38,10 +38,12 @@ #include "srslte/config.h" #include "srslte/common/phy_common.h" +#include "srslte/common/sequence.h" +#include "srslte/modem/mod.h" -#define SRSLTE_PUCCH_N_SEQ 12 // Only Format 1, 1a and 1b supported -#define SRSLTE_PUCCH_MAX_BITS 2 -#define SRSLTE_PUCCH_N_SF_MAX 5 +#define SRSLTE_PUCCH_N_SEQ 12 +#define SRSLTE_PUCCH_MAX_BITS 20 +#define SRSLTE_PUCCH_MAX_SYMBOLS 120 typedef enum SRSLTE_API { SRSLTE_PUCCH_FORMAT_1 = 0, @@ -64,11 +66,16 @@ typedef struct SRSLTE_API { typedef struct SRSLTE_API { srslte_cell_t cell; srslte_pucch_cfg_t pucch_cfg; - + srslte_sequence_t seq_f2[SRSLTE_NSUBFRAMES_X_FRAME]; + srslte_modem_table_t mod; + + uint8_t bits_scram[SRSLTE_PUCCH_MAX_BITS]; + cf_t d[SRSLTE_PUCCH_MAX_BITS/2]; uint32_t n_cs_cell[SRSLTE_NSLOTS_X_FRAME][SRSLTE_CP_NORM_NSYMB]; uint32_t f_gh[SRSLTE_NSLOTS_X_FRAME]; float tmp_arg[SRSLTE_PUCCH_N_SEQ]; - cf_t z[2*SRSLTE_PUCCH_N_SF_MAX*SRSLTE_PUCCH_N_SEQ]; + cf_t z[SRSLTE_PUCCH_MAX_SYMBOLS]; + bool rnti_is_set; }srslte_pucch_t; @@ -77,24 +84,34 @@ SRSLTE_API int srslte_pucch_init(srslte_pucch_t *q, SRSLTE_API void srslte_pucch_free(srslte_pucch_t *q); -SRSLTE_API bool srslte_pucch_set_cfg(srslte_pucch_t* q, srslte_pucch_cfg_t* cfg); +SRSLTE_API bool srslte_pucch_set_cfg(srslte_pucch_t* q, + srslte_pucch_cfg_t* cfg); + +SRSLTE_API int srslte_pucch_set_crnti(srslte_pucch_t *q, + uint16_t c_rnti); SRSLTE_API int srslte_pucch_encode(srslte_pucch_t *q, srslte_pucch_format_t format, - uint32_t n_pucch, + uint32_t n_pucch, // n_pucch_1 or n_pucch_2 depending on format uint32_t sf_idx, uint8_t bits[SRSLTE_PUCCH_MAX_BITS], cf_t *sf_symbols); -SRSLTE_API float srslte_pucch_alpha(uint32_t n_cs_cell[SRSLTE_NSLOTS_X_FRAME][SRSLTE_CP_NORM_NSYMB], - srslte_pucch_cfg_t *cfg, - uint32_t n_pucch, - srslte_cp_t cp, - bool is_dmrs, - uint32_t ns, - uint32_t l, - uint32_t *n_oc, - uint32_t *n_prime_ns); +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, + srslte_cp_t cp, + bool is_dmrs, + uint32_t ns, + uint32_t l, + uint32_t *n_oc, + uint32_t *n_prime_ns); + +SRSLTE_API float srslte_pucch_alpha_format2(uint32_t n_cs_cell[SRSLTE_NSLOTS_X_FRAME][SRSLTE_CP_NORM_NSYMB], + srslte_pucch_cfg_t *cfg, + uint32_t n_pucch, + uint32_t ns, + uint32_t l); SRSLTE_API uint32_t srslte_pucch_m(srslte_pucch_cfg_t *cfg, srslte_pucch_format_t format, @@ -104,6 +121,9 @@ SRSLTE_API uint32_t srslte_pucch_m(srslte_pucch_cfg_t *cfg, 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]); +SRSLTE_API int srslte_pucch_format2ab_mod_bits(srslte_pucch_format_t format, + uint8_t bits[2], + cf_t *d_10); SRSLTE_API bool srslte_pucch_cfg_isvalid(srslte_pucch_cfg_t *cfg, uint32_t nof_prb); diff --git a/srslte/lib/ch_estimation/src/refsignal_ul.c b/srslte/lib/ch_estimation/src/refsignal_ul.c index 0865422a0..51f13449b 100644 --- a/srslte/lib/ch_estimation/src/refsignal_ul.c +++ b/srslte/lib/ch_estimation/src/refsignal_ul.c @@ -375,7 +375,7 @@ static uint32_t get_pucch_dmrs_symbol(uint32_t m, srslte_pucch_format_t format, } /* Generates DMRS for PUCCH according to 5.5.2.2 in 36.211 */ -int srslte_refsignal_dmrs_pucch_gen(srslte_refsignal_ul_t *q, srslte_pucch_format_t format, uint32_t n_pucch, uint32_t sf_idx, cf_t *r_pucch) +int srslte_refsignal_dmrs_pucch_gen(srslte_refsignal_ul_t *q, srslte_pucch_format_t format, uint8_t pucch_bits[2], uint32_t n_pucch, uint32_t sf_idx, cf_t *r_pucch) { int ret = SRSLTE_ERROR_INVALID_INPUTS; if (q && r_pucch) { @@ -383,6 +383,11 @@ int srslte_refsignal_dmrs_pucch_gen(srslte_refsignal_ul_t *q, srslte_pucch_forma uint32_t N_rs=get_N_rs(format, q->cell.cp); + cf_t z_m_1 = 1.0; + if (format == SRSLTE_PUCCH_FORMAT_2A || format == SRSLTE_PUCCH_FORMAT_2B) { + srslte_pucch_format2ab_mod_bits(format, pucch_bits, &z_m_1); + } + for (uint32_t ns=2*sf_idx;ns<2*(sf_idx+1);ns++) { // Get group hopping number u uint32_t f_gh=0; @@ -398,7 +403,12 @@ int srslte_refsignal_dmrs_pucch_gen(srslte_refsignal_ul_t *q, srslte_pucch_forma uint32_t l = get_pucch_dmrs_symbol(m, format, q->cell.cp); // Add cyclic prefix alpha - float alpha = srslte_pucch_alpha(q->n_cs_cell, &q->pucch_cfg, n_pucch, q->cell.cp, true, ns, l, &n_oc, NULL); + float alpha = 0.0; + if (format < SRSLTE_PUCCH_FORMAT_2) { + alpha = srslte_pucch_alpha_format1(q->n_cs_cell, &q->pucch_cfg, n_pucch, q->cell.cp, true, ns, l, &n_oc, NULL); + } else { + alpha = srslte_pucch_alpha_format2(q->n_cs_cell, &q->pucch_cfg, n_pucch, ns, l); + } // Choose number of symbols and orthogonal sequence from Tables 5.5.2.2.1-1 to -3 float *w=NULL; @@ -424,10 +434,13 @@ int srslte_refsignal_dmrs_pucch_gen(srslte_refsignal_ul_t *q, srslte_pucch_forma w=w_arg_pucch_format2_cpnorm; break; } - + cf_t z_m = 1.0; + if (m == 1) { + z_m = z_m_1; + } if (w) { for (uint32_t n=0;npucch_cfg.beta_pucch*cexpf(I*(w[m]+q->tmp_arg[n]+alpha*n)); + r_pucch[(ns%2)*SRSLTE_NRE*N_rs+m*SRSLTE_NRE+n] = q->pucch_cfg.beta_pucch*z_m*cexpf(I*(w[m]+q->tmp_arg[n]+alpha*n)); } } else { return SRSLTE_ERROR; @@ -443,9 +456,10 @@ int srslte_refsignal_dmrs_pucch_gen(srslte_refsignal_ul_t *q, srslte_pucch_forma 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 ret = SRSLTE_ERROR_INVALID_INPUTS; - if (q && output) { + if (q && output && r_pucch) { 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); @@ -458,8 +472,8 @@ int srslte_refsignal_dmrs_pucch_put(srslte_refsignal_ul_t *q, srslte_pucch_forma } for (uint32_t i=0;icell.cp); - memcpy(&output[SRSLTE_RE_IDX(q->cell.nof_prb, l, n_prb*SRSLTE_NRE)], + 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)); } diff --git a/srslte/lib/phch/src/pucch.c b/srslte/lib/phch/src/pucch.c index 807f92c2a..6ddde019b 100644 --- a/srslte/lib/phch/src/pucch.c +++ b/srslte/lib/phch/src/pucch.c @@ -38,6 +38,7 @@ #include "srslte/phch/pucch.h" #include "srslte/common/sequence.h" #include "srslte/common/phy_common.h" +#include "srslte/scrambling/scrambling.h" #include "srslte/utils/debug.h" #include "srslte/utils/vector.h" @@ -65,6 +66,15 @@ bool srslte_pucch_cfg_isvalid(srslte_pucch_cfg_t *cfg, uint32_t nof_prb) { } } +// Verifies n_2_pucch as defined in 5.4 +bool srslte_pucch_n2_isvalid(srslte_pucch_cfg_t *cfg, uint32_t n_pucch_2) { + if (n_pucch_2 < cfg->n_rb_2*SRSLTE_NRE+(uint32_t) ceilf((float) cfg->N_cs/8)*(SRSLTE_NRE-cfg->N_cs-2)) { + return true; + } else { + return false; + } +} + void srslte_pucch_cfg_default(srslte_pucch_cfg_t *cfg) { cfg->beta_pucch = 1.0; cfg->delta_pucch_shift = 1; @@ -84,6 +94,25 @@ uint32_t get_N_sf(srslte_pucch_format_t format) { return 0; } +// Number of bits per subframe (M_bit) Table 5.4-1 36.211 +uint32_t srslte_pucch_nbits_format(srslte_pucch_format_t format) { + switch(format) { + case SRSLTE_PUCCH_FORMAT_1: + return 0; + case SRSLTE_PUCCH_FORMAT_1A: + return 1; + case SRSLTE_PUCCH_FORMAT_1B: + return 2; + case SRSLTE_PUCCH_FORMAT_2: + return 20; + case SRSLTE_PUCCH_FORMAT_2A: + return 21; + case SRSLTE_PUCCH_FORMAT_2B: + return 22; + } + return 0; +} + uint32_t get_pucch_symbol(uint32_t m, srslte_pucch_format_t format, srslte_cp_t cp) { switch (format) { case SRSLTE_PUCCH_FORMAT_1: @@ -157,8 +186,8 @@ int srslte_pucch_n_cs_cell(srslte_cell_t cell, uint32_t n_cs_cell[SRSLTE_NSLOTS_ } -/* Calculates alpha according to 5.5.2.2.2 (is_dmrs=true) or 5.4.1 (is_dmrs=false) of 36.211 */ -float srslte_pucch_alpha(uint32_t n_cs_cell[SRSLTE_NSLOTS_X_FRAME][SRSLTE_CP_NORM_NSYMB], +/* Calculates alpha for format 1/a/b according to 5.5.2.2.2 (is_dmrs=true) or 5.4.1 (is_dmrs=false) of 36.211 */ +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, srslte_cp_t cp, bool is_dmrs, @@ -197,13 +226,40 @@ float srslte_pucch_alpha(uint32_t n_cs_cell[SRSLTE_NSLOTS_X_FRAME][SRSLTE_CP_NOR } uint32_t n_cs = 0; if (SRSLTE_CP_ISNORM(cp)) { - n_cs = (n_cs_cell[ns][l]+(n_prime*cfg->delta_pucch_shift+(n_oc%cfg->delta_pucch_shift))%N_prime)%12; + n_cs = (n_cs_cell[ns][l]+(n_prime*cfg->delta_pucch_shift+(n_oc%cfg->delta_pucch_shift))%N_prime)%SRSLTE_NRE; } else { - n_cs = (n_cs_cell[ns][l]+(n_prime*cfg->delta_pucch_shift+n_oc/n_oc_div)%N_prime)%12; + n_cs = (n_cs_cell[ns][l]+(n_prime*cfg->delta_pucch_shift+n_oc/n_oc_div)%N_prime)%SRSLTE_NRE; } - return 2 * M_PI * (n_cs) / 12; + return 2 * M_PI * (n_cs) / SRSLTE_NRE; } + +/* Calculates alpha for format 2/a/b according to 5.4.2 of 36.211 */ +float srslte_pucch_alpha_format2(uint32_t n_cs_cell[SRSLTE_NSLOTS_X_FRAME][SRSLTE_CP_NORM_NSYMB], + srslte_pucch_cfg_t *cfg, + uint32_t n_pucch, + uint32_t ns, uint32_t l) +{ + uint32_t n_prime = n_pucch%SRSLTE_NRE; + if (n_pucch >= SRSLTE_NRE*cfg->n_rb_2) { + n_prime = (n_pucch + cfg->N_cs + 1)%SRSLTE_NRE; + } + if (ns%2) { + n_prime = (SRSLTE_NRE*(n_prime+1))%(SRSLTE_NRE+1)-1; + if (n_pucch >= SRSLTE_NRE*cfg->n_rb_2) { + int x = (SRSLTE_NRE-2-(int) n_pucch)%SRSLTE_NRE; + if (x >= 0) { + n_prime = (uint32_t) x; + } else { + n_prime = SRSLTE_NRE+x; + } + } + } + uint32_t n_cs = (n_cs_cell[ns][l]+n_prime)%SRSLTE_NRE; + DEBUG("n_pucch: %d, ns: %d, l: %d, n_prime: %d, n_cs: %d\n", n_pucch, ns, l, n_prime, n_cs); + return 2 * M_PI * (n_cs) / SRSLTE_NRE; +} + /* 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) { int ret = SRSLTE_ERROR_INVALID_INPUTS; @@ -248,8 +304,14 @@ int srslte_pucch_init(srslte_pucch_t *q, srslte_cell_t cell) { bzero(q, sizeof(srslte_pucch_t)); q->cell = cell; + q->rnti_is_set = false; + srslte_pucch_cfg_default(&q->pucch_cfg); + if (srslte_modem_table_lte(&q->mod, SRSLTE_MOD_QPSK, false)) { + return SRSLTE_ERROR; + } + // Precompute group hopping values u. if (srslte_group_hopping_f_gh(q->f_gh, q->cell.id)) { return SRSLTE_ERROR; @@ -265,7 +327,25 @@ int srslte_pucch_init(srslte_pucch_t *q, srslte_cell_t cell) { } void srslte_pucch_free(srslte_pucch_t *q) { - bzero(q, sizeof(srslte_pucch_t)); + if (q->rnti_is_set) { + for (uint32_t sf_idx=0;sf_idxseq_f2[sf_idx]); + } + } + srslte_modem_table_free(&q->mod); + bzero(q, sizeof(srslte_pucch_t)); +} + +int srslte_pucch_set_crnti(srslte_pucch_t *q, uint16_t c_rnti) { + for (uint32_t sf_idx=0;sf_idxseq_f2[sf_idx], c_rnti, 2*sf_idx, q->cell.id)) { + fprintf(stderr, "Error computing PUCCH Format 2 scrambling sequence\n"); + return SRSLTE_ERROR; + } + } + q->rnti_is_set = true; + return SRSLTE_SUCCESS; } bool srslte_pucch_set_cfg(srslte_pucch_t *q, srslte_pucch_cfg_t *cfg) @@ -302,27 +382,62 @@ static cf_t uci_encode_format1b(uint8_t bits[2]) { } } +/* Modulates bit 20 and 21 for Formats 2a and 2b as in Table 5.4.2-1 in 36.211 */ +int srslte_pucch_format2ab_mod_bits(srslte_pucch_format_t format, uint8_t bits[2], cf_t *d_10) { + if (d_10) { + if (format == SRSLTE_PUCCH_FORMAT_2A) { + *d_10 = bits[0]?-1.0:1.0; + return SRSLTE_SUCCESS; + } else if (format == SRSLTE_PUCCH_FORMAT_2B) { + if (bits[0] == 0) { + if (bits[1] == 0) { + *d_10 = 1.0; + } else { + *d_10 = -I; + } + } else { + if (bits[1] == 0) { + *d_10 = I; + } else { + *d_10 = -1.0; + } + } + return SRSLTE_SUCCESS; + } else { + return SRSLTE_ERROR; + } + } else { + return SRSLTE_ERROR; + } +} + /* Encode PUCCH bits according to Table 5.4.1-1 in Section 5.4.1 of 36.211 */ -static int uci_mod_bits(srslte_pucch_t *q, srslte_pucch_format_t format, uint8_t bits[SRSLTE_PUCCH_MAX_BITS], cf_t *d_0) +static int uci_mod_bits(srslte_pucch_t *q, srslte_pucch_format_t format, uint8_t bits[SRSLTE_PUCCH_MAX_BITS], uint32_t sf_idx) { - if (d_0) { - uint8_t tmp[2]; - switch(format) { - case SRSLTE_PUCCH_FORMAT_1: - *d_0 = uci_encode_format1(); - break; - case SRSLTE_PUCCH_FORMAT_1A: - *d_0 = uci_encode_format1a(bits[0]); - break; - case SRSLTE_PUCCH_FORMAT_1B: - tmp[0] = bits[0]; - tmp[1] = bits[1]; - *d_0 = uci_encode_format1b(tmp); - break; - default: - fprintf(stderr, "PUCCH format 2 not supported\n"); - return SRSLTE_ERROR; - } + uint8_t tmp[2]; + + switch(format) { + case SRSLTE_PUCCH_FORMAT_1: + q->d[0] = uci_encode_format1(); + break; + case SRSLTE_PUCCH_FORMAT_1A: + q->d[0] = uci_encode_format1a(bits[0]); + break; + case SRSLTE_PUCCH_FORMAT_1B: + tmp[0] = bits[0]; + tmp[1] = bits[1]; + q->d[0] = uci_encode_format1b(tmp); + break; + case SRSLTE_PUCCH_FORMAT_2: + case SRSLTE_PUCCH_FORMAT_2A: + case SRSLTE_PUCCH_FORMAT_2B: + memcpy(q->bits_scram, bits, SRSLTE_PUCCH_MAX_BITS*sizeof(uint8_t)); + srslte_scrambling_b(&q->seq_f2[sf_idx], q->bits_scram); + srslte_mod_modulate(&q->mod, q->bits_scram, q->d, SRSLTE_PUCCH_MAX_BITS); + break; + default: + fprintf(stderr, "PUCCH format 2 not supported\n"); + return SRSLTE_ERROR; } return SRSLTE_SUCCESS; } @@ -331,18 +446,24 @@ static int uci_mod_bits(srslte_pucch_t *q, srslte_pucch_format_t format, uint8_t void srslte_refsignal_r_uv_arg_1prb(float *arg, uint32_t u); /* 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) +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) { int ret = SRSLTE_ERROR_INVALID_INPUTS; if (q != NULL && sf_symbols != NULL) { ret = SRSLTE_ERROR; - cf_t d_0 = 0; - if (uci_mod_bits(q, format, bits, &d_0)) { + + if (format >= SRSLTE_PUCCH_FORMAT_2 && !q->rnti_is_set) { + 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"); return SRSLTE_ERROR; } + uint32_t N_sf=get_N_sf(format); for (uint32_t ns=2*sf_idx;ns<2*(sf_idx+1);ns++) { // Get group hopping number u @@ -358,17 +479,27 @@ int srslte_pucch_encode(srslte_pucch_t* q, srslte_pucch_format_t format, uint32_ uint32_t l = get_pucch_symbol(m, format, q->cell.cp); uint32_t n_prime_ns; uint32_t n_oc; - float alpha = srslte_pucch_alpha(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; + 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->pucch_cfg.beta_pucch + *q->d[(ns%2)*N_sf+m]*cexpf(I*(q->tmp_arg[n]+alpha*n)); + } + } else { + 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", + __real__ q->d[0], __imag__ q->d[0], alpha, n_oc, n_prime_ns); + for (uint32_t n=0;nz[(ns%2)*N_sf*SRSLTE_PUCCH_N_SEQ+m*SRSLTE_PUCCH_N_SEQ+n] = q->pucch_cfg.beta_pucch + *q->d[0]*w_n_oc[n_oc%3][m]*cexpf(I*(q->tmp_arg[n]+alpha*n+S_ns)); + } } - DEBUG("PUCCH d_0: %.1f+%.1fi, alpha: %.1f, n_oc: %d, n_prime_ns: %d\n", __real__ d_0, __imag__ d_0, alpha, n_oc, n_prime_ns); - for (uint32_t n=0;nz[(ns%2)*N_sf*SRSLTE_PUCCH_N_SEQ+m*SRSLTE_PUCCH_N_SEQ+n] = q->pucch_cfg.beta_pucch*d_0*w_n_oc[n_oc%3][m]*cexpf(I*(q->tmp_arg[n]+alpha*n+S_ns)); - } - } + } } if (pucch_put(q, format, n_pucch, sf_symbols)) { diff --git a/srslte/lib/phch/src/sequences.c b/srslte/lib/phch/src/sequences.c index 4d3c39a94..cc6c80694 100644 --- a/srslte/lib/phch/src/sequences.c +++ b/srslte/lib/phch/src/sequences.c @@ -66,7 +66,7 @@ int srslte_sequence_pdcch(srslte_sequence_t *seq, uint32_t nslot, uint32_t cell_ /** * 36.211 6.3.1 */ -int srslte_sequence_pdsch(srslte_sequence_t *seq, unsigned short rnti, int q, uint32_t nslot, uint32_t cell_id, uint32_t len) { +int srslte_sequence_pdsch(srslte_sequence_t *seq, uint16_t rnti, int q, uint32_t nslot, uint32_t cell_id, uint32_t len) { bzero(seq, sizeof(srslte_sequence_t)); return srslte_sequence_LTE_pr(seq, len, (rnti<<14) + (q<<13) + ((nslot/2)<<9) + cell_id); } @@ -74,7 +74,15 @@ int srslte_sequence_pdsch(srslte_sequence_t *seq, unsigned short rnti, int q, ui /** * 36.211 5.3.1 */ -int srslte_sequence_pusch(srslte_sequence_t *seq, unsigned short rnti, uint32_t nslot, uint32_t cell_id, uint32_t len) { +int srslte_sequence_pusch(srslte_sequence_t *seq, uint16_t rnti, uint32_t nslot, uint32_t cell_id, uint32_t len) { bzero(seq, sizeof(srslte_sequence_t)); return srslte_sequence_LTE_pr(seq, len, (rnti<<14) + ((nslot/2)<<9) + cell_id); } + +/** + * 36.211 5.4.2 + */ +int srslte_sequence_pucch(srslte_sequence_t *seq, uint16_t rnti, uint32_t nslot, uint32_t cell_id) { + bzero(seq, sizeof(srslte_sequence_t)); + return srslte_sequence_LTE_pr(seq, 20, ((((nslot/2)+1)*(2*cell_id+1))<<16)+rnti); +} diff --git a/srslte/lib/phch/test/CMakeLists.txt b/srslte/lib/phch/test/CMakeLists.txt index 6bea2f47f..8d13984c3 100644 --- a/srslte/lib/phch/test/CMakeLists.txt +++ b/srslte/lib/phch/test/CMakeLists.txt @@ -145,9 +145,7 @@ ADD_TEST(pusch_test pusch_test) ADD_EXECUTABLE(pucch_test pucch_test.c) TARGET_LINK_LIBRARIES(pucch_test srslte) -ADD_TEST(pucch_test pucch_test -f 0) -ADD_TEST(pucch_test pucch_test -f 1) -ADD_TEST(pucch_test pucch_test -f 2) +ADD_TEST(pucch_test pucch_test) BuildMex(MEXNAME pucch_encode SOURCES pucch_encode_test_mex.c LIBRARIES srslte srslte_mex) diff --git a/srslte/lib/phch/test/pucch_encode_test_mex.c b/srslte/lib/phch/test/pucch_encode_test_mex.c index 3445f3d72..9ccf02277 100644 --- a/srslte/lib/phch/test/pucch_encode_test_mex.c +++ b/srslte/lib/phch/test/pucch_encode_test_mex.c @@ -75,6 +75,15 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) mexErrMsgTxt("Field NSubframe not found in UE config\n"); return; } + uint32_t rnti; + if (mexutils_read_uint32_struct(UECFG, "RNTI", &rnti)) { + mexErrMsgTxt("Field NSubframe not found in UE config\n"); + return; + } + if (srslte_pucch_set_crnti(&pucch, (uint16_t) rnti&0xffff)) { + mexErrMsgTxt("Error setting C-RNTI\n"); + return; + } uint32_t n_pucch; if (mexutils_read_uint32_struct(PUCCHCFG, "ResourceIdx", &n_pucch)) { mexErrMsgTxt("Field ResourceIdx not found in PUCCHCFG\n"); @@ -101,12 +110,9 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) } uint8_t bits[SRSLTE_PUCCH_MAX_BITS]; + uint8_t pucch2_bits[2]; float *bits_ptr; int n = mexutils_read_f(ACK, &bits_ptr); - for (int i=0;i0?1:0; - } - free(bits_ptr); srslte_pucch_format_t format; switch(n) { @@ -119,10 +125,33 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) case 2: format = SRSLTE_PUCCH_FORMAT_1B; break; + case 20: + format = SRSLTE_PUCCH_FORMAT_2; + break; + case 21: + format = SRSLTE_PUCCH_FORMAT_2A; + break; + case 22: + format = SRSLTE_PUCCH_FORMAT_2B; + break; default: mexErrMsgTxt("Invalid number of bits in parameter ack\n"); return; } + if (n > 20) { + n = 20; + } + for (int i=0;i0?1:0; + } + if (format == SRSLTE_PUCCH_FORMAT_2A) { + pucch2_bits[0] = bits_ptr[20]; + } + if (format == SRSLTE_PUCCH_FORMAT_2B) { + pucch2_bits[0] = bits_ptr[20]; + pucch2_bits[1] = bits_ptr[21]; + } + free(bits_ptr); cf_t *sf_symbols = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp)); if (!sf_symbols) { @@ -138,7 +167,11 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) } if (nlhs >= 1) { - mexutils_write_cf(pucch.z, &plhs[0], 96, 1); + uint32_t n_bits = 96; + if (format >= SRSLTE_PUCCH_FORMAT_2) { + n_bits = 120; + } + mexutils_write_cf(pucch.z, &plhs[0], n_bits, 1); } if (nlhs >= 2) { @@ -158,17 +191,21 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) return; } - if (srslte_refsignal_dmrs_pucch_gen(&pucch_dmrs, format, n_pucch, sf_idx, dmrs_pucch)) { + if (srslte_refsignal_dmrs_pucch_gen(&pucch_dmrs, format, pucch2_bits, n_pucch, sf_idx, dmrs_pucch)) { mexErrMsgTxt("Error generating PUCCH DMRS\n"); return; } - mexutils_write_cf(dmrs_pucch, &plhs[1], 2*3*SRSLTE_NRE, 1); + uint32_t n_rs = 3; + if (format >= SRSLTE_PUCCH_FORMAT_2) { + n_rs = 2; + } + mexutils_write_cf(dmrs_pucch, &plhs[1], 2*n_rs*SRSLTE_NRE, 1); if (nlhs >= 3) { if (srslte_refsignal_dmrs_pucch_put(&pucch_dmrs, format, n_pucch, dmrs_pucch, sf_symbols)) { mexErrMsgTxt("Error generating PUCCH DMRS\n"); return; - } + } mexutils_write_cf(sf_symbols, &plhs[2], SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp), 1); } diff --git a/srslte/lib/phch/test/pucch_test.c b/srslte/lib/phch/test/pucch_test.c index 191ee88b7..8139794f5 100644 --- a/srslte/lib/phch/test/pucch_test.c +++ b/srslte/lib/phch/test/pucch_test.c @@ -44,10 +44,9 @@ srslte_cell_t cell = { }; uint32_t subframe = 1; -srslte_pucch_format_t format; void usage(char *prog) { - printf("Usage: %s [csNnv] -f [format (0: Format 1 | 1: Format 1a | 2: Format 1b)]\n", prog); + printf("Usage: %s [csNnv]\n", prog); printf("\t-c cell id [Default %d]\n", cell.id); printf("\t-s subframe [Default %d]\n", subframe); printf("\t-n nof_prb [Default %d]\n", cell.nof_prb); @@ -56,21 +55,8 @@ void usage(char *prog) { void parse_args(int argc, char **argv) { int opt; - while ((opt = getopt(argc, argv, "csNnvf")) != -1) { + while ((opt = getopt(argc, argv, "csNnv")) != -1) { switch(opt) { - case 'f': - switch(atoi(argv[optind])) { - case 0: - format = SRSLTE_PUCCH_FORMAT_1; - break; - case 1: - format = SRSLTE_PUCCH_FORMAT_1A; - break; - case 2: - format = SRSLTE_PUCCH_FORMAT_1B; - break; - } - break; case 's': subframe = atoi(argv[optind]); break; @@ -95,6 +81,7 @@ int main(int argc, char **argv) { srslte_pucch_cfg_t pucch_cfg; srslte_refsignal_ul_t dmrs; uint8_t bits[SRSLTE_PUCCH_MAX_BITS]; + uint8_t pucch2_bits[2]; cf_t *sf_symbols = NULL; cf_t pucch_dmrs[2*SRSLTE_NRE*3]; int ret = -1; @@ -115,44 +102,55 @@ int main(int argc, char **argv) { for (int i=0;i