Commit fa237ffa authored by Robert Schmidt's avatar Robert Schmidt

Merge remote-tracking branch 'origin/oai_ue_perf_opt' into integration_2026_w24

UE DL Channel compensation and LLR optimization (#142)

- Common channel compensation: Extracted nr_channel_compensation() as a
  shared function (AVX2/MRC inline) used by both gNB and UE PDSCH/PUSCH
  paths, eliminating duplicated compensation logic.
- Common ML/MMSE 2-layer MIMO: Created shared ML LLR and MMSE routines
  for 2-layer spatial multiplexing, shared between gNB and UE
  demodulation.
- File segregation: Moved common LLR and channel compensation functions
  into dedicated source files for better modularity and reuse.
- nr_dlsim -E flag: Added a command-line argument to enable/disable
  ML/MMSE equalization at runtime (MMSE default), enabling side-by-side
  performance comparison without recompilation.
- Persistent UE buffer allocation: pdsch_dl_ch_estimates, rxdataF_comp,
  dl_ch_mag,dl_ch_magb,dl_ch_magr and rho_dl are now allocated once in
  PHY_VARS_NR_UE on first use, resize automatically when dimensions
  change (resizeAllowed=true), and are freed at UE teardown in
  term_nr_ue_signal. Eliminates per-slot heap allocation/free overhead.
- PTRS restricted to one antenna port: PTRS phase tracking is only valid
  for a single port; processing now correctly restricted to avoid
  unnecessary computation.
- Reduce rxdataF_comp buffer size: MRC combines all Rx antenna
  contributions into a per-layer output, so the first dimension was
  reduced from Nl * nb_antennas_rx to Nl, reducing buffer footprint
  proportionally.
- 256QAM segfault fix: nr_256qam_llr() on gNB side used a VLA for LLRs
  without alignment, causing AVX2 load faults. Fixed with
  attribute((aligned(32))).
Reviewed-by: default avatarSakthivel Velumani <s.velumani@northeastern.edu>
parents 8c255558 460cbf95
......@@ -924,7 +924,6 @@ set(PHY_SRC_UE
${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_ulsch.c
${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_sch_dmrs.c
${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_prach.c
${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_ulsch_llr_computation.c
${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c
${OPENAIR1_DIR}/PHY/NR_REFSIG/ul_ref_seq_nr.c
${OPENAIR1_DIR}/PHY/NR_REFSIG/nr_dmrs_rx.c
......
......@@ -176,14 +176,14 @@ void phy_init_nr_gNB(PHY_VARS_gNB *gNB)
NR_gNB_PUSCH *pusch = &gNB->pusch_vars[ULSCH_id];
pusch->ul_ch_estimates = (int32_t **)malloc16(n_buf * sizeof(int32_t *));
pusch->ptrs_phase_per_slot = (int32_t **)malloc16(n_buf * sizeof(int32_t *));
pusch->rxdataF_comp = (c16_t **)malloc16(n_buf * sizeof(*pusch->rxdataF_comp));
for (int i = 0; i < n_buf; i++) {
pusch->ul_ch_estimates[i] = (int32_t *)malloc16_clear(sizeof(int32_t) * fp->ofdm_symbol_size * fp->symbols_per_slot);
pusch->ptrs_phase_per_slot[i] = (int32_t *)malloc16_clear(sizeof(int32_t) * fp->symbols_per_slot); // symbols per slot
pusch->rxdataF_comp[i] = (c16_t *)malloc16_clear(sizeof(**pusch->rxdataF_comp) * nb_re_pusch2 * fp->symbols_per_slot);
}
pusch->rxdataF_comp = (c16_t **)malloc16(max_ul_mimo_layers * sizeof(*pusch->rxdataF_comp));
for (int i = 0; i < max_ul_mimo_layers; i++) {
pusch->rxdataF_comp[i] = (c16_t *)malloc16_clear(sizeof(**pusch->rxdataF_comp) * nb_re_pusch2 * fp->symbols_per_slot);
}
pusch->llr = (int16_t *)malloc16_clear((8 * ((3 * 8 * 6144) + 12))
* sizeof(int16_t)); // [hna] 6144 is LTE and (8*((3*8*6144)+12)) is not clear
......@@ -232,8 +232,10 @@ void phy_free_nr_gNB(PHY_VARS_gNB *gNB)
for (int i = 0; i < n_buf; i++) {
free_and_zero(pusch_vars->ul_ch_estimates[i]);
free_and_zero(pusch_vars->ptrs_phase_per_slot[i]);
free_and_zero(pusch_vars->rxdataF_comp[i]);
}
for (int i = 0; i < max_ul_mimo_layers; i++)
free_and_zero(pusch_vars->rxdataF_comp[i]);
free_and_zero(pusch_vars->ul_ch_estimates);
free_and_zero(pusch_vars->ptrs_phase_per_slot);
free_and_zero(pusch_vars->ul_valid_re_per_slot);
......
......@@ -106,62 +106,9 @@ int nr_rx_pusch_tp(PHY_VARS_gNB *gNB,
*/
void nr_idft(int32_t *z, uint32_t Msc_PUSCH);
void nr_ulsch_qpsk_qpsk(c16_t *stream0_in,
c16_t *stream1_in,
c16_t *stream0_out,
c16_t *rho01,
uint32_t length);
void nr_ulsch_qam16_qam16(c16_t *stream0_in,
c16_t *stream1_in,
c16_t *ch_mag,
c16_t *ch_mag_i,
c16_t *stream0_out,
c16_t *rho01,
uint32_t length);
void nr_ulsch_qam64_qam64(c16_t *stream0_in,
c16_t *stream1_in,
c16_t *ch_mag,
c16_t *ch_mag_i,
c16_t *stream0_out,
c16_t *rho01,
uint32_t length);
/** \brief This function computes the log-likelihood ratios for 4, 16, and 64 QAM
@param rxdataF_comp Compensated channel output
@param ul_ch_mag uplink channel magnitude multiplied by the 1st amplitude threshold in QAM 64
@param ul_ch_magb uplink channel magnitude multiplied by the 2bd amplitude threshold in QAM 64
@param ulsch_llr llr output
@param nb_re number of REs for this allocation
@param symbol OFDM symbol index in sub-frame
@param mod_order modulation order
*/
void nr_ulsch_compute_llr(c16_t *rxdataF_comp,
c16_t *ul_ch_mag,
c16_t *ul_ch_magb,
c16_t *ul_ch_magc,
int16_t *ulsch_llr,
uint32_t nb_re,
uint8_t symbol,
uint8_t mod_order);
void reset_active_stats(PHY_VARS_gNB *gNB, int frame);
void reset_active_ulsch(PHY_VARS_gNB *gNB, int frame);
void nr_ulsch_compute_ML_llr(c16_t *rxdataF_comp0,
c16_t *rxdataF_comp1,
c16_t *ul_ch_mag0,
c16_t *ul_ch_mag1,
int16_t *llr_layers0,
int16_t *llr_layers1,
c16_t *rho0,
c16_t *rho1,
uint32_t nb_re,
uint8_t mod_order);
void nr_ulsch_shift_llr(int16_t **llr_layers, uint32_t nb_re, uint32_t rxdataF_ext_offset, uint8_t mod_order, int shift);
void nr_fill_ulsch(PHY_VARS_gNB *gNB,
int frame,
int slot,
......
......@@ -174,686 +174,6 @@ static int get_nb_re_pusch (NR_DL_FRAME_PARMS *frame_parms, const nfapi_nr_pusch
return (rel15_ul->rb_size * NR_NB_SC_PER_RB);
}
static void nr_ulsch_channel_compensation(uint32_t buffer_length,
int nb_rx_ant,
c16_t rxFext[][buffer_length],
c16_t chFext[][nb_rx_ant][buffer_length],
c16_t ul_ch_maga[][buffer_length],
c16_t ul_ch_magb[][buffer_length],
c16_t ul_ch_magc[][buffer_length],
c16_t **rxComp,
int nb_layers,
c16_t rho[][nb_layers][buffer_length],
const nfapi_nr_pusch_pdu_t *rel15_ul,
uint32_t symbol,
uint32_t output_shift)
{
int mod_order = rel15_ul->qam_mod_order;
int nrOfLayers = rel15_ul->nrOfLayers;
simde__m256i QAM_ampa_256 = simde_mm256_setzero_si256();
simde__m256i QAM_ampb_256 = simde_mm256_setzero_si256();
simde__m256i QAM_ampc_256 = simde_mm256_setzero_si256();
if (mod_order == 4) {
QAM_ampa_256 = simde_mm256_set1_epi16(QAM16_n1);
QAM_ampb_256 = simde_mm256_setzero_si256();
QAM_ampc_256 = simde_mm256_setzero_si256();
}
else if (mod_order == 6) {
QAM_ampa_256 = simde_mm256_set1_epi16(QAM64_n1);
QAM_ampb_256 = simde_mm256_set1_epi16(QAM64_n2);
QAM_ampc_256 = simde_mm256_setzero_si256();
}
else if (mod_order == 8) {
QAM_ampa_256 = simde_mm256_set1_epi16(QAM256_n1);
QAM_ampb_256 = simde_mm256_set1_epi16(QAM256_n2);
QAM_ampc_256 = simde_mm256_set1_epi16(QAM256_n3);
}
for (int aatx = 0; aatx < nrOfLayers; aatx++) {
simde__m256i *rxComp_256 = (simde__m256i *)&rxComp[aatx * nb_rx_ant][symbol * buffer_length];
simde__m256i *rxF_ch_maga_256 = (simde__m256i *)ul_ch_maga[aatx];
simde__m256i *rxF_ch_magb_256 = (simde__m256i *)ul_ch_magb[aatx];
simde__m256i *rxF_ch_magc_256 = (simde__m256i *)ul_ch_magc[aatx];
for (int aarx = 0; aarx < nb_rx_ant; aarx++) {
simde__m256i *rxF_256 = (simde__m256i *)rxFext[aarx];
simde__m256i *chF_256 = (simde__m256i *)chFext[aatx][aarx];
for (int i = 0; i < buffer_length >> 3; i++)
{
// MRC
simde__m256i comp = oai_mm256_cpx_mult_conj(chF_256[i], rxF_256[i], output_shift);
rxComp_256[i] = simde_mm256_add_epi16(rxComp_256[i], comp);
if (mod_order > 2) {
simde__m256i mag = oai_mm256_smadd(chF_256[i], chF_256[i], output_shift); // |h|^2
// pack and duplicate
mag = simde_mm256_packs_epi32(mag, mag);
mag = simde_mm256_unpacklo_epi16(mag, mag);
rxF_ch_maga_256[i] = simde_mm256_add_epi16(rxF_ch_maga_256[i], simde_mm256_mulhrs_epi16(mag, QAM_ampa_256));
if (mod_order > 4)
rxF_ch_magb_256[i] = simde_mm256_add_epi16(rxF_ch_magb_256[i], simde_mm256_mulhrs_epi16(mag, QAM_ampb_256));
if (mod_order > 6)
rxF_ch_magc_256[i] = simde_mm256_add_epi16(rxF_ch_magc_256[i], simde_mm256_mulhrs_epi16(mag, QAM_ampc_256));
}
}
if (nb_layers > 1) {
for (int atx = 0; atx < nrOfLayers; atx++) {
simde__m256i *rho_256 = (simde__m256i *)rho[aatx][atx];
simde__m256i *chF_256 = (simde__m256i *)chFext[aatx][aarx];
simde__m256i *chF2_256 = (simde__m256i *)chFext[atx][aarx];
for (int i = 0; i < buffer_length >> 3; i++) {
rho_256[i] = simde_mm256_adds_epi16(rho_256[i], oai_mm256_cpx_mult_conj(chF_256[i], chF2_256[i], output_shift));
}
}
}
}
}
}
// Zero Forcing Rx function: nr_det_HhH()
static void nr_ulsch_det_HhH(c16_t *after_mf_00, // a
c16_t *after_mf_01, // b
c16_t *after_mf_10, // c
c16_t *after_mf_11, // d
uint32_t *det_fin, // 1/ad-bc
unsigned short nb_rb)
{
simde__m128i *after_mf_00_128,*after_mf_01_128, *after_mf_10_128, *after_mf_11_128, ad_re_128, bc_re_128; //ad_im_128, bc_im_128;
simde__m128i *det_fin_128, det_re_128; //det_im_128, tmp_det0, tmp_det1;
after_mf_00_128 = (simde__m128i *)after_mf_00;
after_mf_01_128 = (simde__m128i *)after_mf_01;
after_mf_10_128 = (simde__m128i *)after_mf_10;
after_mf_11_128 = (simde__m128i *)after_mf_11;
det_fin_128 = (simde__m128i *)det_fin;
for (unsigned short rb=0; rb<3*nb_rb; rb++) {
//complex multiplication (I_a+jQ_a)(I_d+jQ_d) = (I_aI_d - Q_aQ_d) + j(Q_aI_d + I_aQ_d)
//The imag part is often zero, we compute only the real part
ad_re_128 = simde_mm_madd_epi16(oai_mm_conj(after_mf_00_128[0]),after_mf_11_128[0]); //Re: I_a0*I_d0 - Q_a1*Q_d1
//ad_im_128 = simde_mm_madd_epi16(oai_mm_swap(after_mf_00_128[0]),after_mf_11_128[0]);//Im: (Q_aI_d + I_aQ_d)
//complex multiplication (I_b+jQ_b)(I_c+jQ_c) = (I_bI_c - Q_bQ_c) + j(Q_bI_c + I_bQ_c)
//The imag part is often zero, we compute only the real part
bc_re_128 = simde_mm_madd_epi16(oai_mm_conj(after_mf_01_128[0]),after_mf_10_128[0]); //Re: I_b0*I_c0 - Q_b1*Q_c1
//bc_im_128 = simde_mm_madd_epi16(oai_mm_swap(after_mf_01_128[0]),after_mf_10_128[0]);//Im: (Q_bI_c + I_bQ_c)
det_re_128 = simde_mm_sub_epi32(ad_re_128, bc_re_128);
//det_im_128 = simde_mm_sub_epi32(ad_im_128, bc_im_128);
//det in Q30 format
det_fin_128[0] = simde_mm_abs_epi32(det_re_128);
#ifdef DEBUG_DLSCH_DEMOD
printf("\n Computing det_HhH_inv \n");
//print_ints("det_re_128:",(int32_t*)&det_re_128);
//print_ints("det_im_128:",(int32_t*)&det_im_128);
print_ints("det_fin_128:",(int32_t*)&det_fin_128[0]);
#endif
det_fin_128+=1;
after_mf_00_128+=1;
after_mf_01_128+=1;
after_mf_10_128+=1;
after_mf_11_128+=1;
}
}
/* Zero Forcing Rx function: nr_conjch0_mult_ch1()
*
*
* */
// TODO: This function is just a wrapper, can be removed.
static void nr_ulsch_conjch0_mult_ch1(c16_t *ch0, c16_t *ch1, c16_t *ch0conj_ch1, unsigned short nb_rb, unsigned char output_shift0)
{
//This function is used to compute multiplications in H_hermitian * H matrix
mult_cpx_conj_vector(ch0, ch1, ch0conj_ch1, 12 * nb_rb, output_shift0);
}
static simde__m128i nr_ulsch_comp_muli_sum(simde__m128i input_x,
simde__m128i input_y,
simde__m128i input_w,
simde__m128i input_z,
simde__m128i det)
{
// complex multiplication (x_re + jx_im)*(y_re + jy_im) = (x_re*y_re - x_im*y_im) + j(x_im*y_re + x_re*y_im)
// complex multiplication (w_re + jw_im)*(z_re + jz_im) = (w_re*z_re - w_im*z_im) + j(w_im*z_re + w_re*z_im)
// the real part
simde__m128i xy_re_128 = simde_mm_madd_epi16(oai_mm_conj(input_x), input_y); //Re: (x_re*y_re - x_im*y_im)
simde__m128i wz_re_128 = simde_mm_madd_epi16(oai_mm_conj(input_w), input_z); //Re: (w_re*z_re - w_im*z_im)
xy_re_128 = simde_mm_sub_epi32(xy_re_128, wz_re_128);
// the imag part
simde__m128i xy_im_128 = simde_mm_madd_epi16(oai_mm_swap(input_x), input_y); //Im: (x_im*y_re + x_re*y_im)
simde__m128i wz_im_128 = simde_mm_madd_epi16(oai_mm_swap(input_w), input_z); //Im: (w_im*z_re + w_re*z_im)
xy_im_128 = simde_mm_sub_epi32(xy_im_128, wz_im_128);
//print_ints("rx_re:",(int32_t*)&xy_re_128[0]);
//print_ints("rx_Img:",(int32_t*)&xy_im_128[0]);
//divide by matrix det and convert back to Q15 before packing
uint64_t sum_det = 0;
for (int k = 0; k < 4; k++) {
sum_det += (((uint32_t *)&det)[k]);
}
// Add bias to reduce rounding error
sum_det = (sum_det + 2) >> 2;
int b = log2_approx(sum_det) - 8;
if (b > 0) {
xy_re_128 = simde_mm_srai_epi32(xy_re_128, b);
xy_im_128 = simde_mm_srai_epi32(xy_im_128, b);
} else {
xy_re_128 = simde_mm_slli_epi32(xy_re_128, -b);
xy_im_128 = simde_mm_slli_epi32(xy_im_128, -b);
}
simde__m128i output = oai_mm_pack(xy_re_128, xy_im_128);
return(output);
}
/* Zero Forcing Rx function: nr_construct_HhH_elements()
*
*
* */
static void nr_ulsch_construct_HhH_elements(c16_t *conjch00_ch00,
c16_t *conjch01_ch01,
c16_t *conjch11_ch11,
c16_t *conjch10_ch10, //
c16_t *conjch20_ch20,
c16_t *conjch21_ch21,
c16_t *conjch30_ch30,
c16_t *conjch31_ch31,
c16_t *conjch00_ch01, // 00_01
c16_t *conjch01_ch00, // 01_00
c16_t *conjch10_ch11, // 10_11
c16_t *conjch11_ch10, // 11_10
c16_t *conjch20_ch21,
c16_t *conjch21_ch20,
c16_t *conjch30_ch31,
c16_t *conjch31_ch30,
c16_t *after_mf_00,
c16_t *after_mf_01,
c16_t *after_mf_10,
c16_t *after_mf_11,
unsigned short nb_rb)
{
//This function is used to construct the (H_hermitian * H matrix) matrix elements
simde__m128i *conjch00_ch00_128 = (simde__m128i *)conjch00_ch00;
simde__m128i *conjch01_ch01_128 = (simde__m128i *)conjch01_ch01;
simde__m128i *conjch11_ch11_128 = (simde__m128i *)conjch11_ch11;
simde__m128i *conjch10_ch10_128 = (simde__m128i *)conjch10_ch10;
simde__m128i *conjch20_ch20_128 = (simde__m128i *)conjch20_ch20;
simde__m128i *conjch21_ch21_128 = (simde__m128i *)conjch21_ch21;
simde__m128i *conjch30_ch30_128 = (simde__m128i *)conjch30_ch30;
simde__m128i *conjch31_ch31_128 = (simde__m128i *)conjch31_ch31;
simde__m128i *conjch00_ch01_128 = (simde__m128i *)conjch00_ch01;
simde__m128i *conjch01_ch00_128 = (simde__m128i *)conjch01_ch00;
simde__m128i *conjch10_ch11_128 = (simde__m128i *)conjch10_ch11;
simde__m128i *conjch11_ch10_128 = (simde__m128i *)conjch11_ch10;
simde__m128i *conjch20_ch21_128 = (simde__m128i *)conjch20_ch21;
simde__m128i *conjch21_ch20_128 = (simde__m128i *)conjch21_ch20;
simde__m128i *conjch30_ch31_128 = (simde__m128i *)conjch30_ch31;
simde__m128i *conjch31_ch30_128 = (simde__m128i *)conjch31_ch30;
simde__m128i *after_mf_00_128 = (simde__m128i *)after_mf_00;
simde__m128i *after_mf_01_128 = (simde__m128i *)after_mf_01;
simde__m128i *after_mf_10_128 = (simde__m128i *)after_mf_10;
simde__m128i *after_mf_11_128 = (simde__m128i *)after_mf_11;
for (unsigned short rb=0; rb<3*nb_rb; rb++) {
after_mf_00_128[0] = simde_mm_adds_epi16(conjch00_ch00_128[0], conjch10_ch10_128[0]); //00_00 + 10_10
if (conjch20_ch20 != NULL) after_mf_00_128[0] = simde_mm_adds_epi16(after_mf_00_128[0], conjch20_ch20_128[0]);
if (conjch30_ch30 != NULL) after_mf_00_128[0] = simde_mm_adds_epi16(after_mf_00_128[0], conjch30_ch30_128[0]);
after_mf_11_128[0] = simde_mm_adds_epi16(conjch01_ch01_128[0], conjch11_ch11_128[0]); //01_01 + 11_11
if (conjch21_ch21 != NULL) after_mf_11_128[0] = simde_mm_adds_epi16(after_mf_11_128[0], conjch21_ch21_128[0]);
if (conjch31_ch31 != NULL) after_mf_11_128[0] = simde_mm_adds_epi16(after_mf_11_128[0], conjch31_ch31_128[0]);
after_mf_01_128[0] = simde_mm_adds_epi16(conjch00_ch01_128[0], conjch10_ch11_128[0]); //00_01 + 10_11
if (conjch20_ch21 != NULL) after_mf_01_128[0] = simde_mm_adds_epi16(after_mf_01_128[0], conjch20_ch21_128[0]);
if (conjch30_ch31 != NULL) after_mf_01_128[0] = simde_mm_adds_epi16(after_mf_01_128[0], conjch30_ch31_128[0]);
after_mf_10_128[0] = simde_mm_adds_epi16(conjch01_ch00_128[0], conjch11_ch10_128[0]); //01_00 + 11_10
if (conjch21_ch20 != NULL) after_mf_10_128[0] = simde_mm_adds_epi16(after_mf_10_128[0], conjch21_ch20_128[0]);
if (conjch31_ch30 != NULL) after_mf_10_128[0] = simde_mm_adds_epi16(after_mf_10_128[0], conjch31_ch30_128[0]);
#ifdef DEBUG_DLSCH_DEMOD
if ((rb<=30))
{
printf(" \n construct_HhH_elements \n");
print_shorts("after_mf_00_128:",(int16_t*)&after_mf_00_128[0]);
print_shorts("after_mf_01_128:",(int16_t*)&after_mf_01_128[0]);
print_shorts("after_mf_10_128:",(int16_t*)&after_mf_10_128[0]);
print_shorts("after_mf_11_128:",(int16_t*)&after_mf_11_128[0]);
}
#endif
conjch00_ch00_128+=1;
conjch10_ch10_128+=1;
conjch01_ch01_128+=1;
conjch11_ch11_128+=1;
if (conjch20_ch20 != NULL) conjch20_ch20_128+=1;
if (conjch21_ch21 != NULL) conjch21_ch21_128+=1;
if (conjch30_ch30 != NULL) conjch30_ch30_128+=1;
if (conjch31_ch31 != NULL) conjch31_ch31_128+=1;
conjch00_ch01_128+=1;
conjch01_ch00_128+=1;
conjch10_ch11_128+=1;
conjch11_ch10_128+=1;
if (conjch20_ch21 != NULL) conjch20_ch21_128+=1;
if (conjch21_ch20 != NULL) conjch21_ch20_128+=1;
if (conjch30_ch31 != NULL) conjch30_ch31_128+=1;
if (conjch31_ch30 != NULL) conjch31_ch30_128+=1;
after_mf_00_128 += 1;
after_mf_01_128 += 1;
after_mf_10_128 += 1;
after_mf_11_128 += 1;
}
}
// MMSE Rx function: nr_ulsch_mmse_2layers()
static uint8_t nr_ulsch_mmse_2layers(c16_t **rxdataF_comp,
uint32_t buffer_length,
int nb_rx_ant,
c16_t ul_ch_mag[][buffer_length],
c16_t ul_ch_magb[][buffer_length],
c16_t ul_ch_magc[][buffer_length],
c16_t ul_ch_estimates_ext[][nb_rx_ant][buffer_length],
unsigned short nb_rb,
unsigned char mod_order,
int shift,
unsigned char symbol,
int length,
uint32_t noise_var)
{
uint32_t nb_rb_0 = length/12 + ((length%12)?1:0);
/* we need at least alignment to 16 bytes, let's put 32 to be sure
* (maybe not necessary but doesn't hurt)
*/
c16_t conjch00_ch01[12 * nb_rb] __attribute__((aligned(32)));
c16_t conjch01_ch00[12 * nb_rb] __attribute__((aligned(32)));
c16_t conjch10_ch11[12 * nb_rb] __attribute__((aligned(32)));
c16_t conjch11_ch10[12 * nb_rb] __attribute__((aligned(32)));
c16_t conjch00_ch00[12 * nb_rb] __attribute__((aligned(32)));
c16_t conjch01_ch01[12 * nb_rb] __attribute__((aligned(32)));
c16_t conjch10_ch10[12 * nb_rb] __attribute__((aligned(32)));
c16_t conjch11_ch11[12 * nb_rb] __attribute__((aligned(32)));
c16_t conjch20_ch20[12 * nb_rb] __attribute__((aligned(32)));
c16_t conjch21_ch21[12 * nb_rb] __attribute__((aligned(32)));
c16_t conjch30_ch30[12 * nb_rb] __attribute__((aligned(32)));
c16_t conjch31_ch31[12 * nb_rb] __attribute__((aligned(32)));
c16_t conjch20_ch21[12 * nb_rb] __attribute__((aligned(32)));
c16_t conjch30_ch31[12 * nb_rb] __attribute__((aligned(32)));
c16_t conjch21_ch20[12 * nb_rb] __attribute__((aligned(32)));
c16_t conjch31_ch30[12 * nb_rb] __attribute__((aligned(32)));
c16_t af_mf_00[12 * nb_rb] __attribute__((aligned(32)));
c16_t af_mf_01[12 * nb_rb] __attribute__((aligned(32)));
c16_t af_mf_10[12 * nb_rb] __attribute__((aligned(32)));
c16_t af_mf_11[12 * nb_rb] __attribute__((aligned(32)));
uint32_t determ_fin[12*nb_rb] __attribute__((aligned(32)));
c16_t *ch00, *ch01, *ch10, *ch11;
c16_t *ch20, *ch30, *ch21, *ch31;
switch (nb_rx_ant) {
case 2://
ch00 = ul_ch_estimates_ext[0][0];
ch01 = ul_ch_estimates_ext[1][0];
ch10 = ul_ch_estimates_ext[0][1];
ch11 = ul_ch_estimates_ext[1][1];
ch20 = NULL;
ch21 = NULL;
ch30 = NULL;
ch31 = NULL;
break;
case 4://
ch00 = ul_ch_estimates_ext[0][0];
ch01 = ul_ch_estimates_ext[1][0];
ch10 = ul_ch_estimates_ext[0][1];
ch11 = ul_ch_estimates_ext[1][1];
ch20 = ul_ch_estimates_ext[0][2];
ch21 = ul_ch_estimates_ext[1][2];
ch30 = ul_ch_estimates_ext[0][3];
ch31 = ul_ch_estimates_ext[1][3];
break;
default:
return -1;
break;
}
/* 1- Compute the rx channel matrix after compensation: (1/2^log2_max)x(H_herm x H)
* for n_rx = 2
* |conj_H_00 conj_H_10| | H_00 H_01| |(conj_H_00xH_00+conj_H_10xH_10) (conj_H_00xH_01+conj_H_10xH_11)|
* | | x | | = | |
* |conj_H_01 conj_H_11| | H_10 H_11| |(conj_H_01xH_00+conj_H_11xH_10) (conj_H_01xH_01+conj_H_11xH_11)|
*
*/
if (nb_rx_ant >= 2) {
// (1/2^log2_maxh)*conj_H_00xH_00: (1/(64*2))conjH_00*H_00*2^15
nr_ulsch_conjch0_mult_ch1(ch00,
ch00,
conjch00_ch00,
nb_rb_0,
shift);
// (1/2^log2_maxh)*conj_H_10xH_10: (1/(64*2))conjH_10*H_10*2^15
nr_ulsch_conjch0_mult_ch1(ch10,
ch10,
conjch10_ch10,
nb_rb_0,
shift);
// conj_H_00xH_01
nr_ulsch_conjch0_mult_ch1(ch00,
ch01,
conjch00_ch01,
nb_rb_0,
shift); // this shift is equal to the channel level log2_maxh
// conj_H_10xH_11
nr_ulsch_conjch0_mult_ch1(ch10,
ch11,
conjch10_ch11,
nb_rb_0,
shift);
// conj_H_01xH_01
nr_ulsch_conjch0_mult_ch1(ch01,
ch01,
conjch01_ch01,
nb_rb_0,
shift);
// conj_H_11xH_11
nr_ulsch_conjch0_mult_ch1(ch11,
ch11,
conjch11_ch11,
nb_rb_0,
shift);
// conj_H_01xH_00
nr_ulsch_conjch0_mult_ch1(ch01,
ch00,
conjch01_ch00,
nb_rb_0,
shift);
// conj_H_11xH_10
nr_ulsch_conjch0_mult_ch1(ch11,
ch10,
conjch11_ch10,
nb_rb_0,
shift);
}
if (nb_rx_ant == 4) {
// (1/2^log2_maxh)*conj_H_20xH_20: (1/(64*2*16))conjH_20*H_20*2^15
nr_ulsch_conjch0_mult_ch1(ch20,
ch20,
conjch20_ch20,
nb_rb_0,
shift);
// (1/2^log2_maxh)*conj_H_30xH_30: (1/(64*2*4))conjH_30*H_30*2^15
nr_ulsch_conjch0_mult_ch1(ch30,
ch30,
conjch30_ch30,
nb_rb_0,
shift);
// (1/2^log2_maxh)*conj_H_20xH_20: (1/(64*2))conjH_20*H_20*2^15
nr_ulsch_conjch0_mult_ch1(ch20,
ch21,
conjch20_ch21,
nb_rb_0,
shift);
nr_ulsch_conjch0_mult_ch1(ch30,
ch31,
conjch30_ch31,
nb_rb_0,
shift);
nr_ulsch_conjch0_mult_ch1(ch21,
ch21,
conjch21_ch21,
nb_rb_0,
shift);
nr_ulsch_conjch0_mult_ch1(ch31,
ch31,
conjch31_ch31,
nb_rb_0,
shift);
// (1/2^log2_maxh)*conj_H_20xH_20: (1/(64*2))conjH_20*H_20*2^15
nr_ulsch_conjch0_mult_ch1(ch21,
ch20,
conjch21_ch20,
nb_rb_0,
shift);
nr_ulsch_conjch0_mult_ch1(ch31,
ch30,
conjch31_ch30,
nb_rb_0,
shift);
nr_ulsch_construct_HhH_elements(conjch00_ch00,
conjch01_ch01,
conjch11_ch11,
conjch10_ch10,//
conjch20_ch20,
conjch21_ch21,
conjch30_ch30,
conjch31_ch31,
conjch00_ch01,
conjch01_ch00,
conjch10_ch11,
conjch11_ch10,//
conjch20_ch21,
conjch21_ch20,
conjch30_ch31,
conjch31_ch30,
af_mf_00,
af_mf_01,
af_mf_10,
af_mf_11,
nb_rb_0);
}
if (nb_rx_ant == 2) {
nr_ulsch_construct_HhH_elements(conjch00_ch00,
conjch01_ch01,
conjch11_ch11,
conjch10_ch10,//
NULL,
NULL,
NULL,
NULL,
conjch00_ch01,
conjch01_ch00,
conjch10_ch11,
conjch11_ch10,//
NULL,
NULL,
NULL,
NULL,
af_mf_00,
af_mf_01,
af_mf_10,
af_mf_11,
nb_rb_0);
}
// Add noise_var such that: H^h * H + noise_var * I
if (noise_var != 0) {
simde__m128i nvar_128i = simde_mm_set1_epi32(noise_var >> shift);
simde__m128i *af_mf_00_128i = (simde__m128i *)af_mf_00;
simde__m128i *af_mf_11_128i = (simde__m128i *)af_mf_11;
for (int k = 0; k < 3 * nb_rb_0; k++) {
af_mf_00_128i[0] = simde_mm_add_epi32(af_mf_00_128i[0], nvar_128i);
af_mf_11_128i[0] = simde_mm_add_epi32(af_mf_11_128i[0], nvar_128i);
af_mf_00_128i++;
af_mf_11_128i++;
}
}
//det_HhH = ad -bc
nr_ulsch_det_HhH(af_mf_00,//a
af_mf_01,//b
af_mf_10,//c
af_mf_11,//d
determ_fin,
nb_rb_0);
/* 2- Compute the channel matrix inversion **********************************
*
* |(conj_H_00xH_00+conj_H_10xH_10) (conj_H_00xH_01+conj_H_10xH_11)|
* A= | |
* |(conj_H_01xH_00+conj_H_11xH_10) (conj_H_01xH_01+conj_H_11xH_11)|
*
*
*
*inv(A) =(1/det)*[d -b
* -c a]
*
*
**************************************************************************/
simde__m128i *ul_ch_mag128_0 = NULL, *ul_ch_mag128b_0 = NULL, *ul_ch_mag128c_0 = NULL; // Layer 0
simde__m128i *ul_ch_mag128_1 = NULL, *ul_ch_mag128b_1 = NULL, *ul_ch_mag128c_1 = NULL; // Layer 1
simde__m128i mmtmpD0, mmtmpD1, mmtmpD2, mmtmpD3;
simde__m128i QAM_amp128 = {0}, QAM_amp128b = {0}, QAM_amp128c = {0};
simde__m128i *determ_fin_128 = (simde__m128i *)&determ_fin[0];
simde__m128i *after_mf_a_128 = (simde__m128i *)af_mf_00;
simde__m128i *after_mf_b_128 = (simde__m128i *)af_mf_01;
simde__m128i *after_mf_c_128 = (simde__m128i *)af_mf_10;
simde__m128i *after_mf_d_128 = (simde__m128i *)af_mf_11;
simde__m128i *rxdataF_comp128_0 = (simde__m128i *)&rxdataF_comp[0][symbol * buffer_length];
simde__m128i *rxdataF_comp128_1 = (simde__m128i *)&rxdataF_comp[nb_rx_ant][symbol * buffer_length];
if (mod_order > 2) {
if (mod_order == 4) {
QAM_amp128 = simde_mm_set1_epi16(QAM16_n1); // 2/sqrt(10)
QAM_amp128b = simde_mm_setzero_si128();
QAM_amp128c = simde_mm_setzero_si128();
} else if (mod_order == 6) {
QAM_amp128 = simde_mm_set1_epi16(QAM64_n1); // 4/sqrt{42}
QAM_amp128b = simde_mm_set1_epi16(QAM64_n2); // 2/sqrt{42}
QAM_amp128c = simde_mm_setzero_si128();
} else if (mod_order == 8) {
QAM_amp128 = simde_mm_set1_epi16(QAM256_n1);
QAM_amp128b = simde_mm_set1_epi16(QAM256_n2);
QAM_amp128c = simde_mm_set1_epi16(QAM256_n3);
}
ul_ch_mag128_0 = (simde__m128i *)&ul_ch_mag[0];
ul_ch_mag128b_0 = (simde__m128i *)&ul_ch_magb[0];
ul_ch_mag128c_0 = (simde__m128i *)&ul_ch_magc[0];
ul_ch_mag128_1 = (simde__m128i *)&ul_ch_mag[1];
ul_ch_mag128b_1 = (simde__m128i *)&ul_ch_magb[1];
ul_ch_mag128c_1 = (simde__m128i *)&ul_ch_magc[1];
}
for (int rb = 0; rb < 3 * nb_rb_0; rb++) {
// Magnitude computation
if (mod_order > 2) {
uint64_t sum_det = 0;
for (int k = 0; k < 4; k++) {
sum_det += (((uint32_t *)&determ_fin_128[0])[k]);
}
// Add bias to reduce rounding error
sum_det = (sum_det + 2) >> 2;
int b = log2_approx(sum_det) - 8;
if (b > 0) {
mmtmpD2 = simde_mm_srai_epi32(determ_fin_128[0], b);
} else {
mmtmpD2 = simde_mm_slli_epi32(determ_fin_128[0], -b);
}
mmtmpD3 = simde_mm_unpacklo_epi32(mmtmpD2, mmtmpD2);
mmtmpD2 = simde_mm_unpackhi_epi32(mmtmpD2, mmtmpD2);
mmtmpD2 = simde_mm_packs_epi32(mmtmpD3, mmtmpD2);
// Layer 0
ul_ch_mag128_0[0] = mmtmpD2;
ul_ch_mag128b_0[0] = mmtmpD2;
ul_ch_mag128c_0[0] = mmtmpD2;
ul_ch_mag128_0[0] = simde_mm_mulhi_epi16(ul_ch_mag128_0[0], QAM_amp128);
ul_ch_mag128_0[0] = simde_mm_slli_epi16(ul_ch_mag128_0[0], 1);
ul_ch_mag128b_0[0] = simde_mm_mulhi_epi16(ul_ch_mag128b_0[0], QAM_amp128b);
ul_ch_mag128b_0[0] = simde_mm_slli_epi16(ul_ch_mag128b_0[0], 1);
ul_ch_mag128c_0[0] = simde_mm_mulhi_epi16(ul_ch_mag128c_0[0], QAM_amp128c);
ul_ch_mag128c_0[0] = simde_mm_slli_epi16(ul_ch_mag128c_0[0], 1);
// Layer 1
ul_ch_mag128_1[0] = mmtmpD2;
ul_ch_mag128b_1[0] = mmtmpD2;
ul_ch_mag128c_1[0] = mmtmpD2;
ul_ch_mag128_1[0] = simde_mm_mulhi_epi16(ul_ch_mag128_1[0], QAM_amp128);
ul_ch_mag128_1[0] = simde_mm_slli_epi16(ul_ch_mag128_1[0], 1);
ul_ch_mag128b_1[0] = simde_mm_mulhi_epi16(ul_ch_mag128b_1[0], QAM_amp128b);
ul_ch_mag128b_1[0] = simde_mm_slli_epi16(ul_ch_mag128b_1[0], 1);
ul_ch_mag128c_1[0] = simde_mm_mulhi_epi16(ul_ch_mag128c_1[0], QAM_amp128c);
ul_ch_mag128c_1[0] = simde_mm_slli_epi16(ul_ch_mag128c_1[0], 1);
}
// multiply by channel Inv
//rxdataF_zf128_0 = rxdataF_comp128_0*d - b*rxdataF_comp128_1
//rxdataF_zf128_1 = rxdataF_comp128_1*a - c*rxdataF_comp128_0
//printf("layer_1 \n");
mmtmpD0 = nr_ulsch_comp_muli_sum(rxdataF_comp128_0[0],
after_mf_d_128[0],
rxdataF_comp128_1[0],
after_mf_b_128[0],
determ_fin_128[0]);
//printf("layer_2 \n");
mmtmpD1 = nr_ulsch_comp_muli_sum(rxdataF_comp128_1[0],
after_mf_a_128[0],
rxdataF_comp128_0[0],
after_mf_c_128[0],
determ_fin_128[0]);
rxdataF_comp128_0[0] = mmtmpD0;
rxdataF_comp128_1[0] = mmtmpD1;
#ifdef DEBUG_DLSCH_DEMOD
printf("\n Rx signal after ZF l%d rb%d\n",symbol,rb);
print_shorts(" Rx layer 1:",(int16_t*)&rxdataF_comp128_0[0]);
print_shorts(" Rx layer 2:",(int16_t*)&rxdataF_comp128_1[0]);
#endif
determ_fin_128 += 1;
ul_ch_mag128_0 += 1;
ul_ch_mag128_1 += 1;
ul_ch_mag128b_0 += 1;
ul_ch_mag128b_1 += 1;
ul_ch_mag128c_0 += 1;
ul_ch_mag128c_1 += 1;
rxdataF_comp128_0 += 1;
rxdataF_comp128_1 += 1;
after_mf_a_128 += 1;
after_mf_b_128 += 1;
after_mf_c_128 += 1;
after_mf_d_128 += 1;
}
return(0);
}
static void inner_rx(PHY_VARS_gNB *gNB,
int slot,
NR_DL_FRAME_PARMS *frame_parms,
......@@ -923,25 +243,22 @@ static void inner_rx(PHY_VARS_gNB *gNB,
c16_t rxF_ch_magc[nb_layer][buffer_length] __attribute__((aligned(64)));
memset(rho, 0, sizeof(rho));
memset(rxF_ch_maga, 0, sizeof(rxF_ch_maga));
memset(rxF_ch_magb, 0, sizeof(rxF_ch_magb));
memset(rxF_ch_magc, 0, sizeof(rxF_ch_magc));
for (int i = 0; i < nb_layer; i++)
memset(&pusch_vars->rxdataF_comp[i*nb_rx_ant][symbol * buffer_length], 0, sizeof(int32_t) * buffer_length);
nr_ulsch_channel_compensation(buffer_length,
nb_rx_ant,
rxFext,
chFext,
rxF_ch_maga,
rxF_ch_magb,
rxF_ch_magc,
pusch_vars->rxdataF_comp,
nb_layer,
rho,
rel15_ul,
symbol,
output_shift);
memset(&pusch_vars->rxdataF_comp[i][symbol * buffer_length], 0, sizeof(int32_t) * buffer_length);
nr_channel_compensation(buffer_length,
nb_rx_ant,
nb_layer,
rxFext,
chFext,
rxF_ch_maga,
rxF_ch_magb,
rxF_ch_magc,
pusch_vars->rxdataF_comp,
(nb_layer > 1) ? rho : NULL,
rel15_ul->qam_mod_order,
symbol,
output_shift);
stop_meas(pusch_ch_comp);
if (nb_layer == 1 && rel15_ul->transform_precoding == transformPrecoder_enabled && rel15_ul->qam_mod_order <= 6) {
......@@ -955,57 +272,57 @@ static void inner_rx(PHY_VARS_gNB *gNB,
rel15_ul->qam_mod_order);
nr_idft((int32_t *)&pusch_vars->rxdataF_comp[0][symbol * buffer_length], pusch_vars->ul_valid_re_per_slot[symbol]);
}
/* PTRS processing for multiple antenna ports is broken because the following
function estimates phase offset from and applies compensation to rxdataF_comp
for each antenna port but rxdataF_comp has MRCed data. */
/* TODO: Move PTRS phase estimation before immediately after DMRS channels
estimation and apply PTRS phase compensation in nr_channel_compensationi() */
if (rel15_ul->pdu_bit_map & PUSCH_PDU_BITMAP_PUSCH_PTRS) {
nr_pusch_ptrs_processing(gNB,
frame_parms,
rel15_ul,
pusch_vars,
slot,
symbol,
nb_rx_ant,
buffer_length);
// rxdataF_comp is MRCed so no point in processing all antenna ports. Fixme.
nr_pusch_ptrs_processing(gNB, frame_parms, rel15_ul, pusch_vars, slot, symbol, 1, buffer_length);
pusch_vars->ul_valid_re_per_slot[symbol] -= pusch_vars->ptrs_re_per_slot;
}
start_meas(ulsch_llr);
if (nb_layer == 2) {
if (rel15_ul->qam_mod_order <= 6) {
nr_ulsch_compute_ML_llr((c16_t *)&pusch_vars->rxdataF_comp[0][symbol * buffer_length],
(c16_t *)&pusch_vars->rxdataF_comp[nb_rx_ant][symbol * buffer_length],
rxF_ch_maga[0],
rxF_ch_maga[1],
llr[0],
llr[1],
rho[0][1],
rho[1][0],
pusch_vars->ul_valid_re_per_slot[symbol],
rel15_ul->qam_mod_order);
nr_compute_ML_llr((c16_t *)&pusch_vars->rxdataF_comp[0][symbol * buffer_length],
(c16_t *)&pusch_vars->rxdataF_comp[1][symbol * buffer_length],
rxF_ch_maga[0],
rxF_ch_maga[1],
llr[0],
llr[1],
rho[0][1],
rho[1][0],
pusch_vars->ul_valid_re_per_slot[symbol],
rel15_ul->qam_mod_order);
}
else {
nr_ulsch_mmse_2layers(pusch_vars->rxdataF_comp,
buffer_length,
nb_rx_ant,
rxF_ch_maga,
rxF_ch_magb,
rxF_ch_magc,
chFext,
rel15_ul->rb_size,
rel15_ul->qam_mod_order,
pusch_vars->log2_maxh,
symbol,
pusch_vars->ul_valid_re_per_slot[symbol],
nvar);
nr_mmse_2layers(pusch_vars->rxdataF_comp,
buffer_length,
nb_rx_ant,
nb_layer,
rxF_ch_maga,
rxF_ch_magb,
rxF_ch_magc,
chFext,
rel15_ul->rb_size,
rel15_ul->qam_mod_order,
pusch_vars->log2_maxh,
symbol,
pusch_vars->ul_valid_re_per_slot[symbol],
nvar);
}
}
if (nb_layer != 2 || rel15_ul->qam_mod_order > 6)
for (int aatx = 0; aatx < nb_layer; aatx++)
nr_ulsch_compute_llr(&pusch_vars->rxdataF_comp[aatx * nb_rx_ant][symbol * buffer_length],
rxF_ch_maga[aatx],
rxF_ch_magb[aatx],
rxF_ch_magc[aatx],
llr[aatx],
pusch_vars->ul_valid_re_per_slot[symbol],
symbol,
rel15_ul->qam_mod_order);
nr_compute_llr(&pusch_vars->rxdataF_comp[aatx][symbol * buffer_length],
rxF_ch_maga[aatx],
rxF_ch_magb[aatx],
rxF_ch_magc[aatx],
llr[aatx],
pusch_vars->ul_valid_re_per_slot[symbol],
symbol,
rel15_ul->qam_mod_order);
stop_meas(ulsch_llr);
}
......@@ -1047,7 +364,7 @@ static void nr_pusch_symbol_processing(void *arg)
continue;
int soffset = (slot % RU_RX_SLOT_DEPTH) * frame_parms->symbols_per_slot * frame_parms->ofdm_symbol_size;
int buffer_length = ceil_mod(pusch_vars->ul_valid_re_per_slot[symbol] * NR_NB_SC_PER_RB, 16);
int16_t llrs[rel15_ul->nrOfLayers][ceil_mod(buffer_length * rel15_ul->qam_mod_order, 64)];
int16_t llrs[rel15_ul->nrOfLayers][ceil_mod(buffer_length * rel15_ul->qam_mod_order, 64)] __attribute__((aligned(32)));
int16_t *llrss[rel15_ul->nrOfLayers];
for (int l = 0; l < rel15_ul->nrOfLayers; l++)
llrss[l] = llrs[l];
......
......@@ -1345,7 +1345,7 @@ void nr_pdsch_ptrs_processing(int nbRx,
int32_t ptrs_re_per_slot[][14],
uint32_t rx_size_symbol,
int nl,
c16_t rxdataF_comp[][nl][nbRx][rx_size_symbol],
c16_t rxdataF_comp[][nl][rx_size_symbol],
NR_DL_FRAME_PARMS *frame_parms,
fapi_nr_dl_config_dlsch_pdu_rel15_t *dlsch_config,
uint8_t nr_slot_rx,
......@@ -1369,7 +1369,7 @@ void nr_pdsch_ptrs_processing(int nbRx,
int nscid = dlsch_config->nscid;
/* loop over antennas */
for (int aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) {
for (int aarx = 0; aarx < nbRx; aarx++) {
c16_t *phase_per_symbol = (c16_t*)ptrs_phase_per_slot[aarx];
ptrs_re_symbol = (int32_t*)ptrs_re_per_slot[aarx];
ptrs_re_symbol[symbol] = 0;
......@@ -1404,7 +1404,7 @@ void nr_pdsch_ptrs_processing(int nbRx,
nb_rb,
rnti,
frame_parms->ofdm_symbol_size,
rxdataF_comp[symbol][0][aarx],
rxdataF_comp[symbol][aarx],
gold,
(int16_t *)&phase_per_symbol[symbol],
&ptrs_re_symbol[symbol]);
......@@ -1436,9 +1436,9 @@ void nr_pdsch_ptrs_processing(int nbRx,
#ifdef DEBUG_DL_PTRS
printf("[PHY][DL][PTRS]: Rotate Symbol %2d with %d + j* %d\n", i, phase_per_symbol[i].r, phase_per_symbol[i].i);
#endif
rotate_cpx_vector(rxdataF_comp[i][0][aarx], &phase_per_symbol[i], rxdataF_comp[i][0][aarx], nb_rb * NR_NB_SC_PER_RB, 15);
rotate_cpx_vector(rxdataF_comp[i][aarx], &phase_per_symbol[i], rxdataF_comp[i][aarx], nb_rb * NR_NB_SC_PER_RB, 15);
}// if not DMRS Symbol
}// symbol loop
}// last symbol check
}//Antenna loop
} // Antenna loop
}//main function
......@@ -119,7 +119,7 @@ void nr_pdsch_ptrs_processing(int nbRx,
int32_t ptrs_re_per_slot[][14],
uint32_t rx_size_symbol,
int nl,
c16_t rxdataF_comp[][nl][nbRx][rx_size_symbol],
c16_t rxdataF_comp[][nl][rx_size_symbol],
NR_DL_FRAME_PARMS *frame_parms,
fapi_nr_dl_config_dlsch_pdu_rel15_t *dlsch_config,
uint8_t nr_slot_rx,
......
......@@ -109,127 +109,6 @@ static uint32_t build_csi_overlap_bitmap(fapi_nr_dl_config_dlsch_pdu_rel15_t *dl
// Pre-processing for LLR computation
//==============================================================================================
static void nr_dlsch_channel_compensation(uint32_t rx_size_symbol,
int nbRx,
uint8_t n_layers,
c16_t rxdataF_ext[][rx_size_symbol],
int32_t dl_ch_estimates_ext[][rx_size_symbol],
c16_t dl_ch_mag[][nbRx][rx_size_symbol],
c16_t dl_ch_magb[][nbRx][rx_size_symbol],
c16_t dl_ch_magr[][nbRx][rx_size_symbol],
c16_t rxdataF_comp[][n_layers][nbRx][rx_size_symbol],
int ***rho,
NR_DL_FRAME_PARMS *frame_parms,
unsigned char symbol,
int length,
unsigned char mod_order,
unsigned short nb_rb,
unsigned char output_shift)
{
simde__m128i *dl_ch128, *dl_ch128_2, *dl_ch_mag128, *dl_ch_mag128b, *dl_ch_mag128r, *rxdataF128, *rxdataF_comp128, *rho128;
simde__m128i QAM_amp128 = {0}, QAM_amp128b = {0}, QAM_amp128r = {0};
uint32_t nb_rb_0 = length / 12 + ((length % 12) ? 1 : 0);
for (int l = 0; l < n_layers; l++) {
if (mod_order == 4) {
QAM_amp128 = simde_mm_set1_epi16(QAM16_n1); // 2/sqrt(10)
QAM_amp128b = simde_mm_setzero_si128();
QAM_amp128r = simde_mm_setzero_si128();
} else if (mod_order == 6) {
QAM_amp128 = simde_mm_set1_epi16(QAM64_n1); //
QAM_amp128b = simde_mm_set1_epi16(QAM64_n2);
QAM_amp128r = simde_mm_setzero_si128();
} else if (mod_order == 8) {
QAM_amp128 = simde_mm_set1_epi16(QAM256_n1);
QAM_amp128b = simde_mm_set1_epi16(QAM256_n2);
QAM_amp128r = simde_mm_set1_epi16(QAM256_n3);
}
for (int aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) {
dl_ch128 = (simde__m128i *)dl_ch_estimates_ext[(l * frame_parms->nb_antennas_rx) + aarx];
dl_ch_mag128 = (simde__m128i *)dl_ch_mag[l][aarx];
dl_ch_mag128b = (simde__m128i *)dl_ch_magb[l][aarx];
dl_ch_mag128r = (simde__m128i *)dl_ch_magr[l][aarx];
rxdataF128 = (simde__m128i *)rxdataF_ext[aarx];
rxdataF_comp128 = (simde__m128i *)(rxdataF_comp[symbol][l][aarx]);
for (int rb = 0; rb < nb_rb_0; rb++) {
if (mod_order > 2) {
// get channel amplitude if not QPSK
simde__m128i mmtmpD0 = simde_mm_madd_epi16(dl_ch128[0], dl_ch128[0]);
mmtmpD0 = simde_mm_srai_epi32(mmtmpD0, output_shift);
simde__m128i mmtmpD1 = simde_mm_madd_epi16(dl_ch128[1], dl_ch128[1]);
mmtmpD1 = simde_mm_srai_epi32(mmtmpD1, output_shift);
mmtmpD0 = simde_mm_packs_epi32(mmtmpD0, mmtmpD1); //|H[0]|^2 |H[1]|^2 |H[2]|^2 |H[3]|^2 |H[4]|^2 |H[5]|^2 |H[6]|^2 |H[7]|^2
// store channel magnitude here in a new field of dlsch
dl_ch_mag128[0] = simde_mm_unpacklo_epi16(mmtmpD0, mmtmpD0);
dl_ch_mag128b[0] = dl_ch_mag128[0];
dl_ch_mag128r[0] = dl_ch_mag128[0];
dl_ch_mag128[0] = simde_mm_mulhrs_epi16(dl_ch_mag128[0], QAM_amp128);
dl_ch_mag128b[0] = simde_mm_mulhrs_epi16(dl_ch_mag128b[0], QAM_amp128b);
dl_ch_mag128r[0] = simde_mm_mulhrs_epi16(dl_ch_mag128r[0], QAM_amp128r);
dl_ch_mag128[1] = simde_mm_unpackhi_epi16(mmtmpD0, mmtmpD0);
dl_ch_mag128b[1] = dl_ch_mag128[1];
dl_ch_mag128r[1] = dl_ch_mag128[1];
dl_ch_mag128[1] = simde_mm_mulhrs_epi16(dl_ch_mag128[1], QAM_amp128);
dl_ch_mag128b[1] = simde_mm_mulhrs_epi16(dl_ch_mag128b[1], QAM_amp128b);
dl_ch_mag128r[1] = simde_mm_mulhrs_epi16(dl_ch_mag128r[1], QAM_amp128r);
mmtmpD0 = simde_mm_madd_epi16(dl_ch128[2], dl_ch128[2]);
mmtmpD0 = simde_mm_srai_epi32(mmtmpD0, output_shift);
mmtmpD1 = simde_mm_packs_epi32(mmtmpD0, mmtmpD0);
dl_ch_mag128[2] = simde_mm_unpacklo_epi16(mmtmpD1, mmtmpD1);
dl_ch_mag128b[2] = dl_ch_mag128[2];
dl_ch_mag128r[2] = dl_ch_mag128[2];
dl_ch_mag128[2] = simde_mm_mulhrs_epi16(dl_ch_mag128[2], QAM_amp128);
dl_ch_mag128b[2] = simde_mm_mulhrs_epi16(dl_ch_mag128b[2], QAM_amp128b);
dl_ch_mag128r[2] = simde_mm_mulhrs_epi16(dl_ch_mag128r[2], QAM_amp128r);
}
// Multiply received data by conjugated channel
rxdataF_comp128[0] = oai_mm_cpx_mult_conj(dl_ch128[0], rxdataF128[0], output_shift);
rxdataF_comp128[1] = oai_mm_cpx_mult_conj(dl_ch128[1], rxdataF128[1], output_shift);
rxdataF_comp128[2] = oai_mm_cpx_mult_conj(dl_ch128[2], rxdataF128[2], output_shift);
dl_ch128 += 3;
dl_ch_mag128 += 3;
dl_ch_mag128b += 3;
dl_ch_mag128r += 3;
rxdataF128 += 3;
rxdataF_comp128 += 3;
}
}
}
if (rho) {
// we compute the Tx correlation matrix for each Rx antenna
// As an example the 2x2 MIMO case requires
// rho[aarx][nl*nl] = [cov(H_aarx_0,H_aarx_0) cov(H_aarx_0,H_aarx_1)
// cov(H_aarx_1,H_aarx_0) cov(H_aarx_1,H_aarx_1)], aarx=0,...,nb_antennas_rx-1
for (int aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) {
for (int l = 0; l < n_layers; l++) {
for (int atx = 0; atx < n_layers; atx++) {
rho128 = (simde__m128i *)&rho[aarx][l * n_layers + atx][symbol * nb_rb * 12];
dl_ch128 = (simde__m128i *)dl_ch_estimates_ext[l * frame_parms->nb_antennas_rx + aarx];
dl_ch128_2 = (simde__m128i *)dl_ch_estimates_ext[atx * frame_parms->nb_antennas_rx + aarx];
// multiply by conjugated channel
mult_cpx_conj_vector((c16_t *)dl_ch128, (c16_t *)dl_ch128_2, (c16_t *)rho128, 12 * nb_rb_0, output_shift);
}
}
}
}
}
static void nr_dlsch_channel_level_median(uint32_t rx_size_symbol,
int32_t dl_ch_estimates_ext[][rx_size_symbol],
int32_t median[MAX_ANT][MAX_ANT],
......@@ -371,64 +250,6 @@ static void nr_dlsch_extract_rbs(uint32_t rxdataF_sz,
}
}
static void nr_dlsch_detection_mrc(uint32_t rx_size_symbol,
short nl,
short n_rx,
c16_t rxdataF_comp[][nl][n_rx][rx_size_symbol],
int ***rho,
c16_t dl_ch_mag[][n_rx][rx_size_symbol],
c16_t dl_ch_magb[][n_rx][rx_size_symbol],
c16_t dl_ch_magr[][n_rx][rx_size_symbol],
unsigned char symbol,
int length)
{
simde__m128i *rxdataF_comp128_0,*rxdataF_comp128_1,*dl_ch_mag128_0,*dl_ch_mag128_1,*dl_ch_mag128_0b,*dl_ch_mag128_1b,*dl_ch_mag128_0r,*dl_ch_mag128_1r;
uint32_t nb_rb_0 = length / 12 + ((length % 12) ? 1 : 0);
if (n_rx > 1) {
for (int l = 0; l < nl; l++) {
rxdataF_comp128_0 = (simde__m128i *)(rxdataF_comp[symbol][l][0]);
dl_ch_mag128_0 = (simde__m128i *)dl_ch_mag[l][0];
dl_ch_mag128_0b = (simde__m128i *)dl_ch_magb[l][0];
dl_ch_mag128_0r = (simde__m128i *)dl_ch_magr[l][0];
for (int aarx = 1; aarx < n_rx; aarx++) {
rxdataF_comp128_1 = (simde__m128i *)(rxdataF_comp[symbol][l][aarx]);
dl_ch_mag128_1 = (simde__m128i *)dl_ch_mag[l][aarx];
dl_ch_mag128_1b = (simde__m128i *)dl_ch_magb[l][aarx];
dl_ch_mag128_1r = (simde__m128i *)dl_ch_magr[l][aarx];
// MRC on each re of rb, both on MF output and magnitude (for 16QAM/64QAM/256 llr computation)
for (int i = 0; i < nb_rb_0 * 3; i++) {
rxdataF_comp128_0[i] = simde_mm_adds_epi16(rxdataF_comp128_0[i],rxdataF_comp128_1[i]);
dl_ch_mag128_0[i] = simde_mm_adds_epi16(dl_ch_mag128_0[i],dl_ch_mag128_1[i]);
dl_ch_mag128_0b[i] = simde_mm_adds_epi16(dl_ch_mag128_0b[i],dl_ch_mag128_1b[i]);
dl_ch_mag128_0r[i] = simde_mm_adds_epi16(dl_ch_mag128_0r[i],dl_ch_mag128_1r[i]);
}
}
}
#ifdef DEBUG_DLSCH_DEMOD
for (int i = 0; i < nb_rb_0 * 3; i++) {
printf("symbol%d RB %d\n", symbol, i / 3);
rxdataF_comp128_0 = (simde__m128i *)(rxdataF_comp[0][0] + symbol * rx_size_symbol);
rxdataF_comp128_1 = (simde__m128i *)(rxdataF_comp[0][n_rx] + symbol * rx_size_symbol);
print_shorts("tx 1 mrc_re/mrc_Im:",(int16_t*)&rxdataF_comp128_0[i]);
print_shorts("tx 2 mrc_re/mrc_Im:",(int16_t*)&rxdataF_comp128_1[i]);
// printf("mrc mag0 = %d = %d \n",((int16_t*)&dl_ch_mag128_0[0])[0],((int16_t*)&dl_ch_mag128_0[0])[1]);
// printf("mrc mag0b = %d = %d \n",((int16_t*)&dl_ch_mag128_0b[0])[0],((int16_t*)&dl_ch_mag128_0b[0])[1]);
}
#endif
if (rho) {
/*rho128_0 = (simde__m128i *) &rho[0][symbol*frame_parms->N_RB_DL*12];
rho128_1 = (simde__m128i *) &rho[1][symbol*frame_parms->N_RB_DL*12];
for (i=0; i<nb_rb_0*3; i++) {
// print_shorts("mrc rho0:",&rho128_0[i]);
// print_shorts("mrc rho1:",&rho128_1[i]);
rho128_0[i] = simde_mm_adds_epi16(simde_mm_srai_epi16(rho128_0[i],1),simde_mm_srai_epi16(rho128_1[i],1));
}*/
}
}
}
/* Zero Forcing Rx function: nr_a_sum_b()
* Compute the complex addition x=x+y
*
......@@ -703,10 +524,10 @@ void nr_conjch0_mult_ch1(c16_t *ch0, c16_t *ch1, c16_t *ch0conj_ch1, unsigned sh
static void nr_dlsch_mmse(uint32_t rx_size_symbol,
unsigned char n_rx,
unsigned char nl, // number of layer
c16_t rxdataF_comp[][nl][n_rx][rx_size_symbol],
c16_t dl_ch_mag[][n_rx][rx_size_symbol],
c16_t dl_ch_magb[][n_rx][rx_size_symbol],
c16_t dl_ch_magr[][n_rx][rx_size_symbol],
c16_t rxdataF_comp[][nl][rx_size_symbol],
c16_t dl_ch_mag[][rx_size_symbol],
c16_t dl_ch_magb[][rx_size_symbol],
c16_t dl_ch_magr[][rx_size_symbol],
int32_t dl_ch_estimates_ext[][rx_size_symbol],
unsigned char mod_order,
int shift,
......@@ -786,7 +607,7 @@ static void nr_dlsch_mmse(uint32_t rx_size_symbol,
// print_shorts(" H_h_H=",(int16_t*)&conjH_H_elements[ctx*nl+rtx][0][0]);
// print_shorts(" Inv_H_h_H=",(int16_t*)&inv_H_h_H[ctx*nl+rtx][0]);
mult_complex_vectors(inv_H_h_H[ctx][rtx],
rxdataF_comp[symbol][ctx][0],
rxdataF_comp[symbol][ctx],
outtemp,
sizeofArray(outtemp),
shift - (fp_flag == 1 ? 1 : 0));
......@@ -802,7 +623,7 @@ static void nr_dlsch_mmse(uint32_t rx_size_symbol,
//Copy zero_forcing out to output array
for (int rtx = 0; rtx < nl; rtx++)
nr_element_sign(rxdataF_zforcing[rtx], rxdataF_comp[symbol][rtx][0], nb_rb_0, +1);
nr_element_sign(rxdataF_zforcing[rtx], rxdataF_comp[symbol][rtx], nb_rb_0, +1);
//Update LLR thresholds with the Matrix determinant
simde__m128i *dl_ch_mag128_0=NULL,*dl_ch_mag128b_0=NULL,*dl_ch_mag128r_0=NULL,*determ_fin_128;
......@@ -825,9 +646,9 @@ static void nr_dlsch_mmse(uint32_t rx_size_symbol,
QAM_amp128b = simde_mm_set1_epi16(QAM256_n2);//4/sqrt{170}
QAM_amp128r = simde_mm_set1_epi16(QAM256_n3);//2/sqrt{170}
}
dl_ch_mag128_0 = (simde__m128i *)dl_ch_mag[0][0];
dl_ch_mag128b_0 = (simde__m128i *)dl_ch_magb[0][0];
dl_ch_mag128r_0 = (simde__m128i *)dl_ch_magr[0][0];
dl_ch_mag128_0 = (simde__m128i *)dl_ch_mag[0];
dl_ch_mag128b_0 = (simde__m128i *)dl_ch_magb[0];
dl_ch_mag128r_0 = (simde__m128i *)dl_ch_magr[0];
for (int rb = 0; rb < 3 * nb_rb_0; rb++) {
//for symmetric H_h_H matrix, the determinant is only real values
......@@ -901,34 +722,29 @@ static int nr_dlsch_llr(const NR_UE_DLSCH_t *dlsch,
const c16_t dl_ch_magb[rx_size_symbol],
const c16_t dl_ch_magr[rx_size_symbol],
const int nb_antennas_rx,
const c16_t rxdataF_comp[dlsch->cw_info.Nl][nb_antennas_rx][rx_size_symbol],
const c16_t rxdataF_comp[dlsch->cw_info.Nl][rx_size_symbol],
const int llrSize,
int16_t layer_llr[dlsch->cw_info.Nl][llrSize])
{
switch (dlsch->cw_info.qamModOrder) {
case 2 :
for (int l = 0; l < dlsch->cw_info.Nl; l++)
nr_qpsk_llr(rxdataF_comp[l][0], layer_llr[l], len);
nr_qpsk_llr(rxdataF_comp[l], layer_llr[l], len);
break;
case 4 :
for (int l = 0; l < dlsch->cw_info.Nl; l++)
nr_16qam_llr(rxdataF_comp[l][0], dl_ch_mag, layer_llr[l], len);
nr_16qam_llr(rxdataF_comp[l], dl_ch_mag, layer_llr[l], len);
break;
case 6 :
for(int l=0; l < dlsch->cw_info.Nl; l++)
nr_64qam_llr(rxdataF_comp[l][0], dl_ch_mag, dl_ch_magb, layer_llr[l], len);
nr_64qam_llr(rxdataF_comp[l], dl_ch_mag, dl_ch_magb, layer_llr[l], len);
break;
case 8:
for(int l=0; l < dlsch->cw_info.Nl; l++)
nr_256qam_llr(rxdataF_comp[l][0],
dl_ch_mag,
dl_ch_magb,
dl_ch_magr,
layer_llr[l],
len);
nr_256qam_llr(rxdataF_comp[l], dl_ch_mag, dl_ch_magb, dl_ch_magr, layer_llr[l], len);
break;
default:
......@@ -941,6 +757,7 @@ static int nr_dlsch_llr(const NR_UE_DLSCH_t *dlsch,
//==============================================================================================
/* Main Function */
int nr_rx_pdsch(PHY_VARS_NR_UE *ue,
const UE_nr_rxtx_proc_t *proc,
NR_UE_DLSCH_t *dlsch,
......@@ -958,22 +775,34 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue,
int32_t *log2_maxh,
int rx_size_symbol,
int nbRx,
c16_t rxdataF_comp[][dlsch->cw_info.Nl][nbRx][rx_size_symbol],
c16_t dl_ch_mag[][dlsch->cw_info.Nl][nbRx][rx_size_symbol],
c16_t dl_ch_magb[][dlsch->cw_info.Nl][nbRx][rx_size_symbol],
c16_t dl_ch_magr[][dlsch->cw_info.Nl][nbRx][rx_size_symbol],
c16_t rxdataF_comp[][dlsch->cw_info.Nl][rx_size_symbol],
c16_t dl_ch_mag[][dlsch->cw_info.Nl][rx_size_symbol],
c16_t dl_ch_magb[][dlsch->cw_info.Nl][rx_size_symbol],
c16_t dl_ch_magr[][dlsch->cw_info.Nl][rx_size_symbol],
c16_t ptrs_phase_per_slot[][NR_SYMBOLS_PER_SLOT],
int32_t ptrs_re_per_slot[][NR_SYMBOLS_PER_SLOT],
uint32_t nvar,
pdsch_scope_req_t *scope_req)
pdsch_scope_req_t *scope_req,
c16_t rho_dl[][dlsch->cw_info.Nl * dlsch->cw_info.Nl][rx_size_symbol])
{
NR_DL_FRAME_PARMS *fp = &ue->frame_parms;
const int nl = dlsch->cw_info.Nl;
const int n_rx = fp->nb_antennas_rx;
const int matrixSz = n_rx * nl;
const int matrixSz = nbRx * nl;
__attribute__((aligned(32))) int32_t dl_ch_estimates_ext[matrixSz][rx_size_symbol];
memset(dl_ch_estimates_ext, 0, sizeof(dl_ch_estimates_ext));
// Use ML-based LLR for 2-layer MIMO with QPSK/16QAM/64QAM (nl==2, qamModOrder<=6).
// Controlled by ue->do_ml (set via -E flag in dlsim, or ue->do_ml in the UE struct).
// When false (default), MMSE equalization is used for all configurations.
bool do_ml = ue->do_ml;
// Reinterpret flat dl_ch_estimates_ext as [nl][nbRx][rx_size_symbol]
c16_t(*chFext)[nbRx][rx_size_symbol] = (void *)dl_ch_estimates_ext;
c16_t *p_rxComp[nl];
for (int l = 0; l < nl; l++)
p_rxComp[l] = rxdataF_comp[symbol][l];
NR_UE_COMMON *common_vars = &ue->common_vars;
const int frame = proc->frame_rx;
const int nr_slot_rx = proc->nr_slot_rx;
......@@ -998,6 +827,9 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue,
uint8_t pilots = (dlsch_config->dlDmrsSymbPos >> symbol) & 1;
uint8_t config_type = dlsch_config->dmrsConfigType;
const bool need_rho = do_ml ? (nl == 2 && dlsch_config->cw_info->qamModOrder <= 6) : false;
//----------------------------------------------------------
//--------------------- RBs extraction ---------------------
//----------------------------------------------------------
......@@ -1084,7 +916,7 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue,
//--------------------- Channel Scaling --------------------
//----------------------------------------------------------
start_meas_nr_ue_phy(ue, DLSCH_CHANNEL_SCALE_STATS);
nr_scale_channel(rx_size_symbol, dl_ch_estimates_ext, 0, nb_re_pdsch, nl, n_rx, 0);
nr_scale_channel(rx_size_symbol, dl_ch_estimates_ext, 0, nb_re_pdsch, nl, nbRx, 0);
stop_meas_nr_ue_phy(ue, DLSCH_CHANNEL_SCALE_STATS);
if (meas_enabled) {
LOG_D(PHY,
......@@ -1101,29 +933,35 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue,
//----------------------------------------------------------
start_meas_nr_ue_phy(ue, DLSCH_CHANNEL_LEVEL_STATS);
if (first_symbol_flag) {
int32_t avg[nl * n_rx];
int32_t avg[nl * nbRx];
if (nb_re_pdsch)
nr_channel_level(0, rx_size_symbol, (c16_t (*)[rx_size_symbol])dl_ch_estimates_ext, n_rx, nl, avg, nb_re_pdsch);
nr_channel_level(0, rx_size_symbol, (c16_t(*)[rx_size_symbol])dl_ch_estimates_ext, nbRx, nl, avg, nb_re_pdsch);
else
LOG_E(NR_PHY, "Average channel level is 0: nb_rb_pdsch = %d, nb_re_pdsch = %d\n", nb_rb_pdsch, nb_re_pdsch);
int avgs = 0;
int32_t median[MAX_ANT][MAX_ANT];
for (int l = 0; l < nl; l++)
for (int aarx = 0; aarx < n_rx; aarx++) {
avgs = cmax(avgs, avg[l * n_rx + aarx]);
LOG_D(PHY, "nb_rb %d avg_%d_%d Power per SC is %d\n", nb_rb_pdsch, aarx, l, avg[l * n_rx + aarx]);
for (int aarx = 0; aarx < nbRx; aarx++) {
avgs = cmax(avgs, avg[l * nbRx + aarx]);
LOG_D(PHY, "nb_rb %d avg_%d_%d Power per SC is %d\n", nb_rb_pdsch, aarx, l, avg[l * nbRx + aarx]);
LOG_D(PHY, "avgs Power per SC is %d\n", avgs);
median[l][aarx] = avg[l * n_rx + aarx];
median[l][aarx] = avg[l * nbRx + aarx];
}
if (nl > 1) {
nr_dlsch_channel_level_median(rx_size_symbol, dl_ch_estimates_ext, median, nl, n_rx, nb_re_pdsch);
nr_dlsch_channel_level_median(rx_size_symbol, dl_ch_estimates_ext, median, nl, nbRx, nb_re_pdsch);
for (int l = 0; l < nl; l++) {
for (int aarx = 0; aarx < n_rx; aarx++) {
for (int aarx = 0; aarx < nbRx; aarx++) {
avgs = cmax(avgs, median[l][aarx]);
}
}
}
*log2_maxh = (log2_approx(avgs) / 2) + 1;
// Output shift: half channel energy (log2|h|^2/2) + MRC antenna gain.
// Single-layer adds +1 guard bit (raw peak); multi-layer uses median so no guard needed.
if (nl == 1)
*log2_maxh = (log2_approx(avgs) >> 1) + 1 + log2_approx(nbRx >> 1);
else
*log2_maxh = (log2_approx(avgs) >> 1) + log2_approx(nbRx >> 1);
LOG_D(PHY, "[DLSCH] AbsSubframe %d.%d log2_maxh = %d (%d)\n", frame % 1024, nr_slot_rx, *log2_maxh, avgs);
#if T_TRACER
T(T_UE_PHY_PDSCH_ENERGY,
......@@ -1131,9 +969,9 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue,
T_INT(frame % 1024),
T_INT(nr_slot_rx),
T_INT(avg[0]), // layer 0, antenna 0
T_INT(n_rx > 1 ? avg[1] : 0), // layer 0, antenna 1
T_INT(nl > 1 ? avg[n_rx] : 0), // layer 1, antenna 0
T_INT(nl > 1 && n_rx > 1 ? avg[n_rx + 1] : 0)); // layer 1, antenna 1
T_INT(nbRx > 1 ? avg[1] : 0), // layer 0, antenna 1
T_INT(nl > 1 ? avg[nbRx] : 0), // layer 1, antenna 0
T_INT(nl > 1 && nbRx > 1 ? avg[nbRx + 1] : 0)); // layer 1, antenna 1
#endif
}
stop_meas_nr_ue_phy(ue, DLSCH_CHANNEL_LEVEL_STATS);
......@@ -1151,24 +989,20 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue,
//----------------------------------------------------------
//--------------------- channel compensation ---------------
//----------------------------------------------------------
// Disable correlation measurement for optimizing UE
start_meas_nr_ue_phy(ue, DLSCH_CHANNEL_COMPENSATION_STATS);
nr_dlsch_channel_compensation(rx_size_symbol,
nbRx,
nl,
rxdataF_ext,
dl_ch_estimates_ext,
dl_ch_mag[symbol],
dl_ch_magb[symbol],
dl_ch_magr[symbol],
rxdataF_comp,
NULL,
fp,
symbol,
nb_re_pdsch,
dlsch->cw_info.qamModOrder,
nb_rb_pdsch,
*log2_maxh); // log2_maxh+I0_shift
nr_channel_compensation(rx_size_symbol,
nbRx,
nl,
rxdataF_ext,
chFext,
dl_ch_mag[symbol],
dl_ch_magb[symbol],
dl_ch_magr[symbol],
p_rxComp,
need_rho ? (c16_t(*)[nl][rx_size_symbol])rho_dl[symbol] : NULL,
dlsch->cw_info.qamModOrder,
0, // symbol already baked into p_rxComp
*log2_maxh);
stop_meas_nr_ue_phy(ue, DLSCH_CHANNEL_COMPENSATION_STATS);
if (meas_enabled) {
LOG_D(PHY,
......@@ -1197,37 +1031,45 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue,
write_output(filename, "dl_ch_estimates_ext0", &dl_ch_estimates_ext[0][0], rx_size_symbol, 1, 1);
snprintf(filename, 50, "rxdataF_comp00_symb_%d_nr_slot_rx_%d.m", symbol, nr_slot_rx);
write_output(filename, "rxdataF_comp00", &rxdataF_comp[0][0][symbol * rx_size_symbol], rx_size_symbol, 1, 1);
write_output(filename, "rxdataF_comp00", rxdataF_comp[symbol][0], rx_size_symbol, 1, 1);
#endif
}
// MRC is performed inline by nr_channel_compensation; apply MMSE for multi-layer
start_meas_nr_ue_phy(ue, DLSCH_MRC_MMSE_STATS);
if (n_rx > 1) {
nr_dlsch_detection_mrc(rx_size_symbol,
nl,
n_rx,
rxdataF_comp,
NULL,
dl_ch_mag[symbol],
dl_ch_magb[symbol],
dl_ch_magr[symbol],
symbol,
nb_re_pdsch);
if (nl >= 2) // Apply MMSE for 2, 3, and 4 Tx layers
if (nb_re_pdsch)
nr_dlsch_mmse(rx_size_symbol,
n_rx,
if (nb_re_pdsch) {
const uint8_t qamModOrder = dlsch->cw_info.qamModOrder;
if ((nl > 2) || (nl == 2 && !do_ml)) {
nr_dlsch_mmse(rx_size_symbol,
nbRx,
nl,
rxdataF_comp,
dl_ch_mag[symbol],
dl_ch_magb[symbol],
dl_ch_magr[symbol],
dl_ch_estimates_ext,
qamModOrder,
*log2_maxh,
symbol,
nb_re_pdsch,
nvar);
} else if ((nl == 2) && (qamModOrder > 6) && do_ml) {
nr_mmse_2layers(p_rxComp,
rx_size_symbol,
nbRx,
nl,
rxdataF_comp,
dl_ch_mag[symbol],
dl_ch_magb[symbol],
dl_ch_magr[symbol],
dl_ch_estimates_ext,
dlsch->cw_info.qamModOrder,
chFext,
freq_alloc->num_rbs,
qamModOrder,
*log2_maxh,
symbol,
0,
nb_re_pdsch,
nvar);
}
}
stop_meas_nr_ue_phy(ue, DLSCH_MRC_MMSE_STATS);
......@@ -1241,8 +1083,6 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue,
ue->phy_cpu_stats.cpu_time_stats[DLSCH_MRC_MMSE_STATS].p_time / (cpuf * 1000.0));
}
/* Store the valid DL RE's */
dl_valid_re[symbol] = nb_re_pdsch;
int startSymbIdx = 0;
......@@ -1255,9 +1095,14 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue,
pduBitmap = dlsch_config->pduBitmap;
}
/* PTRS processing for multiple antenna ports is broken because the following
function estimates phase offset from and applies compensation to rxdataF_comp
for each antenna port but rxdataF_comp has MRCed data. */
/* TODO: Move PTRS phase estimation before immediately after DMRS channels
estimation and apply PTRS phase compensation in nr_channel_compensationi() */
/* Check for PTRS bitmap and process it respectively */
if((pduBitmap & 0x1) && (dlsch->rnti_type == TYPE_C_RNTI_)) {
nr_pdsch_ptrs_processing(nbRx,
nr_pdsch_ptrs_processing(1, // rxdataF_comp is MRCed so no point in processing all antenna ports. Fixme.
ptrs_phase_per_slot,
ptrs_re_per_slot,
rx_size_symbol,
......@@ -1273,6 +1118,7 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue,
&dlsch->ptrs_symbol_index);
dl_valid_re[symbol] -= ptrs_re_per_slot[0][symbol];
}
/* at last symbol in a slot calculate LLR's for whole slot */
if (symbol == (startSymbIdx + nbSymb - 1)) {
/* create LLR layer buffer */
......@@ -1282,18 +1128,35 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue,
__attribute__((aligned(32))) int16_t layer_llr[NR_SYMBOLS_PER_SLOT][nl][llr_per_symbol];
// Generate LLR from PTRS compensated signal
const uint8_t qamModOrder = dlsch->cw_info.qamModOrder;
start_meas_nr_ue_phy(ue, DLSCH_LLR_STATS);
for (int llr_sym = startSymbIdx; llr_sym < startSymbIdx + nbSymb; llr_sym++) {
nr_dlsch_llr(dlsch,
dl_valid_re[llr_sym],
rx_size_symbol,
dl_ch_mag[llr_sym][0][0],
dl_ch_magb[llr_sym][0][0],
dl_ch_magr[llr_sym][0][0],
n_rx,
rxdataF_comp[llr_sym],
llr_per_symbol,
layer_llr[llr_sym]);
if (nl == 2 && qamModOrder <= 6 && do_ml) {
// 2-layer QPSK/16QAM/64QAM: joint ML-LLR using inter-layer Tx correlation
// rho_dl[llr_sym] is laid out as [nl*nl][rx_size_symbol]:
// index 1 = rho[0][1], index nl (=2) = rho[1][0]
nr_compute_ML_llr(rxdataF_comp[llr_sym][0],
rxdataF_comp[llr_sym][1],
dl_ch_mag[llr_sym][0],
dl_ch_mag[llr_sym][1],
layer_llr[llr_sym][0],
layer_llr[llr_sym][1],
rho_dl[llr_sym][1],
rho_dl[llr_sym][nl],
dl_valid_re[llr_sym],
qamModOrder);
} else {
nr_dlsch_llr(dlsch,
dl_valid_re[llr_sym],
rx_size_symbol,
dl_ch_mag[llr_sym][0],
dl_ch_magb[llr_sym][0],
dl_ch_magr[llr_sym][0],
nbRx,
rxdataF_comp[llr_sym],
llr_per_symbol,
layer_llr[llr_sym]);
}
}
stop_meas_nr_ue_phy(ue, DLSCH_LLR_STATS);
start_meas_nr_ue_phy(ue, DLSCH_LAYER_DEMAPPING);
......@@ -1310,13 +1173,13 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue,
size_t offset = 0;
for (int i = startSymbIdx; i < startSymbIdx + nbSymb; i++) {
size_t data_size = sizeof(c16_t) * dl_valid_re[i];
UEscopeCopyUnsafe(ue, pdschRxdataF_comp, &rxdataF_comp[i][0][0][0], data_size, offset, i);
UEscopeCopyUnsafe(ue, pdschRxdataF_comp, &rxdataF_comp[i][0][0], data_size, offset, i);
offset += data_size;
}
UEunlockScopeData(ue, pdschRxdataF_comp)
}
} else {
UEscopeCopy(ue, pdschRxdataF_comp, rxdataF_comp[0], sizeof(c16_t), nbRx, rx_size_symbol, 0);
UEscopeCopy(ue, pdschRxdataF_comp, rxdataF_comp[0], sizeof(c16_t), nl, rx_size_symbol, 0);
}
}
......@@ -1341,14 +1204,15 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue,
T_BUFFER(&rxdataF_comp[gNB_id][0], 2 * fp->N_RB_DL * 12 * fp->symbols_per_slot * 2));
#endif
if (ue->phy_sim_pdsch_rxdataF_comp)
if (ue->phy_sim_pdsch_rxdataF_comp) {
for (int a = 0; a < nbRx; a++) {
for (int l = 0; l < nl; l++) {
int offset = (void *)rxdataF_comp[symbol][l][a] - (void *)rxdataF_comp[0];
memcpy(ue->phy_sim_pdsch_rxdataF_comp + offset, rxdataF_comp[symbol][l][a], sizeof(c16_t) * rx_size_symbol);
}
memcpy((c16_t *)ue->phy_sim_pdsch_dl_ch_estimates + pdsch_est_size * a, dl_ch_estimates, pdsch_est_size * sizeof(c16_t));
}
for (int l = 0; l < nl; l++) {
int offset = (void *)rxdataF_comp[symbol][l] - (void *)rxdataF_comp[0];
memcpy(ue->phy_sim_pdsch_rxdataF_comp + offset, rxdataF_comp[symbol][l], sizeof(c16_t) * rx_size_symbol);
}
}
if (ue->phy_sim_pdsch_dl_ch_estimates_ext)
memcpy(ue->phy_sim_pdsch_dl_ch_estimates_ext + symbol * sizeof(dl_ch_estimates_ext),
dl_ch_estimates_ext,
......
......@@ -277,14 +277,15 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue,
int32_t *log2_maxh,
int rx_size_symbol,
int nbRx,
c16_t rxdataF_comp[][dlsch->cw_info.Nl][nbRx][rx_size_symbol],
c16_t dl_ch_mag[][dlsch->cw_info.Nl][nbRx][rx_size_symbol],
c16_t dl_ch_magb[][dlsch->cw_info.Nl][nbRx][rx_size_symbol],
c16_t dl_ch_magr[][dlsch->cw_info.Nl][nbRx][rx_size_symbol],
c16_t rxdataF_comp[][dlsch->cw_info.Nl][rx_size_symbol],
c16_t dl_ch_mag[][dlsch->cw_info.Nl][rx_size_symbol],
c16_t dl_ch_magb[][dlsch->cw_info.Nl][rx_size_symbol],
c16_t dl_ch_magr[][dlsch->cw_info.Nl][rx_size_symbol],
c16_t ptrs_phase_per_slot[][NR_SYMBOLS_PER_SLOT],
int32_t ptrs_re_per_slot[][NR_SYMBOLS_PER_SLOT],
uint32_t nvar,
pdsch_scope_req_t *scope_req);
pdsch_scope_req_t *scope_req,
c16_t rho_dl[][dlsch->cw_info.Nl * dlsch->cw_info.Nl][rx_size_symbol]);
int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, int frame, uint8_t slot, c16_t **txData);
void apply_ntn_config(PHY_VARS_NR_UE *UE,
......
......@@ -412,6 +412,10 @@ typedef struct PHY_VARS_NR_UE_s {
/// Phase precompensation flag
bool no_phase_pre_comp;
/// Enable ML-based LLR computation for 2-layer MIMO (QPSK/16QAM/64QAM).
/// When false (default), MMSE equalization is used for all configurations.
bool do_ml;
void* scopeData;
// Pointers to hold PDSCH data only for phy simulators
void *phy_sim_rxdataF;
......
# SPDX-License-Identifier: LicenseRef-CSSL-1.0
add_library(nr_phy_common src/nr_phy_common.c)
add_library(nr_phy_common src/nr_phy_common.c
src/nr_channel_compensation.c
src/nr_compute_llr.c)
target_link_libraries(nr_phy_common PRIVATE UTIL PHY_COMMON)
target_include_directories(nr_phy_common PUBLIC inc/)
......
/*
* SPDX-License-Identifier: LicenseRef-CSSL-1.0
*/
#ifndef __NR_CHANNEL_COMPENSATION__H__
#define __NR_CHANNEL_COMPENSATION__H__
#include "PHY/impl_defs_top.h"
/**
* @brief Common channel compensation function shared by DL (PDSCH) and UL (PUSCH) paths.
*
* Computes matched-filter output (rxComp) and channel magnitude arrays used for LLR
* computation. MRC across Rx antennas is performed inline: for each layer, contributions
* from all Rx antennas are accumulated into rxComp[layer * nb_rx_ant][symbol * buffer_length].
* Uses AVX2 (256-bit SIMD) for throughput.
*
* @param buffer_length Number of complex samples per symbol (must be a multiple of 8)
* @param nb_rx_ant Number of Rx antennas
* @param nb_layers Number of spatial layers
* @param rxFext Extracted received signal [nb_rx_ant][buffer_length]
* @param chFext Extracted channel estimates [nb_layers][nb_rx_ant][buffer_length]
* @param ch_maga Output magnitude array for threshold 'a' [nb_layers][buffer_length]
* @param ch_magb Output magnitude array for threshold 'b' [nb_layers][buffer_length]
* @param ch_magc Output magnitude array for threshold 'c' [nb_layers][buffer_length]
* @param rxComp Output compensated signal; row [l * nb_rx_ant] holds the MRC result
* for layer l at offset [symbol * buffer_length]
* @param rho Tx-correlation matrix [nb_layers][nb_layers][buffer_length], or NULL
* @param mod_order Modulation order (2=QPSK, 4=16QAM, 6=64QAM, 8=256QAM)
* @param symbol OFDM symbol index (used to compute offset into rxComp rows)
* @param output_shift Right-shift applied after each complex multiply
*/
void nr_channel_compensation(uint32_t buffer_length,
int nb_rx_ant,
int nb_layers,
c16_t rxFext[nb_rx_ant][buffer_length],
c16_t chFext[nb_layers][nb_rx_ant][buffer_length],
c16_t ch_maga[nb_layers][buffer_length],
c16_t ch_magb[nb_layers][buffer_length],
c16_t ch_magc[nb_layers][buffer_length],
c16_t **rxComp,
c16_t (*rho)[nb_layers][buffer_length],
int mod_order,
uint32_t symbol,
uint32_t output_shift);
#endif /* __NR_CHANNEL_COMPENSATION__H__ */
/*
* SPDX-License-Identifier: LicenseRef-CSSL-1.0
*/
#ifndef __NR_COMPUTE_LLR__H__
#define __NR_COMPUTE_LLR__H__
#include "PHY/impl_defs_top.h"
void nr_compute_llr(c16_t *rxdataF_comp,
c16_t *ch_mag,
c16_t *ch_magb,
c16_t *ch_magc,
int16_t *llr,
uint32_t nb_re,
uint8_t symbol,
uint8_t mod_order);
void nr_qpsk_llr_2layer(c16_t *stream0_in, c16_t *stream1_in, int16_t *stream0_out, c16_t *rho01, uint32_t length);
void nr_qam16_llr_2layer(c16_t *stream0_in,
c16_t *stream1_in,
c16_t *ch_mag,
c16_t *ch_mag_i,
int16_t *stream0_out,
c16_t *rho01,
uint32_t length);
void nr_qam64_llr_2layer(c16_t *stream0_in,
c16_t *stream1_in,
c16_t *ch_mag,
c16_t *ch_mag_i,
int16_t *stream0_out,
c16_t *rho01,
uint32_t length);
void nr_compute_ML_llr(c16_t *rxdataF_comp0,
c16_t *rxdataF_comp1,
c16_t *ch_mag0,
c16_t *ch_mag1,
int16_t *llr_layers0,
int16_t *llr_layers1,
c16_t *rho0,
c16_t *rho1,
uint32_t nb_re,
uint8_t mod_order);
uint8_t nr_mmse_2layers(c16_t **rxdataF_comp,
uint32_t buffer_length,
int nb_rx_ant,
int nb_layers,
c16_t ch_mag[nb_layers][buffer_length],
c16_t ch_magb[nb_layers][buffer_length],
c16_t ch_magc[nb_layers][buffer_length],
c16_t ch_estimates_ext[][nb_rx_ant][buffer_length],
unsigned short nb_rb,
unsigned char mod_order,
int shift,
unsigned char symbol,
int length,
uint32_t noise_var);
#endif /* __NR_COMPUTE_LLR__H__ */
......@@ -376,4 +376,7 @@ int nr_get_ssb_start_sc(int scs,
int ssb_offset_point_a,
int ssb_sco,
frequency_range_t freq_range);
#include "nr_channel_compensation.h"
#include "nr_compute_llr.h"
#endif
/*
* SPDX-License-Identifier: LicenseRef-CSSL-1.0
*/
#include "nr_channel_compensation.h"
#include "bits.h"
#include <complex.h>
#include "PHY/sse_intrin.h"
#include "PHY/impl_defs_top.h"
#ifdef __aarch64__
#define USE_128BIT
#endif
void nr_channel_compensation(uint32_t buffer_length,
int nb_rx_ant,
int nb_layers,
c16_t rxFext[nb_rx_ant][buffer_length],
c16_t chFext[nb_layers][nb_rx_ant][buffer_length],
c16_t ch_maga[nb_layers][buffer_length],
c16_t ch_magb[nb_layers][buffer_length],
c16_t ch_magc[nb_layers][buffer_length],
c16_t **rxComp,
c16_t (*rho)[nb_layers][buffer_length],
int mod_order,
uint32_t symbol,
uint32_t output_shift)
{
simde__m256i QAM_ampa_256 = simde_mm256_setzero_si256();
simde__m256i QAM_ampb_256 = simde_mm256_setzero_si256();
simde__m256i QAM_ampc_256 = simde_mm256_setzero_si256();
if (mod_order == 4) {
QAM_ampa_256 = simde_mm256_set1_epi16(QAM16_n1);
} else if (mod_order == 6) {
QAM_ampa_256 = simde_mm256_set1_epi16(QAM64_n1);
QAM_ampb_256 = simde_mm256_set1_epi16(QAM64_n2);
} else if (mod_order == 8) {
QAM_ampa_256 = simde_mm256_set1_epi16(QAM256_n1);
QAM_ampb_256 = simde_mm256_set1_epi16(QAM256_n2);
QAM_ampc_256 = simde_mm256_set1_epi16(QAM256_n3);
}
for (int aatx = 0; aatx < nb_layers; aatx++) {
simde__m256i *rxComp_256 = (simde__m256i *)&rxComp[aatx][symbol * buffer_length];
simde__m256i *ch_maga_256 = (simde__m256i *)ch_maga[aatx];
simde__m256i *ch_magb_256 = (simde__m256i *)ch_magb[aatx];
simde__m256i *ch_magc_256 = (simde__m256i *)ch_magc[aatx];
// First Rx antenna: direct store — eliminates need to pre memset the output buffers
{
simde__m256i *rxF_256 = (simde__m256i *)rxFext[0];
simde__m256i *chF_256 = (simde__m256i *)chFext[aatx][0];
for (uint32_t i = 0; i < buffer_length >> 3; i++) {
rxComp_256[i] = oai_mm256_cpx_mult_conj(chF_256[i], rxF_256[i], output_shift);
if (mod_order > 2) {
simde__m256i mag = oai_mm256_smadd(chF_256[i], chF_256[i], output_shift);
mag = simde_mm256_packs_epi32(mag, mag);
mag = simde_mm256_unpacklo_epi16(mag, mag);
ch_maga_256[i] = simde_mm256_mulhrs_epi16(mag, QAM_ampa_256);
if (mod_order > 4)
ch_magb_256[i] = simde_mm256_mulhrs_epi16(mag, QAM_ampb_256);
if (mod_order > 6)
ch_magc_256[i] = simde_mm256_mulhrs_epi16(mag, QAM_ampc_256);
}
}
if (rho) {
for (int atx = 0; atx < nb_layers; atx++) {
simde__m256i *rho_256 = (simde__m256i *)rho[aatx][atx];
simde__m256i *chF2_256 = (simde__m256i *)chFext[atx][0];
for (uint32_t i = 0; i < buffer_length >> 3; i++)
rho_256[i] = oai_mm256_cpx_mult_conj(chF_256[i], chF2_256[i], output_shift);
}
}
}
// Remaining Rx antennas: accumulate (MRC)
for (int aarx = 1; aarx < nb_rx_ant; aarx++) {
simde__m256i *rxF_256 = (simde__m256i *)rxFext[aarx];
simde__m256i *chF_256 = (simde__m256i *)chFext[aatx][aarx];
for (uint32_t i = 0; i < buffer_length >> 3; i++) {
simde__m256i comp = oai_mm256_cpx_mult_conj(chF_256[i], rxF_256[i], output_shift);
rxComp_256[i] = simde_mm256_add_epi16(rxComp_256[i], comp);
if (mod_order > 2) {
simde__m256i mag = oai_mm256_smadd(chF_256[i], chF_256[i], output_shift);
mag = simde_mm256_packs_epi32(mag, mag);
mag = simde_mm256_unpacklo_epi16(mag, mag);
ch_maga_256[i] = simde_mm256_add_epi16(ch_maga_256[i], simde_mm256_mulhrs_epi16(mag, QAM_ampa_256));
if (mod_order > 4)
ch_magb_256[i] = simde_mm256_add_epi16(ch_magb_256[i], simde_mm256_mulhrs_epi16(mag, QAM_ampb_256));
if (mod_order > 6)
ch_magc_256[i] = simde_mm256_add_epi16(ch_magc_256[i], simde_mm256_mulhrs_epi16(mag, QAM_ampc_256));
}
}
if (rho) {
for (int atx = 0; atx < nb_layers; atx++) {
simde__m256i *rho_256 = (simde__m256i *)rho[aatx][atx];
simde__m256i *chF2_256 = (simde__m256i *)chFext[atx][aarx];
for (uint32_t i = 0; i < buffer_length >> 3; i++)
rho_256[i] = simde_mm256_adds_epi16(rho_256[i], oai_mm256_cpx_mult_conj(chF_256[i], chF2_256[i], output_shift));
}
}
}
}
}
......@@ -5,6 +5,8 @@
#include "nr_phy_common.h"
#include "bits.h"
#include <complex.h>
#include "PHY/sse_intrin.h"
#include "PHY/impl_defs_top.h"
#ifdef __aarch64__
#define USE_128BIT
#endif
......@@ -486,5 +488,4 @@ int nr_get_ssb_start_sc(int scs, int ssb_offset_point_a, int ssb_sco, frequency_
prb_offset, ssb_sco, scs, freq_range, ssb_start_subcarrier);
return ssb_start_subcarrier;
}
......@@ -475,14 +475,7 @@ static int nr_ue_pdsch_procedures(PHY_VARS_NR_UE *ue,
const uint32_t rx_size_symbol = (freq_alloc->num_rbs * NR_NB_SC_PER_RB + 15) & ~15;
fourDimArray_t *toFree2 = NULL;
allocCast4D(rxdataF_comp,
c16_t,
toFree2,
ue->frame_parms.symbols_per_slot,
dlsch->cw_info.Nl,
ue->frame_parms.nb_antennas_rx,
rx_size_symbol,
false);
allocCast3D(rxdataF_comp, c16_t, toFree2, ue->frame_parms.symbols_per_slot, dlsch->cw_info.Nl, rx_size_symbol, false);
uint32_t nvar = 0;
......@@ -566,32 +559,19 @@ static int nr_ue_pdsch_procedures(PHY_VARS_NR_UE *ue,
&mt);
}
fourDimArray_t *toFree3 = NULL;
allocCast4D(dl_ch_mag,
c16_t,
toFree3,
NR_SYMBOLS_PER_SLOT,
dlsch->cw_info.Nl,
ue->frame_parms.nb_antennas_rx,
rx_size_symbol,
false);
allocCast3D(dl_ch_mag, c16_t, toFree3, NR_SYMBOLS_PER_SLOT, dlsch->cw_info.Nl, rx_size_symbol, false);
fourDimArray_t *toFree4 = NULL;
allocCast4D(dl_ch_magb,
c16_t,
toFree4,
NR_SYMBOLS_PER_SLOT,
dlsch->cw_info.Nl,
ue->frame_parms.nb_antennas_rx,
rx_size_symbol,
false);
allocCast3D(dl_ch_magb, c16_t, toFree4, NR_SYMBOLS_PER_SLOT, dlsch->cw_info.Nl, rx_size_symbol, false);
fourDimArray_t *toFree5 = NULL;
allocCast4D(dl_ch_magr,
c16_t,
toFree5,
NR_SYMBOLS_PER_SLOT,
dlsch->cw_info.Nl,
ue->frame_parms.nb_antennas_rx,
rx_size_symbol,
false);
allocCast3D(dl_ch_magr, c16_t, toFree5, NR_SYMBOLS_PER_SLOT, dlsch->cw_info.Nl, rx_size_symbol, false);
fourDimArray_t *toFreeRho = NULL;
const bool need_rho = ue->do_ml && dlsch->cw_info.Nl == 2 && dlsch->cw_info.qamModOrder <= 6;
c16_t(*rho_dl)[dlsch->cw_info.Nl * dlsch->cw_info.Nl][rx_size_symbol] = NULL;
if (need_rho) {
allocCast3D(rho_dl_buf, c16_t, toFreeRho, NR_SYMBOLS_PER_SLOT, dlsch->cw_info.Nl * dlsch->cw_info.Nl, rx_size_symbol, false);
rho_dl = rho_dl_buf;
}
for (int m = dlschCfg->start_symbol; m < (dlschCfg->number_symbols + dlschCfg->start_symbol); m++) {
bool first_symbol_flag = false;
if (m == first_symbol_with_data)
......@@ -623,7 +603,8 @@ static int nr_ue_pdsch_procedures(PHY_VARS_NR_UE *ue,
ptrs_phase_per_slot,
ptrs_re_per_slot,
nvar,
&scope_req)
&scope_req,
rho_dl)
< 0) {
if (scope_req.copy_chanest_to_scope) {
UEunlockScopeData(ue, pdschChanEstimates);
......@@ -646,6 +627,7 @@ static int nr_ue_pdsch_procedures(PHY_VARS_NR_UE *ue,
free(toFree3);
free(toFree4);
free(toFree5);
free(toFreeRho);
return 0;
}
......
......@@ -409,6 +409,7 @@ int main(int argc, char **argv)
randominit();
int print_perf = 0;
bool do_ml = false;
int use_cuda = 0;
......@@ -421,7 +422,7 @@ int main(int argc, char **argv)
void *d_channel_coeffs_gpu = NULL;
#endif
while ((c = getopt(argc, argv, "--:O:f:hA:p:f:g:i:n:s:S:t:v:x:y:z:o:H:M:N:F:GR:d:PI:L:a:b:e:m:w:T:U:q:X:Y:Z:Q:")) != -1) {
while ((c = getopt(argc, argv, "--:O:f:hA:p:f:g:i:n:s:S:t:v:x:y:z:o:H:M:N:F:GR:d:PI:L:a:b:e:m:w:T:U:q:X:Y:Z:Q:E")) != -1) {
/* ignore long options starting with '--', option '-O' and their arguments that are handled by configmodule */
/* with this opstring getopt returns 1 for non-option arguments, refer to 'man 3 getopt' */
if (c == 1 || c == '-' || c == 'O')
......@@ -539,6 +540,10 @@ int main(int argc, char **argv)
break;
case 'E':
do_ml = true;
break;
case 'P':
print_perf=1;
cpu_meas_enabled = 1;
......@@ -654,6 +659,7 @@ int main(int argc, char **argv)
printf("-b Number of PRB for PDSCH\n");
printf("-d number of dlsch threads, 0: no dlsch parallelization\n");
printf("-e MSC index\n");
printf("-E Enable ML-based LLR for 2-layer MIMO (QPSK/16QAM/64QAM). Default: MMSE equalization\n");
printf("-f <flag> Enable optional feature flag. Available flags:\n");
#ifdef CHANNEL_SIM_CUDA
printf(" cuda Enable CUDA channel simulation\n");
......@@ -935,6 +941,7 @@ int main(int argc, char **argv)
UE->frame_parms.nb_antenna_ports_gNB = n_tx;
UE->nrLDPC_coding_interface = gNB->nrLDPC_coding_interface;
UE->max_ldpc_iterations = max_ldpc_iterations;
UE->do_ml = do_ml;
init_nr_ue_phy_cpu_stats(&UE->phy_cpu_stats);
UE->is_synchronized = 1;
......
......@@ -1639,9 +1639,9 @@ int main(int argc, char *argv[])
1,
1 | log_format);
LOG_M("rxsigF2_comp.m",
"rxsF2_comp",
&pusch_vars->rxdataF_comp[2][start_symbol * (off + (NR_NB_SC_PER_RB * pusch_pdu->rb_size))],
LOG_M("rxsigF1_comp.m",
"rxsF1_comp",
&pusch_vars->rxdataF_comp[1][start_symbol * (off + (NR_NB_SC_PER_RB * pusch_pdu->rb_size))],
nb_symb_sch * (off + (NR_NB_SC_PER_RB * pusch_pdu->rb_size)),
1,
1 | log_format);
......@@ -1667,21 +1667,15 @@ int main(int argc, char *argv[])
1,
1 | log_format);
LOG_M("rxsigF4_comp.m",
"rxsF4_comp",
&pusch_vars->rxdataF_comp[4][start_symbol * (off + (NR_NB_SC_PER_RB * pusch_pdu->rb_size))],
nb_symb_sch * (off + (NR_NB_SC_PER_RB * pusch_pdu->rb_size)),
1,
1 | log_format);
LOG_M("rxsigF8_comp.m",
"rxsF8_comp",
&pusch_vars->rxdataF_comp[8][start_symbol * (off + (NR_NB_SC_PER_RB * pusch_pdu->rb_size))],
LOG_M("rxsigF2_comp.m",
"rxsF2_comp",
&pusch_vars->rxdataF_comp[2][start_symbol * (off + (NR_NB_SC_PER_RB * pusch_pdu->rb_size))],
nb_symb_sch * (off + (NR_NB_SC_PER_RB * pusch_pdu->rb_size)),
1,
1 | log_format);
LOG_M("rxsigF12_comp.m",
"rxsF12_comp",
&pusch_vars->rxdataF_comp[12][start_symbol * (off + (NR_NB_SC_PER_RB * pusch_pdu->rb_size))],
LOG_M("rxsigF3_comp.m",
"rxsF3_comp",
&pusch_vars->rxdataF_comp[3][start_symbol * (off + (NR_NB_SC_PER_RB * pusch_pdu->rb_size))],
nb_symb_sch * (off + (NR_NB_SC_PER_RB * pusch_pdu->rb_size)),
1,
1 | log_format);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment