diff --git a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h index 9679caa18c..881d7fad8e 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h @@ -691,6 +691,7 @@ typedef struct fapi_nr_num_prach_fd_occasions_t* num_prach_fd_occasions_list; uint8_t ssb_per_rach;//SSB-per-RACH-occasion Value: 0: 1/8 1:1/4, 2:1/2 3:1 4:2 5:4, 6:8 7:16 uint8_t prach_multiple_carriers_in_a_band;//0 = disabled 1 = enabled + uint8_t root_seq_computed; // flag set and used only in PHY to indicate if table is computed with this config } fapi_nr_prach_config_t; diff --git a/openair1/PHY/INIT/nr_init_ue.c b/openair1/PHY/INIT/nr_init_ue.c index 5a595af8ab..019e386fd0 100644 --- a/openair1/PHY/INIT/nr_init_ue.c +++ b/openair1/PHY/INIT/nr_init_ue.c @@ -271,7 +271,6 @@ int init_nr_ue_signal(PHY_VARS_NR_UE *ue, int nb_connected_gNB) } ue->init_averaging = 1; - init_nr_prach_tables(839); init_symbol_rotation(fp); init_timeshift_rotation(fp); diff --git a/openair1/PHY/NR_TRANSPORT/nr_prach.c b/openair1/PHY/NR_TRANSPORT/nr_prach.c index b4ab491ac0..5b890e95ac 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_prach.c +++ b/openair1/PHY/NR_TRANSPORT/nr_prach.c @@ -545,7 +545,8 @@ void rx_nr_prach(PHY_VARS_gNB *gNB, } } else { // This is the high-speed case new_dft = 0; - nr_fill_du(N_ZC,prach_root_sequence_map); + uint16_t nr_du[NR_PRACH_SEQ_LEN_L - 1]; + nr_fill_du(N_ZC, prach_root_sequence_map, nr_du); // set preamble_offset to initial rootSequenceIndex and look if we need more root sequences for this // preamble index and find the corresponding cyclic shift // Check if all shifts for that root have been processed diff --git a/openair1/PHY/NR_TRANSPORT/nr_prach.h b/openair1/PHY/NR_TRANSPORT/nr_prach.h index ba170e593d..cddf5abbbc 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_prach.h +++ b/openair1/PHY/NR_TRANSPORT/nr_prach.h @@ -30,9 +30,6 @@ * \warning */ -extern c16_t nr_ru[839]; // quantized roots of unity -extern uint16_t nr_du[838]; - static const char* const prachfmt[] = {"0", "1", "2", "3", "A1", "A2", "A3", "B1", "B4", "C0", "C2", "A1/B1", "A2/B2", "A3/B3"}; /************************************* diff --git a/openair1/PHY/NR_TRANSPORT/nr_prach_common.c b/openair1/PHY/NR_TRANSPORT/nr_prach_common.c index 95d312293a..b680d826fa 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_prach_common.c +++ b/openair1/PHY/NR_TRANSPORT/nr_prach_common.c @@ -38,12 +38,34 @@ #include "common/utils/LOG/log.h" #include "common/utils/LOG/vcd_signal_dumper.h" #include "T.h" -c16_t nr_ru[839]; // quantized roots of unity -static uint32_t nr_ZC_inv[839]; // multiplicative inverse for roots u -uint16_t nr_du[838]; + +/* Extended Euclidean Algorithm to compute modulo inverse */ +static int modulo_multiplicative_inverse(const int a, const int m) +{ + DevAssert(a < m); + int t = 0; + int newt = 1; + int r = m; + int newr = a; + + while (newr != 0) { + const int q = r / newr; + int tmp = t; + t = newt; + newt = tmp - q * newt; + tmp = r; + r = newr; + newr = tmp - q * newr; + } + + AssertFatal(r <= 1, "Modulo inverse doesn't exist for a %d, m %d\n", a, m); + t = (t < 0) ? t + m : t; + LOG_D(PHY, "Modulo %d inverse of %d is %d\n", m, a, t); + return t; +} // This function computes the du -void nr_fill_du(uint16_t N_ZC, const uint16_t *prach_root_sequence_map) +void nr_fill_du(uint16_t N_ZC, const uint16_t* prach_root_sequence_map, uint16_t nr_du[NR_PRACH_SEQ_LEN_L - 1]) { uint16_t iu,u,p; @@ -64,19 +86,15 @@ void nr_fill_du(uint16_t N_ZC, const uint16_t *prach_root_sequence_map) void compute_nr_prach_seq(uint8_t short_sequence, uint8_t num_sequences, uint8_t rootSequenceIndex, c16_t X_u[64][839]) { // Compute DFT of x_u => X_u[k] = x_u(inv(u)*k)^* X_u[k] = exp(j\pi u*inv(u)*k*(inv(u)*k+1)/N_ZC) - unsigned int k,inv_u,i; int N_ZC; - const uint16_t *prach_root_sequence_map; - uint16_t u; + const uint16_t* prach_root_sequence_map; VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_UE_COMPUTE_PRACH, VCD_FUNCTION_IN); LOG_D(PHY,"compute_prach_seq: prach short sequence %x, num_sequences %d, rootSequenceIndex %d\n", short_sequence, num_sequences, rootSequenceIndex); - N_ZC = (short_sequence) ? 139 : 839; - - init_nr_prach_tables(N_ZC); + N_ZC = (short_sequence) ? NR_PRACH_SEQ_LEN_S : NR_PRACH_SEQ_LEN_L; if (short_sequence) { // FIXME cannot be reached @@ -87,7 +105,7 @@ void compute_nr_prach_seq(uint8_t short_sequence, uint8_t num_sequences, uint8_t LOG_D( PHY, "compute_prach_seq: done init prach_tables\n" ); - for (i=0; i u=%d\n",index,u); - inv_u = nr_ZC_inv[u]; // multiplicative inverse of u - + const int inv_u = modulo_multiplicative_inverse(u, N_ZC); // multiplicative inverse of u // X_u[0] stores the first ZC sequence where the root u has a non-zero number of shifts // for the unrestricted case X_u[0] is the first root indicated by the rootSequenceIndex - for (k=0; kprach_tx_power; - int16_t *prachF = prachF_tmp; + c16_t *prachF = prachF_tmp; Mod_id = ue->Mod_id; prach_sequence_length = nrUE_config->prach_config.prach_sequence_length; N_ZC = (prach_sequence_length == 0) ? 839:139; @@ -91,10 +91,13 @@ int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, int frame, uint8_t LOG_D(PHY,"Generate NR PRACH %d.%d\n", frame, slot); - compute_nr_prach_seq(nrUE_config->prach_config.prach_sequence_length, - nrUE_config->prach_config.num_prach_fd_occasions_list[fd_occasion].num_root_sequences, - nrUE_config->prach_config.num_prach_fd_occasions_list[fd_occasion].prach_root_sequence_index, - ue->X_u); + if (nrUE_config->prach_config.root_seq_computed == 0) { + compute_nr_prach_seq(nrUE_config->prach_config.prach_sequence_length, + nrUE_config->prach_config.num_prach_fd_occasions_list[fd_occasion].num_root_sequences, + nrUE_config->prach_config.num_prach_fd_occasions_list[fd_occasion].prach_root_sequence_index, + ue->X_u); + nrUE_config->prach_config.root_seq_computed = 1; + } if (prachStartSymbol == 0) { sample_offset_slot = 0; @@ -137,7 +140,8 @@ int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, int frame, uint8_t #endif not_found = 1; - nr_fill_du(N_ZC,prach_root_sequence_map); + uint16_t nr_du[NR_PRACH_SEQ_LEN_L - 1]; + nr_fill_du(N_ZC, prach_root_sequence_map, nr_du); preamble_index0 = preamble_index; // set preamble_offset to initial rootSequenceIndex and look if we need more root sequences for this // preamble index and find the corresponding cyclic shift @@ -223,7 +227,6 @@ int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, int frame, uint8_t k *= K; k += kbar; - k *= 2; LOG_I(PHY, "PRACH [UE %d] in frame.slot %d.%d, placing PRACH in position %d, Msg1/MsgA-Preamble frequency start %d (k1 %d), " @@ -231,7 +234,7 @@ int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, int frame, uint8_t Mod_id, frame, slot, - k, + k * 2, n_ra_prb, nrUE_config->prach_config.num_prach_fd_occasions_list[fd_occasion].k1, preamble_offset, @@ -413,12 +416,14 @@ int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, int frame, uint8_t if (offset2 >= N_ZC) offset2 -= N_ZC; - const int32_t Xu_re = (Xu[offset].r * amp) >> 15; - const int32_t Xu_im = (Xu[offset].i * amp) >> 15; - prachF[k++] = (Xu_re * nr_ru[offset2].r - Xu_im * nr_ru[offset2].i) >> 15; - prachF[k++] = (Xu_im * nr_ru[offset2].r + Xu_re * nr_ru[offset2].i) >> 15; + const c16_t Xu_t = c16xmulConstShift(Xu[offset], amp, 15); + const double w = 2 * M_PI * (double)offset2 / N_ZC; + const c16_t ru = {.r = (int16_t)(floor(32767.0 * cos(w))), .i = (int16_t)(floor(32767.0 * sin(w)))}; + const c16_t p = c16mulShift(Xu_t, ru, 15); + prachF[k++] = p; - if (k==dftlen) k=0; + if (k * 2 == dftlen) + k = 0; } #if defined (PRACH_WRITE_OUTPUT_DEBUG) @@ -429,7 +434,7 @@ int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, int frame, uint8_t // This is after cyclic prefix c16_t *prach2 = prach + Ncp; const idft_size_idx_t idft_size = get_idft(dftlen); - idft(idft_size, prachF, (int16_t *)prach, 1); + idft(idft_size, (int16_t *)prachF, (int16_t *)prach, 1); memmove(prach2, prach, (dftlen << 2)); if (prach_sequence_length == 0) { @@ -504,21 +509,17 @@ int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, int frame, uint8_t } } - #ifdef NR_PRACH_DEBUG - LOG_I(PHY, "PRACH [UE %d] N_RB_UL %d prach_start %d, prach_len %d\n", Mod_id, - fp->N_RB_UL, - prach_start, - prach_len); - #endif +#ifdef NR_PRACH_DEBUG + LOG_I(PHY, "PRACH [UE %d] N_RB_UL %d prach_start %d, prach_len %d\n", Mod_id, fp->N_RB_UL, prach_start, prach_len); +#endif - for (i = 0; i < prach_len; i++) - ue->common_vars.txData[0][prach_start + i] = prach[i]; + memcpy(ue->common_vars.txData[0] + prach_start, prach, sizeof(c16_t) * prach_len); #ifdef PRACH_WRITE_OUTPUT_DEBUG - LOG_M("prach_tx0.m", "prachtx0", prach+(Ncp<<1), prach_len-Ncp, 1, 1); - LOG_M("Prach_txsig.m","txs",(int16_t*)(&ue->common_vars.txdata[0][prach_start]), 2*(prach_start+prach_len), 1, 1) - #endif + LOG_M("prach_tx0.m", "prachtx0", prach + (Ncp << 1), prach_len - Ncp, 1, 1); + LOG_M("Prach_txsig.m", "txs", (int16_t *)(&ue->common_vars.txdata[0][prach_start]), 2 * (prach_start + prach_len), 1, 1) +#endif - return signal_energy((int*)prach, 256); + return signal_energy((int *)prach, 256); } diff --git a/openair1/PHY/impl_defs_nr.h b/openair1/PHY/impl_defs_nr.h index 16d5854604..123dbe162a 100644 --- a/openair1/PHY/impl_defs_nr.h +++ b/openair1/PHY/impl_defs_nr.h @@ -56,6 +56,8 @@ static const uint8_t N_slot_subframe[MU_NUMBER] = {1, 2, 4, 8, 16}; #define NB_DL_DATA_TO_UL_ACK (8) /* size of table TS 38.213 Table 9.2.3-1 */ +#define NR_PRACH_SEQ_LEN_L 839 +#define NR_PRACH_SEQ_LEN_S 139 /*********************************************************************** *