Commit 0fdc095d authored by Robert Schmidt's avatar Robert Schmidt

Merge remote-tracking branch 'origin/fix-simplify-prach-nrue' into integration_2026_w03 (!3791)

fix array lenght errors, k variable wrapping threshold. Make the code smaller and more efficient

generate_nr_prach() has several errors coming from replace int16_t by
c16_t, and also older error in k wrapping at the end of the symbol

the code is also ridiculously complex, wasting memory and cpu time in
intermediate useless buffers and headache usage of memmove()
parents 815a5719 ae8319db
......@@ -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;
......
......@@ -37,6 +37,7 @@
#include <stdlib.h>
#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);
......
......@@ -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));
......
......@@ -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;
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 {
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;
}
case 2:
Ncp = 4688;
dftlen = 24576;
break;
// 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)
Ncp += 16;
}
case 3:
Ncp = 3168;
dftlen = 6144;
switch (fp->samples_per_subframe) {
case 7680:
// 5 MHz @ 7.68 Ms/s
Ncp >>= 2;
dftlen >>= 2;
break;
default:
AssertFatal(1 == 0, "Illegal PRACH format %d for sequence length 839\n", prach_fmt_id);
break;
}
} else {
switch (prach_fmt_id) {
case 4: //A1
Ncp = 288 >> mu;
case 15360:
// 10, 15 MHz @ 15.36 Ms/s
Ncp >>= 1;
dftlen >>= 1;
break;
case 5: //A2
Ncp = 576 >> mu;
case 23040:
// 20 MHz @ 23.04 Ms/s
Ncp = (Ncp * 3) / 4;
dftlen = (dftlen * 3) / 4;
break;
case 6: //A3
Ncp = 864 >> mu;
case 30720:
// 20, 25, 30 MHz @ 30.72 Ms/s
break;
case 7: //B1
Ncp = 216 >> mu;
case 46080:
// 40 MHz @ 46.08 Ms/s
Ncp = (Ncp * 3) / 2;
dftlen = (dftlen * 3) / 2;
break;
/*
case 4: //B2
Ncp = 360 >> mu;
case 61440:
// 40, 50, 60 MHz @ 61.44 Ms/s
Ncp <<= 1;
dftlen <<= 1;
break;
case 5: //B3
Ncp = 504 >> mu;
case 92160:
// 50, 60, 70, 80, 90 MHz @ 92.16 Ms/s
Ncp *= 3;
dftlen *= 3;
break;
*/
case 8: //B4
Ncp = 936 >> mu;
case 122880:
// 70, 80, 90, 100 MHz @ 122.88 Ms/s
Ncp <<= 2;
dftlen <<= 2;
break;
case 9: //C0
Ncp = 1240 >> mu;
case 184320:
// 100 MHz @ 184.32 Ms/s
Ncp = Ncp * 6;
dftlen = dftlen * 6;
break;
case 10: //C2
Ncp = 2048 >> mu;
case 245760:
// 200 MHz @ 245.76 Ms/s
Ncp <<= 3;
dftlen <<= 3;
break;
default:
AssertFatal(1==0,"Unknown PRACH format ID %d\n", prach_fmt_id);
break;
}
dftlen = 2048 >> mu;
AssertFatal(1 == 0, "sample rate %f MHz not supported for numerology %d\n", fp->samples_per_subframe / 1000.0, 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) {
if (prachStartSymbol == 0 || prachStartSymbol == 7)
Ncp += 16;
}
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;
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 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 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 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 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);
}
#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
for (offset=0,offset2=0; offset<N_ZC; offset++,offset2+=preamble_shift) {
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;
LOG_M("X_u.m", "X_u", (int16_t *)ue->X_u[preamble_offset - first_nonzero_root_idx], N_ZC, 1, 1);
#endif
if (k * 2 == dftlen)
k = 0;
}
c16_t prach[dftlen] __attribute__((aligned(32)));
{
c16_t prachF[dftlen] __attribute__((aligned(32)));
memset(prachF, 0, sizeof(prachF));
for (int offset = 0, offset2 = 0; offset < N_ZC; offset++, offset2 += preamble_shift) {
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 == 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;
}
}
#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);
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 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)
#ifdef NR_PRACH_DEBUG
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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment