Implementation of LLR computation for 4, 16, and 64 QAM (tested)
This commit is contained in:
committed by
Thomas Schlichter
parent
54ebd39b79
commit
66442aa42d
@@ -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
|
||||
|
||||
+22
-23
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
@@ -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<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;
|
||||
}
|
||||
}
|
||||
@@ -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];
|
||||
/*
|
||||
|
||||
+39
-2
@@ -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 //////////////////////
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
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++) {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user