diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 0b9d925017..cf7d95739a 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -1758,6 +1758,7 @@ set(PHY_SRC_UE ${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_prach.c ${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_ulsch_llr_computation.c ${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c + ${OPENAIR1_DIR}/PHY/NR_REFSIG/ul_ref_seq_nr.c ${OPENAIR1_DIR}/PHY/NR_REFSIG/nr_dmrs_rx.c ${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_csi_rs.c ${OPENAIR1_DIR}/PHY/NR_REFSIG/nr_gold.c diff --git a/openair1/PHY/INIT/nr_init.c b/openair1/PHY/INIT/nr_init.c index 49ec60c94b..70f57dd4d1 100644 --- a/openair1/PHY/INIT/nr_init.c +++ b/openair1/PHY/INIT/nr_init.c @@ -43,6 +43,8 @@ #include "SCHED_NR/fapi_nr_l1.h" #include "nfapi_nr_interface.h" +#include "PHY/NR_REFSIG/ul_ref_seq_nr.h" + /* extern uint32_t from_nrarfcn(int nr_bandP,uint32_t dl_nrarfcn); extern openair0_config_t openair0_cfg[MAX_CARDS]; @@ -194,6 +196,10 @@ int phy_init_nr_gNB(PHY_VARS_gNB *gNB, } } + /* Generate low PAPR type 1 sequences for PUSCH DMRS, these are used if transform precoding is enabled. */ + generate_lowpapr_typ1_refsig_sequences(SHRT_MAX); + + nr_init_csi_rs(gNB, 0); // TODO scramblingID currently hardcoded to 0, to be taken from higher layer parameter scramblingID when implemented /// Transport init necessary for NR synchro @@ -388,6 +394,11 @@ void phy_free_nr_gNB(PHY_VARS_gNB *gNB) /* for (UE_id = 0; UE_id < NUMBER_OF_UE_MAX; UE_id++) gNB->UE_stats_ptr[UE_id] = NULL; */ + + + free_gnb_lowpapr_sequences(); + + } /* void install_schedule_handlers(IF_Module_t *if_inst) diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c index 27c1ef2ac6..713e71674b 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c @@ -30,6 +30,9 @@ #include "PHY/NR_TRANSPORT/nr_transport_proto.h" #include "PHY/NR_UE_ESTIMATION/filt16a_32.h" +#include "PHY/NR_REFSIG/ul_ref_seq_nr.h" + + //#define DEBUG_CH //#define DEBUG_PUSCH @@ -119,15 +122,36 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, break; } - //------------------generate DMRS------------------// - if (pusch_pdu->transform_precoding==1) // if transform precoding is disabled + if (pusch_pdu->transform_precoding == transform_precoder_disabled) nr_pusch_dmrs_rx(gNB, Ns, gNB->nr_gold_pusch_dmrs[pusch_pdu->scid][Ns][symbol], &pilot[0], 1000, 0, nb_rb_pusch, pusch_pdu->rb_start*NR_NB_SC_PER_RB, pusch_pdu->dmrs_config_type); - else - nr_pusch_dmrs_rx(gNB, Ns, gNB->nr_gold_pusch_dmrs[pusch_pdu->scid][Ns][symbol], &pilot[0], 1000, 0, nb_rb_pusch, 0, pusch_pdu->dmrs_config_type); + + else { // if transform precoding or SC-FDMA is enabled in Uplink + // NR_SC_FDMA supports type1 DMRS so only 6 DMRS REs per RB possible + uint16_t index = get_index_for_dmrs_lowpapr_seq(nb_rb_pusch * (NR_NB_SC_PER_RB/2)); + uint8_t u = pusch_pdu->dfts_ofdm.low_papr_group_number; + uint8_t v = pusch_pdu->dfts_ofdm.low_papr_sequence_number; + int16_t *dmrs_seq = gNB_dmrs_lowpaprtype1_sequence[u][v][index]; + + AssertFatal(index >= 0, "Num RBs not configured according to 3GPP 38.211 section 6.3.1.4. For PUSCH with transform precoding, num RBs cannot be multiple of any other primenumber other than 2,3,5\n"); + AssertFatal(dmrs_seq != NULL, "DMRS low PAPR seq not found, check if DMRS sequences are generated"); + + LOG_D(PHY,"Transform Precoding params. u: %d, v: %d, index for dmrsseq: %d\n", u, v, index); + + nr_pusch_lowpaprtype1_dmrs_rx(gNB, Ns, dmrs_seq, &pilot[0], 1000, 0, nb_rb_pusch, 0, pusch_pdu->dmrs_config_type); + + #ifdef DEBUG_PUSCH + printf ("NR_UL_CHANNEL_EST: index %d, u %d,v %d\n", index, u, v); + LOG_M("gNb_DMRS_SEQ.m","gNb_DMRS_SEQ", dmrs_seq,6*nb_rb_pusch,1,1); + #endif + + } //------------------------------------------------// + + + #ifdef DEBUG_PUSCH for (int i=0;i<(6*nb_rb_pusch);i++) printf("%d+j*(%d)\n",((int16_t*)pilot)[2*i],((int16_t*)pilot)[1+(2*i)]); diff --git a/openair1/PHY/NR_REFSIG/nr_dmrs_rx.c b/openair1/PHY/NR_REFSIG/nr_dmrs_rx.c index 764885dbf8..5d62f9dbb9 100644 --- a/openair1/PHY/NR_REFSIG/nr_dmrs_rx.c +++ b/openair1/PHY/NR_REFSIG/nr_dmrs_rx.c @@ -247,3 +247,51 @@ void nr_gen_ref_conj_symbols(uint32_t *in, uint32_t length, int16_t *output, uin output[(i<<1)+1] = nr_rx_mod_table[((offset+idx)<<1)+1]; } } + +int nr_pusch_lowpaprtype1_dmrs_rx(PHY_VARS_gNB *gNB, + unsigned int Ns, + int16_t *dmrs_seq, + int32_t *output, + unsigned short p, + unsigned char lp, + unsigned short nb_pusch_rb, + uint32_t re_offset, + uint8_t dmrs_type) +{ + int8_t w, nb_dmrs; + int k; + + int dmrs_offset = re_offset/((dmrs_type==pusch_dmrs_type1)?2:3); + + if (dmrs_type != pusch_dmrs_type1) + LOG_E(PHY,"PUSCH DMRS config type %d not valid\n", dmrs_type); + + if ((p>=1000) && (p<1008)) { + if (gNB->frame_parms.Ncp == NORMAL) { + nb_dmrs = NR_NB_SC_PER_RB/2; // for DMRS TYPE 1 - 6 DMRS REs present per RB + for (int i=dmrs_offset; i= dmrs_ul_allocated_res[(MAX_INDEX_DMRS_UL_ALLOCATED_REs-1)]) + index = MAX_INDEX_DMRS_UL_ALLOCATED_REs-1; + else + index = (num_dmrs_res/6) -1; + + for (;index >= 0; index--) { + if (dmrs_ul_allocated_res[index] == num_dmrs_res) + break; + + } + + LOG_D(PHY, "num_dmrs_res: %d INDEX RETURNED: %d", num_dmrs_res, index); + return index; + +} + /******************************************************************* * * NAME : base_sequence_36_or_larger @@ -126,13 +159,19 @@ int16_t *base_sequence_less_than_36(unsigned int M_ZC, int16_t *base_sequence_36_or_larger(unsigned int Msc_RS, unsigned int u, unsigned int v, - unsigned int scaling) + unsigned int scaling, unsigned int if_dmrs_seq) { int16_t *rv_overbar; - unsigned int N_ZC; + unsigned int N_ZC, M_ZC; double q_overbar, x; unsigned int q,m,n; - unsigned int M_ZC = ul_allocated_re[Msc_RS]; + + + if (if_dmrs_seq) + M_ZC = dmrs_ul_allocated_res[Msc_RS]; + else + M_ZC = ul_allocated_re[Msc_RS]; + rv_overbar = malloc16(IQ_SIZE*M_ZC); if (rv_overbar == NULL) { @@ -140,7 +179,11 @@ int16_t *base_sequence_36_or_larger(unsigned int Msc_RS, assert(0); } - N_ZC = ref_ul_primes[Msc_RS]; /* The length N_ZC is given by the largest prime number such that N_ZC < M_ZC */ + if (if_dmrs_seq) + N_ZC = dmrs_ref_ul_primes[Msc_RS]; + else + N_ZC = ref_ul_primes[Msc_RS]; /* The length N_ZC is given by the largest prime number such that N_ZC < M_ZC */ + q_overbar = N_ZC * (u+1)/(double)31; @@ -159,19 +202,24 @@ int16_t *base_sequence_36_or_larger(unsigned int Msc_RS, return rv_overbar; } -/******************************************************************* -* -* NAME : generate_ul_srs_sequences -* -* PARAMETERS : scaling to apply -* -* RETURN : none -* -* DESCRIPTION : uplink reference signal sequences generation -* which are Low-PAPR base sequences -* see TS 38.211 5.2.2 Low-PAPR sequence generation -* -*********************************************************************/ +void generate_lowpapr_typ1_refsig_sequences(unsigned int scaling) +{ + unsigned int u,Msc_RS; + unsigned int v = 0; // sequence hopping and group hopping are not supported yet + + for (Msc_RS=0; Msc_RS <= INDEX_SB_LESS_32; Msc_RS++) { + for (u=0; u < U_GROUP_NUMBER; u++) { + gNB_dmrs_lowpaprtype1_sequence[u][v][Msc_RS] = base_sequence_less_than_36(ul_allocated_re[Msc_RS], u, scaling); + } + } + + for (Msc_RS=INDEX_SB_LESS_32+1; Msc_RS < MAX_INDEX_DMRS_UL_ALLOCATED_REs; Msc_RS++) { + for (u=0; u < U_GROUP_NUMBER; u++) { + gNB_dmrs_lowpaprtype1_sequence[u][v][Msc_RS] = base_sequence_36_or_larger(Msc_RS, u, v, scaling, 1); + } + } +} + void generate_ul_reference_signal_sequences(unsigned int scaling) { @@ -184,10 +232,13 @@ void generate_ul_reference_signal_sequences(unsigned int scaling) #endif + for (Msc_RS=0; Msc_RS <= INDEX_SB_LESS_32; Msc_RS++) { - v = 0; + v = 0; for (u=0; u < U_GROUP_NUMBER; u++) { rv_ul_ref_sig[u][v][Msc_RS] = base_sequence_less_than_36(ul_allocated_re[Msc_RS], u, scaling); + dmrs_lowpaprtype1_ul_ref_sig[u][v][Msc_RS] = base_sequence_less_than_36(ul_allocated_re[Msc_RS], u, scaling); + #if 0 sprintf(output_file, "rv_seq_%d_%d_%d.m", u, v, ul_allocated_re[Msc_RS]); sprintf(sequence_name, "rv_seq_%d_%d_%d.m", u, v, ul_allocated_re[Msc_RS]); @@ -198,10 +249,19 @@ void generate_ul_reference_signal_sequences(unsigned int scaling) } } + for (Msc_RS=INDEX_SB_LESS_32+1; Msc_RS < MAX_INDEX_DMRS_UL_ALLOCATED_REs; Msc_RS++) { + v = 0; // neither group hopping or sequnce hopping is supported for PUSCH DMRS hence v = 0 + for (u=0; u < U_GROUP_NUMBER; u++) { + dmrs_lowpaprtype1_ul_ref_sig[u][v][Msc_RS] = base_sequence_36_or_larger(Msc_RS, u, v, scaling, 1); + } + + } + for (Msc_RS=INDEX_SB_LESS_32+1; Msc_RS < SRS_SB_CONF; Msc_RS++) { for (u=0; u < U_GROUP_NUMBER; u++) { - for (v=0; v < V_BASE_SEQUENCE_NUMBER; v++) { - rv_ul_ref_sig[u][v][Msc_RS] = base_sequence_36_or_larger(Msc_RS, u, v, scaling); + for (v=0; v < V_BASE_SEQUENCE_NUMBER; v++) { + rv_ul_ref_sig[u][v][Msc_RS] = base_sequence_36_or_larger(Msc_RS, u, v, scaling, 0); + #if 0 sprintf(output_file, "rv_seq_%d_%d_%d.m", u, v, ul_allocated_re[Msc_RS]); sprintf(sequence_name, "rv_seq_%d_%d_%d.m", u, v, ul_allocated_re[Msc_RS]); @@ -212,8 +272,11 @@ void generate_ul_reference_signal_sequences(unsigned int scaling) } } } + + } + /******************************************************************* * * NAME : free_ul_reference_signal_sequences @@ -233,7 +296,33 @@ void free_ul_reference_signal_sequences(void) for (v=0; v < V_BASE_SEQUENCE_NUMBER; v++) { if (rv_ul_ref_sig[u][v][Msc_RS]) free16(rv_ul_ref_sig[u][v][Msc_RS],2*sizeof(int16_t)*ul_allocated_re[Msc_RS]); + if ((v==0) && (Msc_RS < MAX_INDEX_DMRS_UL_ALLOCATED_REs)) + if (dmrs_lowpaprtype1_ul_ref_sig[u][v][Msc_RS]) + free16(dmrs_lowpaprtype1_ul_ref_sig[u][v][Msc_RS],2*sizeof(int16_t)*dmrs_ul_allocated_res[Msc_RS]); } } } } +/******************************************************************* +* +* NAME : free_gnb_lowpapr_sequences +* +* PARAMETERS : none +* +* RETURN : none +* +* DESCRIPTION : free of uplink reference signal sequences +* +*********************************************************************/ +void free_gnb_lowpapr_sequences(void) +{ + unsigned int u,v,Msc_RS; + for (Msc_RS=0; Msc_RS < MAX_INDEX_DMRS_UL_ALLOCATED_REs; Msc_RS++) { + v=0; + for (u=0; u < U_GROUP_NUMBER; u++) { + if (gNB_dmrs_lowpaprtype1_sequence[u][v][Msc_RS]) + free16(gNB_dmrs_lowpaprtype1_sequence[u][v][Msc_RS],2*sizeof(int16_t)*dmrs_ul_allocated_res[Msc_RS]); + } + } +} + diff --git a/openair1/PHY/NR_REFSIG/ul_ref_seq_nr.h b/openair1/PHY/NR_REFSIG/ul_ref_seq_nr.h index dd967e8e5e..44d30da8f3 100644 --- a/openair1/PHY/NR_REFSIG/ul_ref_seq_nr.h +++ b/openair1/PHY/NR_REFSIG/ul_ref_seq_nr.h @@ -38,6 +38,10 @@ #include "PHY/NR_REFSIG/ss_pbch_nr.h" +#include "PHY/defs_nr_common.h" +#include "PHY/defs_gNB.h" + + #ifdef DEFINE_VARIABLES_LOWPAPR_SEQUENCES_NR_H #define EXTERN #define INIT_VARIABLES_LOWPAPR_SEQUENCES_NR_H @@ -255,7 +259,10 @@ const char phi_M_ZC_24[24*U_GROUP_NUMBER] ; /************** FUNCTION ******************************************/ -int16_t *base_sequence_36_or_larger(unsigned int M_ZC, unsigned int u, unsigned int v, unsigned int scaling); + +int16_t *base_sequence_36_or_larger(unsigned int M_ZC, unsigned int u, unsigned int v, unsigned int scaling, unsigned int if_dmrs_seq); + + int16_t *base_sequence_less_than_36(unsigned int M_ZC, unsigned int u, unsigned int scaling); /*! \brief This function generate the sounding reference symbol (SRS) for the uplink. @@ -265,6 +272,72 @@ int16_t *base_sequence_less_than_36(unsigned int M_ZC, unsigned int u, unsigned void generate_ul_reference_signal_sequences(unsigned int scaling); void free_ul_reference_signal_sequences(void); + + +// Supported for 100Mhz configuration - which has max 273 RBs +#define MAX_INDEX_DMRS_UL_ALLOCATED_REs 53 + + +const uint16_t dmrs_ul_allocated_res[MAX_INDEX_DMRS_UL_ALLOCATED_REs] +/* Number of possible DMRS REs based on PRBs allocated for PUSCH. Array has values until 273 RBs (100Mhz BW) + Number of PUSCH RBs allocated should be able to be expressed as 2topowerofn*3topowerofn*5tothepowerofn + According to 3GPP spec 38.211 section 6.3.1.4 + Table used in calculating DMRS low papr type1 sequence for transform precoding */ +#ifdef INIT_VARIABLES_LOWPAPR_SEQUENCES_NR_H += { +/*RBs 1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 16, */ + 6, 12, 18, 24, 30, 36, 48, 54, 60, 72, 90, 96, + +/*RBs 18, 20, 24, 25, 27, 30, 32, 36, 40, 45, 48, 50, */ + 108, 120, 144, 150, 162, 180, 192, 216, 240, 270, 288, 300, + +/*RBs 54, 60, 64, 72 75, 80, 81, 90, 96, 100, (Bw 40Mhz) */ + 324, 360, 384, 432, 450, 480, 486, 540, 576, 600, + +/*RBs 108, 120 125 128 135 144 150 160 162 180 192 200 */ + 648, 720, 750, 768, 810, 864, 900, 960, 972, 1080, 1152, 1200, + +/*RBs 216 225 240 243 250 256 270 supported until 100Mhz */ + 1296, 1350, 1440, 1458, 1500, 1536, 1620 + +} +#endif +; + +/* Table of largest prime number N_ZC < possible DMRS REs M_ZC, this array has values until 100Mhz + According to 3GPP spec 38.211 section 5.2.2.1 + Table used in calculating DMRS low papr type1 sequence for transform precoding */ +const uint16_t dmrs_ref_ul_primes[MAX_INDEX_DMRS_UL_ALLOCATED_REs] +#ifdef INIT_VARIABLES_LOWPAPR_SEQUENCES_NR_H += { +/*DMRS REs 6, 12, 18, 24, 30, 36, 48, 54, 60, 72, 90, 96, */ + 5, 11, 17, 23, 29, 31, 47, 53, 59, 71, 89, 89, + +/*DMRS REs 108, 120, 144, 150, 162, 180, 192, 216, 240, 270, 288, 300, */ + 107, 113, 139, 149, 157, 179, 191, 211, 239, 269, 283, 293, + +/*DMRS REs 324, 360, 384, 432, 450, 480, 486, 540, 576, 600, */ + 317, 359, 383, 431, 449, 479, 479, 523, 571, 599, + +/*DMRS REs 648, 720, 750, 768, 810, 864, 900, 960, 972, 1080, 1152, 1200, */ + 647, 719, 743, 761, 809, 863, 887, 953, 971, 1069, 1151, 1193, + +/*DMRS REs 1296, 1350, 1440, 1458, 1500, 1536 1620 supported until 100Mhz */ + 1291, 1327, 1439, 1453, 1499, 1531, 1619 + + +} +#endif +; + +/// PUSCH DMRS for transform precoding +int16_t *gNB_dmrs_lowpaprtype1_sequence[U_GROUP_NUMBER][V_BASE_SEQUENCE_NUMBER][MAX_INDEX_DMRS_UL_ALLOCATED_REs]; +int16_t *dmrs_lowpaprtype1_ul_ref_sig[U_GROUP_NUMBER][V_BASE_SEQUENCE_NUMBER][MAX_INDEX_DMRS_UL_ALLOCATED_REs]; +int16_t get_index_for_dmrs_lowpapr_seq(int16_t num_dmrs_res); +void generate_lowpapr_typ1_refsig_sequences(unsigned int scaling); +void free_gnb_lowpapr_sequences(void); + + #undef INIT_VARIABLES_LOWPAPR_SEQUENCES_NR_H #undef EXTERN diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c index 1372250aca..7b7e54fa43 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c @@ -1118,6 +1118,7 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB, } LOG_D(PHY,"dmrs_symbol: nb_re_pusch %d\n",nb_re_pusch); gNB->pusch_vars[ulsch_id]->dmrs_symbol = symbol; + } else { nb_re_pusch = rel15_ul->rb_size * NR_NB_SC_PER_RB; } @@ -1219,9 +1220,21 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB, symbol, rel15_ul->rb_size); stop_meas(&gNB->ulsch_mrc_stats); -#ifdef NR_SC_FDMA - nr_idft(&((uint32_t*)gNB->pusch_vars[ulsch_id]->rxdataF_ext[0])[symbol * rel15_ul->rb_size * NR_NB_SC_PER_RB], nb_re_pusch); -#endif + + + if (rel15_ul->transform_precoding == transform_precoder_enabled) { + + #ifdef __AVX2__ + // For odd number of resource blocks need byte alignment to multiple of 8 + int nb_re_pusch2 = nb_re_pusch + (nb_re_pusch&7); + #else + int nb_re_pusch2 = nb_re_pusch; + #endif + + // perform IDFT operation on the compensated rxdata if transform precoding is enabled + nr_idft(&((uint32_t*)gNB->pusch_vars[ulsch_id]->rxdataF_comp[0])[symbol * nb_re_pusch2], nb_re_pusch); + LOG_D(PHY,"Transform precoding being done on data- symbol: %d, nb_re_pusch: %d\n", symbol, nb_re_pusch); + } //---------------------------------------------------------- @@ -1245,32 +1258,33 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB, /* Subtract total PTRS RE's in the symbol from PUSCH RE's */ gNB->pusch_vars[ulsch_id]->ul_valid_re_per_slot[symbol] -= gNB->pusch_vars[ulsch_id]->ptrs_re_per_slot; } - - /*---------------------------------------------------------------------------------------------------- */ - /*-------------------- LLRs computation -------------------------------------------------------------*/ - /*-----------------------------------------------------------------------------------------------------*/ - if(symbol == (rel15_ul->start_symbol_index + rel15_ul->nr_of_symbols -1)) - { -#ifdef __AVX2__ - int off = ((rel15_ul->rb_size&1) == 1)? 4:0; -#else - int off = 0; -#endif - uint32_t rxdataF_ext_offset = 0; - for(uint8_t i =rel15_ul->start_symbol_index; i< (rel15_ul->start_symbol_index + rel15_ul->nr_of_symbols);i++) { - start_meas(&gNB->ulsch_llr_stats); - nr_ulsch_compute_llr(&gNB->pusch_vars[ulsch_id]->rxdataF_comp[0][i * (off + rel15_ul->rb_size * NR_NB_SC_PER_RB)], - gNB->pusch_vars[ulsch_id]->ul_ch_mag0, - gNB->pusch_vars[ulsch_id]->ul_ch_magb0, - &gNB->pusch_vars[ulsch_id]->llr[rxdataF_ext_offset * rel15_ul->qam_mod_order], - rel15_ul->rb_size, - gNB->pusch_vars[ulsch_id]->ul_valid_re_per_slot[i], - i, - rel15_ul->qam_mod_order); - stop_meas(&gNB->ulsch_llr_stats); - rxdataF_ext_offset += gNB->pusch_vars[ulsch_id]->ul_valid_re_per_slot[i]; - }// symbol loop - }// last symbol check } + + /*---------------------------------------------------------------------------------------------------- */ + /*-------------------- LLRs computation -------------------------------------------------------------*/ + /*-----------------------------------------------------------------------------------------------------*/ + if(symbol == (rel15_ul->start_symbol_index + rel15_ul->nr_of_symbols -1)) { + +#ifdef __AVX2__ + int off = ((rel15_ul->rb_size&1) == 1)? 4:0; +#else + int off = 0; +#endif + uint32_t rxdataF_ext_offset = 0; + for(uint8_t i =rel15_ul->start_symbol_index; i< (rel15_ul->start_symbol_index + rel15_ul->nr_of_symbols);i++) { + start_meas(&gNB->ulsch_llr_stats); + nr_ulsch_compute_llr(&gNB->pusch_vars[ulsch_id]->rxdataF_comp[0][i * (off + rel15_ul->rb_size * NR_NB_SC_PER_RB)], + gNB->pusch_vars[ulsch_id]->ul_ch_mag0, + gNB->pusch_vars[ulsch_id]->ul_ch_magb0, + &gNB->pusch_vars[ulsch_id]->llr[rxdataF_ext_offset * rel15_ul->qam_mod_order], + rel15_ul->rb_size, + gNB->pusch_vars[ulsch_id]->ul_valid_re_per_slot[i], + i, + rel15_ul->qam_mod_order); + stop_meas(&gNB->ulsch_llr_stats); + rxdataF_ext_offset += gNB->pusch_vars[ulsch_id]->ul_valid_re_per_slot[i]; + }// symbol loop + }// last symbol check + return (0); } diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c index 61e39aa79d..c36c4b98ed 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c @@ -46,9 +46,11 @@ #include "executables/softmodem-common.h" #include "LAYER2/NR_MAC_UE/mac_proto.h" -//#define DEBUG_SCFDMA +#include "PHY/NR_REFSIG/ul_ref_seq_nr.h" + //#define DEBUG_PUSCH_MAPPING //#define DEBUG_MAC_PDU +//#define DEBUG_DFT_IDFT //extern int32_t uplink_counter; @@ -153,6 +155,8 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, unsigned int G = nr_get_G(nb_rb, number_of_symbols, nb_dmrs_re_per_rb, number_dmrs_symbols, mod_order, Nl); + + nr_ulsch_encoding(ulsch_ue, frame_parms, harq_pid, G); /////////// @@ -184,8 +188,7 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, (int16_t *)ulsch_ue->d_mod); - // pusch_transform_precoding(ulsch_ue, frame_parms, harq_pid); - + /////////// //////////////////////////////////////////////////////////////////////// @@ -243,26 +246,72 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, l_prime[0] = 0; // single symbol ap 0 -#ifdef NR_SC_FDMA - uint32_t nb_re_pusch, nb_re_dmrs_per_rb; - uint32_t y_offset = 0; + uint16_t index; + uint8_t u = 0, v = 0; + int16_t *dmrs_seq = NULL; - for (l = start_symbol; l < start_symbol + number_of_symbols; l++) { + if (pusch_pdu->transform_precoding == transform_precoder_enabled) { - if((ul_dmrs_symb_pos >> l) & 0x01) - nb_re_dmrs_per_rb = nb_dmrs_re_per_rb; - else - nb_re_dmrs_per_rb = 0; + uint32_t nb_re_pusch=nb_rb * NR_NB_SC_PER_RB; + uint32_t y_offset = 0; + uint16_t num_dmrs_res_per_symbol = nb_rb*(NR_NB_SC_PER_RB/2); - nb_re_pusch = nb_rb * (NR_NB_SC_PER_RB - nb_re_dmrs_per_rb); + // Calculate index to dmrs seq array based on number of DMRS Subcarriers on this symbol + index = get_index_for_dmrs_lowpapr_seq(num_dmrs_res_per_symbol); + u = pusch_pdu->dfts_ofdm.low_papr_group_number; + v = pusch_pdu->dfts_ofdm.low_papr_sequence_number; + dmrs_seq = dmrs_lowpaprtype1_ul_ref_sig[u][v][index]; - nr_dft(&ulsch_ue->y[y_offset], &((int32_t*)tx_layers[0])[y_offset], nb_re_pusch); + AssertFatal(index >= 0, "Num RBs not configured according to 3GPP 38.211 section 6.3.1.4. For PUSCH with transform precoding, num RBs cannot be multiple of any other primenumber other than 2,3,5\n"); + AssertFatal(dmrs_seq != NULL, "DMRS low PAPR seq not found, check if DMRS sequences are generated"); + + LOG_D(PHY,"Transform Precoding params. u: %d, v: %d, index for dmrsseq: %d\n", u, v, index); + + for (l = start_symbol; l < start_symbol + number_of_symbols; l++) { + + if((ul_dmrs_symb_pos >> l) & 0x01) + /* In the symbol with DMRS no data would be transmitted CDM groups is 2*/ + continue; + + nr_dft(&ulsch_ue->y[y_offset], &((int32_t*)tx_layers[0])[y_offset], nb_re_pusch); + + y_offset = y_offset + nb_re_pusch; + + LOG_D(PHY,"Transform precoding being done on data- symbol: %d, nb_re_pusch: %d, y_offset: %d\n", l, nb_re_pusch, y_offset); + + #ifdef DEBUG_PUSCH_MAPPING + printf("NR_ULSCH_UE: y_offset %d\t nb_re_pusch %d \t Symbol %d \t nb_rb %d \n", + y_offset, nb_re_pusch, l, nb_rb); + #endif + } + + #ifdef DEBUG_DFT_IDFT + uint32_t debug_symbols[MAX_NUM_NR_RE] __attribute__ ((aligned(16))); + int offset = 0; + printf("NR_ULSCH_UE: available_bits: %d, mod_order: %d", available_bits,mod_order); + + for (int ll = 0; ll < (available_bits/mod_order); ll++) { + debug_symbols[ll] = ulsch_ue->y[ll]; + } + + printf("NR_ULSCH_UE: numSym: %d, num_dmrs_sym: %d", number_of_symbols,number_dmrs_symbols); + for (int ll = 0; ll < (number_of_symbols-number_dmrs_symbols); ll++) { + + nr_idft(&debug_symbols[offset], nb_re_pusch); + + offset = offset + nb_re_pusch; + + } + LOG_M("preDFT_all_symbols.m","UE_preDFT", tx_layers[0],number_of_symbols*nb_re_pusch,1,1); + LOG_M("postDFT_all_symbols.m","UE_postDFT", &(ulsch_ue->y[0]),number_of_symbols*nb_re_pusch,1,1); + LOG_M("DEBUG_IDFT_SYMBOLS.m","UE_Debug_IDFT", debug_symbols,number_of_symbols*nb_re_pusch,1,1); + LOG_M("UE_DMRS_SEQ.m","UE_DMRS_SEQ", dmrs_seq,nb_re_pusch,1,1); + #endif - y_offset = y_offset + nb_re_pusch; } -#else - memcpy(ulsch_ue->y, tx_layers[0], (available_bits/mod_order)*sizeof(int32_t)); -#endif + else + memcpy(ulsch_ue->y, tx_layers[0], (available_bits/mod_order)*sizeof(int32_t)); + /////////// //////////////////////////////////////////////////////////////////////// @@ -279,6 +328,13 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, uint8_t k_prime = 0; uint16_t m = 0; + + #ifdef DEBUG_PUSCH_MAPPING + printf("NR_ULSCH_UE: Value of CELL ID %d /t, u %d \n", frame_parms->Nid_cell, u); + #endif + + + // DMRS params for this ap get_Wt(Wt, ap, dmrs_type); get_Wf(Wf, ap, dmrs_type); @@ -295,18 +351,25 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, if ((ul_dmrs_symb_pos >> l) & 0x01) { is_dmrs_sym = 1; - if (pusch_pdu->transform_precoding == 1){ // if transform precoding is disabled + + if (pusch_pdu->transform_precoding == transform_precoder_disabled){ + if (dmrs_type == pusch_dmrs_type1) dmrs_idx = start_rb*6; else dmrs_idx = start_rb*4; + + // Perform this on gold sequence, not required when SC FDMA operation is done, + nr_modulation(pusch_dmrs[l][0], n_dmrs*2, DMRS_MOD_ORDER, mod_dmrs); // currently only codeword 0 is modulated. Qm = 2 as DMRS is QPSK modulated + } else { dmrs_idx = 0; - } + } + + + } else if (pusch_pdu->pdu_bit_map & PUSCH_PDU_BITMAP_PUSCH_PTRS) { - nr_modulation(pusch_dmrs[l][0], n_dmrs*2, DMRS_MOD_ORDER, mod_dmrs); // currently only codeword 0 is modulated. Qm = 2 as DMRS is QPSK modulated - - } else if (pusch_pdu->pdu_bit_map & PUSCH_PDU_BITMAP_PUSCH_PTRS) { + AssertFatal(pusch_pdu->transform_precoding == transform_precoder_disabled, "PTRS NOT SUPPORTED IF TRANSFORM PRECODING IS ENABLED\n"); if(is_ptrs_symbol(l, ulsch_ue->ptrs_symbols)) { is_ptrs_sym = 1; @@ -338,8 +401,17 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, if (is_dmrs == 1) { - ((int16_t*)txdataF[ap])[(sample_offsetF)<<1] = (Wt[l_prime[0]]*Wf[k_prime]*AMP*mod_dmrs[dmrs_idx<<1]) >> 15; - ((int16_t*)txdataF[ap])[((sample_offsetF)<<1) + 1] = (Wt[l_prime[0]]*Wf[k_prime]*AMP*mod_dmrs[(dmrs_idx<<1) + 1]) >> 15; + if (pusch_pdu->transform_precoding == transform_precoder_enabled) { + + ((int16_t*)txdataF[ap])[(sample_offsetF)<<1] = (Wt[l_prime[0]]*Wf[k_prime]*AMP*dmrs_seq[2*dmrs_idx]) >> 15; + ((int16_t*)txdataF[ap])[((sample_offsetF)<<1) + 1] = (Wt[l_prime[0]]*Wf[k_prime]*AMP*dmrs_seq[(2*dmrs_idx) + 1]) >> 15; + + } else { + + ((int16_t*)txdataF[ap])[(sample_offsetF)<<1] = (Wt[l_prime[0]]*Wf[k_prime]*AMP*mod_dmrs[dmrs_idx<<1]) >> 15; + ((int16_t*)txdataF[ap])[((sample_offsetF)<<1) + 1] = (Wt[l_prime[0]]*Wf[k_prime]*AMP*mod_dmrs[(dmrs_idx<<1) + 1]) >> 15; + + } #ifdef DEBUG_PUSCH_MAPPING printf("dmrs_idx %d\t l %d \t k %d \t k_prime %d \t n %d \t dmrs: %d %d\n", diff --git a/openair1/PHY/defs_nr_common.h b/openair1/PHY/defs_nr_common.h index 89c6a2d9c8..76610da412 100644 --- a/openair1/PHY/defs_nr_common.h +++ b/openair1/PHY/defs_nr_common.h @@ -42,11 +42,6 @@ #define nr_subframe_t lte_subframe_t #define nr_slot_t lte_subframe_t -// [hna] This enables SC-FDMA transmission in Uplink. If disabled, then OFDMA is used in UPLINK. -#ifndef NR_SC_FDMA -// #define NR_SC_FDMA -#endif - #define MAX_NUM_SUBCARRIER_SPACING 5 #define NR_MAX_NB_RB 275 diff --git a/openair1/PHY/impl_defs_nr.h b/openair1/PHY/impl_defs_nr.h index 9d6f1703e5..ceb75c2554 100644 --- a/openair1/PHY/impl_defs_nr.h +++ b/openair1/PHY/impl_defs_nr.h @@ -601,9 +601,11 @@ typedef enum{ ul_rgb_config1 = 1, ul_rgb_config2 = 2 } ul_rgb_Size_t; -typedef enum { - transformPrecoder_enabled = 1, - transformPrecoder_disabled = 2 +/* Aligned values of this enum to other tranform precoder enums + * eg: as defined in fapi_nr_ue_interface.h for transform_precoder_t*/ +typedef enum { + transformPrecoder_enabled = 0, + transformPrecoder_disabled = 1 } transformPrecoder_t; typedef enum { codebookSubset_fullyAndPartialAndNonCoherent = 1, diff --git a/openair1/SIMULATION/NR_PHY/ulsim.c b/openair1/SIMULATION/NR_PHY/ulsim.c index 821ac75a64..d5126ed356 100644 --- a/openair1/SIMULATION/NR_PHY/ulsim.c +++ b/openair1/SIMULATION/NR_PHY/ulsim.c @@ -63,6 +63,8 @@ #include #include +#include "PHY/NR_REFSIG/ul_ref_seq_nr.h" + //#define DEBUG_ULSIM LCHAN_DESC DCCH_LCHAN_DESC,DTCH_DL_LCHAN_DESC,DTCH_UL_LCHAN_DESC; @@ -201,6 +203,10 @@ int main(int argc, char **argv) uint16_t ptrsSymbPerSlot = 0; uint16_t ptrsRePerSymb = 0; + uint8_t transform_precoding = transform_precoder_disabled; // 0 - ENABLE, 1 - DISABLE + uint8_t num_dmrs_cdm_grps_no_data = 1; + uint8_t mcs_table = 0; + UE_nr_rxtx_proc_t UE_proc; FILE *scg_fd=NULL; int file_offset = 0; @@ -221,7 +227,7 @@ int main(int argc, char **argv) /* initialize the sin-cos table */ InitSinLUT(); - while ((c = getopt(argc, argv, "a:b:c:d:ef:g:h:i:j:kl:m:n:p:r:s:y:z:F:G:H:M:N:PR:S:T:U:L:")) != -1) { + while ((c = getopt(argc, argv, "a:b:c:d:ef:g:h:i:j:kl:m:n:p:r:s:y:z:F:G:H:M:N:PR:S:T:U:L:Z")) != -1) { printf("handling optarg %c\n",c); switch (c) { @@ -454,9 +460,19 @@ int main(int argc, char **argv) params_from_file = 1; break; + case 'Z': + + transform_precoding = transform_precoder_enabled; + num_dmrs_cdm_grps_no_data = 2; + mcs_table = 3; + + printf("NOTE: TRANSFORM PRECODING (SC-FDMA) is ENABLED in UPLINK (0 - ENABLE, 1 - DISABLE) : %d \n", transform_precoding); + + break; + default: case 'h': - printf("%s -h(elp) -p(extended_prefix) -N cell_id -f output_filename -F input_filename -g channel_model -n n_frames -t Delayspread -s snr0 -S snr1 -x transmission_mode -y TXant -z RXant -i Intefrence0 -j Interference1 -A interpolation_file -C(alibration offset dB) -N CellId\n", argv[0]); + printf("%s -h(elp) -p(extended_prefix) -N cell_id -f output_filename -F input_filename -g channel_model -n n_frames -t Delayspread -s snr0 -S snr1 -x transmission_mode -y TXant -z RXant -i Intefrence0 -j Interference1 -A interpolation_file -C(alibration offset dB) -N CellId -Z Enable SC-FDMA in Uplink \n", argv[0]); //printf("-d Use TDD\n"); printf("-d Introduce delay in terms of number of samples\n"); printf("-f Number of frames to simulate\n"); @@ -486,6 +502,7 @@ int main(int argc, char **argv) printf("-T Enable PTRS, arguments list L_PTRS{0,1,2} K_PTRS{2,4}, e.g. -T 2 0 2 \n"); printf("-U Change DMRS Config, arguments list DMRS TYPE{0=A,1=B} DMRS AddPos{0:3}, e.g. -U 2 0 2 \n"); printf("-Q If -F used, read parameters from file\n"); + printf("-Z If -Z is used, SC-FDMA or transform precoding is enabled in Uplink \n"); exit(-1); break; @@ -681,13 +698,13 @@ int main(int argc, char **argv) uint8_t ptrs_mcs3 = 10; uint16_t n_rb0 = 25; uint16_t n_rb1 = 75; - uint8_t mcs_table = 0; + uint16_t pdu_bit_map = PUSCH_PDU_BITMAP_PUSCH_DATA; // | PUSCH_PDU_BITMAP_PUSCH_PTRS; uint8_t max_rounds = 4; uint8_t crc_status = 0; - unsigned char mod_order = nr_get_Qm_ul(Imcs, 0); - uint16_t code_rate = nr_get_code_rate_ul(Imcs, 0); + unsigned char mod_order = nr_get_Qm_ul(Imcs, mcs_table); + uint16_t code_rate = nr_get_code_rate_ul(Imcs, mcs_table); uint8_t mapping_type = typeB; // Default Values pusch_dmrs_type_t dmrs_config_type = pusch_dmrs_type1; // Default Values @@ -717,9 +734,32 @@ int main(int argc, char **argv) uint16_t l_prime_mask = get_l_prime(nb_symb_sch, mapping_type, add_pos, length_dmrs); uint16_t number_dmrs_symbols = get_dmrs_symbols_in_slot(l_prime_mask, nb_symb_sch); uint8_t nb_re_dmrs = (dmrs_config_type == pusch_dmrs_type1) ? 6 : 4; + + if (transform_precoding == transform_precoder_enabled) { + + AssertFatal(enable_ptrs == 0, "PTRS NOT SUPPORTED IF TRANSFORM PRECODING IS ENABLED\n"); + + int8_t index = get_index_for_dmrs_lowpapr_seq((NR_NB_SC_PER_RB/2) * nb_rb); + AssertFatal(index >= 0, "Num RBs not configured according to 3GPP 38.211 section 6.3.1.4. For PUSCH with transform precoding, num RBs cannot be multiple of any other primenumber other than 2,3,5\n"); + + dmrs_config_type = pusch_dmrs_type1; + nb_re_dmrs = nb_re_dmrs * num_dmrs_cdm_grps_no_data; + + printf("[ULSIM]: TRANSFORM PRECODING ENABLED. Num RBs: %d, index for DMRS_SEQ: %d\n", nb_rb, index); + } + + unsigned int available_bits = nr_get_G(nb_rb, nb_symb_sch, nb_re_dmrs, number_dmrs_symbols, mod_order, 1); unsigned int TBS = nr_compute_tbs(mod_order, code_rate, nb_rb, nb_symb_sch, nb_re_dmrs * number_dmrs_symbols, 0, 0, precod_nbr_layers); + + printf("[ULSIM]: length_dmrs: %d, l_prime_mask: %d number_dmrs_symbols: %d, mapping_type: %d add_pos: %d \n", length_dmrs, l_prime_mask, number_dmrs_symbols, mapping_type,add_pos); + printf("[ULSIM]: CDM groups: %d, dmrs_config_type: %d, num_rbs: %d, nb_symb_sch: %d\n", num_dmrs_cdm_grps_no_data, dmrs_config_type, nb_rb, nb_symb_sch); + printf("[ULSIM]: MCS: %d, mod order: %d, code_rate: %d\n", Imcs, mod_order, code_rate); + printf("[ULSIM]: VALUE OF G: %d, TBS: %d\n", available_bits, TBS); + + + uint8_t ulsch_input_buffer[TBS/8]; ulsch_input_buffer[0] = 0x31; @@ -874,7 +914,7 @@ int main(int argc, char **argv) pusch_pdu->mcs_table = mcs_table; pusch_pdu->target_code_rate = code_rate; pusch_pdu->qam_mod_order = mod_order; - pusch_pdu->transform_precoding = 1; + pusch_pdu->transform_precoding = transform_precoding; pusch_pdu->data_scrambling_id = *scc->physCellId; pusch_pdu->nrOfLayers = 1; pusch_pdu->ul_dmrs_symb_pos = l_prime_mask << start_symbol; @@ -900,6 +940,13 @@ int main(int argc, char **argv) pusch_pdu->pusch_ptrs.ptrs_ports_list = (nfapi_nr_ptrs_ports_t *) malloc(2*sizeof(nfapi_nr_ptrs_ports_t)); pusch_pdu->pusch_ptrs.ptrs_ports_list[0].ptrs_re_offset = 0; + if (transform_precoding == transform_precoder_enabled) { + + pusch_pdu->dfts_ofdm.low_papr_group_number = *scc->physCellId % 30; // U as defined in 38.211 section 6.4.1.1.1.2 + pusch_pdu->dfts_ofdm.low_papr_sequence_number = 0; // V as defined in 38.211 section 6.4.1.1.1.2 + pusch_pdu->num_dmrs_cdm_grps_no_data = num_dmrs_cdm_grps_no_data; + } + // prepare ULSCH/PUSCH reception nr_schedule_response(Sched_INFO); @@ -951,6 +998,18 @@ int main(int argc, char **argv) ul_config.ul_config_list[0].pusch_config_pdu.pusch_ptrs.ptrs_ports_list = (nfapi_nr_ue_ptrs_ports_t *) malloc(2*sizeof(nfapi_nr_ue_ptrs_ports_t)); ul_config.ul_config_list[0].pusch_config_pdu.pusch_ptrs.ptrs_ports_list[0].ptrs_re_offset = 0; + ul_config.ul_config_list[0].pusch_config_pdu.transform_precoding = transform_precoding; + + if (transform_precoding == transform_precoder_enabled) { + + ul_config.ul_config_list[0].pusch_config_pdu.dfts_ofdm.low_papr_group_number = *scc->physCellId % 30;// U as defined in 38.211 section 6.4.1.1.1.2 + ul_config.ul_config_list[0].pusch_config_pdu.dfts_ofdm.low_papr_sequence_number = 0;// V as defined in 38.211 section 6.4.1.1.1.2 + //ul_config.ul_config_list[0].pusch_config_pdu.pdu_bit_map |= PUSCH_PDU_BITMAP_DFTS_OFDM; + ul_config.ul_config_list[0].pusch_config_pdu.num_dmrs_cdm_grps_no_data = num_dmrs_cdm_grps_no_data; + + } + + nr_fill_ulsch(gNB,frame,slot,pusch_pdu); for (int i=0;i<(TBS/8);i++) ulsch_ue[0]->harq_processes[harq_pid]->a[i]=i&0xff;