feat(nr): implement rank-8 PDSCH

This commit is contained in:
2026-09-15 00:36:01 +09:00
parent 04ee4ea8e5
commit c50fe1af53
42 changed files with 3244 additions and 648 deletions
+1 -1
View File
@@ -475,7 +475,7 @@ int main(int argc, char **argv)
printf("harq process ue mcs = %d Qm = %d, symb %d\n", dlsch_config.cw_info[0].mcs, dlsch_config.cw_info[0].qamModOrder, nb_symb_sch);
uint8_t test_input[TBS / 8 + 4]; // + 3 for CRC + 1 additional byte, see nr_dlsch_encoding()
dlsch->pdu = test_input;
dlsch->pdu[0] = test_input;
//unsigned char test_input[TBS / 8] __attribute__ ((aligned(16)));
for (i = 0; i < TBS / 8; i++)
test_input[i] = (unsigned char) rand();
+90 -56
View File
@@ -240,14 +240,7 @@ void nr_dlsim_preprocessor(gNB_MAC_INST *nr_mac, post_process_pdsch_t *pp_pdsch)
sched_pdsch.Qm = nr_get_Qm_dl(sched_pdsch.mcs, current_BWP->mcsTableIdx);
sched_pdsch.R = nr_get_code_rate_dl(sched_pdsch.mcs, current_BWP->mcsTableIdx);
sched_pdsch.tb_size = nr_compute_tbs(sched_pdsch.Qm,
sched_pdsch.R,
sched_pdsch.rbSize,
sched_pdsch.tda_info.nrOfSymbols,
sched_pdsch.dmrs_parms.N_PRB_DMRS * sched_pdsch.dmrs_parms.N_DMRS_SLOT,
0 /* N_PRB_oh, 0 for initialBWP */,
0 /* tb_scaling */,
sched_pdsch.nrOfLayers) >> 3;
update_sched_pdsch_codeword_tbs(&sched_pdsch);
/* the simulator assumes the HARQ PID is equal to the slot number */
sched_pdsch.dl_harq_pid = pp_pdsch->slot;
@@ -471,7 +464,7 @@ int main(int argc, char **argv)
case 'x':
g_nrOfLayers = atoi(optarg);
if ((g_nrOfLayers == 0) || (g_nrOfLayers > 4)) {
if ((g_nrOfLayers == 0) || (g_nrOfLayers > NR_MAX_NB_LAYERS)) {
printf("Unsupported nr Of Layers %d\n", g_nrOfLayers);
exit(-1);
}
@@ -490,7 +483,7 @@ int main(int argc, char **argv)
case 'y':
n_tx=atoi(optarg);
if ((n_tx==0) || (n_tx>4)) {//extend gNB to support n_tx = 4
if ((n_tx == 0) || (n_tx > NR_MAX_NB_LAYERS)) {
printf("Unsupported number of tx antennas %d\n",n_tx);
exit(-1);
}
@@ -500,7 +493,7 @@ int main(int argc, char **argv)
case 'z':
n_rx=atoi(optarg);
if ((n_rx==0) || (n_rx>4)) {//extend UE to support n_tx = 4
if ((n_rx == 0) || (n_rx > NR_MAX_NB_LAYERS)) {
printf("Unsupported number of rx antennas %d\n",n_rx);
exit(-1);
}
@@ -940,8 +933,6 @@ int main(int argc, char **argv)
UE_mac->if_module = nr_ue_if_module_init(0);
unsigned int available_bits=0;
unsigned char *estimated_output_bit=NULL;
unsigned char *test_input_bit=NULL;
unsigned int errors_bit = 0;
initFloatingCoresTpool(dlsch_threads, &nrUE_params.Tpool, false, "UE-tpool");
@@ -987,7 +978,7 @@ int main(int argc, char **argv)
a_segments = (a_segments/273)+1;
}
uint32_t dlsch_bytes = a_segments*1056; // allocated bytes per segment
UE->phy_sim_dlsch_b = calloc(1, dlsch_bytes);
UE->phy_sim_dlsch_b = calloc(NR_MAX_NB_CODEWORDS, dlsch_bytes);
// csv file
if (filename_csv != NULL) {
@@ -1069,17 +1060,19 @@ int main(int argc, char **argv)
UE_proc.nr_slot_rx = slot;
UE_proc.gNB_id = 0;
NR_UE_DLSCH_t *dlsch0 = &phy_data.dlsch[0];
int harq_pid = slot;
NR_DL_UE_HARQ_t *UE_harq_process = &UE->dl_harq_processes[0][harq_pid];
UE_harq_process->decodeResult = false;
NR_DL_UE_HARQ_t *UE_harq_process[NR_MAX_NB_CODEWORDS];
round = 0;
UE_harq_process->DLround = round;
UE_harq_process->first_rx = 1;
for (int c = 0; c < NR_MAX_NB_CODEWORDS; c++) {
UE_harq_process[c] = &UE->dl_harq_processes[c][harq_pid];
UE_harq_process[c]->decodeResult = false;
UE_harq_process[c]->DLround = round;
UE_harq_process[c]->first_rx = 1;
}
int n_codewords = 0;
bool all_codewords_decoded = false;
while (round < num_rounds && !UE_harq_process->decodeResult && !stop) {
while (round < num_rounds && !all_codewords_decoded && !stop) {
reset_sched_response(Sched_INFO, frame, slot, 0, 0);
clear_nr_nfapi_information(RC.nrmac[0], 0, frame, slot);
UE_info->UE_sched_ctrl.harq_processes[harq_pid].ndi = !(trial&1);
@@ -1302,59 +1295,97 @@ int main(int argc, char **argv)
//---------------------- count errors ----------------------
//----------------------------------------------------------
if (dlsch0->last_iteration_cnt >= dlsch0->max_ldpc_iterations)
n_codewords = phy_data.n_dlsch_codewords;
AssertFatal(n_codewords >= 1 && n_codewords <= NR_MAX_NB_CODEWORDS,
"Invalid number of decoded PDSCH codewords %d\n",
n_codewords);
bool block_error = false;
bool any_active_codeword = false;
all_codewords_decoded = true;
for (int c = 0; c < n_codewords; c++) {
NR_UE_DLSCH_t *dlsch = &phy_data.dlsch[c];
any_active_codeword |= dlsch->active;
block_error |= dlsch->active && dlsch->last_iteration_cnt >= dlsch->max_ldpc_iterations;
all_codewords_decoded &= UE_harq_process[c]->decodeResult;
}
if (block_error)
n_errors[round]++;
if (dlsch0->active)
if (any_active_codeword)
round_trials[round]++;
int16_t *UE_llr = (int16_t*)UE->phy_sim_pdsch_llr;
TBS = phy_data.dlsch_config.cw_info[0].TBS;
TBS = 0;
uint16_t length_dmrs = get_num_dmrs(phy_data.dlsch_config.dlDmrsSymbPos);
uint16_t nb_rb = phy_data.dlsch_config.number_rbs;
uint8_t nb_re_dmrs = phy_data.dlsch_config.dmrsConfigType == NFAPI_NR_DMRS_TYPE1 ?
6 * phy_data.dlsch_config.n_dmrs_cdm_groups :
4 * phy_data.dlsch_config.n_dmrs_cdm_groups;
uint8_t mod_order = phy_data.dlsch_config.cw_info[0].qamModOrder;
uint8_t nb_symb_sch = phy_data.dlsch_config.number_symbols;
uint32_t unav_res = ptrsSymbPerSlot * ptrsRePerSymb;
available_bits = nr_get_G(nb_rb, nb_symb_sch, nb_re_dmrs, length_dmrs, unav_res, mod_order, pdsch_pdu_rel15->nrOfLayers);
available_bits = 0;
for (int c = 0; c < n_codewords; c++) {
const fapi_nr_dl_cw_info_t *cw_info = &phy_data.dlsch_config.cw_info[c];
TBS += cw_info->TBS;
available_bits += nr_get_G(nb_rb,
nb_symb_sch,
nb_re_dmrs,
length_dmrs,
unav_res,
cw_info->qamModOrder,
cw_info->Nl);
}
if (pdu_bit_map & 0x1) {
if (trial == 0 && round == 0) {
printf("[DLSIM][PTRS] Available bits are: %5u, removed PTRS bits are: %5u \n", available_bits, (ptrsSymbPerSlot * ptrsRePerSymb * pdsch_pdu_rel15->nrOfLayers * mod_order));
printf("[DLSIM][PTRS] Available bits are: %5u, removed PTRS REs are: %5u \n",
available_bits,
ptrsSymbPerSlot * ptrsRePerSymb * pdsch_pdu_rel15->nrOfLayers);
}
}
for (i = 0; i < available_bits; i++) {
const uint8_t current_bit = (gNB_dlsch->f[i / 8] & (1 << (i & 7))) >> (i & 7);
if (((current_bit == 0) && (UE_llr[i] <= 0)) || ((current_bit == 1) && (UE_llr[i] >= 0))) {
if (errors_scrambling[round] == 0) {
LOG_D(PHY,"First bit in error in unscrambling = %d\n",i);
uint32_t llr_offset = 0;
for (int c = 0; c < n_codewords; c++) {
const fapi_nr_dl_cw_info_t *cw_info = &phy_data.dlsch_config.cw_info[c];
const uint32_t codeword_bits = nr_get_G(nb_rb,
nb_symb_sch,
nb_re_dmrs,
length_dmrs,
unav_res,
cw_info->qamModOrder,
cw_info->Nl);
for (i = 0; i < codeword_bits; i++) {
const uint8_t current_bit = (gNB_dlsch->f[c][i / 8] & (1 << (i & 7))) >> (i & 7);
if (((current_bit == 0) && (UE_llr[llr_offset + i] <= 0))
|| ((current_bit == 1) && (UE_llr[llr_offset + i] >= 0))) {
if (errors_scrambling[round] == 0)
LOG_D(PHY, "First bit in error in unscrambling = CW%d bit %d\n", c, i);
errors_scrambling[round]++;
}
errors_scrambling[round]++;
}
llr_offset += codeword_bits;
}
AssertFatal(llr_offset == available_bits,
"PDSCH LLR accounting mismatch: %u of %u bits\n",
llr_offset,
available_bits);
//printf("dlsim round %d ends\n",round);
round++;
} // round
if (test_input_bit == NULL) {
test_input_bit = (unsigned char *)malloc16(8 * pdsch_pdu_rel15->TBSize[0]);
estimated_output_bit = (unsigned char *)malloc16(8 * pdsch_pdu_rel15->TBSize[0]);
}
for (i = 0; i < TBS; i++) {
for (int c = 0; c < n_codewords; c++) {
const uint32_t codeword_tbs = phy_data.dlsch_config.cw_info[c].TBS;
const uint8_t *decoded = UE->phy_sim_dlsch_b + c * dlsch_bytes;
for (i = 0; i < codeword_tbs; i++) {
const uint8_t estimated_output_bit = (decoded[i / 8] & (1 << (i & 7))) >> (i & 7);
const uint8_t test_input_bit = (gNB_dlsch->b[c][i / 8] & (1 << (i & 7))) >> (i & 7);
estimated_output_bit[i] = (UE->phy_sim_dlsch_b[i/8] & (1 << (i & 7))) >> (i & 7);
test_input_bit[i] = (gNB_dlsch->b[i / 8] & (1 << (i & 7))) >> (i & 7); // Further correct for multiple segments
if (estimated_output_bit[i] != test_input_bit[i]) {
if(errors_bit == 0)
LOG_D(PHY,"First bit in error in decoding = %d\n",i);
errors_bit++;
}
if (estimated_output_bit != test_input_bit) {
if (errors_bit == 0)
LOG_D(PHY, "First bit in error in decoding = CW%d bit %d\n", c, i);
errors_bit++;
}
}
}
////////////////////////////////////////////////////////////
@@ -1364,7 +1395,7 @@ int main(int argc, char **argv)
printf("errors_bit = %u (trial %d)\n", errors_bit, trial);
}
roundStats += round;
if (UE_harq_process->decodeResult)
if (all_codewords_decoded)
effRate += ((double)TBS) / round;
} // noise trials
@@ -1391,7 +1422,11 @@ int main(int argc, char **argv)
printf("), Channel BER (%e", berStats[0]);
for (int r = 1; r < num_rounds; r++)
printf(",%e", berStats[r]);
printf(") Avg round %.2f, Eff Rate %.4f bits/slot, Eff Throughput %.2f, TBS %u bits/slot\n", roundStats, effRate, effRate / (8 * pdsch_pdu_rel15->TBSize[0]) * 100, 8 * pdsch_pdu_rel15->TBSize[0]);
printf(") Avg round %.2f, Eff Rate %.4f bits/slot, Eff Throughput %.2f, TBS %u bits/slot\n",
roundStats,
effRate,
effRate / TBS * 100,
TBS);
printf("*****************************************\n");
printf("\n");
// writing to csv file
@@ -1399,7 +1434,7 @@ int main(int argc, char **argv)
fprintf(csv_file,"%f,%d/%d,",SNR,n_false_positive,n_trials);
for (int r = 0; r < num_rounds; r++)
fprintf(csv_file,"%d/%d,%u/%u,%f,%e,",n_errors[r], round_trials[r], errors_scrambling[r], available_bits * round_trials[r],blerStats[r],berStats[r]);
fprintf(csv_file,"%.2f,%.4f,%.2f,%u\n", roundStats, effRate, effRate / (8 * pdsch_pdu_rel15->TBSize[0]) * 100, 8 * pdsch_pdu_rel15->TBSize[0]);
fprintf(csv_file, "%.2f,%.4f,%.2f,%u\n", roundStats, effRate, effRate / TBS * 100, TBS);
}
if (print_perf==1) {
printf("\ngNB TX function statistics (per %d us slot, NPRB %d, mcs %d, C %d, block %d)\n",
@@ -1407,7 +1442,7 @@ int main(int argc, char **argv)
g_rbSize,
g_mcsIndex,
UE->dl_harq_processes[0][slot].C,
8 * pdsch_pdu_rel15->TBSize[0]);
TBS);
printDistribution(&gNB->phy_proc_tx,table_tx,"PHY proc tx");
printStatIndent2(&gNB->dci_generation_stats, "DCI encoding time");
printStatIndent2(&gNB->dlsch_encoding_stats,"DLSCH encoding time");
@@ -1490,10 +1525,11 @@ int main(int argc, char **argv)
LOG_M("chestF0.m", "chF0", UE->phy_sim_pdsch_dl_ch_estimates, frame_parms->ofdm_symbol_size * 14, dec, op_format);
op_format = (op_format & (~1));
LOG_M("rxF_llr.m", "rxFllr", UE->phy_sim_pdsch_llr, available_bits, dec, op_format);
ret = n_errors[0] == 0 && n_false_positive == 0 ? 0 : 1;
break;
}
if (effRate >= (eff_tp_check * 8 * pdsch_pdu_rel15->TBSize[0])) {
if (effRate >= eff_tp_check * TBS) {
printf("PDSCH test OK\n");
ret = 0;
break;
@@ -1530,8 +1566,6 @@ int main(int argc, char **argv)
free(r_re);
free(r_im);
free(txdata);
free(test_input_bit);
free(estimated_output_bit);
free(UE->phy_sim_rxdataF);
free(UE->phy_sim_pdsch_llr);
free(UE->phy_sim_pdsch_rxdataF_ext);
@@ -2277,6 +2277,14 @@ void init_channelmod(void) {
int load_channellist(uint8_t nb_tx, uint8_t nb_rx, double sampling_rate, uint64_t center_freq, double channel_bandwidth) {
// nakaolab Fix 9: ensure RNG is initialized exactly once, before any
// random_channel call (TDL/EPA/Rayleigh need gaussZiggurat). Static guard
// prevents multiple init races on the global tableNor* arrays.
static bool nakaolab_rng_done = false;
if (!nakaolab_rng_done) {
randominit();
nakaolab_rng_done = true;
}
paramdef_t achannel_params[] = CHANNELMOD_MODEL_PARAMS_DESC;
paramlist_def_t channel_list;
memset(&channel_list,0,sizeof(paramlist_def_t));