Make the decidated structure the PRACH decoding values contextual

The function rx_nr_prach become autonomous, it doesn't read anymore global variables
So, it can become (later) a threadpool work, that will send a message when it finishes
rx_nr_prach_ru() still use some global variables, but it is executed in sequence, inside the ru main loop, that limits the probability of race conditions
This commit is contained in:
Laurent THOMAS
2025-09-19 15:08:26 +02:00
committed by Robert Schmidt
parent 4f39ba8f51
commit d745e6fcd3
8 changed files with 314 additions and 305 deletions

View File

@@ -1034,7 +1034,7 @@ void *ru_thread(void *param)
RU_t *ru = (RU_t *)param;
RU_proc_t *proc = &ru->proc;
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
PHY_VARS_gNB *gNB = RC.gNB[0];
PHY_VARS_gNB *gNB = RC.gNB[0]; // this RU main loop handes only one RU
int ret;
int slot = fp->slots_per_frame-1;
int frame = 1023;
@@ -1047,7 +1047,7 @@ void *ru_thread(void *param)
// set default return value
sprintf(threadname,"ru_thread %u",ru->idx);
LOG_I(PHY,"Starting RU %d (%s,%s) on cpu %d\n",ru->idx,NB_functions[ru->function],NB_timing[ru->if_timing],sched_getcpu());
ru->config = RC.gNB[0]->gNB_config;
ru->config = gNB->gNB_config;
nr_init_frame_parms(&ru->config, fp);
nr_dump_frame_parms(fp);
@@ -1179,12 +1179,17 @@ void *ru_thread(void *param)
proc->timestamp_tx += fp->get_samples_per_slot(i % fp->slots_per_frame, fp);
proc->tti_tx = (proc->tti_rx + ru->sl_ahead) % fp->slots_per_frame;
proc->frame_tx = proc->tti_rx > proc->tti_tx ? (proc->frame_rx + 1) & 1023 : proc->frame_rx;
LOG_D(PHY,"AFTER fh_south_in - SFN/SL:%d%d RU->proc[RX:%d.%d TX:%d.%d] RC.gNB[0]:[RX:%d%d TX(SFN):%d]\n",
frame,slot,
proc->frame_rx,proc->tti_rx,
proc->frame_tx,proc->tti_tx,
RC.gNB[0]->proc.frame_rx,RC.gNB[0]->proc.slot_rx,
RC.gNB[0]->proc.frame_tx);
LOG_D(PHY,
"AFTER fh_south_in - SFN/SL:%d%d RU->proc[RX:%d.%d TX:%d.%d] RC.gNB[0]:[RX:%d%d TX(SFN):%d]\n",
frame,
slot,
proc->frame_rx,
proc->tti_rx,
proc->frame_tx,
proc->tti_tx,
gNB->proc.frame_rx,
gNB->proc.slot_rx,
gNB->proc.frame_tx);
if (ru->idx != 0)
proc->frame_tx = (proc->frame_tx + proc->frame_offset) & 1023;
@@ -1199,7 +1204,7 @@ void *ru_thread(void *param)
LOG_D(NR_PHY, "Setting %d.%d (%d) to busy\n", proc->frame_rx, proc->tti_rx, proc->tti_rx % RU_RX_SLOT_DEPTH);
//LOG_M("rxdata.m","rxs",ru->common.rxdata[0],1228800,1,1);
LOG_D(PHY,"RU proc: frame_rx = %d, tti_rx = %d\n", proc->frame_rx, proc->tti_rx);
gNBscopeCopy(RC.gNB[0],
gNBscopeCopy(gNB,
gNBRxdataF,
ru->common.rxdataF[0],
sizeof(c16_t),
@@ -1208,33 +1213,12 @@ void *ru_thread(void *param)
proc->tti_rx * gNB->frame_parms.samples_per_slot_wCP);
// Do PRACH RU processing
prach_item_t *p = find_nr_prach(&ru->prach_list, proc->frame_rx, proc->tti_rx, SEARCH_EXIST);
prach_item_t *p = find_nr_prach(&gNB->prach_list, proc->frame_rx, proc->tti_rx, SEARCH_EXIST);
if (p) {
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_RU_PRACH_RX, 1 );
T(T_GNB_PHY_PRACH_INPUT_SIGNAL,
T_INT(proc->frame_rx),
T_INT(proc->tti_rx),
T_INT(0),
T_BUFFER(&ru->common.rxdata[0][fp->get_samples_slot_timestamp(proc->tti_rx - 1, fp, 0) /*-ru->N_TA_offset*/],
(fp->get_samples_per_slot(proc->tti_rx - 1, fp) + fp->get_samples_per_slot(proc->tti_rx, fp)) * 4));
int N_dur = get_nr_prach_duration(p->pdu.prach_format);
LOG_D(NR_PHY_RACH, "%d.%d try to decode %d occasions \n", frame, slot, p->pdu.num_prach_ocas);
for (int prach_oc = 0; prach_oc < p->pdu.num_prach_ocas; prach_oc++) {
int prachStartSymbol = p->pdu.prach_start_symbol + prach_oc * N_dur;
int beam_id = p->beams[prach_oc];
//comment FK: the standard 38.211 section 5.3.2 has one extra term +14*N_RA_slot. This is because there prachStartSymbol is given wrt to start of the 15kHz slot or 60kHz slot. Here we work slot based, so this function is anyway only called in slots where there is PRACH. Its up to the MAC to schedule another PRACH PDU in the case there are there N_RA_slot \in {0,1}.
rx_nr_prach_ru(ru,
p->pdu.prach_format, // could also use format
p->pdu.num_ra,
beam_id,
prachStartSymbol,
p->slot,
prach_oc,
proc->frame_rx,
proc->tti_rx);
}
free_nr_prach_entry(&ru->prach_list, p);
// this fills ru->prach_rxsigF for processing by gNB
p->rxsigF = (c16_t ***)ru->prach_rxsigF;
rx_nr_prach_ru(p, ru->common.rxdata, ru->nr_frame_parms, ru->N_TA_offset);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_RU_PRACH_RX, 0);
} // end if (prach_id >= 0)
} // end if (ru->feprx)

