diff --git a/common/utils/nr/nr_common.c b/common/utils/nr/nr_common.c index a842f66443..64902c6be2 100644 --- a/common/utils/nr/nr_common.c +++ b/common/utils/nr/nr_common.c @@ -874,6 +874,7 @@ void get_samplerate_and_bw(int mu, switch(n_rb) { case 270: if (threequarter_fs) { + warn_higher_threequarter_fs(n_rb, mu); *sample_rate=92.16e6; *samples_per_frame = 921600; *tx_bw = 50e6; @@ -973,6 +974,7 @@ void get_samplerate_and_bw(int mu, case 273: if (threequarter_fs) { + warn_higher_threequarter_fs(n_rb, mu); *sample_rate=184.32e6; *samples_per_frame = 1843200; *tx_bw = 100e6; diff --git a/common/utils/nr/nr_common.h b/common/utils/nr/nr_common.h index 52eb305824..84de7805ec 100644 --- a/common/utils/nr/nr_common.h +++ b/common/utils/nr/nr_common.h @@ -37,6 +37,7 @@ #include #include "assertions.h" #include "common/utils/utils.h" +#include "common/utils/LOG/log.h" #define MAX_SI_GROUPS 3 #define NR_MAX_PDSCH_TBS 3824 @@ -272,6 +273,19 @@ static __attribute__((always_inline)) inline int count_bits64_with_mask(uint64_t return count_bits64(v & mask); } +static inline void warn_higher_threequarter_fs(const int n_rb, const int mu) +{ + LOG_W(PHY, + "3/4 sampling is not possible for current PRB size: %d and numerology: %d.\n " + "So 6/4 sampling is chosen to support x3xx type USRPs.\n " + "Note that this sampling rate increases fronthaul traffic, FFT buffer size and processing time by a factor of two compared " + "to 3/4 sampling rate.\n " + "Some PRACH configuration might not be supported with 6/4 FFT size.\n " + "Consider reducing the PRB size that would fit within the FFT size of 3/4 sampling\n", + n_rb, + mu); +} + uint64_t reverse_bits(uint64_t in, int n_bits); void reverse_bits_u8(uint8_t const* in, size_t sz, uint8_t* out); diff --git a/openair1/PHY/INIT/nr_parms.c b/openair1/PHY/INIT/nr_parms.c index 880d568ca6..6fbfcb3cac 100644 --- a/openair1/PHY/INIT/nr_parms.c +++ b/openair1/PHY/INIT/nr_parms.c @@ -199,14 +199,26 @@ void set_scs_parameters (NR_DL_FRAME_PARMS *fp, int mu, int N_RB_DL) AssertFatal(1==0,"Invalid numerology index %d", mu); } - if(fp->threequarter_fs) - fp->ofdm_symbol_size = 3 * 128; - else - fp->ofdm_symbol_size = 4 * 128; + // Start with FFT size 512 + fp->ofdm_symbol_size = 512; - while(fp->ofdm_symbol_size < N_RB_DL * 12) + // Choose the right FFT size for the BW + while(fp->ofdm_symbol_size < N_RB_DL * NR_NB_SC_PER_RB) fp->ofdm_symbol_size <<= 1; + // Do 3/4 sampling + if (fp->threequarter_fs) { + const uint16_t threeq_fft_size = fp->ofdm_symbol_size * 3 / 4; + if (threeq_fft_size < (N_RB_DL * NR_NB_SC_PER_RB)) { + // 3/4 sampling FFT size not enough + warn_higher_threequarter_fs(N_RB_DL, fp->numerology_index); + // Choose 2 times 3/4 sampling + fp->ofdm_symbol_size = threeq_fft_size << 1; + } else { + fp->ofdm_symbol_size = threeq_fft_size; + } + } + fp->first_carrier_offset = fp->ofdm_symbol_size - (N_RB_DL * 12 / 2); fp->nb_prefix_samples = fp->ofdm_symbol_size / 128 * 9; fp->nb_prefix_samples0 = fp->ofdm_symbol_size / 128 * (9 + (1 << mu)); diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_prach.c b/openair1/PHY/NR_UE_TRANSPORT/nr_prach.c index 9405315e04..05a251d999 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_prach.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_prach.c @@ -58,34 +58,19 @@ int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, int frame, uint8_t fapi_nr_config_request_t *nrUE_config = &ue->nrUE_config; fapi_nr_ul_config_prach_pdu *prach_pdu = &ue->prach_vars[gNB_id]->prach_pdu; - uint8_t Mod_id, fd_occasion, preamble_index, restricted_set, not_found; - uint16_t rootSequenceIndex, prach_fmt_id, NCS, preamble_offset = 0; - const uint16_t *prach_root_sequence_map; - uint16_t preamble_shift = 0, preamble_index0, n_shift_ra, n_shift_ra_bar, d_start=INT16_MAX, numshift, N_ZC, u, offset, offset2, first_nonzero_root_idx; - c16_t prach[(4688 + 4 * 24576) * 2] __attribute__((aligned(32))) = {0}; - c16_t prachF_tmp[(4688 + 4 * 24576) * 4] __attribute__((aligned(32))) = {0}; - - int Ncp = 0; - int prach_start, prach_sequence_length, prach_len, dftlen, mu, n_ra_prb, k, prachStartSymbol; - - fd_occasion = prach_pdu->num_ra; - prach_len = 0; - dftlen = 0; - first_nonzero_root_idx = 0; - int16_t amp = prach_pdu->prach_tx_power; - 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; - mu = nrUE_config->prach_config.prach_sub_c_spacing; - restricted_set = prach_pdu->restricted_set; - rootSequenceIndex = prach_pdu->root_seq_id; - n_ra_prb = nrUE_config->prach_config.num_prach_fd_occasions_list[fd_occasion].k1,//prach_pdu->freq_msg1; - NCS = prach_pdu->num_cs; - prach_fmt_id = prach_pdu->prach_format; - preamble_index = prach_pdu->ra_PreambleIndex; - k = 12*n_ra_prb - 6*fp->N_RB_UL; - prachStartSymbol = prach_pdu->prach_start_symbol; + const int fd_occasion = prach_pdu->num_ra; + const int16_t amp = prach_pdu->prach_tx_power; + const int prach_sequence_length = nrUE_config->prach_config.prach_sequence_length; + const int N_ZC = (prach_sequence_length == 0) ? 839 : 139; + const int mu = nrUE_config->prach_config.prach_sub_c_spacing; + const int restricted_set = prach_pdu->restricted_set; + const int rootSequenceIndex = prach_pdu->root_seq_id; + const int n_ra_prb = nrUE_config->prach_config.num_prach_fd_occasions_list[fd_occasion].k1; // prach_pdu->freq_msg1; + const int NCS = prach_pdu->num_cs; + const int prach_fmt_id = prach_pdu->prach_format; + const int preamble_index = prach_pdu->ra_PreambleIndex; + int k = 12 * n_ra_prb - 6 * fp->N_RB_UL; + const int prachStartSymbol = prach_pdu->prach_start_symbol; LOG_D(PHY,"Generate NR PRACH %d.%d\n", frame, slot); @@ -97,6 +82,7 @@ int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, int frame, uint8_t nrUE_config->prach_config.root_seq_computed = 1; } + int prach_start; if (prachStartSymbol == 0) { prach_start = 0; } else if (fp->slots_per_subframe == 1) { @@ -122,29 +108,30 @@ int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, int frame, uint8_t * NOTE: Restricted set type B is not implemented *************************************************************************/ - prach_root_sequence_map = (prach_sequence_length == 0) ? prach_root_sequence_map_0_3 : prach_root_sequence_map_abc; - + const uint16_t *prach_root_sequence_map = + (prach_sequence_length == 0) ? prach_root_sequence_map_0_3 : prach_root_sequence_map_abc; + int preamble_offset, preamble_shift = 0, first_nonzero_root_idx = 0; if (restricted_set == 0) { // This is the relative offset (for unrestricted case) in the root sequence table (5.7.2-4 from 36.211) for the given preamble index - preamble_offset = ((NCS==0)? preamble_index : (preamble_index/(N_ZC/NCS))); + preamble_offset = NCS == 0 ? preamble_index : preamble_index / (N_ZC / NCS); // This is the \nu corresponding to the preamble index - preamble_shift = (NCS==0)? 0 : (preamble_index % (N_ZC/NCS)); + preamble_shift = NCS == 0 ? 0 : preamble_index % (N_ZC / NCS); preamble_shift *= NCS; } else { // This is the high-speed case - #ifdef NR_PRACH_DEBUG - LOG_I(PHY, "PRACH [UE %d] High-speed mode, NCS %d\n", Mod_id, NCS); - #endif +#ifdef NR_PRACH_DEBUG + LOG_I(PHY, "PRACH [UE %d] High-speed mode, NCS %d\n", ue->Mod_id, NCS); +#endif - not_found = 1; 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; + int 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 preamble_offset = 0; // relative rootSequenceIndex; - while (not_found == 1) { + bool not_found = true; + while (not_found) { // current root depending on rootSequenceIndex and preamble_offset int index = (rootSequenceIndex + preamble_offset) % N_ZC; uint16_t n_group_ra = 0; @@ -157,8 +144,8 @@ int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, int frame, uint8_t DevAssert( index < sizeof(prach_root_sequence_map_abc) / sizeof(prach_root_sequence_map_abc[0]) ); } - u = prach_root_sequence_map[index]; - + int u = prach_root_sequence_map[index]; + int n_shift_ra, d_start = INT16_MAX, n_shift_ra_bar; if ( (nr_du[u]<(N_ZC/3)) && (nr_du[u]>=NCS) ) { n_shift_ra = nr_du[u]/NCS; d_start = (nr_du[u]<<1) + (n_shift_ra * NCS); @@ -175,13 +162,12 @@ int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, int frame, uint8_t } // This is the number of cyclic shifts for the current root u - numshift = (n_shift_ra*n_group_ra) + n_shift_ra_bar; - + int numshift = (n_shift_ra * n_group_ra) + n_shift_ra_bar; if (numshift>0 && preamble_index0==preamble_index) first_nonzero_root_idx = preamble_offset; if (preamble_index0 < numshift) { - not_found = 0; + not_found = false; preamble_shift = (d_start * (preamble_index0/n_shift_ra)) + ((preamble_index0%n_shift_ra)*NCS); } else { // skip to next rootSequenceIndex and recompute parameters @@ -193,23 +179,22 @@ int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, int frame, uint8_t // now generate PRACH signal #ifdef NR_PRACH_DEBUG - if (NCS>0) - LOG_I(PHY, "PRACH [UE %d] generate PRACH in frame.slot %d.%d for RootSeqIndex %d, Preamble Index %d, PRACH Format %s, NCS %d (N_ZC %d): Preamble_offset %d, Preamble_shift %d msg1 frequency start %d\n", - Mod_id, - frame, - slot, - rootSequenceIndex, - preamble_index, - prachfmt[prach_fmt_id], - NCS, - N_ZC, - preamble_offset, - preamble_shift, - n_ra_prb); - #endif - - // nsymb = (frame_parms->Ncp==0) ? 14:12; - // subframe_offset = (unsigned int)frame_parms->ofdm_symbol_size*slot*nsymb; + if (NCS > 0) + LOG_I(PHY, + "PRACH [UE %d] generate PRACH in frame.slot %d.%d for RootSeqIndex %d, Preamble Index %d, PRACH Format %s, NCS %d " + "(N_ZC %d): Preamble_offset %d, Preamble_shift %d msg1 frequency start %d\n", + ue->Mod_id, + frame, + slot, + rootSequenceIndex, + preamble_index, + prachfmt[prach_fmt_id], + NCS, + N_ZC, + preamble_offset, + preamble_shift, + n_ra_prb); +#endif const unsigned int K = get_prach_K(prach_sequence_length, prach_fmt_id, fp->numerology_index, mu); const uint8_t kbar = get_PRACH_k_bar(mu, fp->numerology_index); @@ -223,7 +208,7 @@ int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, int frame, uint8_t LOG_I(PHY, "PRACH [UE %d] in frame.slot %d.%d, placing PRACH in position %d, Msg1/MsgA-Preamble frequency start %d (k1 %d), " "preamble_offset %d, first_nonzero_root_idx %d, preambleIndex = %d\n", - Mod_id, + ue->Mod_id, frame, slot, k * 2, @@ -234,155 +219,96 @@ int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, int frame, uint8_t prach_pdu->ra_PreambleIndex); // Ncp and dftlen here is given in terms of T_s wich is 30.72MHz sampling + int dftlen, Ncp; if (prach_sequence_length == 0) { - switch (prach_fmt_id) { - case 0: - Ncp = 3168; - dftlen = 24576; - break; - - case 1: - Ncp = 21024; - dftlen = 24576; - break; - - case 2: - Ncp = 4688; - dftlen = 24576; - break; - - case 3: - Ncp = 3168; - dftlen = 6144; - break; - - default: - AssertFatal(1 == 0, "Illegal PRACH format %d for sequence length 839\n", prach_fmt_id); - break; - } + AssertFatal(prach_fmt_id >= 0 && prach_fmt_id <= 3, "Unknown PRACH format ID %d for sequence length 839\n", prach_fmt_id); + const int ncp[4] = {3168, 21024, 4688, 3168}; + const int dft[4] = {24576, 24576, 24576, 6144}; + Ncp = ncp[prach_fmt_id]; + dftlen = dft[prach_fmt_id]; } else { - switch (prach_fmt_id) { - case 4: //A1 - Ncp = 288 >> mu; - break; - - case 5: //A2 - Ncp = 576 >> mu; - break; - - case 6: //A3 - Ncp = 864 >> mu; - break; - - case 7: //B1 - Ncp = 216 >> mu; - break; - - /* - case 4: //B2 - Ncp = 360 >> mu; - break; - - case 5: //B3 - Ncp = 504 >> mu; - break; - */ - - case 8: //B4 - Ncp = 936 >> mu; - break; - - case 9: //C0 - Ncp = 1240 >> mu; - break; - - case 10: //C2 - Ncp = 2048 >> mu; - break; - - default: - AssertFatal(1==0,"Unknown PRACH format ID %d\n", prach_fmt_id); - break; - } + AssertFatal(prach_fmt_id >= 4 && prach_fmt_id <= 10, "Unknown PRACH format ID %d\n", prach_fmt_id); + const int ncp[7] = {288, 576, 864, 216, 936, 1240, 2048}; + Ncp = ncp[prach_fmt_id - 4] >> mu; dftlen = 2048 >> mu; } - //actually what we should be checking here is how often the current prach crosses a 0.5ms boundary. I am not quite sure for which paramter set this would be the case, so I will ignore it for now and just check if the prach starts on a 0.5ms boundary - if(fp->numerology_index == 0) { + // actually what we should be checking here is how often the current prach crosses a 0.5ms boundary. I am not quite sure for + // which paramter set this would be the case, so I will ignore it for now and just check if the prach starts on a 0.5ms boundary + if (fp->numerology_index == 0) { if (prachStartSymbol == 0 || prachStartSymbol == 7) Ncp += 16; - } - else { - if (slot%(fp->slots_per_subframe/2)==0 && prachStartSymbol == 0) + } else { + if (slot % (fp->slots_per_subframe / 2) == 0 && prachStartSymbol == 0) Ncp += 16; } - switch(fp->samples_per_subframe) { - case 7680: - // 5 MHz @ 7.68 Ms/s - Ncp >>= 2; - dftlen >>= 2; - break; + switch (fp->samples_per_subframe) { + case 7680: + // 5 MHz @ 7.68 Ms/s + Ncp >>= 2; + dftlen >>= 2; + break; - case 15360: - // 10, 15 MHz @ 15.36 Ms/s - Ncp >>= 1; - dftlen >>= 1; - break; + case 15360: + // 10, 15 MHz @ 15.36 Ms/s + Ncp >>= 1; + dftlen >>= 1; + break; - case 23040: - // 20 MHz @ 23.04 Ms/s - Ncp = (Ncp * 3) / 4; - dftlen = (dftlen * 3) / 4; - break; + case 23040: + // 20 MHz @ 23.04 Ms/s + Ncp = (Ncp * 3) / 4; + dftlen = (dftlen * 3) / 4; + break; - case 30720: - // 20, 25, 30 MHz @ 30.72 Ms/s - break; + case 30720: + // 20, 25, 30 MHz @ 30.72 Ms/s + break; - case 46080: - // 40 MHz @ 46.08 Ms/s - Ncp = (Ncp*3)/2; - dftlen = (dftlen*3)/2; - break; + case 46080: + // 40 MHz @ 46.08 Ms/s + Ncp = (Ncp * 3) / 2; + dftlen = (dftlen * 3) / 2; + break; - case 61440: - // 40, 50, 60 MHz @ 61.44 Ms/s - Ncp <<= 1; - dftlen <<= 1; - break; + case 61440: + // 40, 50, 60 MHz @ 61.44 Ms/s + Ncp <<= 1; + dftlen <<= 1; + break; - case 92160: - // 50, 60, 70, 80, 90 MHz @ 92.16 Ms/s - Ncp *= 3; - dftlen *= 3; - break; + case 92160: + // 50, 60, 70, 80, 90 MHz @ 92.16 Ms/s + Ncp *= 3; + dftlen *= 3; + break; - case 122880: - // 70, 80, 90, 100 MHz @ 122.88 Ms/s - Ncp <<= 2; - dftlen <<= 2; - break; + case 122880: + // 70, 80, 90, 100 MHz @ 122.88 Ms/s + Ncp <<= 2; + dftlen <<= 2; + break; - case 184320: - // 100 MHz @ 184.32 Ms/s - Ncp = Ncp*6; - dftlen = dftlen*6; - break; + case 184320: + // 100 MHz @ 184.32 Ms/s + Ncp = Ncp * 6; + dftlen = dftlen * 6; + break; - case 245760: - // 200 MHz @ 245.76 Ms/s - Ncp <<= 3; - dftlen <<= 3; - break; + case 245760: + // 200 MHz @ 245.76 Ms/s + Ncp <<= 3; + dftlen <<= 3; + break; - default: - AssertFatal(1==0,"sample rate %f MHz not supported for numerology %d\n", fp->samples_per_subframe / 1000.0, mu); + default: + AssertFatal(1 == 0, "sample rate %f MHz not supported for numerology %d\n", fp->samples_per_subframe / 1000.0, mu); } - #ifdef NR_PRACH_DEBUG - LOG_I(PHY, "PRACH [UE %d] Ncp %d, dftlen %d \n", Mod_id, Ncp, dftlen); - #endif +#ifdef NR_PRACH_DEBUG + LOG_I(PHY, "PRACH [UE %d] Ncp %d, dftlen %d \n", ue->Mod_id, Ncp, dftlen); +#endif /******************************************************** * @@ -390,7 +316,8 @@ int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, int frame, uint8_t * to compute quantized roots of unity ru(n) = 32767 * exp j*[ (2 * PI * n) / N_ZC ] * * In compute_prach_seq: - * to calculate Xu = DFT xu = xu (inv_u*k) * Xu[0] (This is a Zadoff-Chou sequence property: DFT ZC sequence is another ZC sequence) + * to calculate Xu = DFT xu = xu (inv_u*k) * Xu[0] (This is a Zadoff-Chou sequence property: DFT ZC sequence is another ZC + * sequence) * * In generate_prach: * to do the cyclic-shifted DFT by multiplying Xu[k] * ru[k*preamble_shift] as: @@ -398,118 +325,55 @@ int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, int frame, uint8_t * *********************************************************/ - c16_t *Xu = ue->X_u[preamble_offset - first_nonzero_root_idx]; + const c16_t *Xu = ue->X_u[preamble_offset - first_nonzero_root_idx]; #if defined (PRACH_WRITE_OUTPUT_DEBUG) - LOG_M("X_u.m", "X_u", (int16_t*)ue->X_u[preamble_offset-first_nonzero_root_idx], N_ZC, 1, 1); - #endif + LOG_M("X_u.m", "X_u", (int16_t *)ue->X_u[preamble_offset - first_nonzero_root_idx], N_ZC, 1, 1); +#endif - for (offset=0,offset2=0; offset= N_ZC) + offset2 -= N_ZC; + 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 (offset2 >= N_ZC) - offset2 -= N_ZC; - 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 * 2 == dftlen) - k = 0; - } - - #if defined (PRACH_WRITE_OUTPUT_DEBUG) +#if defined(PRACH_WRITE_OUTPUT_DEBUG) LOG_M("prachF.m", "prachF", &prachF[1804], 1024, 1, 1); LOG_M("Xu.m", "Xu", Xu, N_ZC, 1, 1); - #endif +#endif - // This is after cyclic prefix - c16_t *prach2 = prach + Ncp; + // This is after cyclic prefix const idft_size_idx_t idft_size = get_idft(dftlen); idft(idft_size, (int16_t *)prachF, (int16_t *)prach, 1); - memmove(prach2, prach, (dftlen << 2)); + } - if (prach_sequence_length == 0) { - if (prach_fmt_id == 0) { - // here we have | empty | Prach | - memcpy(prach, prach + dftlen, (Ncp << 2)); - // here we have | Prefix | Prach | - prach_len = dftlen + Ncp; - } else if (prach_fmt_id == 1) { - // here we have | empty | Prach | empty | - memcpy(prach2 + dftlen, prach2, (dftlen << 2)); - // here we have | empty | Prach | Prach | - memcpy(prach, prach + dftlen * 2, (Ncp << 2)); - // here we have | Prefix | Prach | Prach | - prach_len = (dftlen * 2) + Ncp; - } else if (prach_fmt_id == 2 || prach_fmt_id == 3) { - // here we have | empty | Prach | empty | empty | empty | - memcpy(prach2 + dftlen, prach2, (dftlen << 2)); - // here we have | empty | Prach | Prach | empty | empty | - memcpy(prach2 + dftlen * 2, prach2, (dftlen << 3)); - // here we have | empty | Prach | Prach | Prach | Prach | - memcpy(prach, prach + dftlen * 4, (Ncp << 2)); - // here we have | Prefix | Prach | Prach | Prach | Prach | - prach_len = (dftlen * 4) + Ncp; - } - } else { // short PRACH sequence - if (prach_fmt_id == 9) { - // here we have | empty | Prach | - memcpy(prach, prach + dftlen, (Ncp << 2)); - // here we have | Prefix | Prach | - prach_len = (dftlen*1)+Ncp; - } else if (prach_fmt_id == 4 || prach_fmt_id == 7) { - // here we have | empty | Prach | empty | - memcpy(prach2 + dftlen, prach2, (dftlen << 2)); - // here we have | empty | Prach | Prach | - memcpy(prach, prach+(dftlen<<1), (Ncp<<2)); - // here we have | Prefix | Prach | Prach | - prach_len = (dftlen*2)+Ncp; - } else if (prach_fmt_id == 5 || prach_fmt_id == 10) { // 4xdftlen - // here we have | empty | Prach | empty | empty | empty | - memcpy(prach2 + dftlen, prach2, (dftlen << 2)); - // here we have | empty | Prach | Prach | empty | empty | - memcpy(prach2 + dftlen * 2, prach2, (dftlen << 3)); - // here we have | empty | Prach | Prach | Prach | Prach | - memcpy(prach, prach + dftlen, (Ncp << 2)); - // here we have | Prefix | Prach | Prach | Prach | Prach | - prach_len = (dftlen*4)+Ncp; - } else if (prach_fmt_id == 6) { // 6xdftlen - // here we have | empty | Prach | empty | empty | empty | empty | empty | - memcpy(prach2 + dftlen, prach2, (dftlen << 2)); - // here we have | empty | Prach | Prach | empty | empty | empty | empty | - memcpy(prach2 + dftlen * 2, prach2, (dftlen << 3)); - // here we have | empty | Prach | Prach | Prach | Prach | empty | empty | - memcpy(prach2 + dftlen * 4, prach2, (dftlen << 3)); - // here we have | empty | Prach | Prach | Prach | Prach | Prach | Prach | - memcpy(prach, prach + dftlen, (Ncp << 2)); - // here we have | Prefix | Prach | Prach | Prach | Prach | Prach | Prach | - prach_len = (dftlen*6)+Ncp; - } else if (prach_fmt_id == 8) { // 12xdftlen - // here we have | empty | Prach | empty | empty | empty | empty | empty | empty | empty | empty | empty | empty | empty | - memcpy(prach2 + dftlen, prach2, (dftlen << 2)); - // here we have | empty | Prach | Prach | empty | empty | empty | empty | empty | empty | empty | empty | empty | empty | - memcpy(prach2 + dftlen * 2, prach2, (dftlen << 3)); - // here we have | empty | Prach | Prach | Prach | Prach | empty | empty | empty | empty | empty | empty | empty | empty | - memcpy(prach2 + dftlen * 4, prach2, (dftlen << 3)); - // here we have | empty | Prach | Prach | Prach | Prach | Prach | Prach | empty | empty | empty | empty | empty | empty | - memcpy(prach2 + dftlen * 6, prach2, (dftlen << 2) * 6); - // here we have | empty | Prach | Prach | Prach | Prach | Prach | Prach | Prach | Prach | Prach | Prach | Prach | Prach | - memcpy(prach, prach + dftlen, (Ncp << 2)); - // here we have | Prefix | Prach | Prach | Prach | Prach | Prach | Prach | Prach | Prach | Prach | Prach | Prach | Prach | - prach_len = (dftlen*12)+Ncp; - } + c16_t *out = txData[0] + prach_start; + memcpy(out, prach + dftlen - Ncp, Ncp * sizeof(*prach)); + out += Ncp; + const int copies[11] = {1, 2, 4, 4, 2, 4, 6, 2, 12, 1, 4}; + DevAssert(prach_fmt_id < sizeofArray(copies)); + for (int i = 0; i < copies[prach_fmt_id]; i++) { + memcpy(out, prach, dftlen * sizeof(*prach)); + out += dftlen; } #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 - - memcpy(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 *)(&txdata[0][prach_start]), 2 * (prach_start + prach_len), 1, 1) + LOG_I(PHY, + "PRACH [UE %d] N_RB_UL %d prach_start %d, prach_len %d\n", + ue->Mod_id, + fp->N_RB_UL, + prach_start, + out - (txData[0] + prach_start)); #endif return signal_energy((int *)prach, 256);