diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt
index bcfcb6fc77..b2ede601f7 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/cmake_targets/autotests/test_case_list.xml b/cmake_targets/autotests/test_case_list.xml
index e081a4186e..6d3424b420 100644
--- a/cmake_targets/autotests/test_case_list.xml
+++ b/cmake_targets/autotests/test_case_list.xml
@@ -1289,7 +1289,10 @@
(Test5: MCS 9 273 PRBs),
(Test6: DMRS Type A, 3 DMRS, 4 PTRS, 5 Interpolated Symbols),
(Test7: DMRS Type B, 3 DMRS, 2 PTRS, 7 Interpolated Symbols),
- (Test8: DMRS Type B, 3 DMRS, 2 PTRS, 3 Interpolated Symbols)
+ (Test8: DMRS Type B, 3 DMRS, 2 PTRS, 3 Interpolated Symbols),
+ (Test9: SC-FDMA, 50 PRBs),
+ (Test10: SC-FDMA, 75 PRBs),
+ (Test11: SC-FDMA, 3 DMRS)
$OPENAIR_DIR/cmake_targets/build_oai
--phy_simulators -c
@@ -1303,8 +1306,11 @@
-n100 -m9 -R273 -r273 -s5
-n100 -s5 -T 2 1 2 -U 2 0 2
-n100 -s5 -T 2 2 2 -U 2 1 2
- -n100 -s5 -a4 -b8 -T 2 1 2 -U 2 1 3
- nr_ulsim.test1 nr_ulsim.test2 nr_ulsim.test3 nr_ulsim.test4 nr_ulsim.test5 nr_ulsim.test6 nr_ulsim.test7 nr_ulsim.test8
+ -n100 -s5 -a4 -b8 -T 2 1 2 -U 2 1 3
+ -n100 -s20 -Z
+ -n100 -s20 -Z -r75
+ -n100 -s20 -Z -U 2 0 2
+ nr_ulsim.test1 nr_ulsim.test2 nr_ulsim.test3 nr_ulsim.test4 nr_ulsim.test5 nr_ulsim.test6 nr_ulsim.test7 nr_ulsim.test8 nr_ulsim.test9 nr_ulsim.test10 nr_ulsim.test11
PUSCH test OK
segmentation fault|assertion|exiting|fatal
3
diff --git a/doc/FEATURE_SET.md b/doc/FEATURE_SET.md
index 2840eed73c..2171fc2f1f 100644
--- a/doc/FEATURE_SET.md
+++ b/doc/FEATURE_SET.md
@@ -264,6 +264,7 @@ The following features are valid for the gNB and the 5G-NR UE.
* Highly efficient 3GPP compliant LDPC encoder and decoder (BG1 and BG2 supported)
* Highly efficient 3GPP compliant polar encoder and decoder
* Encoder and decoder for short blocks
+* Support for UL transform precoding (SC-FDMA)
## gNB PHY Layer ##
diff --git a/openair1/PHY/INIT/nr_init.c b/openair1/PHY/INIT/nr_init.c
index 63c80a136b..9897a4d399 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];
@@ -195,6 +197,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
@@ -389,6 +395,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_transport_proto.h b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h
index 5228cad98c..e5e81109e4 100644
--- a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h
+++ b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h
@@ -212,7 +212,7 @@ void nr_ulsch_channel_compensation(int **rxdataF_ext,
\param z Pointer to input in frequnecy domain, and it is also the output in time domain
\param Msc_PUSCH number of allocated data subcarriers
*/
-void nr_idft(uint32_t *z, uint32_t Msc_PUSCH);
+void nr_idft(int32_t *z, uint32_t Msc_PUSCH);
/** \brief This function generates log-likelihood ratios (decoder input) for single-stream QPSK received waveforms.
@param rxdataF_comp Compensated channel output
diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c
index 1372250aca..7e6becb4a8 100644
--- a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c
+++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c
@@ -12,7 +12,7 @@
//#define DEBUG_RB_EXT
//#define DEBUG_CH_MAG
-void nr_idft(uint32_t *z, uint32_t Msc_PUSCH)
+void nr_idft(int32_t *z, uint32_t Msc_PUSCH)
{
#if defined(__x86_64__) || defined(__i386__)
@@ -38,7 +38,7 @@ void nr_idft(uint32_t *z, uint32_t Msc_PUSCH)
}
for (i=0,ip=0; ipusch_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(&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_transport_ue.h b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h
index 7d0febbb5a..464bcfcfba 100644
--- a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h
+++ b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h
@@ -181,9 +181,9 @@ typedef struct {
/// Scrambled "b"-sequences (for definition see 36-211 V8.6 2009-03, p.14)
uint8_t b_tilde[MAX_NUM_NR_CHANNEL_BITS];
/// Modulated "d"-sequences (for definition see 36-211 V8.6 2009-03, p.14)
- uint32_t d_mod[MAX_NUM_NR_RE] __attribute__ ((aligned(16)));
+ int32_t d_mod[MAX_NUM_NR_RE] __attribute__ ((aligned(16)));
/// Transform-coded "y"-sequences (for definition see 38-211 V15.3.0 2018-09, subsection 6.3.1.4)
- uint32_t y[MAX_NUM_NR_RE] __attribute__ ((aligned(16)));
+ int32_t y[MAX_NUM_NR_RE] __attribute__ ((aligned(16)));
/*
/// "q" sequences for CQI/PMI (for definition see 36-212 V8.6 2009-03, p.27)
uint8_t q[MAX_CQI_PAYLOAD];
diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c
index 61e39aa79d..208901f289 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
+ int32_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,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/TOOLS/oai_dfts.c b/openair1/PHY/TOOLS/oai_dfts.c
index 25244eeff5..e4e85f7ba9 100644
--- a/openair1/PHY/TOOLS/oai_dfts.c
+++ b/openair1/PHY/TOOLS/oai_dfts.c
@@ -112,7 +112,7 @@ static inline void cmac_256(__m256i a,__m256i b, __m256i *re32, __m256i *im32)
{
__m256i cmac_tmp,cmac_tmp_re32,cmac_tmp_im32;
- __m256i imshuffle = _mm256_set_epi8(29,28,31,30,25,24,27,26,21,20,19,18,17,16,19,18,13,12,15,14,9,8,11,10,5,4,7,6,1,0,3,2);
+ __m256i imshuffle = _mm256_set_epi8(29,28,31,30,25,24,27,26,21,20,23,22,17,16,19,18,13,12,15,14,9,8,11,10,5,4,7,6,1,0,3,2);
cmac_tmp = _mm256_sign_epi16(b,*(__m256i*)reflip);
cmac_tmp_re32 = _mm256_madd_epi16(a,cmac_tmp);
@@ -129,7 +129,7 @@ static inline void cmacc_256(__m256i a,__m256i b, __m256i *re32, __m256i *im32)
{
__m256i cmac_tmp,cmac_tmp_re32,cmac_tmp_im32;
- __m256i imshuffle = _mm256_set_epi8(29,28,31,30,25,24,27,26,21,20,19,18,17,16,19,18,13,12,15,14,9,8,11,10,5,4,7,6,1,0,3,2);
+ __m256i imshuffle = _mm256_set_epi8(29,28,31,30,25,24,27,26,21,20,23,22,17,16,19,18,13,12,15,14,9,8,11,10,5,4,7,6,1,0,3,2);
cmac_tmp_re32 = _mm256_madd_epi16(a,b);
diff --git a/openair1/PHY/defs_nr_common.h b/openair1/PHY/defs_nr_common.h
index 08b54c5c98..d1d47e0391 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 bc29419afb..670cf5cc9f 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;
@@ -205,6 +207,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;
@@ -225,7 +231,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) {
@@ -458,9 +464,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");
@@ -490,6 +506,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;
@@ -685,13 +702,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
@@ -721,9 +738,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: %u, l_prime_mask: %u number_dmrs_symbols: %u, mapping_type: %u add_pos: %d \n", length_dmrs, l_prime_mask, number_dmrs_symbols, mapping_type, add_pos);
+ printf("[ULSIM]: CDM groups: %u, dmrs_config_type: %d, num_rbs: %u, nb_symb_sch: %u\n", num_dmrs_cdm_grps_no_data, dmrs_config_type, nb_rb, nb_symb_sch);
+ printf("[ULSIM]: MCS: %d, mod order: %u, code_rate: %u\n", Imcs, mod_order, code_rate);
+ printf("[ULSIM]: VALUE OF G: %u, TBS: %u\n", available_bits, TBS);
+
+
+
uint8_t ulsch_input_buffer[TBS/8];
ulsch_input_buffer[0] = 0x31;
@@ -878,7 +918,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;
@@ -904,6 +944,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);
@@ -955,6 +1002,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;
diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c
index be476c2775..bf95e38ae2 100644
--- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c
+++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c
@@ -1259,6 +1259,44 @@ NR_UE_L2_STATE_t nr_ue_scheduler(nr_downlink_indication_t *dl_info, nr_uplink_in
ulcfg_pdu->pusch_config_pdu.pdu_bit_map &= ~PUSCH_PDU_BITMAP_PUSCH_PTRS; // disable PUSCH PTRS
}
+ /* TRANSFORM PRECODING ------------------------------------------------------------------------------------------*/
+
+ if (ulcfg_pdu->pusch_config_pdu.transform_precoding == transform_precoder_enabled) {
+
+ uint32_t n_RS_Id = 0;
+
+ NR_PUSCH_Config_t *pusch_config=mac->ULbwp[0]->bwp_Dedicated->pusch_Config->choice.setup;
+ NR_DMRS_UplinkConfig_t *NR_DMRS_ulconfig = NULL;
+
+ ulcfg_pdu->pusch_config_pdu.num_dmrs_cdm_grps_no_data = 2;
+
+ if(pusch_config->dmrs_UplinkForPUSCH_MappingTypeA != NULL)
+ NR_DMRS_ulconfig = pusch_config->dmrs_UplinkForPUSCH_MappingTypeA->choice.setup;
+ else
+ NR_DMRS_ulconfig = pusch_config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup;
+
+
+ if (NR_DMRS_ulconfig->transformPrecodingEnabled->nPUSCH_Identity != NULL)
+ n_RS_Id = *NR_DMRS_ulconfig->transformPrecodingEnabled->nPUSCH_Identity;
+ else
+ n_RS_Id = *mac->scc->physCellId;
+
+ // U as specified in section 6.4.1.1.1.2 in 38.211, if sequence hopping and group hopping are disabled
+ ulcfg_pdu->pusch_config_pdu.dfts_ofdm.low_papr_group_number = n_RS_Id % 30;
+
+ // V as specified in section 6.4.1.1.1.2 in 38.211 V = 0 if sequence hopping and group hopping are disabled
+ if ((NR_DMRS_ulconfig->transformPrecodingEnabled->sequenceGroupHopping == NULL) &&
+ (NR_DMRS_ulconfig->transformPrecodingEnabled->sequenceHopping == NULL))
+ ulcfg_pdu->pusch_config_pdu.dfts_ofdm.low_papr_sequence_number = 0;
+ else
+ AssertFatal(1==0,"SequenceGroupHopping or sequenceHopping are NOT Supported\n");
+
+ LOG_D(MAC,"TRANSFORM PRECODING IS ENABLED. CDM groups: %d, U: %d \n", ulcfg_pdu->pusch_config_pdu.num_dmrs_cdm_grps_no_data,
+ ulcfg_pdu->pusch_config_pdu.dfts_ofdm.low_papr_group_number);
+ }
+
+ /* TRANSFORM PRECODING --------------------------------------------------------------------------------------------------------*/
+
get_num_re_dmrs(&ulcfg_pdu->pusch_config_pdu,
&nb_dmrs_re_per_rb,
&number_dmrs_symbols);
@@ -2908,9 +2946,9 @@ int8_t nr_ue_process_dci(module_id_t module_id, int cc_id, uint8_t gNB_index, fr
/* MCS TABLE */
if (mac->scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg3_transformPrecoder == NULL)
- pusch_config_pdu_0_0->transform_precoding = 1;
+ pusch_config_pdu_0_0->transform_precoding = transform_precoder_disabled;
else
- pusch_config_pdu_0_0->transform_precoding = 0;
+ pusch_config_pdu_0_0->transform_precoding = transform_precoder_enabled;
if (pusch_config_pdu_0_0->transform_precoding == transform_precoder_disabled)
pusch_config_pdu_0_0->mcs_table = get_pusch_mcs_table(pusch_config->mcs_Table, 0,
@@ -3028,9 +3066,9 @@ int8_t nr_ue_process_dci(module_id_t module_id, int cc_id, uint8_t gNB_index, fr
/* MCS TABLE */
if (pusch_config->transformPrecoder == NULL) {
if (mac->scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg3_transformPrecoder == NULL)
- pusch_config_pdu_0_1->transform_precoding = 1;
+ pusch_config_pdu_0_1->transform_precoding = transform_precoder_disabled;
else
- pusch_config_pdu_0_1->transform_precoding = 0;
+ pusch_config_pdu_0_1->transform_precoding = transform_precoder_enabled;
}
else
pusch_config_pdu_0_1->transform_precoding = *pusch_config->transformPrecoder;
@@ -3144,14 +3182,58 @@ int8_t nr_ue_process_dci(module_id_t module_id, int cc_id, uint8_t gNB_index, fr
}
}
}
+
+/*-------------------- Changed to enable Transform precoding in RF SIM------------------------------------------------*/
+
+ NR_DMRS_UplinkConfig_t *NR_DMRS_ulconfig = NULL;
+
+ if (pusch_config_pdu_0_1->transform_precoding == transform_precoder_enabled) {
+
+ mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.transform_precoder = transform_precoder_enabled;
+
+ if(pusch_config->dmrs_UplinkForPUSCH_MappingTypeA != NULL) {
+
+ NR_DMRS_ulconfig = pusch_config->dmrs_UplinkForPUSCH_MappingTypeA->choice.setup;
+
+ if (NR_DMRS_ulconfig->dmrs_Type == NULL)
+ mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.dmrs_ul_for_pusch_mapping_type_a.dmrs_type = 1;
+ if (NR_DMRS_ulconfig->maxLength == NULL)
+ mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.dmrs_ul_for_pusch_mapping_type_a.max_length = 1;
+
+ } else if(pusch_config->dmrs_UplinkForPUSCH_MappingTypeB != NULL) {
+
+ NR_DMRS_ulconfig = pusch_config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup;
+
+ if (NR_DMRS_ulconfig->dmrs_Type == NULL)
+ mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.dmrs_ul_for_pusch_mapping_type_b.dmrs_type = 1;
+ if (NR_DMRS_ulconfig->maxLength == NULL)
+ mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.dmrs_ul_for_pusch_mapping_type_b.max_length = 1;
+
+ }
+ } else
+ mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.transform_precoder = transform_precoder_disabled;
+
+ // mapping type b configured from RRC. TBD: Mapping type b is not handled in this function.
+ if ((mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.transform_precoder == transform_precoder_enabled) &&
+ (mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.dmrs_ul_for_pusch_mapping_type_b.dmrs_type == 1) &&
+ (mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.dmrs_ul_for_pusch_mapping_type_b.max_length == 1)) { // tables 7.3.1.1.2-6
+ pusch_config_pdu_0_1->num_dmrs_cdm_grps_no_data = 2;
+ pusch_config_pdu_0_1->dmrs_ports = dci->antenna_ports.val;
+ }
+
+ /*-------------------- ---------------------------------------------------------------------------------------------------------------*/
+
+
/* ANTENNA_PORTS */
uint8_t rank=0; // We need to initialize rank FIXME!!!
+
if ((mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.transform_precoder == transform_precoder_enabled) &&
(mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.dmrs_ul_for_pusch_mapping_type_a.dmrs_type == 1) &&
(mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.dmrs_ul_for_pusch_mapping_type_a.max_length == 1)) { // tables 7.3.1.1.2-6
pusch_config_pdu_0_1->num_dmrs_cdm_grps_no_data = 2; //TBC
pusch_config_pdu_0_1->dmrs_ports = dci->antenna_ports.val; //TBC
}
+
if ((mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.transform_precoder == transform_precoder_enabled) &&
(mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.dmrs_ul_for_pusch_mapping_type_a.dmrs_type == 1) &&
(mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.dmrs_ul_for_pusch_mapping_type_a.max_length == 2)) { // tables 7.3.1.1.2-7
diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c
index 13f49257de..ebe8e4cb87 100644
--- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c
+++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c
@@ -221,7 +221,6 @@ void nr_save_pusch_fields(const NR_ServingCellConfigCommon_t *scc,
{
ps->dci_format = dci_format;
ps->time_domain_allocation = tda;
- ps->num_dmrs_cdm_grps_no_data = num_dmrs_cdm_grps_no_data;
const struct NR_PUSCH_TimeDomainResourceAllocationList *tdaList =
ubwp->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList;
@@ -243,13 +242,17 @@ void nr_save_pusch_fields(const NR_ServingCellConfigCommon_t *scc,
NR_RNTI_C,
target_ss,
false);
- else
+ else {
ps->mcs_table = get_pusch_mcs_table(ps->pusch_Config->mcs_TableTransformPrecoder,
1,
ps->dci_format,
NR_RNTI_C,
target_ss,
false);
+ num_dmrs_cdm_grps_no_data = 2; // in case of transform precoding - no Data sent in DMRS symbol
+ }
+
+ ps->num_dmrs_cdm_grps_no_data = num_dmrs_cdm_grps_no_data;
/* DMRS calculations */
ps->mapping_type = tdaList->list.array[tda]->mappingType;
diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c
index 75b00ea6ba..b92ee1dba3 100644
--- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c
+++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c
@@ -742,6 +742,25 @@ void nr_schedule_ulsch(module_id_t module_id,
pusch_pdu->pusch_data.tb_size = sched_pusch->tb_size;
pusch_pdu->pusch_data.num_cb = 0; //CBG not supported
+ /* TRANSFORM PRECODING --------------------------------------------------------*/
+
+ if (pusch_pdu->transform_precoding == NR_PUSCH_Config__transformPrecoder_enabled){
+
+ // U as specified in section 6.4.1.1.1.2 in 38.211, if sequence hopping and group hopping are disabled
+ pusch_pdu->dfts_ofdm.low_papr_group_number = pusch_pdu->pusch_identity % 30;
+
+ // V as specified in section 6.4.1.1.1.2 in 38.211 V = 0 if sequence hopping and group hopping are disabled
+ if ((ps->NR_DMRS_UplinkConfig->transformPrecodingEnabled->sequenceGroupHopping == NULL) &&
+ (ps->NR_DMRS_UplinkConfig->transformPrecodingEnabled->sequenceHopping == NULL))
+ pusch_pdu->dfts_ofdm.low_papr_sequence_number = 0;
+ else
+ AssertFatal(1==0,"SequenceGroupHopping or sequenceHopping are NOT Supported\n");
+
+ LOG_D(NR_MAC,"TRANSFORM PRECODING IS ENABLED. CDM groups: %d, U: %d MCS table: %d\n", pusch_pdu->num_dmrs_cdm_grps_no_data, pusch_pdu->dfts_ofdm.low_papr_group_number, ps->mcs_table);
+ }
+
+ /*-----------------------------------------------------------------------------*/
+
/* PUSCH PTRS */
if (ps->NR_DMRS_UplinkConfig->phaseTrackingRS != NULL) {
// TODO to be fixed from RRC config
diff --git a/openair2/RRC/NR/rrc_gNB_reconfig.c b/openair2/RRC/NR/rrc_gNB_reconfig.c
index a9e48efe28..56b3b74050 100644
--- a/openair2/RRC/NR/rrc_gNB_reconfig.c
+++ b/openair2/RRC/NR/rrc_gNB_reconfig.c
@@ -888,8 +888,12 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco
pusch_Config->pusch_AggregationFactor=NULL;
pusch_Config->mcs_Table=NULL;
pusch_Config->mcs_TableTransformPrecoder=NULL;
- pusch_Config->transformPrecoder=calloc(1,sizeof(*pusch_Config->transformPrecoder));
- *pusch_Config->transformPrecoder = NR_PUSCH_Config__transformPrecoder_disabled;
+ pusch_Config->transformPrecoder= NULL;
+ /* if msg3_transformprecoding is set in conf file - pusch config should not disable it */
+ if (servingcellconfigcommon->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg3_transformPrecoder == NULL) {
+ pusch_Config->transformPrecoder=calloc(1,sizeof(*pusch_Config->transformPrecoder));
+ *pusch_Config->transformPrecoder = NR_PUSCH_Config__transformPrecoder_disabled;
+ }
pusch_Config->codebookSubset=calloc(1,sizeof(*pusch_Config->codebookSubset));
*pusch_Config->codebookSubset = NR_PUSCH_Config__codebookSubset_nonCoherent;
pusch_Config->maxRank=calloc(1,sizeof(*pusch_Config->maxRank));
@@ -898,6 +902,39 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco
pusch_Config->uci_OnPUSCH=NULL;
pusch_Config->tp_pi2BPSK=NULL;
+ /*------------------------------TRANSFORM PRECODING- -----------------------------------------------------------------------*/
+
+ uint8_t transform_precoding = NR_PUSCH_Config__transformPrecoder_disabled;
+
+ // TBD: configure this from .conf file, Dedicated params cannot yet be configured in .conf file.
+ // Enable this to test transform precoding enabled from dedicated config.
+ /*if (pusch_Config->transformPrecoder == NULL)
+ pusch_Config->transformPrecoder=calloc(1,sizeof(*pusch_Config->transformPrecoder));
+
+ *pusch_Config->transformPrecoder = NR_PUSCH_Config__transformPrecoder_enabled; */
+ // END -------
+
+ if (pusch_Config->transformPrecoder == NULL) {
+ if (servingcellconfigcommon->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg3_transformPrecoder != NULL)
+ transform_precoding = NR_PUSCH_Config__transformPrecoder_enabled;
+ }
+ else
+ transform_precoding = *pusch_Config->transformPrecoder;
+
+
+ if (transform_precoding == NR_PUSCH_Config__transformPrecoder_enabled ) {
+ /* Enable DMRS uplink config for transform precoding enabled */
+ NR_DMRS_UplinkConfig->transformPrecodingEnabled = calloc(1,sizeof(*NR_DMRS_UplinkConfig->transformPrecodingEnabled));
+ NR_DMRS_UplinkConfig->transformPrecodingEnabled->nPUSCH_Identity = NULL;
+ NR_DMRS_UplinkConfig->transformPrecodingEnabled->sequenceGroupHopping = NULL;
+ NR_DMRS_UplinkConfig->transformPrecodingEnabled->sequenceHopping = NULL;
+ NR_DMRS_UplinkConfig->transformPrecodingEnabled->ext1 = NULL;
+
+ LOG_I(RRC,"TRANSFORM PRECODING ENABLED......\n");
+
+ }
+ /*----------------------------------------------------------------------------------------------------------------------------*/
+
initialUplinkBWP->srs_Config = calloc(1,sizeof(*initialUplinkBWP->srs_Config));
initialUplinkBWP->srs_Config->present = NR_SetupRelease_SRS_Config_PR_setup;
NR_SRS_Config_t *srs_Config = calloc(1,sizeof(*srs_Config));