From 66442aa42d119e2e5e8b12948cf110c56904a1f2 Mon Sep 17 00:00:00 2001 From: Ahmed Hussein Date: Tue, 2 Apr 2019 19:16:27 +0200 Subject: [PATCH] Implementation of LLR computation for 4, 16, and 64 QAM (tested) --- cmake_targets/CMakeLists.txt | 1 + openair1/PHY/INIT/nr_init.c | 45 ++- .../PHY/NR_TRANSPORT/nr_transport_proto.h | 91 +++++ .../NR_TRANSPORT/nr_ulsch_llr_computation.c | 365 ++++++++++++++++++ .../PHY/NR_UE_TRANSPORT/nr_transport_ue.h | 2 +- openair1/PHY/defs_gNB.h | 41 +- openair1/SIMULATION/NR_PHY/ulsim.c | 87 +++-- 7 files changed, 581 insertions(+), 51 deletions(-) create mode 100644 openair1/PHY/NR_TRANSPORT/nr_transport_proto.h create mode 100644 openair1/PHY/NR_TRANSPORT/nr_ulsch_llr_computation.c diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 39abbc8f29..95b6385d68 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -1285,6 +1285,7 @@ set(PHY_SRC_UE ${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_ulsch.c ${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_tbs_tools.c ${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_sch_dmrs.c + ${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_ulsch_llr_computation.c ${OPENAIR1_DIR}/PHY/NR_REFSIG/nr_gold.c ${OPENAIR1_DIR}/PHY/TOOLS/file_output.c ${OPENAIR1_DIR}/PHY/TOOLS/cadd_vv.c diff --git a/openair1/PHY/INIT/nr_init.c b/openair1/PHY/INIT/nr_init.c index e699944a52..e929720897 100644 --- a/openair1/PHY/INIT/nr_init.c +++ b/openair1/PHY/INIT/nr_init.c @@ -80,8 +80,8 @@ int phy_init_nr_gNB(PHY_VARS_gNB *gNB, NR_DL_FRAME_PARMS *const fp = &gNB->frame_parms; nfapi_nr_config_request_t *cfg = &gNB->gNB_config; NR_gNB_COMMON *const common_vars = &gNB->common_vars; - /*LTE_eNB_PUSCH **const pusch_vars = gNB->pusch_vars; - LTE_eNB_SRS *const srs_vars = gNB->srs_vars; + NR_gNB_PUSCH **const pusch_vars = gNB->pusch_vars; + /*LTE_eNB_SRS *const srs_vars = gNB->srs_vars; LTE_eNB_PRACH *const prach_vars = &gNB->prach_vars;*/ int i; @@ -200,39 +200,38 @@ int phy_init_nr_gNB(PHY_VARS_gNB *gNB, for (i=0; i<64; i++) prach_vars->prach_ifft[0][i] = (int32_t *)malloc16_clear(1024*2*sizeof(int32_t)); prach_vars->rxsigF[0] = (int16_t **)malloc16_clear(64*sizeof(int16_t *)); +*/ - for (int ulsch_id=0; ulsch_idrxdataF_ext = (int32_t **)malloc16( 2*sizeof(int32_t *) ); - pusch_vars[UE_id]->rxdataF_ext2 = (int32_t **)malloc16( 2*sizeof(int32_t *) ); - pusch_vars[UE_id]->drs_ch_estimates = (int32_t **)malloc16( 2*sizeof(int32_t *) ); + pusch_vars[UE_id] = (NR_gNB_PUSCH *)malloc16_clear( sizeof(NR_gNB_PUSCH) ); + pusch_vars[UE_id]->rxdataF_ext = (int32_t **)malloc16( 2*sizeof(int32_t *) ); + pusch_vars[UE_id]->rxdataF_ext2 = (int32_t **)malloc16( 2*sizeof(int32_t *) ); + pusch_vars[UE_id]->drs_ch_estimates = (int32_t **)malloc16( 2*sizeof(int32_t *) ); pusch_vars[UE_id]->drs_ch_estimates_time = (int32_t **)malloc16( 2*sizeof(int32_t *) ); - pusch_vars[UE_id]->rxdataF_comp = (int32_t **)malloc16( 2*sizeof(int32_t *) ); - pusch_vars[UE_id]->ul_ch_mag = (int32_t **)malloc16( 2*sizeof(int32_t *) ); - pusch_vars[UE_id]->ul_ch_magb = (int32_t **)malloc16( 2*sizeof(int32_t *) ); + pusch_vars[UE_id]->rxdataF_comp = (int32_t **)malloc16( 2*sizeof(int32_t *) ); + pusch_vars[UE_id]->ul_ch_mag = (int32_t **)malloc16( 2*sizeof(int32_t *) ); + pusch_vars[UE_id]->ul_ch_magb = (int32_t **)malloc16( 2*sizeof(int32_t *) ); for (i=0; i<2; i++) { // RK 2 times because of output format of FFT! // FIXME We should get rid of this - pusch_vars[UE_id]->rxdataF_ext[i] = (int32_t *)malloc16_clear( sizeof(int32_t)*cfg->rf_config.ul_carrier_bandwidth.value*12*fp->symbols_per_slot ); - pusch_vars[UE_id]->rxdataF_ext2[i] = (int32_t *)malloc16_clear( sizeof(int32_t)*cfg->rf_config.ul_carrier_bandwidth.value*12*fp->symbols_per_slot ); - pusch_vars[UE_id]->drs_ch_estimates[i] = (int32_t *)malloc16_clear( sizeof(int32_t)*cfg->rf_config.ul_carrier_bandwidth.value*12*fp->symbols_per_slot ); + pusch_vars[UE_id]->rxdataF_ext[i] = (int32_t *)malloc16_clear( sizeof(int32_t)*cfg->rf_config.ul_carrier_bandwidth.value*12*fp->symbols_per_slot ); + pusch_vars[UE_id]->rxdataF_ext2[i] = (int32_t *)malloc16_clear( sizeof(int32_t)*cfg->rf_config.ul_carrier_bandwidth.value*12*fp->symbols_per_slot ); + pusch_vars[UE_id]->drs_ch_estimates[i] = (int32_t *)malloc16_clear( sizeof(int32_t)*cfg->rf_config.ul_carrier_bandwidth.value*12*fp->symbols_per_slot ); pusch_vars[UE_id]->drs_ch_estimates_time[i] = (int32_t *)malloc16_clear( 2*sizeof(int32_t)*fp->ofdm_symbol_size ); - pusch_vars[UE_id]->rxdataF_comp[i] = (int32_t *)malloc16_clear( sizeof(int32_t)*cfg->rf_config.ul_carrier_bandwidth.value*12*fp->symbols_per_slot ); - pusch_vars[UE_id]->ul_ch_mag[i] = (int32_t *)malloc16_clear( fp->symbols_per_slot*sizeof(int32_t)*cfg->rf_config.ul_carrier_bandwidth.value*12 ); - pusch_vars[UE_id]->ul_ch_magb[i] = (int32_t *)malloc16_clear( fp->symbols_per_slot*sizeof(int32_t)*cfg->rf_config.ul_carrier_bandwidth.value*12 ); + pusch_vars[UE_id]->rxdataF_comp[i] = (int32_t *)malloc16_clear( sizeof(int32_t)*cfg->rf_config.ul_carrier_bandwidth.value*12*fp->symbols_per_slot ); + pusch_vars[UE_id]->ul_ch_mag[i] = (int32_t *)malloc16_clear( fp->symbols_per_slot*sizeof(int32_t)*cfg->rf_config.ul_carrier_bandwidth.value*12 ); + pusch_vars[UE_id]->ul_ch_magb[i] = (int32_t *)malloc16_clear( fp->symbols_per_slot*sizeof(int32_t)*cfg->rf_config.ul_carrier_bandwidth.value*12 ); } - pusch_vars[UE_id]->llr = (int16_t *)malloc16_clear( (8*((3*8*6144)+12))*sizeof(int16_t) ); + pusch_vars[UE_id]->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 } //UE_id - +/* for (UE_id=0; UE_idUE_stats_ptr[UE_id] = &gNB->UE_stats[UE_id]; - - gNB->pdsch_config_dedicated->p_a = dB0; //defaul value until overwritten by RRCConnectionReconfiguration */ + gNB->pdsch_config_dedicated->p_a = dB0; //defaul value until overwritten by RRCConnectionReconfiguration return (0); } /* @@ -283,8 +282,8 @@ void phy_free_nr_gNB(PHY_VARS_gNB *gNB) { //NR_DL_FRAME_PARMS* const fp = &gNB->frame_parms; //nfapi_nr_config_request_t *cfg = &gNB->gNB_config; NR_gNB_COMMON *const common_vars = &gNB->common_vars; - /*LTE_eNB_PUSCH **const pusch_vars = gNB->pusch_vars; - LTE_eNB_SRS *const srs_vars = gNB->srs_vars; + NR_gNB_PUSCH **const pusch_vars = gNB->pusch_vars; + /*LTE_eNB_SRS *const srs_vars = gNB->srs_vars; LTE_eNB_PRACH *const prach_vars = &gNB->prach_vars;*/ uint32_t ***pdcch_dmrs = gNB->nr_gold_pdcch_dmrs; diff --git a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h new file mode 100644 index 0000000000..b4662084e0 --- /dev/null +++ b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h @@ -0,0 +1,91 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file PHY/NR_TRANSPORT/nr_transport_proto.h.c +* \brief Function prototypes for PHY physical/transport channel processing and generation +* \author Ahmed Hussein +* \date 2019 +* \version 0.1 +* \company Fraunhofer IIS +* \email: ahmed.hussein@iis.fraunhofer.de +* \note +* \warning +*/ + +#include "PHY/defs_nr_common.h" + + +/** \brief This function generates log-likelihood ratios (decoder input) for single-stream QPSK received waveforms. + @param rxdataF_comp Compensated channel output + @param ulsch_llr llr output + @param nb_re number of REs for this allocation + @param symbol OFDM symbol index in sub-frame +*/ +void nr_ulsch_qpsk_llr(int32_t *rxdataF_comp, + int16_t *ulsch_llr, + uint32_t nb_re, + uint8_t symbol); + +/** \brief This function generates log-likelihood ratios (decoder input) for single-stream 16 QAM received waveforms. + @param rxdataF_comp Compensated channel output + @param ul_ch_mag uplink channel magnitude multiplied by the 1st amplitude threshold in QAM 16 + @param ulsch_llr llr output + @param nb_re number of RBs for this allocation + @param symbol OFDM symbol index in sub-frame +*/ +void nr_ulsch_16qam_llr(int32_t *rxdataF_comp, + int32_t **ul_ch_mag, + int16_t *ulsch_llr, + uint32_t nb_re, + uint8_t symbol); + +/** \brief This function generates log-likelihood ratios (decoder input) for single-stream 64 QAM received waveforms. + @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 +*/ +void nr_ulsch_64qam_llr(int32_t *rxdataF_comp, + int32_t **ul_ch_mag, + int32_t **ul_ch_magb, + int16_t *ulsch_llr, + uint32_t nb_re, + uint8_t symbol); + + +/** \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(int32_t *rxdataF_comp, + int32_t **ul_ch_mag, + int32_t **ul_ch_magb, + int16_t *ulsch_llr, + uint32_t nb_re, + uint8_t symbol, + uint8_t mod_order); \ No newline at end of file diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_llr_computation.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_llr_computation.c new file mode 100644 index 0000000000..270b5e14cf --- /dev/null +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_llr_computation.c @@ -0,0 +1,365 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file PHY/NR_TRANSPORT/nr_ulsch_llr_computation.c + * \brief Top-level routines for LLR computation of the PDSCH physical channel + * \author Ahmed Hussein + * \date 2019 + * \version 0.1 + * \company Fraunhofer IIS + * \email: ahmed.hussein@iis.fraunhofer.de + * \note + * \warning + */ + + +#include "PHY/defs_nr_common.h" +#include "PHY/sse_intrin.h" +#include "PHY/impl_defs_top.h" + +__m128i xmm0 __attribute__ ((aligned(16))); +__m128i xmm1 __attribute__ ((aligned(16))); +__m128i xmm2 __attribute__ ((aligned(16))); + + +//---------------------------------------------------------------------------------------------- +// QPSK +//---------------------------------------------------------------------------------------------- +void nr_ulsch_qpsk_llr(int32_t *rxdataF_comp, + int16_t *ulsch_llr, + uint32_t nb_re, + uint8_t symbol) +{ + int i; + + uint32_t *rxF = (uint32_t*)rxdataF_comp; + uint32_t *llr32 = (uint32_t*)ulsch_llr; + + if (!llr32) { + LOG_E(PHY,"nr_ulsch_qpsk_llr: llr is null, symbol %d, llr32 = %p\n",symbol, llr32); + } + + for (i = 0; i < nb_re; i++) { + *llr32 = *rxF; + rxF++; + llr32++; + } +} + +//---------------------------------------------------------------------------------------------- +// 16-QAM +//---------------------------------------------------------------------------------------------- + +void nr_ulsch_16qam_llr(int32_t *rxdataF_comp, + int32_t **ul_ch_mag, + int16_t *ulsch_llr, + uint32_t nb_re, + uint8_t symbol) +{ +#if defined(__x86_64__) || defined(__i386__) + __m128i *rxF = (__m128i*)rxdataF_comp; + // __m128i *ch_mag; // [hna] This should be uncommented once channel estimation is implemented + __m128i llr128[2]; + uint32_t *llr32; + + // [hna] temp_channel and one_over_sqrt_2 are for temporary use until channel estimation is implemented + // else ul_ch_mag and ul_ch_magb should be used after channel estimation has benn implemented + __m128i temp_channel; + int16_t one_over_sqrt_2 = 23170; + +#elif defined(__arm__) + int16x8_t *rxF = (int16x8_t*)&rxdataF_comp; + // int16x8_t *ch_mag; // [hna] This should be uncommented once channel estimation is implemented + int16x8_t xmm0; + int16_t *llr16; +#endif + + + int i; + unsigned char len_mod4 = 0; + + +#if defined(__x86_64__) || defined(__i386__) + llr32 = (uint32_t*)ulsch_llr; +#elif defined(__arm__) + llr16 = (int16_t*)ulsch_llr; +#endif + +// [hna] This should be uncommented once channel estimation is implemented +// ------------------------------------------------------------ +// #if defined(__x86_64__) || defined(__i386__) +// ch_mag = (__m128i*)&ul_ch_mag[0][(symbol*nb_rb*12)]; +// #elif defined(__arm__) +// ch_mag = (int16x8_t*)&ul_ch_mag[0][(symbol*nb_rb*12)]; +// #endif +// ------------------------------------------------------------ + + len_mod4 = nb_re&3; + nb_re >>= 2; // length in quad words (4 REs) + nb_re += (len_mod4 == 0 ? 0 : 1); + + temp_channel = _mm_set1_epi16((int16_t)((QAM64_n1 * one_over_sqrt_2)>>15)); + + for (i=0; i |y_R|, registers of odd index in xmm0-> |y_I| + + + xmm0 = _mm_subs_epi16(temp_channel,xmm0); // registers of even index in xmm0-> |y_R|-|h|^2, registers of odd index in xmm0-> |y_I|-|h|^2 + + llr128[0] = _mm_unpacklo_epi32(rxF[i],xmm0); // llr128[0] contains the llrs of the 1st and 2nd REs + llr128[1] = _mm_unpackhi_epi32(rxF[i],xmm0); // llr128[1] contains the llrs of the 3rd and 4th REs + + // 1st RE + llr32[0] = _mm_extract_epi32(llr128[0],0); // llr32[0] low 16 bits-> y_R , high 16 bits-> y_I + llr32[1] = _mm_extract_epi32(llr128[0],1); // llr32[1] low 16 bits-> |h|-|y_R|^2, high 16 bits-> |h|-|y_I|^2 + + // 2nd RE + llr32[2] = _mm_extract_epi32(llr128[0],2); // llr32[2] low 16 bits-> y_R , high 16 bits-> y_I + llr32[3] = _mm_extract_epi32(llr128[0],3); // llr32[3] low 16 bits-> |h|-|y_R|^2, high 16 bits-> |h|-|y_I|^2 + + // 3rd RE + llr32[4] = _mm_extract_epi32(llr128[1],0); // llr32[4] low 16 bits-> y_R , high 16 bits-> y_I + llr32[5] = _mm_extract_epi32(llr128[1],1); // llr32[5] low 16 bits-> |h|-|y_R|^2, high 16 bits-> |h|-|y_I|^2 + + // 4th RE + llr32[6] = _mm_extract_epi32(llr128[1],2); // llr32[6] low 16 bits-> y_R , high 16 bits-> y_I + llr32[7] = _mm_extract_epi32(llr128[1],3); // llr32[7] low 16 bits-> |h|-|y_R|^2, high 16 bits-> |h|-|y_I|^2 + + llr32+=8; +#elif defined(__arm__) + xmm0 = vabsq_s16(rxF[i]); + xmm0 = vqsubq_s16((*(__m128i*)&ones[0]),xmm0); + + llr16[0] = vgetq_lane_s16(rxF[i],0); + llr16[1] = vgetq_lane_s16(rxF[i],1); + llr16[2] = vgetq_lane_s16(xmm0,0); + llr16[3] = vgetq_lane_s16(xmm0,1); + llr16[4] = vgetq_lane_s16(rxF[i],2); + llr16[5] = vgetq_lane_s16(rxF[i],3); + llr16[6] = vgetq_lane_s16(xmm0,2); + llr16[7] = vgetq_lane_s16(xmm0,3); + llr16[8] = vgetq_lane_s16(rxF[i],4); + llr16[9] = vgetq_lane_s16(rxF[i],5); + llr16[10] = vgetq_lane_s16(xmm0,4); + llr16[11] = vgetq_lane_s16(xmm0,5); + llr16[12] = vgetq_lane_s16(rxF[i],6); + llr16[13] = vgetq_lane_s16(rxF[i],6); + llr16[14] = vgetq_lane_s16(xmm0,7); + llr16[15] = vgetq_lane_s16(xmm0,7); + llr16+=16; +#endif + + } + +#if defined(__x86_64__) || defined(__i386__) + _mm_empty(); + _m_empty(); +#endif +} + +//---------------------------------------------------------------------------------------------- +// 64-QAM +//---------------------------------------------------------------------------------------------- + +void nr_ulsch_64qam_llr(int32_t *rxdataF_comp, + int32_t **ul_ch_mag, + int32_t **ul_ch_magb, + int16_t *ulsch_llr, + uint32_t nb_re, + uint8_t symbol) +{ +#if defined(__x86_64__) || defined(__i386__) + __m128i *rxF = (__m128i*)rxdataF_comp; + // __m128i *ch_mag,*ch_magb; // [hna] This should be uncommented once channel estimation is implemented + + // [hna] temp_channel and one_over_sqrt_2 are for temporary use until channel estimation is implemented + // else ul_ch_mag and ul_ch_magb should be used after channel estimation has been implemented + __m128i temp_channel[2]; + int16_t one_over_sqrt_2 = 23170; + +#elif defined(__arm__) + int16x8_t *rxF = (int16x8_t*)&rxdataF_comp; + // int16x8_t *ch_mag,*ch_magb; // [hna] This should be uncommented once channel estimation is implemented + int16x8_t xmm1,xmm2; +#endif + + int i; + unsigned char len_mod4; + +// [hna] This should be uncommented once channel estimation is implemented +// ------------------------------------------------------------------------- +// #if defined(__x86_64__) || defined(__i386__) +// ch_mag = (__m128i*)&ul_ch_mag[0][(symbol*frame_parms->N_RB_UL*12)]; +// ch_magb = (__m128i*)&ul_ch_magb[0][(symbol*frame_parms->N_RB_UL*12)]; +// #elif defined(__arm__) +// ch_mag = (int16x8_t*)&ul_ch_mag[0][(symbol*frame_parms->N_RB_UL*12)]; +// ch_magb = (int16x8_t*)&ul_ch_magb[0][(symbol*frame_parms->N_RB_UL*12)]; +// #endif +// ------------------------------------------------------------------------- + + len_mod4 =nb_re&3; + nb_re=nb_re>>2; // length in quad words (4 REs) + nb_re+=((len_mod4==0)?0:1); + + + temp_channel[0] = _mm_set1_epi16((int16_t)((QAM64_n1 * one_over_sqrt_2)>>15)); + temp_channel[1] = _mm_set1_epi16((int16_t)((QAM64_n2 * one_over_sqrt_2)>>15)); + + for (i=0; isymbols_per_tti[ + int32_t **rxdataF_ext2; + /// \brief Hold the channel estimates in time domain based on DRS. + /// - first index: rx antenna id [0..nb_antennas_rx[ + /// - second index: ? [0..4*ofdm_symbol_size[ + int32_t **drs_ch_estimates_time; + /// \brief Hold the channel estimates in frequency domain based on DRS. + /// - first index: rx antenna id [0..nb_antennas_rx[ + /// - second index: ? [0..12*N_RB_UL*frame_parms->symbols_per_tti[ + int32_t **drs_ch_estimates; + /// \brief Holds the compensated signal. + /// - first index: rx antenna id [0..nb_antennas_rx[ + /// - second index: ? [0..12*N_RB_UL*frame_parms->symbols_per_tti[ + int32_t **rxdataF_comp; + /// \brief Magnitude of the UL channel estimates. Used for 2nd-bit level thresholds in LLR computation + /// - first index: rx antenna id [0..nb_antennas_rx[ + /// - second index: ? [0..12*N_RB_UL*frame_parms->symbols_per_tti[ + int32_t **ul_ch_mag; + /// \brief Magnitude of the UL channel estimates scaled for 3rd bit level thresholds in LLR computation + /// - first index: rx antenna id [0..nb_antennas_rx[ + /// - second index: ? [0..12*N_RB_UL*frame_parms->symbols_per_tti[ + int32_t **ul_ch_magb; + /// measured RX power based on DRS + int ulsch_power[2]; + /// \brief llr values. + /// - first index: ? [0..1179743] (hard coded) + int16_t *llr; +} NR_gNB_PUSCH; + + /// Context data structure for RX/TX portion of slot processing typedef struct { /// Component Carrier index @@ -569,13 +606,13 @@ typedef struct PHY_VARS_gNB_s { Sched_Rsp_t Sched_INFO; NR_gNB_PDCCH pdcch_vars; NR_gNB_PBCH pbch; - LTE_eNB_PHICH phich_vars[2]; + // LTE_eNB_PHICH phich_vars[2]; NR_gNB_COMMON common_vars; /* LTE_eNB_UCI uci_vars[NUMBER_OF_UE_MAX]; LTE_eNB_SRS srs_vars[NUMBER_OF_UE_MAX]; - LTE_eNB_PUSCH *pusch_vars[NUMBER_OF_UE_MAX]; LTE_eNB_PRACH prach_vars;*/ + NR_gNB_PUSCH *pusch_vars[NUMBER_OF_UE_MAX]; NR_gNB_DLSCH_t *dlsch[NUMBER_OF_NR_DLSCH_MAX][2]; // Nusers times two spatial streams NR_gNB_ULSCH_t *ulsch[NUMBER_OF_NR_ULSCH_MAX+1][2]; // [Nusers times + number of RA][2 codewords], index 0 in [NUMBER_OF_UE_MAX+1] is for RA // LTE_eNB_ULSCH_t *ulsch[NUMBER_OF_UE_MAX+1]; // Nusers + number of RA diff --git a/openair1/SIMULATION/NR_PHY/ulsim.c b/openair1/SIMULATION/NR_PHY/ulsim.c index 0f895b68d4..47fec1f25b 100644 --- a/openair1/SIMULATION/NR_PHY/ulsim.c +++ b/openair1/SIMULATION/NR_PHY/ulsim.c @@ -48,16 +48,14 @@ #include "PHY/NR_TRANSPORT/nr_ulsch.h" #include "PHY/NR_TRANSPORT/nr_sch_dmrs.h" #include "PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h" - +#include "PHY/NR_TRANSPORT/nr_transport_proto.h" #include "SCHED_NR/sched_nr.h" - //#include "PHY/MODULATION/modulation_common.h" //#include "common/config/config_load_configmodule.h" //#include "UTIL/LISTS/list.h" //#include "common/ran_context.h" //#define DEBUG_ULSCHSIM - PHY_VARS_gNB *gNB; PHY_VARS_NR_UE *UE; RAN_CONTEXT_t RC; @@ -487,6 +485,7 @@ int main(int argc, char **argv) { uint8_t bit_index; uint32_t errors_scrambling; uint32_t scrambling_index; + uint8_t symbol; int16_t **tx_layers; int32_t *mod_symbols[MAX_NUM_NR_RE]; uint16_t n_dmrs; @@ -573,7 +572,7 @@ int main(int argc, char **argv) { nr_modulation(scrambled_output[cwd], // assume one codeword for the moment available_bits, mod_order, - ulsch_ue[cwd]->d_mod); + (int16_t *)ulsch_ue[cwd]->d_mod); /////////// //////////////////////////////////////////////////////////////////////// @@ -718,12 +717,12 @@ m, l, k, ((int16_t*)txdataF[ap])[(sample_offsetF)<<1], n_errors = 0; n_false_positive = 0; - SNR_lin = pow(10, SNR / 10.0); - sigma = 1.0 / sqrt(2 * SNR_lin); + SNR_lin = pow(10, SNR / 10.0); + sigma = 1.0 / sqrt(2 * SNR_lin); - //AWGN - sigma2_dB = 10*log10((double)txlev)-SNR; - sigma2 = pow(10,sigma2_dB/10); + //AWGN + sigma2_dB = 10*log10((double)txlev)-SNR; + sigma2 = pow(10,sigma2_dB/10); for (trial = 0; trial < n_trials; trial++) { @@ -795,37 +794,70 @@ m, l, k, ((int16_t*)txdataF[ap])[(sample_offsetF)<<1], #endif - //////////////////////////////////////////////////////////// - //////////////////// ULSCH unscrambling //////////////////// - //////////////////////////////////////////////////////////// + //---------------------------------------------------------- + //-------------------- LLRs computation -------------------- + //---------------------------------------------------------- - nr_ulsch_unscrambling(channel_output_fixed, available_bits, 0, Nid_cell, n_rnti); + int sch_sym_start = NR_SYMBOLS_PER_SLOT-nb_symb_sch; + uint32_t nb_re; + uint32_t d_mod_offset = 0; + uint32_t llr_offset = 0; + + for(symbol = sch_sym_start; symbol < 14; symbol++) { + + if (symbol == 2) // [hna] here it is assumed that symbol 2 carries 6 DMRS REs (dmrs-type 1) + nb_re = nb_rb*6; + else + nb_re = nb_rb*12; + + nr_ulsch_compute_llr(&ulsch_ue[0]->d_mod[d_mod_offset], + gNB->pusch_vars[UE_id]->ul_ch_mag, + gNB->pusch_vars[UE_id]->ul_ch_magb, + &gNB->pusch_vars[UE_id]->llr[llr_offset], + nb_re, + symbol, + rel15_ul->Qm); + + d_mod_offset = d_mod_offset + nb_re; // [hna] d_mod is incremented by nb_re + llr_offset = llr_offset + (nb_re * rel15_ul->Qm); // [hna] llr is incremented by (nb_re*mod_order) because each RE has (mod_order) coded bit (i.e LLRs) + } //////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////// + + //---------------------------------------------------------- + //------------------- ULSCH unscrambling ------------------- + //---------------------------------------------------------- + + nr_ulsch_unscrambling(gNB->pusch_vars[UE_id]->llr, available_bits, 0, Nid_cell, n_rnti); //////////////////////////////////////////////////////////// - ////////////////////// ULSCH decoding ////////////////////// - //////////////////////////////////////////////////////////// + - ret = nr_ulsch_decoding(gNB, UE_id, channel_output_fixed, frame_parms, frame, + //---------------------------------------------------------- + //--------------------- ULSCH decoding --------------------- + //---------------------------------------------------------- + + ret = nr_ulsch_decoding(gNB, UE_id, gNB->pusch_vars[UE_id]->llr, frame_parms, frame, nb_symb_sch, subframe, harq_pid, is_crnti, llr8_flag); if (ret > ulsch_gNB->max_ldpc_iterations) n_errors++; //////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////// - /////////////////////// count errors /////////////////////// - //////////////////////////////////////////////////////////// + //---------------------------------------------------------- + //---------------------- count errors ---------------------- + //---------------------------------------------------------- for (i = 0; i < TBS; i++) { - if(((ulsch_ue[0]->g[i] == 0) && (channel_output_fixed[i] < 0)) || ((ulsch_ue[0]->g[i] == 1) && (channel_output_fixed[i] >= 0))) { + if(((ulsch_ue[0]->g[i] == 0) && (gNB->pusch_vars[UE_id]->llr[i] <= 0)) || + ((ulsch_ue[0]->g[i] == 1) && (gNB->pusch_vars[UE_id]->llr[i] >= 0))) + { + if(errors_scrambling == 0) + printf("First bit in error = %d\n",i); errors_scrambling++; } @@ -839,14 +871,18 @@ m, l, k, ((int16_t*)txdataF[ap])[(sample_offsetF)<<1], } //////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////// + + if (errors_scrambling > 0) { + if (n_trials == 1) + printf("errors_scrambling %d (trial %d)\n", errors_scrambling, trial); + } if (errors_bit > 0) { n_false_positive++; if (n_trials == 1) printf("errors_bit %d (trial %d)\n", errors_bit, trial); } - } + } // [hna] for (trial = 0; trial < n_trials; trial++) printf("*****************************************\n"); printf("SNR %f, BLER %f (false positive %f)\n", SNR, @@ -858,7 +894,8 @@ m, l, k, ((int16_t*)txdataF[ap])[(sample_offsetF)<<1], printf("PUSCH test OK\n"); break; } - } + } // [hna] for (SNR = snr0; SNR < snr1; SNR += snr_step) + for (i = 0; i < 2; i++) {