View File

@@ -87,9 +87,8 @@ prach_item_t *nr_fill_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach
return NULL;
}
const int fmt = prach_pdu->prach_format;
*prach = (prach_item_t){.frame = SFN,
.slot = Slot,
.num_slots = (fmt < 4) ? get_long_prach_dur(fmt, gNB->frame_parms.numerology_index) : 1};
NR_DL_FRAME_PARMS *fp = &gNB->frame_parms;
*prach = (prach_item_t){.frame = SFN, .slot = Slot, .num_slots = (fmt < 4) ? get_long_prach_dur(fmt, fp->numerology_index) : 1};
if (gNB->common_vars.beam_id) {
int n_symb = get_nr_prach_duration(prach_pdu->prach_format);
AssertFatal(prach_pdu->beamforming.dig_bf_interface < NFAPI_MAX_NUM_BG_IF,
@@ -109,6 +108,18 @@ prach_item_t *nr_fill_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach
}
}
prach->pdu = *prach_pdu;
nfapi_nr_prach_config_t *cfg = &gNB->gNB_config.prach_config;
nfapi_nr_num_prach_fd_occasions_t *occ = &cfg->num_prach_fd_occasions_list[prach_pdu->num_ra];
prach->rootSequenceIndex = occ->prach_root_sequence_index.value;
prach->numrootSequenceIndex = occ->num_root_sequences.value;
prach->msg1_frequencystart = occ->k1.value;
prach->mu = cfg->prach_sub_c_spacing.value;
prach->prach_sequence_length = cfg->prach_sequence_length.value;
prach->restricted_set = cfg->restricted_set_config.value;
prach->numerology_index = fp->numerology_index;
prach->nb_rx = gNB->gNB_config.carrier_config.num_rx_ant.value;
prach->Xu = gNB->X_u;
prach->rx_prach = &gNB->rx_prach;
return prach;
}
@@ -122,152 +133,140 @@ void nr_fill_prach_ru(RU_t *ru, prach_item_t *gnb_prach)
*prach = *gnb_prach;
}
void rx_nr_prach_ru(RU_t *ru,
int prachFormat,
int numRA,
int beam,
int prachStartSymbol,
int prachStartSlot,
int prachOccasion,
int frame,
int slot)
static void rx_nr_prach_ru_internal(prach_item_t *p,
int beam_id,
int prachStartSymbol,
int prachOccasion,
int32_t **rxdata,
NR_DL_FRAME_PARMS *fp,
int N_TA_offset)
{
AssertFatal(ru != NULL,"ru is null\n");
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
int prach_sequence_length = ru->config.prach_config.prach_sequence_length.value;
int msg1_frequencystart = ru->config.prach_config.num_prach_fd_occasions_list[numRA].k1.value;
const uint8_t prach_mu = ru->config.prach_config.prach_sub_c_spacing.value;
int sample_offset_slot;
const int sum = fp->ofdm_symbol_size + fp->nb_prefix_samples;
const int sum0 = fp->ofdm_symbol_size + fp->nb_prefix_samples0;
if (prachStartSymbol == 0) {
sample_offset_slot = 0;
} else if (fp->slots_per_subframe == 1) {
if (prachStartSymbol <= 7)
sample_offset_slot = (fp->ofdm_symbol_size + fp->nb_prefix_samples) * (prachStartSymbol - 1) + (fp->ofdm_symbol_size + fp->nb_prefix_samples0);
sample_offset_slot = sum * (prachStartSymbol - 1) + sum0;
else
sample_offset_slot = (fp->ofdm_symbol_size + fp->nb_prefix_samples) * (prachStartSymbol - 2) + (fp->ofdm_symbol_size + fp->nb_prefix_samples0) * 2;
sample_offset_slot = sum * (prachStartSymbol - 2) + sum0 * 2;
} else {
if (!(slot%(fp->slots_per_subframe/2)))
sample_offset_slot = (fp->ofdm_symbol_size + fp->nb_prefix_samples) * (prachStartSymbol - 1) + (fp->ofdm_symbol_size + fp->nb_prefix_samples0);
if (!(p->slot % (fp->slots_per_subframe / 2)))
sample_offset_slot = sum * (prachStartSymbol - 1) + sum0;
else
sample_offset_slot = (fp->ofdm_symbol_size + fp->nb_prefix_samples) * prachStartSymbol;
sample_offset_slot = sum * prachStartSymbol;
}
LOG_D(PHY,
"frame %d, slot %d: doing rx_nr_prach_ru for format %d, numRA %d, prachStartSymbol %d, prachOccasion %d\n",
frame,
slot,
prachFormat,
numRA,
p->frame,
p->slot,
p->pdu.prach_format,
p->pdu.num_ra,
prachStartSymbol,
prachOccasion);
AssertFatal(ru->if_south == LOCAL_RF || ru->if_south == REMOTE_IF5,
"we shouldn't call this if if_south != LOCAL_RF or REMOTE_IF5\n");
int reps;
int Ncp;
int dftlen;
int mu = fp->numerology_index;
int mu = p->numerology_index;
if (prach_sequence_length == 0) {
if (p->prach_sequence_length == 0) {
LOG_D(PHY,
"PRACH (ru %d) in %d.%d, format %d, msg1_frequencyStart %d\n",
ru->idx,
frame,
prachStartSlot,
prachFormat,
msg1_frequencystart);
switch (prachFormat) {
case 0:
reps = 1;
Ncp = 3168;
dftlen = 24576;
break;
"PRACH in %d.%d, format %d, msg1_frequencyStart %d\n",
p->frame,
p->slot,
p->pdu.prach_format,
p->msg1_frequencystart);
switch (p->pdu.prach_format) {
case 0:
reps = 1;
Ncp = 3168;
dftlen = 24576;
break;
case 1:
reps = 2;
Ncp = 21024;
dftlen = 24576;
break;
case 1:
reps = 2;
Ncp = 21024;
dftlen = 24576;
break;
case 2:
reps = 4;
Ncp = 4688;
dftlen = 24576;
break;
case 2:
reps = 4;
Ncp = 4688;
dftlen = 24576;
break;
case 3:
reps = 4;
Ncp = 3168;
dftlen = 6144;
break;
case 3:
reps = 4;
Ncp = 3168;
dftlen = 6144;
break;
default:
AssertFatal(1==0, "Illegal prach format %d for length 839\n", prachFormat);
break;
default:
AssertFatal(1 == 0, "Illegal prach format %d for length 839\n", p->pdu.prach_format);
break;
}
}
else {
} else {
LOG_D(PHY,
"PRACH (ru %d) in %d.%d, format %s, msg1_frequencyStart %d,startSymbol %d\n",
ru->idx,
frame,
slot,
prachfmt[prachFormat],
msg1_frequencystart,
prachStartSymbol);
switch (prachFormat) {
case 4: //A1
reps = 2;
Ncp = 288 >> mu;
break;
"PRACH in %d.%d, format %s, msg1_frequencyStart %d,startSymbol %d\n",
p->frame,
p->slot,
prachfmt[p->pdu.prach_format],
p->msg1_frequencystart,
prachStartSymbol);
switch (p->pdu.prach_format) {
case 4: // A1
reps = 2;
Ncp = 288 >> mu;
break;
case 5: //A2
reps = 4;
Ncp = 576 >> mu;
break;
case 5: // A2
reps = 4;
Ncp = 576 >> mu;
break;
case 6: //A3
reps = 6;
Ncp = 864 >> mu;
break;
case 6: // A3
reps = 6;
Ncp = 864 >> mu;
break;
case 7: //B1
reps = 2;
Ncp = 216 >> mu;
break;
case 7: // B1
reps = 2;
Ncp = 216 >> mu;
break;
/*
// B2 and B3 do not exist in FAPI
case 4: //B2
reps = 4;
Ncp = 360 >> mu;
break;
/*
// B2 and B3 do not exist in FAPI
case 4: //B2
reps = 4;
Ncp = 360 >> mu;
break;
case 5: //B3
reps = 6;
Ncp = 504 >> mu;
break;
*/
case 5: //B3
reps = 6;
Ncp = 504 >> mu;
break;
*/
case 8: //B4
reps = 12;
Ncp = 936 >> mu;
break;
case 8: // B4
reps = 12;
Ncp = 936 >> mu;
break;
case 9: //C0
reps = 1;
Ncp = 1240 >> mu;
break;
case 9: // C0
reps = 1;
Ncp = 1240 >> mu;
break;
case 10: //C2
reps = 4;
Ncp = 2048 >> mu;
break;
case 10: // C2
reps = 4;
Ncp = 2048 >> mu;
break;
default:
AssertFatal(1==0,"unknown prach format %x\n",prachFormat);
break;
default:
AssertFatal(1 == 0, "unknown prach format %x\n", p->pdu.prach_format);
break;
}
dftlen = 2048 >> mu;
}
@@ -275,12 +274,11 @@ void rx_nr_prach_ru(RU_t *ru,
//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 (p->numerology_index == 0) {
if (prachStartSymbol == 0 || prachStartSymbol == 7)
Ncp += 16;
}
else {
if (slot%(fp->slots_per_subframe/2)==0 && prachStartSymbol == 0)
} else {
if (p->slot % (fp->slots_per_subframe / 2) == 0 && prachStartSymbol == 0)
Ncp += 16;
}
@@ -351,27 +349,27 @@ void rx_nr_prach_ru(RU_t *ru,
// Do forward transform
if (LOG_DEBUGFLAG(DEBUG_PRACH)) {
LOG_D(PHY, "rx_prach: Doing PRACH FFT for nb_rx:%d Ncp:%d dftlen:%d\n", ru->nb_rx, Ncp, dftlen);
LOG_D(PHY, "rx_prach: Doing PRACH FFT for nb_rx:%d Ncp:%d dftlen:%d\n", p->nb_rx, Ncp, dftlen);
}
const unsigned int K = get_prach_K(prach_sequence_length, prachFormat, fp->numerology_index, prach_mu);
const uint8_t kbar = get_PRACH_k_bar(prach_mu, fp->numerology_index);
const unsigned int K = get_prach_K(p->prach_sequence_length, p->pdu.prach_format, p->numerology_index, p->mu);
const uint8_t kbar = get_PRACH_k_bar(p->mu, p->numerology_index);
int n_ra_prb = msg1_frequencystart;
int n_ra_prb = p->msg1_frequencystart;
int k = (12*n_ra_prb) - 6*fp->N_RB_UL;
int N_ZC = (prach_sequence_length == 0) ? 839 : 139;
int N_ZC = (p->prach_sequence_length == 0) ? 839 : 139;
if (k<0) k+=(fp->ofdm_symbol_size);
k*=K;
k+=kbar;
for (int aa=0; aa<ru->nb_rx; aa++) {
int slot2 = prach_sequence_length ? slot : prachStartSlot;
int idx = aa + beam * ru->nb_rx;
c16_t *prach =
(c16_t *)&ru->common.rxdata[idx][fp->get_samples_slot_timestamp(slot2, fp, 0) + sample_offset_slot - ru->N_TA_offset];
for (int aa = 0; aa < p->nb_rx; aa++) {
// Fixme: slot or slot makes no sense ???
int slot2 = p->prach_sequence_length ? p->slot : p->slot;
int idx = aa + beam_id * p->nb_rx;
c16_t *prach = (c16_t *)&rxdata[idx][fp->get_samples_slot_timestamp(slot2, fp, 0) + sample_offset_slot - N_TA_offset];
// do DFT
c16_t *prach2 = prach + Ncp;
@@ -390,60 +388,56 @@ void rx_nr_prach_ru(RU_t *ru,
rxsigF_tmp[j] = c16add(rxsigF_tmp[j], tmp[k2]);
}
}
memcpy(ru->prach_rxsigF[prachOccasion][aa], rxsigF_tmp, sizeof(rxsigF_tmp));
memcpy(p->rxsigF[prachOccasion][aa], rxsigF_tmp, sizeof(rxsigF_tmp));
}
}
void rx_nr_prach(PHY_VARS_gNB *gNB,
nfapi_nr_prach_pdu_t *prach_pdu,
int frame,
int slot,
uint16_t *max_preamble,
uint16_t *max_preamble_energy,
uint16_t *max_preamble_delay,
c16_t **rxsigF)
void rx_nr_prach_ru(prach_item_t *p, int32_t **rxdata, NR_DL_FRAME_PARMS *fp, int N_TA_offset)
{
AssertFatal(gNB != NULL, "Can only be called from gNB\n");
nfapi_nr_prach_config_t *cfg = &gNB->gNB_config.prach_config;
int N_dur = get_nr_prach_duration(p->pdu.prach_format);
LOG_D(NR_PHY_RACH, "%d.%d try to decode %d occasions \n", p->frame, p->slot, p->pdu.num_prach_ocas);
for (int prach_oc = 0; prach_oc < p->pdu.num_prach_ocas; prach_oc++) {
int prachStartSymbol = p->pdu.prach_start_symbol + prach_oc * N_dur;
int beam_id = p->beams[prach_oc];
// comment FK: the standard 38.211 section 5.3.2 has one extra term +14*N_RA_slot. This is because there prachStartSymbol is
// given wrt to start of the 15kHz slot or 60kHz slot. Here we work slot based, so this function is anyway only called in slots
// where there is PRACH. Its up to the MAC to schedule another PRACH PDU in the case there are there N_RA_slot \in {0,1}.
rx_nr_prach_ru_internal(p, beam_id, prachStartSymbol, prach_oc, rxdata, fp, N_TA_offset);
}
}
rx_prach_out_t rx_nr_prach(const prach_item_t *in, int occasion)
{
rx_prach_out_t out = {};
c16_t **input = in->rxsigF[occasion];
uint16_t preamble_index0 = 0;
uint16_t numshift = 0;
int first_nonzero_root_idx = 0;
bool new_dft = false;
int log2_ifft_size = 10;
NR_DL_FRAME_PARMS *fp = &gNB->frame_parms;
const int nb_rx = gNB->gNB_config.carrier_config.num_rx_ant.value;
const int rootSequenceIndex = cfg->num_prach_fd_occasions_list[prach_pdu->num_ra].prach_root_sequence_index.value;
const int numrootSequenceIndex = cfg->num_prach_fd_occasions_list[prach_pdu->num_ra].num_root_sequences.value;
const int NCS = prach_pdu->num_cs; // cfg->num_prach_fd_occasions_list[0].prach_zero_corr_conf.value;
const int prach_sequence_length = cfg->prach_sequence_length.value;
const int msg1_frequencystart = cfg->num_prach_fd_occasions_list[prach_pdu->num_ra].k1.value;
const int restricted_set = cfg->restricted_set_config.value;
const int prach_fmt = prach_pdu->prach_format;
const int N_ZC = prach_sequence_length == 0 ? 839 : 139;
const int nb_rx = in->nb_rx;
const int NCS = in->pdu.num_cs;
const int prach_fmt = in->pdu.prach_format;
const int N_ZC = in->prach_sequence_length == 0 ? 839 : 139;
LOG_D(NR_PHY_RACH,
"L1 PRACH RX: rooSequenceIndex %d, numRootSeqeuences %d, NCS %d, N_ZC %d, format %d \n",
rootSequenceIndex,
numrootSequenceIndex,
in->rootSequenceIndex,
in->numrootSequenceIndex,
NCS,
N_ZC,
prach_fmt);
if (LOG_DEBUGFLAG(DEBUG_PRACH)) {
if ((frame & 1023) < 20)
LOG_D(PHY,
"PRACH (gNB) : running rx_prach for slot %d, msg1_frequencystart %d, rootSequenceIndex %d\n",
slot,
msg1_frequencystart,
rootSequenceIndex);
if ((in->frame & 1023) < 20)
LOG_D(PHY, "PRACH (gNB) : running rx_prach for slot %d, rootSequenceIndex %d\n", in->slot, in->rootSequenceIndex);
}
start_meas(&gNB->rx_prach);
start_meas(in->rx_prach);
const uint16_t *prach_root_sequence_map =
cfg->prach_sequence_length.value == 0 ? prach_root_sequence_map_0_3 : prach_root_sequence_map_abc;
in->prach_sequence_length == 0 ? prach_root_sequence_map_0_3 : prach_root_sequence_map_abc;
// PDP is oversampled, e.g. 1024 sample instead of 839
// Adapt the NCS (zero-correlation zones) with oversampling factor e.g. 1024/839
@@ -454,19 +448,16 @@ void rx_nr_prach(PHY_VARS_gNB *gNB,
int preamble_offset = 0, preamble_offset_old = 99;
*max_preamble_energy = 0;
*max_preamble_delay = 0;
*max_preamble = 0;
int16_t preamble_shift = 0;
const int dft_sz = N_ZC == 839 ? 1024 : 256;
int32_t prach_ifft[dft_sz] __attribute__((aligned(32)));
for (int preamble_index = 0; preamble_index < 64; preamble_index++) {
if (LOG_DEBUGFLAG(DEBUG_PRACH)) {
int en = dB_fixed(signal_energy((int32_t *)rxsigF[0], N_ZC == 839 ? 840 : 140));
int en = dB_fixed(signal_energy((int32_t *)input[0], N_ZC == 839 ? 840 : 140));
if (en > 60)
LOG_D(PHY, "frame %d, slot %d : Trying preamble %d \n", frame, slot, preamble_index);
LOG_D(PHY, "frame %d, slot %d : Trying preamble %d \n", in->frame, in->slot, preamble_index);
}
if (restricted_set == 0) {
if (in->restricted_set == 0) {
// This is the relative offset 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)));
@@ -495,7 +486,7 @@ void rx_nr_prach(PHY_VARS_gNB *gNB,
preamble_index0 -= numshift;
while (not_found) {
// current root depending on rootSequenceIndex
int index = (rootSequenceIndex + preamble_offset) % N_ZC;
int index = (in->rootSequenceIndex + preamble_offset) % N_ZC;
int u = nr_du[prach_root_sequence_map[index]];
uint16_t n_group_ra = 0;
@@ -538,12 +529,12 @@ void rx_nr_prach(PHY_VARS_gNB *gNB,
// Compute DFT of RX signal (conjugate input, results in conjugate output) for each new rootSequenceIndex
if (LOG_DEBUGFLAG(DEBUG_PRACH)) {
int en = dB_fixed(signal_energy((int32_t *)rxsigF[0], 840));
int en = dB_fixed(signal_energy((int32_t *)input[0], 840));
if (en>60)
LOG_D(PHY,
"frame %d, slot %d : preamble index %d, NCS %d, N_ZC/NCS %d: offset %d, preamble shift %d , en %d)\n",
frame,
slot,
in->frame,
in->slot,
preamble_index,
NCS,
N_ZC / NCS,
@@ -562,19 +553,19 @@ void rx_nr_prach(PHY_VARS_gNB *gNB,
if (new_dft) {
new_dft = false;
c16_t *Xu = (c16_t *)gNB->X_u[preamble_offset - first_nonzero_root_idx];
c16_t *Xu = in->Xu[preamble_offset - first_nonzero_root_idx];
LOG_D(PHY,"PRACH RX new dft preamble_offset-first_nonzero_root_idx %d\n",preamble_offset-first_nonzero_root_idx);
memset(prach_ifft, 0, sizeof(prach_ifft));
if (LOG_DUMPFLAG(DEBUG_PRACH)) {
LOG_M("prach_rxF0.m","prach_rxF0",rxsigF[0],N_ZC,1,1);
LOG_M("prach_rxF1.m","prach_rxF1",rxsigF[1],6144,1,1);
LOG_M("prach_rxF0.m", "prach_rxF0", input[0], N_ZC, 1, 1);
LOG_M("prach_rxF1.m", "prach_rxF1", input[1], 6144, 1, 1);
}
c16_t prachF[dft_sz] __attribute__((aligned(32)));
for (int aa = 0; aa < nb_rx; aa++) {
// Do componentwise product with Xu* on each antenna
for (int offset = 0; offset < N_ZC; offset++) {
prachF[offset] = c16MulConjShift(Xu[offset], rxsigF[aa][offset], 15);
prachF[offset] = c16MulConjShift(Xu[offset], input[aa][offset], 15);
}
memset(prachF + N_ZC, 0, sizeof(*prachF) * (dft_sz - N_ZC));
// Now do IFFT of size 1024 (N_ZC=839) or 256 (N_ZC=139)
@@ -613,11 +604,11 @@ void rx_nr_prach(PHY_VARS_gNB *gNB,
for (int i = 0; i < NCS2; i++) {
int lev = prach_ifft[preamble_shift2 + i];
int levdB = dB_fixed_times10(lev);
if (levdB > *max_preamble_energy || (levdB == *max_preamble_energy && *max_preamble_delay > i)) {
LOG_D(NR_PHY_RACH, "preamble_index %d, delay %d en %d dB > %d dB\n", preamble_index, i, levdB, *max_preamble_energy);
*max_preamble_energy = levdB;
*max_preamble_delay = i; // Note: This has to be normalized to the 30.72 Ms/s sampling rate
*max_preamble = preamble_index;
if (levdB > out.max_preamble_energy || (levdB == out.max_preamble_energy && out.max_preamble_delay > i)) {
LOG_D(NR_PHY_RACH, "preamble_index %d, delay %d en %d dB > %d dB\n", preamble_index, i, levdB, out.max_preamble_energy);
out.max_preamble_energy = levdB;
out.max_preamble_delay = i; // Note: This has to be normalized to the 30.72 Ms/s sampling rate
out.max_preamble = preamble_index;
}
}
} // preamble_index
@@ -637,16 +628,15 @@ void rx_nr_prach(PHY_VARS_gNB *gNB,
// Format >3: 2048/2^mu samples @ 30.72 Ms/s, 2048/2^mu * 4 samples @ 122.88 Ms/s
// By solving:
// max_preamble_delay * ( (2048/2^mu*(fs/30.72M)) / 256 ) / fs = TA * 16 * 64 / 2^mu * Tc
uint16_t *TA = max_preamble_delay;
int mu = fp->numerology_index;
if (cfg->prach_sequence_length.value == 0) {
int mu = in->numerology_index;
if (in->prach_sequence_length == 0) {
if (prach_fmt == 0 || prach_fmt == 1 || prach_fmt == 2)
*TA = *TA * 3 * (1 << mu) / 2;
out.max_preamble_delay *= 3 * (1 << mu) / 2;
else if (prach_fmt == 3)
*TA = *TA * 3 * (1 << mu) / 8;
}
else *TA = *TA/2;
stop_meas(&gNB->rx_prach);
out.max_preamble_delay *= 3 * (1 << mu) / 8;
} else
out.max_preamble_delay /= 2;
stop_meas(in->rx_prach);
return out;
}

View File

@@ -202,24 +202,14 @@ void nr_fill_ulsch(PHY_VARS_gNB *gNB,
prach_item_t *nr_fill_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu);
void rx_nr_prach(PHY_VARS_gNB *gNB,
nfapi_nr_prach_pdu_t *prach_pdu,
int frame,
int subframe,
uint16_t *max_preamble,
uint16_t *max_preamble_energy,
uint16_t *max_preamble_delay,
c16_t **rxsigF);
typedef struct rx_prach_out {
uint16_t max_preamble;
uint16_t max_preamble_energy;
uint16_t max_preamble_delay;
} rx_prach_out_t;
rx_prach_out_t rx_nr_prach(const prach_item_t *, int occasion);
void rx_nr_prach_ru(RU_t *ru,
int prach_fmt,
int numRA,
int beam,
int prachStartSymbol,
int prachStartSlot,
int prachOccasion,
int frame,
int subframe);
void rx_nr_prach_ru(prach_item_t *, int32_t **, NR_DL_FRAME_PARMS *frame_parms, int N_TA_offset);
void nr_fill_prach_ru(RU_t *ru,prach_item_t * );
prach_item_t *find_nr_prach(prach_list_t *, int frame, int slot, find_type_t type);

View File

@@ -1007,6 +1007,17 @@ typedef struct {
int num_slots; // prach duration in slots
int beams[NFAPI_MAX_NUM_BG_IF];
nfapi_nr_prach_pdu_t pdu;
int rootSequenceIndex;
int numrootSequenceIndex;
int msg1_frequencystart;
int mu;
int prach_sequence_length;
int restricted_set;
int numerology_index;
int nb_rx;
c16_t ***rxsigF;
c16_t (*Xu)[839];
time_stats_t *rx_prach;
} prach_item_t;
typedef struct {

View File

@@ -156,8 +156,12 @@ void nr_schedule_ul_tti_req(PHY_VARS_gNB *gNB, nfapi_nr_ul_tti_request_t *UL_tti
nfapi_nr_prach_pdu_t *prach_pdu = &UL_tti_req->pdus_list[i].prach_pdu;
LOG_D(NR_PHY_RACH, "Add prach decoding request for %d.%d\n", UL_tti_req->SFN, UL_tti_req->Slot);
prach_item_t *prach = nr_fill_prach(gNB, UL_tti_req->SFN, UL_tti_req->Slot, prach_pdu);
if (!prach)
LOG_W(NR_PHY_RACH, "Error in scheduling rach\n");
/* the present design is not supporting multiple gNB in one RU
if (prach && (gNB->RU_list[0]->if_south == LOCAL_RF || gNB->RU_list[0]->if_south == REMOTE_IF5))
nr_fill_prach_ru(gNB->RU_list[0], prach);
*/
break;
case NFAPI_NR_UL_CONFIG_SRS_PDU_TYPE:
LOG_D(NR_PHY,

View File

@@ -49,16 +49,11 @@ int get_nr_prach_duration(uint8_t prach_format)
void L1_nr_prach_procedures(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_rach_indication_t *rach_ind)
{
uint16_t max_preamble[4]={0},max_preamble_energy[4]={0},max_preamble_delay[4]={0};
RU_t *ru;
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_PRACH_RX,1);
rach_ind->sfn = frame;
rach_ind->slot = slot;
rach_ind->number_of_pdus = 0;
ru=gNB->RU_list[0];
prach_item_t *prach_id = find_nr_prach(&gNB->prach_list, frame, slot, SEARCH_EXIST);
if (!prach_id) {
return;
@@ -74,11 +69,7 @@ void L1_nr_prach_procedures(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_rac
// comment FK: the standard 38.211 section 5.3.2 has one extra term +14*N_RA_slot. This is because there prachStartSymbol is
// given wrt to start of the 15kHz slot or 60kHz slot. Here we work slot based, so this function is anyway only called in slots
// where there is PRACH. Its up to the MAC to schedule another PRACH PDU in the case there are there N_RA_slot \in {0,1}.
c16_t *rxsigF[ru->nb_rx];
for (int i = 0; i < ru->nb_rx; ++i)
rxsigF[i] = (c16_t *)ru->prach_rxsigF[prach_oc][i];
rx_nr_prach(gNB, prach_pdu, frame, slot, max_preamble, max_preamble_energy, max_preamble_delay, rxsigF);
rx_prach_out_t res = rx_nr_prach(prach_id, prach_oc);
LOG_D(NR_PHY,
"[RAPROC] Frame %d, slot %d, occasion %d (prachStartSymbol %d) : Most likely preamble %d, energy %d.%d dB delay %d "
"(prach_energy counter %d)\n",
@@ -86,26 +77,26 @@ void L1_nr_prach_procedures(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_rac
slot,
prach_oc,
prachStartSymbol,
max_preamble[0],
max_preamble_energy[0] / 10,
max_preamble_energy[0] % 10,
max_preamble_delay[0],
res.max_preamble,
res.max_preamble_energy / 10,
res.max_preamble_energy % 10,
res.max_preamble_delay,
gNB->prach_energy_counter);
if ((gNB->prach_energy_counter == NUM_PRACH_RX_FOR_NOISE_ESTIMATE)
&& (max_preamble_energy[0] > gNB->measurements.prach_I0 + gNB->prach_thres)
&& (res.max_preamble_energy > gNB->measurements.prach_I0 + gNB->prach_thres)
&& (rach_ind->number_of_pdus < MAX_NUM_NR_RX_RACH_PDUS)) {
LOG_A(NR_PHY,
"[RAPROC] %d.%d Initiating RA procedure with preamble %d, energy %d.%d dB (I0 %d, thres %d), delay %d start symbol "
"%u freq index %u\n",
frame,
prach_start_slot,
max_preamble[0],
max_preamble_energy[0] / 10,
max_preamble_energy[0] % 10,
res.max_preamble,
res.max_preamble_energy / 10,
res.max_preamble_energy % 10,
gNB->measurements.prach_I0,
gNB->prach_thres,
max_preamble_delay[0],
res.max_preamble_delay,
prachStartSymbol,
prach_pdu->num_ra);
@@ -113,9 +104,9 @@ void L1_nr_prach_procedures(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_rac
T_INT(gNB->Mod_id),
T_INT(frame),
T_INT(slot),
T_INT(max_preamble[0]),
T_INT(max_preamble_energy[0]),
T_INT(max_preamble_delay[0]));
T_INT(res.max_preamble),
T_INT(res.max_preamble_energy),
T_INT(res.max_preamble_delay));
nfapi_nr_prach_indication_pdu_t *ind = rach_ind->pdu_list + rach_ind->number_of_pdus;
*ind = (nfapi_nr_prach_indication_pdu_t){
@@ -123,14 +114,14 @@ void L1_nr_prach_procedures(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_rac
.symbol_index = prachStartSymbol,
.slot_index = slot,
.freq_index = prach_pdu->num_ra,
.avg_rssi = (max_preamble_energy[0] < 631) ? (128 + (max_preamble_energy[0] / 5)) : 254,
.avg_rssi = (res.max_preamble_energy < 631) ? (128 + (res.max_preamble_energy / 5)) : 254,
.avg_snr = 0xff, // invalid for now
.num_preamble = 1,
.preamble_list = {
{.preamble_index = max_preamble[0], .timing_advance = max_preamble_delay[0], .preamble_pwr = 0xffffffff}}};
{.preamble_index = res.max_preamble, .timing_advance = res.max_preamble_delay, .preamble_pwr = 0xffffffff}}};
rach_ind->number_of_pdus++;
}
gNB->measurements.prach_I0 = ((gNB->measurements.prach_I0 * 900) >> 10) + ((max_preamble_energy[0] * 124) >> 10);
gNB->measurements.prach_I0 = ((gNB->measurements.prach_I0 * 900) >> 10) + ((res.max_preamble_energy * 124) >> 10);
if (frame == 0)
LOG_I(PHY, "prach_I0 = %d.%d dB\n", gNB->measurements.prach_I0 / 10, gNB->measurements.prach_I0 % 10);
if (gNB->prach_energy_counter < NUM_PRACH_RX_FOR_NOISE_ESTIMATE)

View File

@@ -135,10 +135,11 @@ int main(int argc, char **argv){
double **s_re, **s_im, **r_re, **r_im, iqim = 0.0, delay_avg = 0, ue_speed = 0, fs=-1, bw;
int i, l, aa, aarx, trial, n_frames = 1, rx_prach_start; //, ntrials=1;
c16_t **txdata;
int N_RB_UL = 106, delay = 0, NCS_config = 13, rootSequenceIndex = 1, threequarter_fs = 0, mu = 1, fd_occasion = 0, loglvl = OAILOG_INFO, numRA = 0, prachStartSymbol = 0;
int N_RB_UL = 106, delay = 0, NCS_config = 13, rootSequenceIndex = 1, threequarter_fs = 0, mu = 1, fd_occasion = 0,
loglvl = OAILOG_INFO;
uint8_t snr1set = 0, ue_speed1set = 0, transmission_mode = 1, n_tx = 1, n_rx = 1, awgn_flag = 0, msg1_frequencystart = 0, num_prach_fd_occasions = 1, prach_format=0;
uint8_t config_index = 98, prach_sequence_length = 1, restrictedSetConfig = 0;
uint16_t Nid_cell = 0, preamble_tx = 0, preamble_delay, format0, format1;
uint16_t Nid_cell = 0, preamble_tx = 0, format0, format1;
uint32_t tx_lev = 10000, prach_errors = 0; //,tx_lev_dB;
uint64_t SSB_positions = 0x01;
uint16_t RA_sfn_index;
@@ -714,9 +715,17 @@ int main(int argc, char **argv){
}
rx_prach_start = subframe*frame_parms->samples_per_subframe;
if (n_frames==1) printf("slot %d, rx_prach_start %d\n",slot,rx_prach_start);
uint16_t preamble_rx, preamble_energy;
if (n_frames == 1)
printf("slot %d, rx_prach_start %d\n", slot, rx_prach_start);
c16_t **rxsigF[NUMBER_OF_NR_RU_PRACH_OCCASIONS_MAX];
for (int j = 0; j < NUMBER_OF_NR_RU_PRACH_OCCASIONS_MAX; j++) {
rxsigF[j] = malloc(ru->nb_rx * sizeof(*rxsigF));
for (int i = 0; i < ru->nb_rx; i++) {
// largest size for PRACH FFT is 4x98304 (16*24576)
rxsigF[j][i] = malloc16_clear(4 * 98304 * sizeof(**rxsigF));
}
}
for (SNR = snr0; SNR < snr1 && !stop; SNR += .1) {
for (ue_speed = ue_speed0; ue_speed < ue_speed1 && !stop; ue_speed += 10) {
@@ -727,8 +736,7 @@ int main(int argc, char **argv){
prach_errors=0;
for (trial = 0; trial < n_frames && !stop; trial++) {
if (input_fd==NULL) {
if (input_fd == NULL) {
sigma2_dB = 10*log10((double)tx_lev) - SNR - 10*log10(N_RB_UL*12/N_ZC);
if (n_frames==1)
@@ -755,52 +763,72 @@ int main(int argc, char **argv){
tmp->i = (short)(.167 * (r_im[aa][i] + (iqim * r_re[aa][i]) + sqrt(sigma2 / 2) * gaussdouble(0.0, 1.0)));
}
}
} else {
n_bytes = fread(&ru->common.rxdata[0][rx_prach_start],sizeof(int32_t),frame_parms->samples_per_subframe,input_fd);
printf("fread %d bytes from file %s\n",n_bytes,input_file);
if (n_bytes!=frame_parms->samples_per_subframe) {
printf("expected %d bytes\n",frame_parms->samples_per_subframe);
exit(-1);
}
}
} else {
n_bytes = fread(&ru->common.rxdata[0][rx_prach_start], sizeof(int32_t), frame_parms->samples_per_subframe, input_fd);
printf("fread %d bytes from file %s\n", n_bytes, input_file);
if (n_bytes != frame_parms->samples_per_subframe) {
printf("expected %d bytes\n", frame_parms->samples_per_subframe);
exit(-1);
}
}
for (l = 0; l < frame_parms->symbols_per_slot; l++) {
for (aa = 0; aa < frame_parms->nb_antennas_rx; aa++) {
nr_slot_fep_ul(frame_parms, ru->common.rxdata[aa], ru->common.rxdataF[aa], l, slot, ru->N_TA_offset);
}
}
rx_nr_prach_ru(ru, prach_format, numRA, 0, prachStartSymbol, slot, prachOccasion, frame, slot);
c16_t *rxsigF[ru->nb_rx];
for (int i = 0; i < ru->nb_rx; ++i)
rxsigF[i] = (c16_t *)ru->prach_rxsigF[prachOccasion][i];
if (n_frames == 1)
LOG_I(PHY,
"ncs %d,num_seq %d\n",
prach_pdu->num_cs,
prach_config->num_prach_fd_occasions_list[fd_occasion].num_root_sequences.value);
rx_nr_prach(gNB, prach_pdu, frame, subframe, &preamble_rx, &preamble_energy, &preamble_delay, rxsigF);
for (l = 0; l < frame_parms->symbols_per_slot; l++) {
for (aa = 0; aa < frame_parms->nb_antennas_rx; aa++) {
nr_slot_fep_ul(frame_parms, ru->common.rxdata[aa], ru->common.rxdataF[aa], l, slot, ru->N_TA_offset);
}
}
// printf(" preamble_energy %d preamble_rx %d preamble_tx %d \n", preamble_energy, preamble_rx, preamble_tx);
nfapi_nr_prach_config_t *cfg = &gNB->gNB_config.prach_config;
nfapi_nr_num_prach_fd_occasions_t *occ = &cfg->num_prach_fd_occasions_list[prach_pdu->num_ra];
prach_pdu->num_prach_ocas=1;
prach_item_t in = {.frame = frame,
.slot = slot,
.pdu = *prach_pdu,
.rootSequenceIndex = occ->prach_root_sequence_index.value,
.numrootSequenceIndex = occ->num_root_sequences.value,
.msg1_frequencystart = occ->k1.value,
.mu = cfg->prach_sub_c_spacing.value,
.prach_sequence_length = cfg->prach_sequence_length.value,
.restricted_set = cfg->restricted_set_config.value,
.numerology_index = gNB->frame_parms.numerology_index,
.nb_rx = gNB->gNB_config.carrier_config.num_rx_ant.value,
.rxsigF = rxsigF,
.Xu = gNB->X_u,
.rx_prach = &gNB->rx_prach};
rx_nr_prach_ru(&in, ru->common.rxdata, ru->nr_frame_parms, ru->N_TA_offset);
if (n_frames == 1)
LOG_I(PHY,
"ncs %d,num_seq %d\n",
prach_pdu->num_cs,
prach_config->num_prach_fd_occasions_list[fd_occasion].num_root_sequences.value);
rx_prach_out_t out = rx_nr_prach(&in, prachOccasion);
if (preamble_rx != preamble_tx)
prach_errors++;
else
delay_avg += (double)preamble_delay;
// printf(" preamble_energy %d preamble_rx %d preamble_tx %d \n", out.max_preamble_energy, out.max_preamble,
// preamble_tx);
N_ZC = (prach_sequence_length) ? 139 : 839;
if (out.max_preamble != preamble_tx)
prach_errors++;
else
delay_avg += (double)out.max_preamble_delay;
if (n_frames == 1) {
printf("preamble %d (tx %d) : energy %d, delay %d\n", preamble_rx, preamble_tx, preamble_energy, preamble_delay);
N_ZC = (prach_sequence_length) ? 139 : 839;
if (n_frames == 1) {
printf("preamble %d (tx %d) : energy %d, delay %d\n",
out.max_preamble,
preamble_tx,
out.max_preamble_energy,
out.max_preamble_delay);
#ifdef NR_PRACH_DEBUG
LOG_M("prach0.m","prach0", &txdata[0][prach_start], frame_parms->samples_per_subframe, 1, 1);
LOG_M("rxsig0.m","rxs0", &ru->common.rxdata[0][subframe*frame_parms->samples_per_subframe], frame_parms->samples_per_subframe, 1, 1);
LOG_M("ru_rxsig0.m","rxs0", &ru->common.rxdata[0][subframe*frame_parms->samples_per_subframe], frame_parms->samples_per_subframe, 1, 1);
LOG_M("ru_rxsigF0.m","rxsF0", ru->common.rxdataF[0], frame_parms->ofdm_symbol_size*frame_parms->symbols_per_slot, 1, 1);
LOG_M("ru_prach_rxsigF0.m","rxsF0", ru->prach_rxsigF[0][0], N_ZC, 1, 1);
LOG_M("ru_prach_rxsigF0.m", "rxsF0", rxsigF[0][0], N_ZC, 1, 1);
LOG_M("prach_preamble.m","prachp", &gNB->X_u[0], N_ZC, 1, 1);
LOG_M("ue_prach_preamble.m","prachp", &UE->X_u[0], N_ZC, 1, 1);
#endif
}
}
}
printf("SNR %f dB, UE Speed %f km/h: errors %u/%d (delay %f)\n", SNR, ue_speed, prach_errors, n_frames, delay_avg/(double)(n_frames-prach_errors));
@@ -817,7 +845,13 @@ int main(int argc, char **argv){
if (input_fd)
break;
} //SNR loop
for (int j = 0; j < NUMBER_OF_NR_RU_PRACH_OCCASIONS_MAX; j++) {
for (int i = 0; i < ru->nb_rx; i++) {
// largest size for PRACH FFT is 4x98304 (16*24576)
free(rxsigF[j][i]);
}
free(rxsigF[j]);
}
free_channel_desc_scm(UE2gNB);
nr_phy_free_RU(ru);

View File

@@ -1430,7 +1430,12 @@ static void nr_generate_Msg2(module_id_t module_idP,
scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.ra_ResponseWindow;
const int n_slots_frame = nr_mac->frame_structure.numb_slots_frame;
if (!msg2_in_response_window(ra->preamble_frame, ra->preamble_slot, n_slots_frame, rrc_ra_ResponseWindow, frameP, slotP)) {
LOG_E(NR_MAC, "UE RA-RNTI %04x TC-RNTI %04x: exceeded RA window, cannot schedule Msg2\n", ra->RA_rnti, UE->rnti);
LOG_E(NR_MAC,
"sfn: %d.%d UE RA-RNTI %04x TC-RNTI %04x: exceeded RA window, cannot schedule Msg2\n",
frameP,
slotP,
ra->RA_rnti,
UE->rnti);
nr_release_ra_UE(nr_mac, UE->rnti);
return;
}