Commit 66442aa4 authored by Ahmed Hussein's avatar Ahmed Hussein Committed by Thomas Schlichter

Implementation of LLR computation for 4, 16, and 64 QAM (tested)

parent 54ebd39b
......@@ -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
......
......@@ -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_id<NUMBER_OF_NR_ULSCH_MAX; ulsch_id++) {
for (int UE_id=0; UE_id<NUMBER_OF_UE_MAX; UE_id++) {
//FIXME
pusch_vars[UE_id] = (LTE_eNB_PUSCH *)malloc16_clear( NUMBER_OF_UE_MAX*sizeof(LTE_eNB_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] = (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_id<NUMBER_OF_UE_MAX; UE_id++)
gNB->UE_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;
......
/*
* 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
/*
* 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<nb_re; i++) {
#if defined(__x86_64__) || defined(__i386)
xmm0 = _mm_abs_epi16(rxF[i]); // registers of even index in xmm0-> |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; i<nb_re; i++) {
#if defined(__x86_64__) || defined(__i386__)
xmm1 = _mm_abs_epi16(rxF[i]);
xmm1 = _mm_subs_epi16(temp_channel[0],xmm1);
xmm2 = _mm_abs_epi16(xmm1);
xmm2 = _mm_subs_epi16(temp_channel[1],xmm2);
#elif defined(__arm__)
xmm1 = vabsq_s16(rxF[i]);
xmm1 = vsubq_s16(ch_mag[i],xmm1);
xmm2 = vabsq_s16(xmm1);
xmm2 = vsubq_s16(ch_magb[i],xmm2);
#endif
// ---------------------------------------s
// 1st RE
// ---------------------------------------
ulsch_llr[0] = ((short *)&rxF[i])[0];
ulsch_llr[1] = ((short *)&rxF[i])[1];
#if defined(__x86_64__) || defined(__i386__)
ulsch_llr[2] = _mm_extract_epi16(xmm1,0);
ulsch_llr[3] = _mm_extract_epi16(xmm1,1);
ulsch_llr[4] = _mm_extract_epi16(xmm2,0);
ulsch_llr[5] = _mm_extract_epi16(xmm2,1);
#elif defined(__arm__)
ulsch_llr[2] = vgetq_lane_s16(xmm1,0);
ulsch_llr[3] = vgetq_lane_s16(xmm1,1);
ulsch_llr[4] = vgetq_lane_s16(xmm2,0);
ulsch_llr[5] = vgetq_lane_s16(xmm2,1);
#endif
// ---------------------------------------
ulsch_llr+=6;
// ---------------------------------------
// 2nd RE
// ---------------------------------------
ulsch_llr[0] = ((short *)&rxF[i])[2];
ulsch_llr[1] = ((short *)&rxF[i])[3];
#if defined(__x86_64__) || defined(__i386__)
ulsch_llr[2] = _mm_extract_epi16(xmm1,2);
ulsch_llr[3] = _mm_extract_epi16(xmm1,3);
ulsch_llr[4] = _mm_extract_epi16(xmm2,2);
ulsch_llr[5] = _mm_extract_epi16(xmm2,3);
#elif defined(__arm__)
ulsch_llr[2] = vgetq_lane_s16(xmm1,2);
ulsch_llr[3] = vgetq_lane_s16(xmm1,3);
ulsch_llr[4] = vgetq_lane_s16(xmm2,2);
ulsch_llr[5] = vgetq_lane_s16(xmm2,3);
#endif
// ---------------------------------------
ulsch_llr+=6;
// ---------------------------------------
// 3rd RE
// ---------------------------------------
ulsch_llr[0] = ((short *)&rxF[i])[4];
ulsch_llr[1] = ((short *)&rxF[i])[5];
#if defined(__x86_64__) || defined(__i386__)
ulsch_llr[2] = _mm_extract_epi16(xmm1,4);
ulsch_llr[3] = _mm_extract_epi16(xmm1,5);
ulsch_llr[4] = _mm_extract_epi16(xmm2,4);
ulsch_llr[5] = _mm_extract_epi16(xmm2,5);
#elif defined(__arm__)
ulsch_llr[2] = vgetq_lane_s16(xmm1,4);
ulsch_llr[3] = vgetq_lane_s16(xmm1,5);
ulsch_llr[4] = vgetq_lane_s16(xmm2,4);
ulsch_llr[5] = vgetq_lane_s16(xmm2,5);
#endif
// ---------------------------------------
ulsch_llr+=6;
// ---------------------------------------
// 4th RE
// ---------------------------------------
ulsch_llr[0] = ((short *)&rxF[i])[6];
ulsch_llr[1] = ((short *)&rxF[i])[7];
#if defined(__x86_64__) || defined(__i386__)
ulsch_llr[2] = _mm_extract_epi16(xmm1,6);
ulsch_llr[3] = _mm_extract_epi16(xmm1,7);
ulsch_llr[4] = _mm_extract_epi16(xmm2,6);
ulsch_llr[5] = _mm_extract_epi16(xmm2,7);
#elif defined(__arm__)
ulsch_llr[2] = vgetq_lane_s16(xmm1,6);
ulsch_llr[3] = vgetq_lane_s16(xmm1,7);
ulsch_llr[4] = vgetq_lane_s16(xmm2,6);
ulsch_llr[5] = vgetq_lane_s16(xmm2,7);
#endif
// ---------------------------------------
ulsch_llr+=6;
}
#if defined(__x86_64__) || defined(__i386__)
_mm_empty();
_m_empty();
#endif
}
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)
{
switch(mod_order){
case 2:
nr_ulsch_qpsk_llr(rxdataF_comp,
ulsch_llr,
nb_re,
symbol);
break;
case 4:
nr_ulsch_16qam_llr(rxdataF_comp,
ul_ch_mag,
ulsch_llr,
nb_re,
symbol);
break;
case 6:
nr_ulsch_64qam_llr(rxdataF_comp,
ul_ch_mag,
ul_ch_magb,
ulsch_llr,
nb_re,
symbol);
break;
default:
LOG_E(PHY,"nr_ulsch_compute_llr: invalid Qm value, symbol = %d, Qm = %d\n",symbol, mod_order);
break;
}
}
\ No newline at end of file
......@@ -204,7 +204,7 @@ typedef struct {
/// Scrambled "b"-sequences (for definition see 36-211 V8.6 2009-03, p.14)
uint8_t b_tilde[MAX_NUM_NR_CHANNEL_BITS];
/// Modulated "d"-sequences (for definition see 36-211 V8.6 2009-03, p.14)
int32_t d_mod[MAX_NUM_NR_RE];
int32_t d_mod[MAX_NUM_NR_RE] __attribute__ ((aligned(16)));
/// Transform-coded "z"-sequences (for definition see 36-211 V8.6 2009-03, p.14-15)
int32_t z[MAX_NUM_NR_RE];
/*
......
......@@ -354,6 +354,43 @@ typedef struct {
} NR_gNB_COMMON;
typedef struct {
/// \brief Holds the received data in the frequency domain for the allocated RBs in repeated format.
/// - first index: rx antenna id [0..nb_antennas_rx[
/// - second index: ? [0..2*ofdm_symbol_size[
int32_t **rxdataF_ext;
/// \brief Holds the received data in the frequency domain for the allocated RBs in normal format.
/// - first index: rx antenna id [0..nb_antennas_rx[
/// - second index (definition from phy_init_lte_eNB()): ? [0..12*N_RB_UL*frame_parms->symbols_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
......
......@@ -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 //////////////////////
////////////////////////////////////////////////////////////
//----------------------------------------------------------
//--------------------- ULSCH decoding ---------------------
//----------------------------------------------------------
ret = nr_ulsch_decoding(gNB, UE_id, channel_output_fixed, frame_parms, frame,
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++;
}
......@@ -838,15 +870,19 @@ 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++) {
......
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