Optimization for unused symbols in NR UE

After processing TX frequency domain data skip IFFT call for symbols that aren't
used, the time domain buffer is memset instead.
This commit is contained in:
Bartosz Podrygajlo
2025-04-04 11:12:48 +02:00
parent 23c909e28e
commit 0161a1c4fd
13 changed files with 129 additions and 52 deletions
+1
View File
@@ -84,6 +84,7 @@ static inline const char *rnti_types(nr_rnti_type_t rr)
#define MU_SCS(m) (15 << m)
#define MAX_GSCN_BAND 620 // n78 has the highest GSCN range of 619
#define NR_NUMBER_OF_SYMBOLS_PER_SLOT 14
#define NR_NUMBER_OF_SYMBOLS_PER_SLOT_EXTENDED_CP 12
#define NR_MAX_NB_LAYERS 4 // 8
// Since the IQ samples are represented by SQ15 R+I (see https://en.wikipedia.org/wiki/Q_(number_format)) we need to compensate when
+6 -1
View File
@@ -48,7 +48,12 @@ void PHY_ofdm_mod(const int *input,
void normal_prefix_mod(int32_t *txdataF,int32_t *txdata,uint8_t nsymb,LTE_DL_FRAME_PARMS *frame_parms);
void nr_normal_prefix_mod(c16_t *txdataF, c16_t *txdata, uint8_t nsymb, const NR_DL_FRAME_PARMS *frame_parms, uint32_t slot);
void nr_normal_prefix_mod(c16_t *txdataF,
c16_t *txdata,
uint8_t nsymb,
const NR_DL_FRAME_PARMS *frame_parms,
uint32_t slot,
bool was_symbol_used[NR_NUMBER_OF_SYMBOLS_PER_SLOT]);
void do_OFDM_mod(c16_t **txdataF, c16_t **txdata, uint32_t frame,uint16_t next_slot, LTE_DL_FRAME_PARMS *frame_parms);
+43 -19
View File
@@ -67,31 +67,55 @@ void normal_prefix_mod(int32_t *txdataF,int32_t *txdata,uint8_t nsymb,LTE_DL_FRA
}
void nr_normal_prefix_mod(c16_t *txdataF, c16_t *txdata, uint8_t nsymb, const NR_DL_FRAME_PARMS *frame_parms, uint32_t slot)
void nr_normal_prefix_mod(c16_t *txdataF,
c16_t *txdata,
uint8_t nsymb,
const NR_DL_FRAME_PARMS *frame_parms,
uint32_t slot,
bool was_symbol_used[NR_NUMBER_OF_SYMBOLS_PER_SLOT])
{
// This function works only slot wise. For more generic symbol generation refer nr_feptx0()
if (frame_parms->numerology_index != 0) { // case where numerology != 0
if (!(slot%(frame_parms->slots_per_subframe/2))) {
PHY_ofdm_mod((int *)txdataF,
(int *)txdata,
frame_parms->ofdm_symbol_size,
1,
frame_parms->nb_prefix_samples0,
CYCLIC_PREFIX);
PHY_ofdm_mod((int *)txdataF + frame_parms->ofdm_symbol_size,
(int *)txdata + frame_parms->ofdm_symbol_size + frame_parms->nb_prefix_samples0,
frame_parms->ofdm_symbol_size,
nsymb - 1,
frame_parms->nb_prefix_samples,
CYCLIC_PREFIX);
if (was_symbol_used[0]) {
PHY_ofdm_mod((int *)txdataF,
(int *)txdata,
frame_parms->ofdm_symbol_size,
1,
frame_parms->nb_prefix_samples0,
CYCLIC_PREFIX);
} else {
memset(txdata, 0, (frame_parms->nb_prefix_samples0 + frame_parms->ofdm_symbol_size) * sizeof(c16_t));
}
for (int i = 1; i < nsymb; i++) {
c16_t* tx_data_ptr = txdata + (i - 1) * (frame_parms->ofdm_symbol_size + frame_parms->nb_prefix_samples) +
frame_parms->ofdm_symbol_size + frame_parms->nb_prefix_samples0;
if (was_symbol_used[i]) {
PHY_ofdm_mod((int *)txdataF + frame_parms->ofdm_symbol_size * i,
(int *)tx_data_ptr,
frame_parms->ofdm_symbol_size,
1,
frame_parms->nb_prefix_samples,
CYCLIC_PREFIX);
} else {
memset(tx_data_ptr, 0, (frame_parms->nb_prefix_samples + frame_parms->ofdm_symbol_size) * sizeof(c16_t));
}
}
}
else {
PHY_ofdm_mod((int *)txdataF,
(int *)txdata,
frame_parms->ofdm_symbol_size,
nsymb,
frame_parms->nb_prefix_samples,
CYCLIC_PREFIX);
for (int i = 0; i < nsymb; i++) {
c16_t* tx_data_ptr = txdata + i * (frame_parms->ofdm_symbol_size + frame_parms->nb_prefix_samples);
if (was_symbol_used[i]) {
PHY_ofdm_mod((int *)txdataF + frame_parms->ofdm_symbol_size * i,
(int *)tx_data_ptr,
frame_parms->ofdm_symbol_size,
1,
frame_parms->nb_prefix_samples,
CYCLIC_PREFIX);
} else {
memset(tx_data_ptr, 0, (frame_parms->nb_prefix_samples + frame_parms->ofdm_symbol_size) * sizeof(c16_t));
}
}
}
}
else { // numerology = 0, longer CP for every 7th symbol
@@ -144,7 +144,8 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE,
const uint32_t frame,
const uint8_t slot,
nr_phy_data_tx_t *phy_data,
c16_t **txdataF);
c16_t **txdataF,
bool was_symbol_used[NR_NUMBER_OF_SYMBOLS_PER_SLOT]);
/** \brief This function does IFFT for PUSCH
*/
@@ -154,7 +155,8 @@ uint8_t nr_ue_pusch_common_procedures(PHY_VARS_NR_UE *UE,
const NR_DL_FRAME_PARMS *frame_parms,
const uint8_t n_antenna_ports,
c16_t **txdataF,
uint32_t linktype);
uint32_t linktype,
bool was_symbol_used[NR_NUMBER_OF_SYMBOLS_PER_SLOT]);
void clean_UE_harq(PHY_VARS_NR_UE *UE);
+35 -18
View File
@@ -465,7 +465,8 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE,
const uint32_t frame,
const uint8_t slot,
nr_phy_data_tx_t *phy_data,
c16_t **txdataF)
c16_t **txdataF,
bool was_symbol_used[NR_NUMBER_OF_SYMBOLS_PER_SLOT])
{
int harq_pid = phy_data->ulsch.pusch_pdu.pusch_data.harq_process_id;
@@ -500,6 +501,7 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE,
uint16_t rnti = pusch_pdu->rnti;
for (int i = start_symbol; i < start_symbol + number_of_symbols; i++) {
was_symbol_used[i] = true;
if ((ul_dmrs_symb_pos >> i) & 0x01)
number_dmrs_symbols += 1;
}
@@ -831,37 +833,52 @@ uint8_t nr_ue_pusch_common_procedures(PHY_VARS_NR_UE *UE,
const NR_DL_FRAME_PARMS *frame_parms,
const uint8_t n_antenna_ports,
c16_t **txdataF,
uint32_t linktype)
uint32_t linktype,
bool was_symbol_used[NR_NUMBER_OF_SYMBOLS_PER_SLOT])
{
const int tx_offset = frame_parms->get_samples_slot_timestamp(slot, frame_parms, 0);
int N_RB = (linktype == link_type_sl) ? frame_parms->N_RB_SL : frame_parms->N_RB_UL;
c16_t **txdata = UE->common_vars.txData;
for(int ap = 0; ap < n_antenna_ports; ap++) {
apply_nr_rotation_TX(frame_parms,
txdataF[ap],
frame_parms->symbol_rotation[linktype],
slot,
N_RB,
0,
NR_NUMBER_OF_SYMBOLS_PER_SLOT);
for (int i = 0; i < NR_NUMBER_OF_SYMBOLS_PER_SLOT; i++) {
if (was_symbol_used[i] == false)
continue;
for(int ap = 0; ap < n_antenna_ports; ap++) {
apply_nr_rotation_TX(frame_parms,
txdataF[ap],
frame_parms->symbol_rotation[linktype],
slot,
N_RB,
i,
1);
}
}
for (int ap = 0; ap < n_antenna_ports; ap++) {
if (frame_parms->Ncp == 1) { // extended cyclic prefix
PHY_ofdm_mod((int *)txdataF[ap],
(int *)&txdata[ap][tx_offset],
frame_parms->ofdm_symbol_size,
12,
frame_parms->nb_prefix_samples,
CYCLIC_PREFIX);
for (int i = 0; i < NR_NUMBER_OF_SYMBOLS_PER_SLOT_EXTENDED_CP; i++) {
if (was_symbol_used[i] == false) {
memset(&txdata[ap][tx_offset + (frame_parms->ofdm_symbol_size + frame_parms->nb_prefix_samples) * i],
0,
(frame_parms->nb_prefix_samples + frame_parms->ofdm_symbol_size) * sizeof(int32_t));
continue;
}
PHY_ofdm_mod((int *)&txdataF[ap][frame_parms->ofdm_symbol_size * i],
(int *)&txdata[ap][tx_offset + frame_parms->ofdm_symbol_size * i],
frame_parms->ofdm_symbol_size,
1,
frame_parms->nb_prefix_samples,
CYCLIC_PREFIX);
}
} else { // normal cyclic prefix
nr_normal_prefix_mod(txdataF[ap],
&txdata[ap][tx_offset],
14,
NR_NUMBER_OF_SYMBOLS_PER_SLOT,
frame_parms,
slot);
slot,
was_symbol_used);
}
}
@@ -423,7 +423,10 @@ int generate_srs_nr(nfapi_nr_srs_pdu_t *srs_config_pdu,
* send srs according to current configuration
*
*********************************************************************/
int ue_srs_procedures_nr(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, c16_t **txdataF)
int ue_srs_procedures_nr(PHY_VARS_NR_UE *ue,
const UE_nr_rxtx_proc_t *proc,
c16_t **txdataF,
bool was_symbol_used[NR_NUMBER_OF_SYMBOLS_PER_SLOT])
{
if(!ue->srs_vars[0]->active) {
return -1;
@@ -432,6 +435,14 @@ int ue_srs_procedures_nr(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, c16_
nfapi_nr_srs_pdu_t *srs_config_pdu = (nfapi_nr_srs_pdu_t*)&ue->srs_vars[0]->srs_config_pdu;
int first_srs_symbol = ue->frame_parms.symbols_per_slot - 1 - srs_config_pdu->time_start_position;
// Num consecutive SRS symbols according to 38.211 6.4.1.4.1
int num_srs_symbols[] = {1, 2, 4, 8, 12};
int last_srs_symbol = first_srs_symbol + num_srs_symbols[srs_config_pdu->num_symbols] - 1;
for (int i = first_srs_symbol; i <= last_srs_symbol; i++) {
was_symbol_used[i] = true;
}
#ifdef SRS_DEBUG
LOG_I(NR_PHY,"Frame = %i, slot = %i\n", proc->frame_tx, proc->nr_slot_tx);
LOG_I(NR_PHY,"srs_config_pdu->rnti = 0x%04x\n", srs_config_pdu->rnti);
@@ -79,6 +79,6 @@ int is_srs_period_nr(SRS_Resource_t *p_SRS_Resource,
@param current gNB_id identifier
@returns 0 if srs is transmitted -1 otherwise */
int ue_srs_procedures_nr(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, c16_t **txdataF);
int ue_srs_procedures_nr(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, c16_t **txdataF, bool was_symbol_used[14]);
#endif /* SRS_MODULATION_NR_H */
+6 -4
View File
@@ -284,14 +284,15 @@ void phy_procedures_nrUE_TX(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, n
txdataF[i] = &txdataF_buf[i * samplesF_per_slot];
LOG_D(PHY,"****** start TX-Chain for AbsSubframe %d.%d ******\n", frame_tx, slot_tx);
bool was_symbol_used[NR_NUMBER_OF_SYMBOLS_PER_SLOT] = {0};
start_meas_nr_ue_phy(ue, PHY_PROC_TX);
nr_ue_ulsch_procedures(ue, frame_tx, slot_tx, phy_data, (c16_t **)&txdataF);
nr_ue_ulsch_procedures(ue, frame_tx, slot_tx, phy_data, (c16_t **)&txdataF, was_symbol_used);
ue_srs_procedures_nr(ue, proc, (c16_t **)&txdataF);
ue_srs_procedures_nr(ue, proc, (c16_t **)&txdataF, was_symbol_used);
pucch_procedures_ue_nr(ue, proc, phy_data, (c16_t **)&txdataF);
pucch_procedures_ue_nr(ue, proc, phy_data, (c16_t **)&txdataF, was_symbol_used);
LOG_D(PHY, "Sending Uplink data \n");
@@ -304,7 +305,8 @@ void phy_procedures_nrUE_TX(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, n
&ue->frame_parms,
ue->frame_parms.nb_antennas_tx,
(c16_t **)txdataF,
link_type_ul);
link_type_ul,
was_symbol_used);
stop_meas_nr_ue_phy(ue, OFDM_MOD_STATS);
}
@@ -308,9 +308,12 @@ void phy_procedures_nrUE_SL_TX(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc
tx_action = 1;
}
bool was_symbol_used[NR_NUMBER_OF_SYMBOLS_PER_SLOT];
for (int i = 0; i < 14; i++)
was_symbol_used[i] = true;
if (tx_action) {
LOG_D(NR_PHY, "Sending Uplink data \n");
nr_ue_pusch_common_procedures(ue, proc->nr_slot_tx, fp, fp->nb_antennas_tx, txdataF, link_type_sl);
nr_ue_pusch_common_procedures(ue, proc->nr_slot_tx, fp, fp->nb_antennas_tx, txdataF, link_type_sl, was_symbol_used);
}
LOG_D(NR_PHY, "****** end Sidelink TX-Chain for AbsSubframe %d.%d ******\n", frame_tx, slot_tx);
+9 -2
View File
@@ -132,8 +132,11 @@ binary_search_float_nr(
* TS 38.213 9 UE procedure for reporting control information
*
*********************************************************************/
void pucch_procedures_ue_nr(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr_phy_data_tx_t *phy_data, c16_t **txdataF)
void pucch_procedures_ue_nr(PHY_VARS_NR_UE *ue,
const UE_nr_rxtx_proc_t *proc,
nr_phy_data_tx_t *phy_data,
c16_t **txdataF,
bool was_symbol_used[NR_NUMBER_OF_SYMBOLS_PER_SLOT])
{
const int nr_slot_tx = proc->nr_slot_tx;
NR_UE_PUCCH *pucch_vars = &phy_data->pucch_vars;
@@ -141,6 +144,10 @@ void pucch_procedures_ue_nr(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, n
for (int i=0; i<2; i++) {
if(pucch_vars->active[i]) {
const fapi_nr_ul_config_pucch_pdu *pucch_pdu = &pucch_vars->pucch_pdu[i];
for (int symb_idx = 0; symb_idx < pucch_pdu->nr_of_symbols; symb_idx++) {
int symb = pucch_pdu->start_symbol_index + symb_idx;
was_symbol_used[symb] = true;
}
uint16_t nb_of_prbs = pucch_pdu->prb_size;
/* Generate PUCCH signal according to its format and parameters */
+1 -1
View File
@@ -50,6 +50,6 @@
/*************** FUNCTIONS ****************************************/
void pucch_procedures_ue_nr(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr_phy_data_tx_t *phy_data, c16_t **txdataF);
void pucch_procedures_ue_nr(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr_phy_data_tx_t *phy_data, c16_t **txdataF, bool was_symbol_used[14]);
#endif /* PUCCH_UCI_UE_NR_H */
+6 -1
View File
@@ -1091,11 +1091,16 @@ printf("%d\n", slot);
frame_parms->nb_prefix_samples,
CYCLIC_PREFIX);
} else {
bool was_symbol_used[NR_NUMBER_OF_SYMBOLS_PER_SLOT];
for (int i = 0; i < 14; i++) {
was_symbol_used[i] = true;
}
nr_normal_prefix_mod(&gNB->common_vars.txdataF[0][aa][txdataF_offset],
&txdata[aa][slot_offset],
14,
frame_parms,
slot);
slot,
was_symbol_used);
}
}
if (n_trials==1) {
+1 -1
View File
@@ -1525,7 +1525,7 @@ int main(int argc, char *argv[])
printStatIndent(&gNB->ulsch_decoding_stats,"ULSCH total decoding time");
printf("\nUE TX\n");
for (int i = PHY_PROC_TX; i <= ULSCH_ENCODING_STATS; i++) {
for (int i = PHY_PROC_TX; i <= OFDM_MOD_STATS; i++) {
printStatIndent(&UE->phy_cpu_stats.cpu_time_stats[i], UE->phy_cpu_stats.cpu_time_stats[i].meas_name);
}
printStatIndent(&gNB->rx_srs_stats,"RX SRS time");