mirror of
https://gitlab.eurecom.fr/oai/openairinterface5g.git
synced 2026-07-17 06:30:31 +00:00
Compare commits
10 Commits
develop
...
ul_mu_mimo
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1d8932cbdf | ||
|
|
e7fea4aaec | ||
|
|
506fd4e928 | ||
|
|
157ea51bf9 | ||
|
|
5d3b8f36ef | ||
|
|
c0f741a36c | ||
|
|
05cc5be04f | ||
|
|
a8971f94b8 | ||
|
|
2a7b90e810 | ||
|
|
fcca760982 |
@@ -2099,6 +2099,19 @@ target_link_libraries(nr_srssim PRIVATE
|
||||
m pthread ITTI dl nr_ue_phy_meas physim_common softmodem_common
|
||||
)
|
||||
|
||||
add_executable(nr_ulsim_mu_mimo
|
||||
${OPENAIR1_DIR}/SIMULATION/NR_PHY/ulsim_mu_mimo.c
|
||||
${NFAPI_USER_DIR}/nfapi.c
|
||||
${NFAPI_USER_DIR}/gnb_ind_vars.c
|
||||
${PHY_INTERFACE_DIR}/queue_t.c
|
||||
)
|
||||
|
||||
target_link_libraries(nr_ulsim_mu_mimo PRIVATE
|
||||
-Wl,--start-group UTIL SIMU PHY_NR_COMMON PHY_NR PHY_NR_UE SCHED_NR_LIB SCHED_NR_UE_LIB MAC_UE_NR MAC_NR_COMMON CONFIG_LIB L2_NR -Wl,--end-group
|
||||
m pthread ${T_LIB} ITTI dl nr_ue_phy_meas physim_common softmodem_common NR_L2_UE
|
||||
)
|
||||
target_link_libraries(nr_ulsim_mu_mimo PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs)
|
||||
|
||||
if(CUDA_ENABLE)
|
||||
if (TARGET oai_cuda_lib)
|
||||
target_link_libraries(nr_dlsim PRIVATE oai_cuda_lib)
|
||||
@@ -2156,7 +2169,7 @@ if (${T_TRACER})
|
||||
nr-uesoftmodem dlsim dlsim_tm4 dlsim_tm7
|
||||
ulsim pbchsim scansim mbmssim pdcchsim pucchsim prachsim
|
||||
syncsim nr_ulsim nr_dlsim nr_dlschsim nr_pbchsim nr_pucchsim
|
||||
nr_ulschsim ldpctest polartest smallblocktest nr_srssim
|
||||
nr_ulschsim ldpctest polartest smallblocktest nr_srssim nr_ulsim_mu_mimo
|
||||
#all "add_library" definitions
|
||||
ITTI lte_rrc nr_rrc s1ap x2ap m2ap m3ap f1ap
|
||||
params_libconfig
|
||||
|
||||
@@ -277,7 +277,7 @@ function main() {
|
||||
SIMUS_PHY=1
|
||||
CMAKE_CMD="$CMAKE_CMD -DENABLE_PHYSIM_TESTS=ON"
|
||||
# TODO: fix: dlsim_tm4 pucchsim prachsim pdcchsim pbchsim mbmssim
|
||||
TARGET_LIST="$TARGET_LIST dlsim ulsim ldpctest polartest smallblocktest nr_pbchsim nr_dlschsim nr_ulschsim nr_dlsim nr_ulsim nr_pucchsim nr_prachsim nr_psbchsim nr_srssim"
|
||||
TARGET_LIST="$TARGET_LIST dlsim ulsim ldpctest polartest smallblocktest nr_pbchsim nr_dlschsim nr_ulschsim nr_dlsim nr_ulsim nr_pucchsim nr_prachsim nr_psbchsim nr_srssim nr_ulsim_mu_mimo"
|
||||
echo_info "Will compile dlsim, ulsim, ..."
|
||||
shift;;
|
||||
-V | --vcd)
|
||||
|
||||
@@ -92,13 +92,14 @@ void free_gNB_dlsch(NR_gNB_DLSCH_t *dlsch, uint16_t N_RB, const NR_DL_FRAME_PARM
|
||||
@param frame Frame number
|
||||
@param slot Slot number
|
||||
*/
|
||||
int nr_rx_pusch_tp(PHY_VARS_gNB *gNB,
|
||||
NR_gNB_PUSCH *pusch_vars,
|
||||
const nfapi_nr_pusch_pdu_t *rel15_ul,
|
||||
uint32_t *ret_unav_res,
|
||||
uint32_t frame,
|
||||
uint8_t slot,
|
||||
int beam_nb);
|
||||
int nr_rx_pusch_group_tp(PHY_VARS_gNB *gNB,
|
||||
NR_gNB_PUSCH **pusch_vars,
|
||||
const nfapi_nr_pusch_pdu_t **rel15_ul,
|
||||
uint32_t **ret_unav_res,
|
||||
uint8_t group_size,
|
||||
uint32_t frame,
|
||||
uint8_t slot,
|
||||
int beam_nb);
|
||||
|
||||
/*!
|
||||
\brief This function implements the idft transform precoding in PUSCH
|
||||
@@ -166,7 +167,9 @@ void nr_ulsch_shift_llr(int16_t **llr_layers, uint32_t nb_re, uint32_t rxdataF_e
|
||||
void nr_fill_ulsch(PHY_VARS_gNB *gNB,
|
||||
int frame,
|
||||
int slot,
|
||||
nfapi_nr_pusch_pdu_t *ulsch_pdu);
|
||||
nfapi_nr_pusch_pdu_t *ulsch_pdu,
|
||||
int16_t mu_group_idx,
|
||||
uint8_t mu_group_size);
|
||||
|
||||
void nr_schedule_rx_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu);
|
||||
|
||||
|
||||
@@ -89,8 +89,12 @@ static void dump_pusch_pdu(int instance, int frame, int slot, nfapi_nr_pusch_pdu
|
||||
pusch_pdu->pusch_data.num_cb);
|
||||
}
|
||||
|
||||
|
||||
void nr_fill_ulsch(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_pusch_pdu_t *ulsch_pdu)
|
||||
void nr_fill_ulsch(PHY_VARS_gNB *gNB,
|
||||
int frame,
|
||||
int slot,
|
||||
nfapi_nr_pusch_pdu_t *ulsch_pdu,
|
||||
int16_t mu_group_idx,
|
||||
uint8_t mu_group_size)
|
||||
{
|
||||
dump_pusch_pdu(gNB->Mod_id, frame, slot, ulsch_pdu);
|
||||
LOG_D(NR_PHY,
|
||||
@@ -101,7 +105,11 @@ void nr_fill_ulsch(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_pusch_pdu_t
|
||||
ulsch_pdu->pusch_data.harq_process_id,
|
||||
ulsch_pdu->pusch_data.new_data_indicator);
|
||||
|
||||
NR_gNB_PUSCH_job_t pusch = {.frame = frame, .slot = slot, .pusch_pdu = *ulsch_pdu};
|
||||
NR_gNB_PUSCH_job_t pusch = {.frame = frame,
|
||||
.slot = slot,
|
||||
.pusch_pdu = *ulsch_pdu,
|
||||
.mu_group_idx = mu_group_idx,
|
||||
.mu_group_size = mu_group_size};
|
||||
if (gNB->common_vars.beam_id) {
|
||||
int fapi_beam_idx = ulsch_pdu->beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx;
|
||||
int bitmap = SL_to_bitmap(ulsch_pdu->start_symbol_index, ulsch_pdu->nr_of_symbols);
|
||||
|
||||
@@ -1011,12 +1011,16 @@ typedef struct puschSymbolProc_s {
|
||||
int startSymbol;
|
||||
int numSymbols;
|
||||
int16_t *llr;
|
||||
int16_t *scramblingSequence;
|
||||
uint32_t nvar;
|
||||
int beam_nb;
|
||||
task_ans_t *ans;
|
||||
c16_t *pusch_ch_est_dmrs_interpl_slot_mem;
|
||||
c16_t *rxFext_slot_mem;
|
||||
uint8_t group_size;
|
||||
const nfapi_nr_pusch_pdu_t **rel15_ul_group;
|
||||
NR_gNB_PUSCH **pusch_vars_group;
|
||||
int16_t **scrambling_sequences;
|
||||
int *layer_offsets;
|
||||
} puschSymbolProc_t;
|
||||
|
||||
static void nr_pusch_symbol_processing(void *arg)
|
||||
@@ -1053,22 +1057,34 @@ static void nr_pusch_symbol_processing(void *arg)
|
||||
rdata->pusch_ch_est_dmrs_interpl_slot_mem);
|
||||
|
||||
int nb_re_pusch = pusch_vars->ul_valid_re_per_slot[symbol];
|
||||
// layer de-mapping
|
||||
int16_t *llr_ptr = llrs[0];
|
||||
if (rel15_ul->nrOfLayers != 1) {
|
||||
llr_ptr = &rdata->llr[pusch_vars->llr_offset[symbol] * rel15_ul->nrOfLayers];
|
||||
for (int i = 0; i < (nb_re_pusch); i++)
|
||||
for (int l = 0; l < rel15_ul->nrOfLayers; l++)
|
||||
for (int m = 0; m < rel15_ul->qam_mod_order; m++)
|
||||
llr_ptr[i * rel15_ul->nrOfLayers * rel15_ul->qam_mod_order + l * rel15_ul->qam_mod_order + m] =
|
||||
llrss[l][i * rel15_ul->qam_mod_order + m];
|
||||
|
||||
for (int u = 0; u < rdata->group_size; u++) {
|
||||
NR_gNB_PUSCH *ue_pusch_vars = rdata->pusch_vars_group[u];
|
||||
const nfapi_nr_pusch_pdu_t *ue_pdu = rdata->rel15_ul_group[u];
|
||||
int16_t *ue_scrambling_seq = rdata->scrambling_sequences[u];
|
||||
|
||||
int ue_layers = ue_pdu->nrOfLayers;
|
||||
int qam = ue_pdu->qam_mod_order;
|
||||
|
||||
ue_pusch_vars->llr_offset[symbol] = pusch_vars->llr_offset[symbol];
|
||||
ue_pusch_vars->ul_valid_re_per_slot[symbol] = nb_re_pusch;
|
||||
|
||||
int sym_bit_offset = ue_pusch_vars->llr_offset[symbol] * ue_layers;
|
||||
int16_t *llr_dest = &ue_pusch_vars->llr[sym_bit_offset];
|
||||
int16_t *s_seq = &ue_scrambling_seq[sym_bit_offset];
|
||||
|
||||
for (int i = 0; i < nb_re_pusch; i++) {
|
||||
for (int l = 0; l < ue_layers; l++) {
|
||||
int joint_l = rdata->layer_offsets[u] + l;
|
||||
for (int m = 0; m < qam; m++) {
|
||||
int16_t soft_bit = llrss[joint_l][i * qam + m];
|
||||
|
||||
int bit_idx = i * ue_layers * qam + l * qam + m;
|
||||
llr_dest[bit_idx] = soft_bit * s_seq[bit_idx];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// unscrambling
|
||||
int16_t *llr16 = (int16_t*)&rdata->llr[pusch_vars->llr_offset[symbol] * rel15_ul->nrOfLayers];
|
||||
int16_t *s = rdata->scramblingSequence + pusch_vars->llr_offset[symbol] * rel15_ul->nrOfLayers;
|
||||
const int end = nb_re_pusch * rel15_ul->qam_mod_order * rel15_ul->nrOfLayers;
|
||||
for (int i = 0; i < end; i++)
|
||||
llr16[i] = llr_ptr[i] * s[i];
|
||||
}
|
||||
|
||||
// Task running in // completed
|
||||
@@ -1098,22 +1114,33 @@ static uint32_t average_u32(const uint32_t *x, uint16_t size)
|
||||
return (uint32_t)(sum_x / size);
|
||||
}
|
||||
|
||||
int nr_rx_pusch_tp(PHY_VARS_gNB *gNB,
|
||||
NR_gNB_PUSCH *pusch_vars,
|
||||
const nfapi_nr_pusch_pdu_t *rel15_ul,
|
||||
uint32_t *ret_unav_res,
|
||||
uint32_t frame,
|
||||
uint8_t slot,
|
||||
int beam_nb)
|
||||
int nr_rx_pusch_group_tp(PHY_VARS_gNB *gNB,
|
||||
NR_gNB_PUSCH **pusch_vars_group,
|
||||
const nfapi_nr_pusch_pdu_t **rel15_ul_group,
|
||||
uint32_t **ret_unav_res_group,
|
||||
uint8_t group_size,
|
||||
uint32_t frame,
|
||||
uint8_t slot,
|
||||
int beam_nb)
|
||||
{
|
||||
// This is a reference pdu since all the UEs in the group have same resource related parameters.
|
||||
const nfapi_nr_pusch_pdu_t *rel15_ul_ref = rel15_ul_group[0];
|
||||
NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms;
|
||||
|
||||
uint32_t bwp_start_subcarrier = ((rel15_ul->rb_start + rel15_ul->bwp_start) * NR_NB_SC_PER_RB + frame_parms->first_carrier_offset) % frame_parms->ofdm_symbol_size;
|
||||
LOG_D(PHY,"pusch %d.%d : bwp_start_subcarrier %d, rb_start %d, first_carrier_offset %d\n", frame,slot,bwp_start_subcarrier, rel15_ul->rb_start, frame_parms->first_carrier_offset);
|
||||
LOG_D(PHY,"pusch %d.%d : ul_dmrs_symb_pos %x\n",frame,slot,rel15_ul->ul_dmrs_symb_pos);
|
||||
uint32_t bwp_start_subcarrier =
|
||||
((rel15_ul_ref->rb_start + rel15_ul_ref->bwp_start) * NR_NB_SC_PER_RB + frame_parms->first_carrier_offset)
|
||||
% frame_parms->ofdm_symbol_size;
|
||||
LOG_D(PHY,
|
||||
"pusch %d.%d : bwp_start_subcarrier %d, rb_start %d, first_carrier_offset %d\n",
|
||||
frame,
|
||||
slot,
|
||||
bwp_start_subcarrier,
|
||||
rel15_ul_ref->rb_start,
|
||||
frame_parms->first_carrier_offset);
|
||||
LOG_D(PHY, "pusch %d.%d : ul_dmrs_symb_pos %x\n", frame, slot, rel15_ul_ref->ul_dmrs_symb_pos);
|
||||
|
||||
// Memories to store data for data recording
|
||||
int buffer_length_slot = rel15_ul->rb_size * NR_NB_SC_PER_RB * 14; // 14 OFDM Symbols per slot
|
||||
int buffer_length_slot = rel15_ul_ref->rb_size * NR_NB_SC_PER_RB * NR_SYMBOLS_PER_SLOT;
|
||||
// data recording application supports only a single layer.
|
||||
// nb_rx_ant (= frame_parms->nb_antennas_rx) is limited to 1 for data recording application.
|
||||
// int nb_layer (= rel15_ul->nrOfLayers) is limited to 1 for data recording application.
|
||||
@@ -1145,40 +1172,85 @@ int nr_rx_pusch_tp(PHY_VARS_gNB *gNB,
|
||||
memset(rxFext_slot_mem, 0, sizeof(c16_t) * buffer_length_slot * 1 * 1);
|
||||
#endif
|
||||
|
||||
// Create a virtual multi layer pdu by accumulating the layers over UEs in the group and storing dmrs ports for joint processing
|
||||
uint32_t combined_dmrs_ports = 0;
|
||||
int total_layers = 0;
|
||||
int layer_offset[group_size];
|
||||
for (int u = 0; u < group_size; u++) {
|
||||
const nfapi_nr_pusch_pdu_t *p = rel15_ul_group[u];
|
||||
combined_dmrs_ports |= p->dmrs_ports;
|
||||
layer_offset[u] = total_layers;
|
||||
total_layers += rel15_ul_group[u]->nrOfLayers;
|
||||
}
|
||||
AssertFatal(total_layers <= NR_MAX_NB_LAYERS,
|
||||
"MU-MIMO group total_layers=%d > NR_MAX_NB_LAYERS=%d\n",
|
||||
total_layers,
|
||||
NR_MAX_NB_LAYERS);
|
||||
|
||||
nfapi_nr_pusch_pdu_t joint_pdu = *rel15_ul_ref;
|
||||
joint_pdu.nrOfLayers = total_layers;
|
||||
joint_pdu.dmrs_ports = combined_dmrs_ports;
|
||||
|
||||
NR_gNB_PUSCH *joint_pv = pusch_vars_group[0];
|
||||
LOG_D(PHY,
|
||||
"%4u.%u MU-MIMO joint RX: %d UEs, %d total layers, rb_start=%u rb_size=%u qam=%u\n",
|
||||
frame,
|
||||
slot,
|
||||
group_size,
|
||||
total_layers,
|
||||
rel15_ul_ref->rb_start,
|
||||
rel15_ul_ref->rb_size,
|
||||
rel15_ul_ref->qam_mod_order);
|
||||
|
||||
//----------------------------------------------------------
|
||||
//------------------- Channel estimation -------------------
|
||||
//----------------------------------------------------------
|
||||
start_meas(&gNB->ulsch_channel_estimation_stats);
|
||||
int max_ch = 0;
|
||||
uint32_t nvar = 0;
|
||||
int end_symbol = rel15_ul->start_symbol_index + rel15_ul->nr_of_symbols;
|
||||
for (uint8_t symbol = rel15_ul->start_symbol_index; symbol < end_symbol; symbol++) {
|
||||
uint8_t dmrs_symbol_flag = (rel15_ul->ul_dmrs_symb_pos >> symbol) & 0x01;
|
||||
int end_symbol = rel15_ul_ref->start_symbol_index + rel15_ul_ref->nr_of_symbols;
|
||||
for (uint8_t symbol = rel15_ul_ref->start_symbol_index; symbol < end_symbol; symbol++) {
|
||||
uint8_t dmrs_symbol_flag = (rel15_ul_ref->ul_dmrs_symb_pos >> symbol) & 0x01;
|
||||
LOG_D(PHY, "symbol %d, dmrs_symbol_flag :%d\n", symbol, dmrs_symbol_flag);
|
||||
|
||||
if (dmrs_symbol_flag == 1) {
|
||||
for (int nl = 0; nl < rel15_ul->nrOfLayers; nl++) {
|
||||
uint32_t nvar_tmp = 0;
|
||||
nr_pusch_channel_estimation(gNB,
|
||||
slot,
|
||||
nl,
|
||||
get_dmrs_port(nl, rel15_ul->dmrs_ports),
|
||||
symbol,
|
||||
pusch_vars,
|
||||
beam_nb,
|
||||
bwp_start_subcarrier,
|
||||
rel15_ul,
|
||||
&max_ch,
|
||||
&nvar_tmp,
|
||||
pusch_dmrs_slot_mem,
|
||||
pusch_ch_est_dmrs_pos_slot_mem);
|
||||
nvar += nvar_tmp;
|
||||
for (int u = 0; u < group_size; u++) {
|
||||
const nfapi_nr_pusch_pdu_t *p = rel15_ul_group[u];
|
||||
for (int nl = 0; nl < p->nrOfLayers; nl++) {
|
||||
int global_layer = layer_offset[u] + nl;
|
||||
uint32_t nvar_tmp = 0;
|
||||
nr_pusch_channel_estimation(gNB,
|
||||
slot,
|
||||
global_layer,
|
||||
get_dmrs_port(nl, p->dmrs_ports),
|
||||
symbol,
|
||||
joint_pv,
|
||||
beam_nb,
|
||||
bwp_start_subcarrier,
|
||||
&joint_pdu,
|
||||
&max_ch,
|
||||
&nvar_tmp,
|
||||
pusch_dmrs_slot_mem,
|
||||
pusch_ch_est_dmrs_pos_slot_mem);
|
||||
nvar += nvar_tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nvar /= (rel15_ul->nr_of_symbols * rel15_ul->nrOfLayers * frame_parms->nb_antennas_rx);
|
||||
nvar /= (rel15_ul_ref->nr_of_symbols * total_layers * frame_parms->nb_antennas_rx);
|
||||
|
||||
// averaging time domain channel estimates
|
||||
// Change to joint processing
|
||||
if (gNB->chest_time == 1)
|
||||
nr_chest_time_domain_avg(frame_parms,
|
||||
joint_pv->ul_ch_estimates,
|
||||
rel15_ul_ref->nr_of_symbols,
|
||||
rel15_ul_ref->start_symbol_index,
|
||||
rel15_ul_ref->ul_dmrs_symb_pos, // change needed ?
|
||||
rel15_ul_ref->rb_size);
|
||||
|
||||
// ULSCH signal and noise power measurements
|
||||
// This is same for all the UEs in the group
|
||||
allocCast2D(n0_subband_power,
|
||||
unsigned int,
|
||||
gNB->measurements.n0_subband_power,
|
||||
@@ -1186,15 +1258,15 @@ int nr_rx_pusch_tp(PHY_VARS_gNB *gNB,
|
||||
frame_parms->N_RB_UL,
|
||||
false);
|
||||
|
||||
int start_sc = (rel15_ul->bwp_start + rel15_ul->rb_start) * NR_NB_SC_PER_RB;
|
||||
int start_sc = (rel15_ul_ref->bwp_start + rel15_ul_ref->rb_start) * NR_NB_SC_PER_RB;
|
||||
int middle_sc = frame_parms->ofdm_symbol_size - frame_parms->first_carrier_offset;
|
||||
int end_sc = (start_sc + rel15_ul->rb_size * NR_NB_SC_PER_RB - 1) % frame_parms->ofdm_symbol_size;
|
||||
int end_sc = (start_sc + rel15_ul_ref->rb_size * NR_NB_SC_PER_RB - 1) % frame_parms->ofdm_symbol_size;
|
||||
for (int aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) {
|
||||
pusch_vars->ulsch_power[aarx] = 0;
|
||||
pusch_vars->ulsch_noise_power[aarx] = 0;
|
||||
joint_pv->ulsch_power[aarx] = 0;
|
||||
joint_pv->ulsch_noise_power[aarx] = 0;
|
||||
int64_t symb_energy = 0;
|
||||
|
||||
for (uint8_t symbol = rel15_ul->start_symbol_index; symbol < end_symbol; symbol++) {
|
||||
for (uint8_t symbol = rel15_ul_ref->start_symbol_index; symbol < end_symbol; symbol++) {
|
||||
int offset0 = ((slot % RU_RX_SLOT_DEPTH) * frame_parms->symbols_per_slot + symbol) * frame_parms->ofdm_symbol_size;
|
||||
int offset = offset0 + (frame_parms->first_carrier_offset + start_sc) % frame_parms->ofdm_symbol_size;
|
||||
c16_t *ul_ch = &gNB->common_vars.rxdataF[beam_nb][aarx][offset];
|
||||
@@ -1202,82 +1274,78 @@ int nr_rx_pusch_tp(PHY_VARS_gNB *gNB,
|
||||
int64_t symb_energy_aux = signal_energy_nodc(ul_ch, middle_sc - start_sc) * (middle_sc - start_sc);
|
||||
ul_ch = &gNB->common_vars.rxdataF[beam_nb][aarx][offset0];
|
||||
symb_energy_aux += (signal_energy_nodc(ul_ch, end_sc + 1) * (end_sc + 1));
|
||||
symb_energy += symb_energy_aux / (rel15_ul->rb_size * NR_NB_SC_PER_RB);
|
||||
symb_energy += symb_energy_aux / (rel15_ul_ref->rb_size * NR_NB_SC_PER_RB);
|
||||
} else {
|
||||
symb_energy += signal_energy_nodc(ul_ch, rel15_ul->rb_size * NR_NB_SC_PER_RB);
|
||||
symb_energy += signal_energy_nodc(ul_ch, rel15_ul_ref->rb_size * NR_NB_SC_PER_RB);
|
||||
}
|
||||
}
|
||||
pusch_vars->ulsch_power[aarx] += (symb_energy / rel15_ul->nr_of_symbols);
|
||||
joint_pv->ulsch_power[aarx] += (symb_energy / rel15_ul_ref->nr_of_symbols);
|
||||
|
||||
pusch_vars->ulsch_noise_power[aarx] +=
|
||||
average_u32(&n0_subband_power[aarx][rel15_ul->bwp_start + rel15_ul->rb_start], rel15_ul->rb_size);
|
||||
joint_pv->ulsch_noise_power[aarx] +=
|
||||
average_u32(&n0_subband_power[aarx][rel15_ul_ref->bwp_start + rel15_ul_ref->rb_start], rel15_ul_ref->rb_size);
|
||||
|
||||
LOG_D(PHY,
|
||||
"aa %d, bwp_start%d, rb_start %d, rb_size %d: ulsch_power %d, ulsch_noise_power %d\n",
|
||||
aarx,
|
||||
rel15_ul->bwp_start,
|
||||
rel15_ul->rb_start,
|
||||
rel15_ul->rb_size,
|
||||
pusch_vars->ulsch_power[aarx],
|
||||
pusch_vars->ulsch_noise_power[aarx]);
|
||||
rel15_ul_ref->bwp_start,
|
||||
rel15_ul_ref->rb_start,
|
||||
rel15_ul_ref->rb_size,
|
||||
joint_pv->ulsch_power[aarx],
|
||||
joint_pv->ulsch_noise_power[aarx]);
|
||||
}
|
||||
|
||||
// averaging time domain channel estimates
|
||||
if (gNB->chest_time == 1)
|
||||
nr_chest_time_domain_avg(frame_parms,
|
||||
pusch_vars->ul_ch_estimates,
|
||||
rel15_ul->nr_of_symbols,
|
||||
rel15_ul->start_symbol_index,
|
||||
rel15_ul->ul_dmrs_symb_pos,
|
||||
rel15_ul->rb_size);
|
||||
|
||||
stop_meas(&gNB->ulsch_channel_estimation_stats);
|
||||
|
||||
start_meas(&gNB->rx_pusch_init_stats);
|
||||
|
||||
// Scrambling initialization
|
||||
int number_dmrs_symbols = 0;
|
||||
for (int l = rel15_ul->start_symbol_index; l < end_symbol; l++)
|
||||
number_dmrs_symbols += ((rel15_ul->ul_dmrs_symb_pos)>>l) & 0x01;
|
||||
int nb_re_dmrs;
|
||||
if (rel15_ul->dmrs_config_type == pusch_dmrs_type1)
|
||||
nb_re_dmrs = 6*rel15_ul->num_dmrs_cdm_grps_no_data;
|
||||
else
|
||||
nb_re_dmrs = 4*rel15_ul->num_dmrs_cdm_grps_no_data;
|
||||
|
||||
// Calculate number of unavailable resources due to PTRS
|
||||
// This is assumed to be same for all the UEs (same PTRS configuration for all UEs)
|
||||
uint32_t unav_res = 0;
|
||||
if (rel15_ul->pdu_bit_map & PUSCH_PDU_BITMAP_PUSCH_PTRS) {
|
||||
if (rel15_ul_ref->pdu_bit_map & PUSCH_PDU_BITMAP_PUSCH_PTRS) {
|
||||
uint16_t ptrsSymbPos = 0;
|
||||
set_ptrs_symb_idx(&ptrsSymbPos,
|
||||
rel15_ul->nr_of_symbols,
|
||||
rel15_ul->start_symbol_index,
|
||||
1 << rel15_ul->pusch_ptrs.ptrs_time_density,
|
||||
rel15_ul->ul_dmrs_symb_pos);
|
||||
int ptrsSymbPerSlot = get_ptrs_symbols_in_slot(ptrsSymbPos, rel15_ul->start_symbol_index, rel15_ul->nr_of_symbols);
|
||||
int n_ptrs = (rel15_ul->rb_size + rel15_ul->pusch_ptrs.ptrs_freq_density - 1) / rel15_ul->pusch_ptrs.ptrs_freq_density;
|
||||
rel15_ul_ref->nr_of_symbols,
|
||||
rel15_ul_ref->start_symbol_index,
|
||||
1 << rel15_ul_ref->pusch_ptrs.ptrs_time_density,
|
||||
rel15_ul_ref->ul_dmrs_symb_pos);
|
||||
int ptrsSymbPerSlot = get_ptrs_symbols_in_slot(ptrsSymbPos, rel15_ul_ref->start_symbol_index, rel15_ul_ref->nr_of_symbols);
|
||||
int n_ptrs =
|
||||
(rel15_ul_ref->rb_size + rel15_ul_ref->pusch_ptrs.ptrs_freq_density - 1) / rel15_ul_ref->pusch_ptrs.ptrs_freq_density;
|
||||
unav_res = n_ptrs * ptrsSymbPerSlot;
|
||||
}
|
||||
|
||||
// get how many bit in a slot //
|
||||
int G = nr_get_G(rel15_ul->rb_size,
|
||||
rel15_ul->nr_of_symbols,
|
||||
nb_re_dmrs,
|
||||
number_dmrs_symbols, // number of dmrs symbols irrespective of single or double symbol dmrs
|
||||
unav_res,
|
||||
rel15_ul->qam_mod_order,
|
||||
rel15_ul->nrOfLayers);
|
||||
*ret_unav_res = unav_res;
|
||||
// Scrambling initialization
|
||||
int number_dmrs_symbols = 0;
|
||||
for (int l = rel15_ul_ref->start_symbol_index; l < end_symbol; l++)
|
||||
number_dmrs_symbols += ((rel15_ul_ref->ul_dmrs_symb_pos) >> l) & 0x01;
|
||||
int nb_re_dmrs;
|
||||
if (rel15_ul_ref->dmrs_config_type == pusch_dmrs_type1)
|
||||
nb_re_dmrs = 6 * rel15_ul_ref->num_dmrs_cdm_grps_no_data;
|
||||
else
|
||||
nb_re_dmrs = 4 * rel15_ul_ref->num_dmrs_cdm_grps_no_data;
|
||||
|
||||
// initialize scrambling sequence //
|
||||
int16_t scramblingSequence[G + 96] __attribute__((aligned(32)));
|
||||
int max_G = 0;
|
||||
for (int u = 0; u < group_size; u++) {
|
||||
const nfapi_nr_pusch_pdu_t *p = rel15_ul_group[u];
|
||||
int G_u = nr_get_G(p->rb_size, p->nr_of_symbols, nb_re_dmrs, number_dmrs_symbols, unav_res, p->qam_mod_order, p->nrOfLayers);
|
||||
if (G_u > max_G)
|
||||
max_G = G_u;
|
||||
}
|
||||
|
||||
nr_codeword_unscrambling_init(scramblingSequence, G, 0, rel15_ul->data_scrambling_id, rel15_ul->rnti);
|
||||
int16_t scrambling_sequences[group_size][max_G + 96] __attribute__((aligned(32)));
|
||||
int16_t *scrambling_sequences_arr[group_size];
|
||||
|
||||
// first the computation of channel levels
|
||||
for (int u = 0; u < group_size; u++) {
|
||||
scrambling_sequences_arr[u] = scrambling_sequences[u];
|
||||
const nfapi_nr_pusch_pdu_t *p = rel15_ul_group[u];
|
||||
int G_u = nr_get_G(p->rb_size, p->nr_of_symbols, nb_re_dmrs, number_dmrs_symbols, unav_res, p->qam_mod_order, p->nrOfLayers);
|
||||
nr_codeword_unscrambling_init(scrambling_sequences_arr[u], G_u, 0, p->data_scrambling_id, p->rnti);
|
||||
}
|
||||
|
||||
// Computation of channel levels
|
||||
int nb_re_pusch = 0, meas_symbol = -1;
|
||||
for(meas_symbol = rel15_ul->start_symbol_index; meas_symbol < end_symbol; meas_symbol++)
|
||||
if ((nb_re_pusch = get_nb_re_pusch(frame_parms, rel15_ul, meas_symbol)) > 0)
|
||||
for (meas_symbol = rel15_ul_ref->start_symbol_index; meas_symbol < end_symbol; meas_symbol++)
|
||||
if ((nb_re_pusch = get_nb_re_pusch(frame_parms, &joint_pdu, meas_symbol)) > 0)
|
||||
break;
|
||||
|
||||
AssertFatal(nb_re_pusch > 0 && meas_symbol >= 0,
|
||||
@@ -1292,27 +1360,27 @@ int nr_rx_pusch_tp(PHY_VARS_gNB *gNB,
|
||||
nb_re_pusch = ceil_mod(nb_re_pusch, 16);
|
||||
int dmrs_symbol;
|
||||
if (gNB->chest_time == 0)
|
||||
dmrs_symbol = get_valid_dmrs_idx_for_channel_est(rel15_ul->ul_dmrs_symb_pos, meas_symbol);
|
||||
dmrs_symbol = get_valid_dmrs_idx_for_channel_est(rel15_ul_ref->ul_dmrs_symb_pos, meas_symbol);
|
||||
else // average of channel estimates stored in first symbol
|
||||
dmrs_symbol = get_next_dmrs_symbol_in_slot(rel15_ul->ul_dmrs_symb_pos, rel15_ul->start_symbol_index, end_symbol);
|
||||
dmrs_symbol = get_next_dmrs_symbol_in_slot(rel15_ul_ref->ul_dmrs_symb_pos, rel15_ul_ref->start_symbol_index, end_symbol);
|
||||
int size_est = nb_re_pusch * frame_parms->symbols_per_slot;
|
||||
__attribute__((aligned(32))) int ul_ch_estimates_ext[rel15_ul->nrOfLayers * frame_parms->nb_antennas_rx][size_est];
|
||||
__attribute__((aligned(32))) int ul_ch_estimates_ext[total_layers * frame_parms->nb_antennas_rx][size_est];
|
||||
memset(ul_ch_estimates_ext, 0, sizeof(ul_ch_estimates_ext));
|
||||
int buffer_length = rel15_ul->rb_size * NR_NB_SC_PER_RB;
|
||||
int buffer_length = rel15_ul_ref->rb_size * NR_NB_SC_PER_RB;
|
||||
c16_t temp_rxFext[frame_parms->nb_antennas_rx][buffer_length] __attribute__((aligned(32)));
|
||||
for (int aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++)
|
||||
for (int nl = 0; nl < rel15_ul->nrOfLayers; nl++)
|
||||
for (int aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++)
|
||||
for (int nl = 0; nl < total_layers; nl++)
|
||||
nr_ulsch_extract_rbs(gNB->common_vars.rxdataF[beam_nb][aarx],
|
||||
(c16_t *)pusch_vars->ul_ch_estimates[nl * frame_parms->nb_antennas_rx + aarx],
|
||||
(c16_t *)joint_pv->ul_ch_estimates[nl * frame_parms->nb_antennas_rx + aarx],
|
||||
temp_rxFext[aarx],
|
||||
(c16_t*)&ul_ch_estimates_ext[nl * frame_parms->nb_antennas_rx + aarx][meas_symbol * nb_re_pusch],
|
||||
(c16_t *)&ul_ch_estimates_ext[nl * frame_parms->nb_antennas_rx + aarx][meas_symbol * nb_re_pusch],
|
||||
soffset + meas_symbol * frame_parms->ofdm_symbol_size,
|
||||
dmrs_symbol * frame_parms->ofdm_symbol_size,
|
||||
(rel15_ul->ul_dmrs_symb_pos >> meas_symbol) & 0x01,
|
||||
rel15_ul,
|
||||
(rel15_ul_ref->ul_dmrs_symb_pos >> meas_symbol) & 0x01,
|
||||
&joint_pdu,
|
||||
frame_parms);
|
||||
|
||||
uint8_t shift_ch_ext = rel15_ul->nrOfLayers > 1 ? log2_approx(max_ch >> 11) : 0;
|
||||
uint8_t shift_ch_ext = total_layers > 1 ? log2_approx(max_ch >> 11) : 0;
|
||||
|
||||
//----------------------------------------------------------
|
||||
//--------------------- Channel Scaling --------------------
|
||||
@@ -1321,54 +1389,55 @@ int nr_rx_pusch_tp(PHY_VARS_gNB *gNB,
|
||||
ul_ch_estimates_ext,
|
||||
meas_symbol,
|
||||
nb_re_pusch,
|
||||
rel15_ul->nrOfLayers,
|
||||
total_layers,
|
||||
frame_parms->nb_antennas_rx,
|
||||
shift_ch_ext);
|
||||
|
||||
int avg[frame_parms->nb_antennas_rx*rel15_ul->nrOfLayers];
|
||||
int avg[frame_parms->nb_antennas_rx * total_layers];
|
||||
nr_channel_level(meas_symbol,
|
||||
size_est,
|
||||
(c16_t (*)[size_est])ul_ch_estimates_ext,
|
||||
(c16_t(*)[size_est])ul_ch_estimates_ext,
|
||||
frame_parms->nb_antennas_rx,
|
||||
rel15_ul->nrOfLayers,
|
||||
total_layers,
|
||||
avg,
|
||||
nb_re_pusch);
|
||||
|
||||
int avgs = 0;
|
||||
for (int nl = 0; nl < rel15_ul->nrOfLayers; nl++)
|
||||
for (int nl = 0; nl < total_layers; nl++)
|
||||
for (int aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++)
|
||||
avgs = cmax(avgs, avg[nl * frame_parms->nb_antennas_rx + aarx]);
|
||||
|
||||
if (rel15_ul->nrOfLayers == 2 && rel15_ul->qam_mod_order > 6)
|
||||
pusch_vars->log2_maxh = (log2_approx(avgs) >> 1) - 3; // for MMSE
|
||||
else if (rel15_ul->nrOfLayers == 2)
|
||||
pusch_vars->log2_maxh = (log2_approx(avgs) >> 1) - 2 + log2_approx(frame_parms->nb_antennas_rx >> 1);
|
||||
else
|
||||
pusch_vars->log2_maxh = (log2_approx(avgs) >> 1) + 1 + log2_approx(frame_parms->nb_antennas_rx >> 1);
|
||||
if (total_layers == 2 && rel15_ul_ref->qam_mod_order > 6)
|
||||
joint_pv->log2_maxh = (log2_approx(avgs) >> 1) - 3; // for MMSE
|
||||
else if (total_layers == 2)
|
||||
joint_pv->log2_maxh = (log2_approx(avgs) >> 1) - 2 + log2_approx(frame_parms->nb_antennas_rx >> 1);
|
||||
else
|
||||
joint_pv->log2_maxh = (log2_approx(avgs) >> 1) + 1 + log2_approx(frame_parms->nb_antennas_rx >> 1);
|
||||
|
||||
if (pusch_vars->log2_maxh < 0)
|
||||
pusch_vars->log2_maxh = 0;
|
||||
if (joint_pv->log2_maxh < 0)
|
||||
joint_pv->log2_maxh = 0;
|
||||
|
||||
stop_meas(&gNB->rx_pusch_init_stats);
|
||||
|
||||
start_meas(&gNB->rx_pusch_symbol_processing_stats);
|
||||
int numSymbols = gNB->num_pusch_symbols_per_thread;
|
||||
int total_res = 0;
|
||||
int const loop_iter = CEILIDIV(rel15_ul->nr_of_symbols, numSymbols);
|
||||
int const loop_iter = CEILIDIV(rel15_ul_ref->nr_of_symbols, numSymbols);
|
||||
puschSymbolProc_t arr[loop_iter];
|
||||
task_ans_t ans;
|
||||
init_task_ans(&ans, loop_iter);
|
||||
|
||||
int sz_arr = 0;
|
||||
for(uint8_t task_index = 0; task_index < loop_iter; task_index++) {
|
||||
int symbol = task_index * numSymbols + rel15_ul->start_symbol_index;
|
||||
int symbol = task_index * numSymbols + rel15_ul_ref->start_symbol_index;
|
||||
int res_per_task = 0;
|
||||
for (int s = 0; s < numSymbols && s + symbol < end_symbol; s++) {
|
||||
pusch_vars->ul_valid_re_per_slot[symbol+s] = get_nb_re_pusch(frame_parms,rel15_ul,symbol+s);
|
||||
pusch_vars->llr_offset[symbol+s] = ((symbol+s) == rel15_ul->start_symbol_index) ?
|
||||
0 :
|
||||
pusch_vars->llr_offset[symbol+s-1] + pusch_vars->ul_valid_re_per_slot[symbol+s-1] * rel15_ul->qam_mod_order;
|
||||
res_per_task += pusch_vars->ul_valid_re_per_slot[symbol + s];
|
||||
joint_pv->ul_valid_re_per_slot[symbol + s] = get_nb_re_pusch(frame_parms, &joint_pdu, symbol + s);
|
||||
joint_pv->llr_offset[symbol + s] =
|
||||
((symbol + s) == rel15_ul_ref->start_symbol_index)
|
||||
? 0
|
||||
: joint_pv->llr_offset[symbol + s - 1] + joint_pv->ul_valid_re_per_slot[symbol + s - 1] * rel15_ul_ref->qam_mod_order;
|
||||
res_per_task += joint_pv->ul_valid_re_per_slot[symbol + s];
|
||||
}
|
||||
total_res += res_per_task;
|
||||
if (res_per_task > 0) {
|
||||
@@ -1378,20 +1447,24 @@ int nr_rx_pusch_tp(PHY_VARS_gNB *gNB,
|
||||
|
||||
rdata->gNB = gNB;
|
||||
rdata->frame_parms = frame_parms;
|
||||
rdata->rel15_ul = rel15_ul;
|
||||
rdata->rel15_ul = &joint_pdu;
|
||||
rdata->slot = slot;
|
||||
rdata->startSymbol = symbol;
|
||||
// Last task processes remainder symbols
|
||||
rdata->numSymbols = task_index == loop_iter - 1 ? rel15_ul->nr_of_symbols - (loop_iter - 1) * numSymbols : numSymbols;
|
||||
rdata->pusch_vars = pusch_vars;
|
||||
rdata->llr = pusch_vars->llr;
|
||||
rdata->scramblingSequence = scramblingSequence;
|
||||
rdata->numSymbols = task_index == loop_iter - 1 ? rel15_ul_ref->nr_of_symbols - (loop_iter - 1) * numSymbols : numSymbols;
|
||||
rdata->pusch_vars = joint_pv;
|
||||
rdata->llr = joint_pv->llr;
|
||||
rdata->nvar = nvar;
|
||||
rdata->beam_nb = beam_nb;
|
||||
rdata->rxFext_slot_mem = rxFext_slot_mem;
|
||||
rdata->pusch_ch_est_dmrs_interpl_slot_mem = pusch_ch_est_dmrs_interpl_slot_mem;
|
||||
rdata->group_size = group_size;
|
||||
rdata->rel15_ul_group = rel15_ul_group;
|
||||
rdata->pusch_vars_group = pusch_vars_group;
|
||||
rdata->scrambling_sequences = scrambling_sequences_arr;
|
||||
rdata->layer_offsets = layer_offset;
|
||||
|
||||
if (rel15_ul->pdu_bit_map & PUSCH_PDU_BITMAP_PUSCH_PTRS) {
|
||||
if (rel15_ul_ref->pdu_bit_map & PUSCH_PDU_BITMAP_PUSCH_PTRS) {
|
||||
nr_pusch_symbol_processing(rdata);
|
||||
} else {
|
||||
task_t t = {.func = &nr_pusch_symbol_processing, .args = rdata};
|
||||
@@ -1405,52 +1478,85 @@ int nr_rx_pusch_tp(PHY_VARS_gNB *gNB,
|
||||
} // symbol loop
|
||||
|
||||
#if T_TRACER
|
||||
int dmrs_port = get_dmrs_port(0, rel15_ul->dmrs_ports);
|
||||
int dmrs_port = get_dmrs_port(0, rel15_ul_ref->dmrs_ports);
|
||||
|
||||
log_ul_fd_dmrs(frame, slot, frame_parms, rel15_ul,
|
||||
number_dmrs_symbols, dmrs_port,
|
||||
log_ul_fd_dmrs(frame,
|
||||
slot,
|
||||
frame_parms,
|
||||
rel15_ul_ref,
|
||||
number_dmrs_symbols,
|
||||
dmrs_port,
|
||||
(const c16_t *)(&(pusch_dmrs_slot_mem[0])),
|
||||
rel15_ul->rb_size * NR_NB_SC_PER_RB * rel15_ul->nr_of_symbols * 4);
|
||||
rel15_ul_ref->rb_size * NR_NB_SC_PER_RB * rel15_ul_ref->nr_of_symbols * 4);
|
||||
|
||||
log_ul_fd_chan_est_dmrs_pos(frame, slot, frame_parms, rel15_ul,
|
||||
number_dmrs_symbols, dmrs_port,
|
||||
log_ul_fd_chan_est_dmrs_pos(frame,
|
||||
slot,
|
||||
frame_parms,
|
||||
rel15_ul_ref,
|
||||
number_dmrs_symbols,
|
||||
dmrs_port,
|
||||
(const c16_t *)(&(pusch_ch_est_dmrs_pos_slot_mem[0])),
|
||||
rel15_ul->rb_size * NR_NB_SC_PER_RB * rel15_ul->nr_of_symbols * 4);
|
||||
rel15_ul_ref->rb_size * NR_NB_SC_PER_RB * rel15_ul_ref->nr_of_symbols * 4);
|
||||
|
||||
log_ul_fd_pusch_iq(frame, slot, frame_parms, rel15_ul,
|
||||
number_dmrs_symbols, dmrs_port,
|
||||
log_ul_fd_pusch_iq(frame,
|
||||
slot,
|
||||
frame_parms,
|
||||
rel15_ul_ref,
|
||||
number_dmrs_symbols,
|
||||
dmrs_port,
|
||||
(const c16_t *)(&(rxFext_slot_mem[0])),
|
||||
rel15_ul->rb_size * NR_NB_SC_PER_RB * rel15_ul->nr_of_symbols * frame_parms->nb_antennas_rx * 4);
|
||||
rel15_ul_ref->rb_size * NR_NB_SC_PER_RB * rel15_ul_ref->nr_of_symbols * frame_parms->nb_antennas_rx * 4);
|
||||
|
||||
log_ul_fd_chan_est_dmrs_interpl(frame, slot, frame_parms, rel15_ul,
|
||||
number_dmrs_symbols, dmrs_port,
|
||||
(const c16_t *)pusch_ch_est_dmrs_interpl_slot_mem,
|
||||
rel15_ul->rb_size * NR_NB_SC_PER_RB * rel15_ul->nr_of_symbols
|
||||
* frame_parms->nb_antennas_rx * rel15_ul->nrOfLayers * 4);
|
||||
log_ul_fd_chan_est_dmrs_interpl(
|
||||
frame,
|
||||
slot,
|
||||
frame_parms,
|
||||
rel15_ul_ref,
|
||||
number_dmrs_symbols,
|
||||
dmrs_port,
|
||||
(const c16_t *)pusch_ch_est_dmrs_interpl_slot_mem,
|
||||
rel15_ul_ref->rb_size * NR_NB_SC_PER_RB * rel15_ul_ref->nr_of_symbols * frame_parms->nb_antennas_rx * total_layers * 4);
|
||||
#endif
|
||||
|
||||
join_task_ans(&ans);
|
||||
|
||||
for (int u = 0; u < group_size; u++) {
|
||||
NR_gNB_PUSCH *pv = pusch_vars_group[u];
|
||||
// Copy unavailable resources per UE
|
||||
*ret_unav_res_group[u] = unav_res;
|
||||
// Copy power measurements per UE
|
||||
pv->ulsch_power_tot = 0;
|
||||
pv->ulsch_noise_power_tot = 0;
|
||||
for (int aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) {
|
||||
pv->ulsch_power[aarx] = joint_pv->ulsch_power[aarx];
|
||||
pv->ulsch_noise_power[aarx] = joint_pv->ulsch_noise_power[aarx];
|
||||
pv->ulsch_power_tot += pv->ulsch_power[aarx];
|
||||
pv->ulsch_noise_power_tot += pv->ulsch_noise_power[aarx];
|
||||
}
|
||||
}
|
||||
|
||||
stop_meas(&gNB->rx_pusch_symbol_processing_stats);
|
||||
|
||||
// Copy the data to the scope. This cannot be performed in one call to gNBscopeCopy because the data is not contiguous in the
|
||||
// buffer due to reference symbol extraction and padding. The gNBscopeCopy call is broken up into steps: trylock, copy, unlock.
|
||||
metadata mt = {.slot = slot, .frame = frame};
|
||||
if (gNBTryLockScopeData(gNB, gNBPuschRxIq, sizeof(c16_t), 1, total_res, &mt)) {
|
||||
int buffer_length = ceil_mod(rel15_ul->rb_size * NR_NB_SC_PER_RB, 16);
|
||||
int buffer_length = ceil_mod(rel15_ul_ref->rb_size * NR_NB_SC_PER_RB, 16);
|
||||
size_t offset = 0;
|
||||
for (uint8_t symbol = rel15_ul->start_symbol_index; symbol < (rel15_ul->start_symbol_index + rel15_ul->nr_of_symbols);
|
||||
for (uint8_t symbol = rel15_ul_ref->start_symbol_index;
|
||||
symbol < (rel15_ul_ref->start_symbol_index + rel15_ul_ref->nr_of_symbols);
|
||||
symbol++) {
|
||||
gNBscopeCopyUnsafe(gNB,
|
||||
gNBPuschRxIq,
|
||||
&pusch_vars->rxdataF_comp[0][symbol * buffer_length],
|
||||
sizeof(c16_t) * pusch_vars->ul_valid_re_per_slot[symbol],
|
||||
&pusch_vars_group[0]->rxdataF_comp[0][symbol * buffer_length],
|
||||
sizeof(c16_t) * pusch_vars_group[0]->ul_valid_re_per_slot[symbol],
|
||||
offset,
|
||||
symbol - rel15_ul->start_symbol_index);
|
||||
offset += sizeof(c16_t) * pusch_vars->ul_valid_re_per_slot[symbol];
|
||||
symbol - rel15_ul_ref->start_symbol_index);
|
||||
offset += sizeof(c16_t) * pusch_vars_group[0]->ul_valid_re_per_slot[symbol];
|
||||
}
|
||||
gNBunlockScopeData(gNB, gNBPuschRxIq)
|
||||
}
|
||||
uint32_t total_llrs = total_res * rel15_ul->qam_mod_order * rel15_ul->nrOfLayers;
|
||||
gNBscopeCopyWithMetadata(gNB, gNBPuschLlr, pusch_vars->llr, sizeof(c16_t), 1, total_llrs, 0, &mt);
|
||||
uint32_t total_llrs = total_res * rel15_ul_ref->qam_mod_order * rel15_ul_ref->nrOfLayers;
|
||||
gNBscopeCopyWithMetadata(gNB, gNBPuschLlr, pusch_vars_group[0]->llr, sizeof(c16_t), 1, total_llrs, 0, &mt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -189,6 +189,11 @@ typedef struct {
|
||||
uint32_t slot;
|
||||
/// ULSCH PDU
|
||||
nfapi_nr_pusch_pdu_t pusch_pdu;
|
||||
// Multi-User (MU) group index
|
||||
// -1 : unallocated
|
||||
int16_t mu_group_idx;
|
||||
// 1 for Single-User (SU) and > 1 is MU
|
||||
uint8_t mu_group_size;
|
||||
} NR_gNB_PUSCH_job_t;
|
||||
|
||||
typedef struct {
|
||||
|
||||
@@ -939,18 +939,15 @@ static void handle_pucch(PHY_VARS_gNB *gNB, c16_t **rxdataF, const NR_gNB_PUCCH_
|
||||
}
|
||||
}
|
||||
|
||||
static bool handle_pusch_decode_trigger(PHY_VARS_gNB *gNB, NR_gNB_PUSCH *pusch_vars, NR_gNB_ULSCH_t *ulsch, NR_UL_IND_t *UL_INFO, int *pusch_DTX)
|
||||
{
|
||||
NR_UL_gNB_HARQ_t *ulsch_harq = ulsch->harq_process;
|
||||
AssertFatal(ulsch_harq != NULL, "harq_pid %d is not allocated\n", ulsch->harq_pid);
|
||||
const nfapi_nr_pusch_pdu_t *pdu = &ulsch_harq->ulsch_pdu;
|
||||
|
||||
#ifdef DEBUG_RXDATA
|
||||
static void dump_pusch_rx_data(PHY_VARS_gNB *gNB, NR_gNB_ULSCH_t *ulsch, const nfapi_nr_pusch_pdu_t *pdu)
|
||||
{
|
||||
NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms;
|
||||
RU_t *ru = gNB->RU_list[0];
|
||||
int slot_offset = frame_parms->get_samples_slot_timestamp(ulsch->slot, frame_parms, 0);
|
||||
int slot_offset = get_samples_slot_timestamp(frame_parms, ulsch->slot);
|
||||
slot_offset -= ru->N_TA_offset;
|
||||
int32_t sample_offset = gNB->common_vars.debugBuff_sample_offset;
|
||||
int16_t buf = (int16_t *)&gNB->common_vars.debugBuff[offset];
|
||||
int16_t *buf = (int16_t *)&gNB->common_vars.debugBuff[sample_offset];
|
||||
buf[0] = (int16_t)ulsch->rnti;
|
||||
buf[1] = (int16_t)pdu->rb_size;
|
||||
buf[2] = (int16_t)pdu->rb_start;
|
||||
@@ -961,30 +958,49 @@ static bool handle_pusch_decode_trigger(PHY_VARS_gNB *gNB, NR_gNB_PUSCH *pusch_v
|
||||
buf[7] = (int16_t)ulsch->harq_pid;
|
||||
memcpy(&gNB->common_vars.debugBuff[gNB->common_vars.debugBuff_sample_offset + 4],
|
||||
&ru->common.rxdata[0][slot_offset],
|
||||
frame_parms->get_samples_per_slot(ulsch->slot, frame_parms) * sizeof(int32_t));
|
||||
gNB->common_vars.debugBuff_sample_offset += (frame_parms->get_samples_per_slot(ulsch->slot, frame_parms) + 1000 + 4);
|
||||
if (gNB->common_vars.debugBuff_sample_offset > ((frame_parms->get_samples_per_slot(ulsch->slot, frame_parms) + 1000 + 2) * 20)) {
|
||||
FILE *f;
|
||||
f = fopen("rxdata_buff.raw", "w");
|
||||
get_samples_per_slot(ulsch->slot, frame_parms) * sizeof(int32_t));
|
||||
gNB->common_vars.debugBuff_sample_offset += (get_samples_per_slot(ulsch->slot, frame_parms) + 1000 + 4);
|
||||
if (gNB->common_vars.debugBuff_sample_offset > ((get_samples_per_slot(ulsch->slot, frame_parms) + 1000 + 2) * 20)) {
|
||||
FILE *f = fopen("rxdata_buff.raw", "w");
|
||||
if (f == NULL)
|
||||
exit(1);
|
||||
fwrite((int16_t *)gNB->common_vars.debugBuff,
|
||||
2,
|
||||
(frame_parms->get_samples_per_slot(ulsch->slot, frame_parms) + 1000 + 4) * 20 * 2,
|
||||
f);
|
||||
fwrite((int16_t *)gNB->common_vars.debugBuff, 2, (get_samples_per_slot(ulsch->slot, frame_parms) + 1000 + 4) * 20 * 2, f);
|
||||
fclose(f);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void handle_pusch_rx_group_trigger(PHY_VARS_gNB *gNB,
|
||||
NR_gNB_PUSCH **pusch_vars_group,
|
||||
const nfapi_nr_pusch_pdu_t **ulsch_pdu_group,
|
||||
uint32_t **ret_unav_res_group,
|
||||
int group_size,
|
||||
uint32_t frame,
|
||||
uint8_t slot,
|
||||
int beam_nb)
|
||||
{
|
||||
#ifdef DEBUG_RXDATA
|
||||
NR_gNB_ULSCH_t *ulsch = ulsch_group[0]; // fix this
|
||||
const nfapi_nr_pusch_pdu_t *pdu = ulsch_pdu_group[0];
|
||||
dump_pusch_rx_data(gNB, ulsch, pdu);
|
||||
#endif
|
||||
|
||||
start_meas(&gNB->rx_pusch_stats);
|
||||
nr_rx_pusch_tp(gNB, pusch_vars, pdu, &ulsch->unav_res, ulsch->frame, ulsch->slot, ulsch->beam_nb);
|
||||
pusch_vars->ulsch_power_tot = 0;
|
||||
pusch_vars->ulsch_noise_power_tot = 0;
|
||||
for (int aarx = 0; aarx < gNB->frame_parms.nb_antennas_rx; aarx++) {
|
||||
pusch_vars->ulsch_power_tot += pusch_vars->ulsch_power[aarx];
|
||||
pusch_vars->ulsch_noise_power_tot += pusch_vars->ulsch_noise_power[aarx];
|
||||
}
|
||||
nr_rx_pusch_group_tp(gNB, pusch_vars_group, ulsch_pdu_group, ret_unav_res_group, group_size, frame, slot, beam_nb);
|
||||
stop_meas(&gNB->rx_pusch_stats);
|
||||
}
|
||||
|
||||
static bool handle_pusch_DTX(PHY_VARS_gNB *gNB,
|
||||
NR_gNB_PUSCH *pusch_vars,
|
||||
NR_gNB_ULSCH_t *ulsch,
|
||||
NR_UL_IND_t *UL_INFO,
|
||||
int *pusch_DTX)
|
||||
{
|
||||
NR_UL_gNB_HARQ_t *ulsch_harq = ulsch->harq_process;
|
||||
AssertFatal(ulsch_harq != NULL, "harq_pid %d is not allocated\n", ulsch->harq_pid);
|
||||
const nfapi_nr_pusch_pdu_t *pdu = &ulsch_harq->ulsch_pdu;
|
||||
|
||||
if (dB_fixed_x10(pusch_vars->ulsch_power_tot) < dB_fixed_x10(pusch_vars->ulsch_noise_power_tot) + gNB->pusch_thres) {
|
||||
NR_gNB_PHY_STATS_t *stats = get_phy_stats(gNB, ulsch->rnti);
|
||||
|
||||
@@ -1020,7 +1036,6 @@ static bool handle_pusch_decode_trigger(PHY_VARS_gNB *gNB, NR_gNB_PUSCH *pusch_v
|
||||
|
||||
pusch_vars->DTX = 0;
|
||||
}
|
||||
stop_meas(&gNB->rx_pusch_stats);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1191,35 +1206,62 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, N
|
||||
UL_INFO->rx_ind.pdu_list = UL_INFO->rx_pdu_list;
|
||||
int ulsch_idx_to_decode[MAX_UL_PDUS_PER_SLOT];
|
||||
int num_pusch = 0;
|
||||
|
||||
// Group the jobs using group index
|
||||
int group_jobs[MAX_UL_PDUS_PER_SLOT][MAX_UL_PDUS_PER_SLOT];
|
||||
uint8_t group_size[MAX_UL_PDUS_PER_SLOT] = {0};
|
||||
int16_t active_groups[MAX_UL_PDUS_PER_SLOT];
|
||||
int n_active_groups = 0;
|
||||
for (int i = 0; i < n_pusch_jobs; ++i) {
|
||||
int ULSCH_id = handle_pusch_job_trigger(gNB, &pusch[i]);
|
||||
if (ULSCH_id < 0)
|
||||
continue;
|
||||
NR_gNB_PUSCH *pusch_vars = &gNB->pusch_vars[ULSCH_id];
|
||||
NR_gNB_ULSCH_t *ulsch = &gNB->ulsch[ULSCH_id];
|
||||
if (handle_pusch_decode_trigger(gNB, pusch_vars, ulsch, UL_INFO, &pusch_DTX))
|
||||
ulsch_idx_to_decode[num_pusch++] = ULSCH_id;
|
||||
int g = pusch[i].mu_group_idx;
|
||||
AssertFatal(g >= 0, "Ungrouped ULSCH_id %d\n", ULSCH_id);
|
||||
if (group_size[g] == 0)
|
||||
active_groups[n_active_groups++] = g;
|
||||
group_jobs[g][group_size[g]++] = ULSCH_id;
|
||||
}
|
||||
|
||||
/* Do ULSCH decoding time measurement only when number of PUSCH is limited to 1
|
||||
* (valid for unitary physical simulators). ULSCH processing lopp is then executed
|
||||
* only once, which ensures exactly one start and stop of the ULSCH decoding time
|
||||
* measurement per processed TB.*/
|
||||
if (gNB->max_nb_pusch == 1)
|
||||
start_meas(&gNB->ulsch_decoding_stats);
|
||||
for (int i = 0; i < n_active_groups; i++) {
|
||||
int g = active_groups[i];
|
||||
int gsz = group_size[g];
|
||||
NR_gNB_PUSCH *pusch_vars_group[gsz];
|
||||
const nfapi_nr_pusch_pdu_t *ulsch_pdu_group[gsz];
|
||||
uint32_t *unav_res_group[gsz];
|
||||
int beam_nb = -1;
|
||||
for (int u = 0; u < gsz; u++) {
|
||||
int ulsch_id = group_jobs[g][u];
|
||||
LOG_I(NR_PHY, "Group %d, Group size %d, ulsch_id %d\n", g, gsz, ulsch_id);
|
||||
pusch_vars_group[u] = &gNB->pusch_vars[ulsch_id];
|
||||
ulsch_pdu_group[u] = &gNB->ulsch[ulsch_id].harq_process->ulsch_pdu;
|
||||
unav_res_group[u] = &gNB->ulsch[ulsch_id].unav_res;
|
||||
int this_beam = gNB->ulsch[ulsch_id].beam_nb;
|
||||
if (beam_nb < 0) {
|
||||
beam_nb = this_beam;
|
||||
} else {
|
||||
AssertFatal(beam_nb == this_beam, "MU-MIMO group %d has inconsistent beam_nb : %d and %d\n", g, beam_nb, this_beam);
|
||||
}
|
||||
}
|
||||
|
||||
handle_pusch_rx_group_trigger(gNB, pusch_vars_group, ulsch_pdu_group, unav_res_group, gsz, frame_rx, slot_rx, beam_nb);
|
||||
|
||||
for (int u = 0; u < gsz; u++) {
|
||||
int ULSCH_id = group_jobs[g][u];
|
||||
NR_gNB_PUSCH *pusch_vars = &gNB->pusch_vars[ULSCH_id];
|
||||
NR_gNB_ULSCH_t *ulsch = &gNB->ulsch[ULSCH_id];
|
||||
if (handle_pusch_DTX(gNB, pusch_vars, ulsch, UL_INFO, &pusch_DTX))
|
||||
ulsch_idx_to_decode[num_pusch++] = ULSCH_id;
|
||||
}
|
||||
}
|
||||
|
||||
start_meas(&gNB->ulsch_decoding_stats);
|
||||
if (num_pusch > 0) {
|
||||
int ret_nr_ulsch_procedures = nr_ulsch_procedures(gNB, frame_rx, slot_rx, ulsch_idx_to_decode, num_pusch, UL_INFO);
|
||||
if (ret_nr_ulsch_procedures != 0)
|
||||
LOG_E(PHY,"Error in nr_ulsch_procedures, returned %d\n",ret_nr_ulsch_procedures);
|
||||
}
|
||||
|
||||
/* Do ULSCH decoding time measurement only when number of PUSCH is limited to 1
|
||||
* (valid for unitary physical simulators). ULSCH processing loop is then executed
|
||||
* only once, which ensures exactly one start and stop of the ULSCH decoding time
|
||||
* measurement per processed TB.*/
|
||||
if (gNB->max_nb_pusch == 1)
|
||||
stop_meas(&gNB->ulsch_decoding_stats);
|
||||
stop_meas(&gNB->ulsch_decoding_stats);
|
||||
|
||||
UL_INFO->srs_ind.sfn = frame_rx;
|
||||
UL_INFO->srs_ind.slot = slot_rx;
|
||||
@@ -1252,6 +1294,19 @@ void nr_save_ul_tti_req(PHY_VARS_gNB *gNB, nfapi_nr_ul_tti_request_t *UL_tti_req
|
||||
int frame = UL_tti_req->SFN;
|
||||
int slot = UL_tti_req->Slot;
|
||||
|
||||
int16_t pdu_group_idx[MAX_UL_PDUS_PER_SLOT] = {[0 ... MAX_UL_PDUS_PER_SLOT - 1] = -1};
|
||||
uint8_t pdu_group_size[MAX_UL_PDUS_PER_SLOT] = {0};
|
||||
for (int g = 0; g < UL_tti_req->n_group; g++) {
|
||||
const nfapi_nr_ul_tti_request_number_of_groups_t *grp = &UL_tti_req->groups_list[g];
|
||||
for (int u = 0; u < grp->n_ue; u++) {
|
||||
int pdu_idx = grp->ue_list[u].pdu_idx;
|
||||
if (pdu_idx >= 0 && pdu_idx < UL_tti_req->n_pdus) {
|
||||
pdu_group_idx[pdu_idx] = g;
|
||||
pdu_group_size[pdu_idx] = grp->n_ue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < UL_tti_req->n_pdus; i++) {
|
||||
int type = UL_tti_req->pdus_list[i].pdu_type;
|
||||
LOG_D(NR_PHY,
|
||||
@@ -1263,7 +1318,12 @@ void nr_save_ul_tti_req(PHY_VARS_gNB *gNB, nfapi_nr_ul_tti_request_t *UL_tti_req
|
||||
UL_tti_req->Slot);
|
||||
switch (type) {
|
||||
case NFAPI_NR_UL_CONFIG_PUSCH_PDU_TYPE:
|
||||
nr_fill_ulsch(gNB, UL_tti_req->SFN, UL_tti_req->Slot, &UL_tti_req->pdus_list[i].pusch_pdu);
|
||||
nr_fill_ulsch(gNB,
|
||||
UL_tti_req->SFN,
|
||||
UL_tti_req->Slot,
|
||||
&UL_tti_req->pdus_list[i].pusch_pdu,
|
||||
pdu_group_idx[i],
|
||||
pdu_group_size[i]);
|
||||
break;
|
||||
case NFAPI_NR_UL_CONFIG_PUCCH_PDU_TYPE:
|
||||
nr_fill_pucch(gNB, UL_tti_req->SFN, UL_tti_req->Slot, &UL_tti_req->pdus_list[i].pucch_pdu);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
1181
openair1/SIMULATION/NR_PHY/ulsim_mu_mimo.c
Normal file
1181
openair1/SIMULATION/NR_PHY/ulsim_mu_mimo.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -373,3 +373,45 @@ void multipath_channel_float(channel_desc_t *desc,
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// \f$\mathbf{y} = y + \mathbf{x}\f$
|
||||
#ifdef CHANNEL_SSE
|
||||
void __attribute__((no_sanitize_address)) add_rx_signals_simde(float **y_re,
|
||||
float **y_im,
|
||||
float **x_re,
|
||||
float **x_im,
|
||||
int n_rx,
|
||||
int length)
|
||||
{
|
||||
for (int aarx = 0; aarx < n_rx; aarx++) {
|
||||
int i = 0;
|
||||
for (; i <= length - 4; i += 4) {
|
||||
// Add real values
|
||||
simde__m128 vec_re_x = simde_mm_loadu_ps(&x_re[aarx][i]);
|
||||
simde__m128 vec_re_y = simde_mm_loadu_ps(&y_re[aarx][i]);
|
||||
simde_mm_storeu_ps(&y_re[aarx][i], simde_mm_add_ps(vec_re_y, vec_re_x));
|
||||
|
||||
// Add imaginary values
|
||||
simde__m128 vec_im_x = simde_mm_loadu_ps(&x_im[aarx][i]);
|
||||
simde__m128 vec_im_y = simde_mm_loadu_ps(&y_im[aarx][i]);
|
||||
simde_mm_storeu_ps(&y_im[aarx][i], simde_mm_add_ps(vec_im_y, vec_im_x));
|
||||
}
|
||||
|
||||
// Add remaining samples
|
||||
for (; i < length; i++) {
|
||||
y_re[aarx][i] += x_re[aarx][i];
|
||||
y_im[aarx][i] += x_im[aarx][i];
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
void add_rx_signals_simde(float **y_re, float **y_im, float **x_re, float **x_im, int n_rx, int length)
|
||||
{
|
||||
for (int aarx = 0; aarx < n_rx; aarx++) {
|
||||
for (int i = 0; i < length; i++) {
|
||||
y_re[aarx][i] += x_re[aarx][i];
|
||||
y_im[aarx][i] += x_im[aarx][i];
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -428,6 +428,8 @@ void add_noise_float(c16_t **rxdata,
|
||||
bool apply_phase_noise,
|
||||
const uint8_t nb_antennas_rx);
|
||||
|
||||
void add_rx_signals_simde(float **y_re, float **y_im, float **x_re, float **x_im, int n_rx, int length);
|
||||
|
||||
/*
|
||||
\fn double compute_pbch_sinr(channel_desc_t *desc,
|
||||
channel_desc_t *desc_i1,
|
||||
|
||||
@@ -115,6 +115,48 @@ static void copy_ul_tti_req(nfapi_nr_ul_tti_request_t *to, nfapi_nr_ul_tti_reque
|
||||
to->groups_list[i] = from->groups_list[i];
|
||||
}
|
||||
|
||||
static void nr_schedule_pusch_fapi_groups(nfapi_nr_ul_tti_request_t *UL_tti_req)
|
||||
{
|
||||
UL_tti_req->n_group = 0;
|
||||
bool pdu_grouped[MAX_UL_PDUS_PER_SLOT] = {false};
|
||||
for (int i = 0; i < UL_tti_req->n_pdus; i++) {
|
||||
// We only group PUSCH PDUs
|
||||
if (UL_tti_req->pdus_list[i].pdu_type != NFAPI_NR_UL_CONFIG_PUSCH_PDU_TYPE)
|
||||
continue;
|
||||
if (pdu_grouped[i])
|
||||
continue;
|
||||
nfapi_nr_ul_tti_request_number_of_groups_t *group = &UL_tti_req->groups_list[UL_tti_req->n_group];
|
||||
group->n_ue = 0;
|
||||
group->ue_list[group->n_ue++].pdu_idx = i;
|
||||
pdu_grouped[i] = true;
|
||||
|
||||
nfapi_nr_pusch_pdu_t *pdu_i = &UL_tti_req->pdus_list[i].pusch_pdu;
|
||||
|
||||
// Group the UEs sharing the exact same resource blocks
|
||||
for (int j = i + 1; j < UL_tti_req->n_pdus; j++) {
|
||||
if (UL_tti_req->pdus_list[j].pdu_type != NFAPI_NR_UL_CONFIG_PUSCH_PDU_TYPE)
|
||||
continue;
|
||||
if (pdu_grouped[j])
|
||||
continue;
|
||||
|
||||
nfapi_nr_pusch_pdu_t *pdu_j = &UL_tti_req->pdus_list[j].pusch_pdu;
|
||||
|
||||
// Check for resource overlap
|
||||
bool same_alloc = (pdu_i->rb_start == pdu_j->rb_start) && (pdu_i->rb_size == pdu_j->rb_size)
|
||||
&& (pdu_i->start_symbol_index == pdu_j->start_symbol_index)
|
||||
&& (pdu_i->nr_of_symbols == pdu_j->nr_of_symbols) && (pdu_i->qam_mod_order == pdu_j->qam_mod_order);
|
||||
|
||||
// Check orthogonal DMRS ports
|
||||
bool orthogonal_dmrs = ((pdu_i->dmrs_ports & pdu_j->dmrs_ports) == 0);
|
||||
if (same_alloc && orthogonal_dmrs) {
|
||||
group->ue_list[group->n_ue++].pdu_idx = j;
|
||||
pdu_grouped[j] = true;
|
||||
}
|
||||
}
|
||||
UL_tti_req->n_group++;
|
||||
}
|
||||
}
|
||||
|
||||
void gNB_dlsch_ulsch_scheduler(module_id_t module_idP, frame_t frame, slot_t slot, NR_Sched_Rsp_t *sched_info)
|
||||
{
|
||||
protocol_ctxt_t ctxt = {0};
|
||||
@@ -232,6 +274,8 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP, frame_t frame, slot_t slo
|
||||
const int current_index = ul_buffer_index(frame, slot, slots_frame, gNB->UL_tti_req_ahead_size);
|
||||
copy_ul_tti_req(&sched_info->UL_tti_req, &gNB->UL_tti_req_ahead[0][current_index]);
|
||||
|
||||
nr_schedule_pusch_fapi_groups(&sched_info->UL_tti_req);
|
||||
|
||||
stop_meas(&gNB->gNB_scheduler);
|
||||
NR_SCHED_UNLOCK(&gNB->sched_lock);
|
||||
}
|
||||
|
||||
@@ -1263,7 +1263,17 @@ void config_uldci(const NR_UE_ServingCell_Info_t *sc_info,
|
||||
|
||||
// antenna_ports.val = 0 for transform precoder is disabled, dmrs-Type=1, maxLength=1, Rank=1/2/3/4
|
||||
// Antenna Ports
|
||||
dci_pdu_rel15->antenna_ports.val = 0;
|
||||
// dci_pdu_rel15->antenna_ports.val = 0;
|
||||
// MU-MIMO HACK
|
||||
if (pusch_pdu->rb_size == 90) {
|
||||
if (pusch_pdu->dmrs_ports == 1) {
|
||||
dci_pdu_rel15->antenna_ports.val = 0;
|
||||
} else {
|
||||
dci_pdu_rel15->antenna_ports.val = 1;
|
||||
}
|
||||
} else {
|
||||
dci_pdu_rel15->antenna_ports.val = 0;
|
||||
}
|
||||
|
||||
// DMRS sequence initialization
|
||||
dci_pdu_rel15->dmrs_sequence_initialization.val = pusch_pdu->scid;
|
||||
|
||||
@@ -1885,6 +1885,8 @@ static int pf_ul(gNB_MAC_INST *nrmac,
|
||||
const int CC_id = 0;
|
||||
int frame = pp_pusch->frame;
|
||||
int slot = pp_pusch->slot;
|
||||
bool used_pusch_dmrs_ports[4] = {0};
|
||||
int mu_mimo_users_scheduled = 0;
|
||||
NR_ServingCellConfigCommon_t *scc = nrmac->common_channels[CC_id].ServingCellConfigCommon;
|
||||
int slots_per_frame = nrmac->frame_structure.numb_slots_frame;
|
||||
DevAssert(tda_info->valid_tda);
|
||||
@@ -2182,6 +2184,58 @@ static int pf_ul(gNB_MAC_INST *nrmac,
|
||||
>> 3;
|
||||
}
|
||||
|
||||
// MU-MIMO HACK
|
||||
// ------------
|
||||
bool is_user_data = false;
|
||||
for (int lcid = 4; lcid <= 32; lcid++) {
|
||||
if (iterator->UE->mac_stats.ul.lc_bytes[lcid] > 0) {
|
||||
is_user_data = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_user_data) {
|
||||
for (int rb = 16; rb < 16 + 90; rb++) {
|
||||
if (nrmac->ulprbbl[rb] != 0) {
|
||||
LOG_D(NR_MAC, "MU-MIMO region blocked by PUCCH/SRS at PRB %d. Falling back to SU-MIMO.\n", rb);
|
||||
is_user_data = false; // Cancel MU-MIMO for this UE, use default OAI scheduling
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (is_user_data) {
|
||||
sched.rbStart = 16;
|
||||
sched.rbSize = 90;
|
||||
|
||||
int assigned_port = -1;
|
||||
for (int p = 0; p < 2; p++) {
|
||||
if (used_pusch_dmrs_ports[p] == 0) {
|
||||
assigned_port = p;
|
||||
used_pusch_dmrs_ports[p] = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (assigned_port == -1) {
|
||||
LOG_W(NR_MAC, "MU-MIMO limit reached in this slot. Deferring UE %04x to next slot.\n", iterator->UE->rnti);
|
||||
continue; // Skip scheduling this UE until the next slot
|
||||
}
|
||||
|
||||
sched.dmrs_info.dmrs_ports = (assigned_port == 0) ? 1 : 2;
|
||||
|
||||
sched.tb_size = nr_compute_tbs(sched.Qm,
|
||||
sched.R,
|
||||
sched.rbSize,
|
||||
sched.tda_info.nrOfSymbols,
|
||||
sched.dmrs_info.N_PRB_DMRS * sched.dmrs_info.num_dmrs_symb,
|
||||
0, // nb_rb_oh
|
||||
0,
|
||||
sched.nrOfLayers)
|
||||
>> 3;
|
||||
}
|
||||
// --------------
|
||||
|
||||
LOG_D(NR_MAC,
|
||||
"rbSize %d (available_rb %d), TBS %d, est buf %d, sched_ul %d, B %d, CCE %d, num_dmrs_symb %d, N_PRB_DMRS %d\n",
|
||||
sched.rbSize,
|
||||
@@ -2202,9 +2256,25 @@ static int pf_ul(gNB_MAC_INST *nrmac,
|
||||
/* save allocation to FAPI structures */
|
||||
post_process_ulsch(nrmac, pp_pusch, iterator->UE, &sched);
|
||||
|
||||
n_rb_sched[beam.idx] -= sched.rbSize;
|
||||
for (int rb = bi.bwpStart + sched.rbStart; rb < bi.bwpStart + sched.rbStart + sched.rbSize; rb++)
|
||||
rballoc_mask[rb] |= slbitmap;
|
||||
if (is_user_data) {
|
||||
mu_mimo_users_scheduled++;
|
||||
|
||||
// If we have successfully scheduled 2 UEs, the MU-MIMO group is full.
|
||||
// We MUST lock the PRB mask now so a 3rd UE doesn't overwrite them.
|
||||
if (mu_mimo_users_scheduled == 2) {
|
||||
n_rb_sched[beam.idx] -= sched.rbSize;
|
||||
for (int rb = bi.bwpStart + sched.rbStart; rb < bi.bwpStart + sched.rbStart + sched.rbSize; rb++) {
|
||||
rballoc_mask[rb] |= slbitmap;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Standard SU-MIMO / Control Traffic: Lock the PRB mask immediately
|
||||
n_rb_sched[beam.idx] -= sched.rbSize;
|
||||
for (int rb = bi.bwpStart + sched.rbStart; rb < bi.bwpStart + sched.rbStart + sched.rbSize; rb++) {
|
||||
rballoc_mask[rb] |= slbitmap;
|
||||
}
|
||||
}
|
||||
// ==========================================================
|
||||
|
||||
/* reduce max_num_ue once we are sure UE can be allocated, i.e., has CCE */
|
||||
remainUEs[beam.idx]--;
|
||||
@@ -2252,7 +2322,16 @@ nfapi_nr_pusch_pdu_t *prepare_pusch_pdu(nfapi_nr_ul_tti_request_t *future_ul_tti
|
||||
pusch_pdu->nrOfLayers = sched_pusch->nrOfLayers;
|
||||
// DMRS
|
||||
pusch_pdu->num_dmrs_cdm_grps_no_data = sched_pusch->dmrs_info.num_dmrs_cdm_grps_no_data;
|
||||
pusch_pdu->dmrs_ports = ((1 << sched_pusch->nrOfLayers) - 1);
|
||||
|
||||
// MU-MIMO HACK
|
||||
if (sched_pusch->rbSize == 90) {
|
||||
pusch_pdu->dmrs_ports = sched_pusch->dmrs_info.dmrs_ports;
|
||||
} else {
|
||||
// Normal SU-MIMO behavior for RRC Signaling
|
||||
pusch_pdu->dmrs_ports = ((1 << sched_pusch->nrOfLayers) - 1);
|
||||
}
|
||||
|
||||
// pusch_pdu->dmrs_ports = ((1 << sched_pusch->nrOfLayers) - 1);
|
||||
pusch_pdu->ul_dmrs_symb_pos = sched_pusch->dmrs_info.ul_dmrs_symb_pos;
|
||||
pusch_pdu->dmrs_config_type = sched_pusch->dmrs_info.dmrs_config_type;
|
||||
pusch_pdu->scid = sched_pusch->dmrs_info.scid; // DMRS sequence initialization [TS38.211, sec 6.4.1.1.1]
|
||||
|
||||
@@ -417,6 +417,7 @@ typedef struct NR_pusch_dmrs {
|
||||
uint8_t num_dmrs_symb;
|
||||
uint16_t ul_dmrs_symb_pos;
|
||||
uint8_t num_dmrs_cdm_grps_no_data;
|
||||
uint16_t dmrs_ports;
|
||||
nfapi_nr_dmrs_type_e dmrs_config_type;
|
||||
int dmrs_scrambling_id;
|
||||
int pusch_identity;
|
||||
|
||||
@@ -487,6 +487,7 @@ void reset_sched_response(NR_Sched_Rsp_t *sched_response, int frame, int slot, i
|
||||
UL_tti_req->SFN = frame;
|
||||
UL_tti_req->Slot = slot;
|
||||
UL_tti_req->n_pdus = 0;
|
||||
UL_tti_req->n_group = 0;
|
||||
|
||||
nfapi_nr_tx_data_request_t *TX_req = &sched_response->TX_req;
|
||||
TX_req->SFN = frame;
|
||||
|
||||
@@ -222,7 +222,7 @@ if(PACKAGING_PHYSIM)
|
||||
--------------------------------------------------------
|
||||
Coding focused: polartest, smallblocktest, ldpctest
|
||||
Downlink PHY: nr_dlschsim, nr_psbchsim, nr_dlsim
|
||||
Uplink PHY: nr_pucchsim nr_prachsim nr_ulschsim nr_ulsim
|
||||
Uplink PHY: nr_pucchsim nr_prachsim nr_ulschsim nr_ulsim nr_ulsim_mu_mimo
|
||||
--------------------------------------------------------
|
||||
polartest: test polar codes which are used in 5G control channels, validates encoding, decoding and error correction performance*
|
||||
smallblocktest: generic test for small channel coding blocks, validates encoding and decoding for small transport blocks
|
||||
@@ -233,7 +233,8 @@ if(PACKAGING_PHYSIM)
|
||||
nr_dlsim: simulates NR downlink, including multiple downlink channels and measurements of BLER/throughput
|
||||
nr_prachsim: simulates the Physical Random Access Channel, including UE initial access, preamble detection and timing alignment
|
||||
nr_ulschsim: simulates the Uplink Shared Channel, including LDPC encoding, modulation, transmission and decoding
|
||||
nr_ulsim: simulates the NR uplink simulation, including PUCCH, PUSCH and PRACH")
|
||||
nr_ulsim: simulates the NR uplink simulation, including PUCCH, PUSCH and PRACH
|
||||
nr_ulsim_mu_mimo: simulates the NR uplink simulation with PUSCH multi user MIMO")
|
||||
|
||||
if(PACKAGING_RPM)
|
||||
set(CPACK_RPM_PACKAGE_OAI-PHYSIM_SUMMARY "OpenAirInterface PhySim package")
|
||||
@@ -254,7 +255,7 @@ if(PACKAGING_PHYSIM)
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/doc/physical-simulators.md" DESTINATION share/doc/ COMPONENT oai-physim)
|
||||
|
||||
#Add the targets to the package
|
||||
install(TARGETS polartest smallblocktest ldpctest nr_dlschsim nr_psbchsim nr_pucchsim nr_dlsim nr_prachsim nr_ulschsim nr_ulsim
|
||||
install(TARGETS polartest smallblocktest ldpctest nr_dlschsim nr_psbchsim nr_pucchsim nr_dlsim nr_prachsim nr_ulschsim nr_ulsim nr_ulsim_mu_mimo
|
||||
COMPONENT oai-physim
|
||||
RUNTIME DESTINATION /usr/bin
|
||||
LIBRARY DESTINATION /usr/lib
|
||||
|
||||
Reference in New Issue
Block a user