Commit bd03c211 authored by Matthieu Kanj's avatar Matthieu Kanj

creation of new rx_ulsch function for NB-IoT (rx_ulsch_NB_IoT)

+ creation of three new files:
openair1/PHY/LTE_ESTIMATION/freq_equalization_NB_IoT.c
openair1/PHY/LTE_ESTIMATION/lte_ul_channel_estimation_NB_IoT.c
openair1/PHY/LTE_TRANSPORT/ulsch_demodulation_NB_IoT.c
parent 320f896f
......@@ -1021,6 +1021,7 @@ set(PHY_SRC
${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/drs_modulation.c
${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/ulsch_modulation.c
${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/ulsch_demodulation.c
${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/ulsch_demodulation_NB_IoT.c
${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/ulsch_coding.c
${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/ulsch_decoding.c
${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/ulsch_decoding_NB_IoT.c
......@@ -1037,6 +1038,7 @@ set(PHY_SRC
${OPENAIR1_DIR}/PHY/MODULATION/beamforming.c
${OPENAIR1_DIR}/PHY/MODULATION/compute_bf_weights.c
${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/freq_equalization.c
${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/freq_equalization_NB_IoT.c
${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/lte_sync_time.c
${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/lte_sync_timefreq.c
${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/lte_adjust_sync.c
......@@ -1045,6 +1047,7 @@ set(PHY_SRC
${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/lte_dl_bf_channel_estimation.c
${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/lte_dl_mbsfn_channel_estimation.c
${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/lte_ul_channel_estimation.c
${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/lte_ul_channel_estimation_NB_IoT.c
${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/lte_est_freq_offset.c
${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/lte_ue_measurements.c
${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/lte_eNB_measurements.c
......
......@@ -36,5 +36,26 @@ int lte_est_timing_advance(NB_IoT_DL_FRAME_PARMS *frame_parms,
int NB_IoT_est_timing_advance_pusch(PHY_VARS_eNB_NB_IoT* phy_vars_eNB,module_id_t UE_id);
int lte_ul_channel_estimation_NB_IoT(PHY_VARS_eNB_NB_IoT *phy_vars_eNB,
eNB_rxtx_proc_NB_IoT_t *proc,
module_id_t eNB_id,
module_id_t UE_id,
uint8_t l,
uint8_t Ns,
uint8_t cooperation_flag);
int16_t lte_ul_freq_offset_estimation_NB_IoT(NB_IoT_DL_FRAME_PARMS *frame_parms,
int32_t *ul_ch_estimates,
uint16_t nb_rb);
void freq_equalization_NB_IoT(NB_IoT_DL_FRAME_PARMS *frame_parms,
int **rxdataF_comp,
int **ul_ch_mag,
int **ul_ch_mag_b,
unsigned char symbol,
unsigned short Msc_RS,
unsigned char Qm);
/** @} */
#endif
/*
* 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.0 (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
*/
#include "PHY/defs_NB_IoT.h"
#include "PHY/extern_NB_IoT.h"
//#include "PHY/sse_intrin.h"
// This is 512/(1:256) in __m128i format
int16_t inv_ch_NB_IoT[256*8] = {512,512,512,512,512,512,512,512,
256,256,256,256,256,256,256,256,
170,170,170,170,170,170,170,170,
128,128,128,128,128,128,128,128,
102,102,102,102,102,102,102,102,
85,85,85,85,85,85,85,85,
73,73,73,73,73,73,73,73,
64,64,64,64,64,64,64,64,
56,56,56,56,56,56,56,56,
51,51,51,51,51,51,51,51,
46,46,46,46,46,46,46,46,
42,42,42,42,42,42,42,42,
39,39,39,39,39,39,39,39,
36,36,36,36,36,36,36,36,
34,34,34,34,34,34,34,34,
32,32,32,32,32,32,32,32,
30,30,30,30,30,30,30,30,
28,28,28,28,28,28,28,28,
26,26,26,26,26,26,26,26,
25,25,25,25,25,25,25,25,
24,24,24,24,24,24,24,24,
23,23,23,23,23,23,23,23,
22,22,22,22,22,22,22,22,
21,21,21,21,21,21,21,21,
20,20,20,20,20,20,20,20,
19,19,19,19,19,19,19,19,
18,18,18,18,18,18,18,18,
18,18,18,18,18,18,18,18,
17,17,17,17,17,17,17,17,
17,17,17,17,17,17,17,17,
16,16,16,16,16,16,16,16,
16,16,16,16,16,16,16,16,
15,15,15,15,15,15,15,15,
15,15,15,15,15,15,15,15,
14,14,14,14,14,14,14,14,
14,14,14,14,14,14,14,14,
13,13,13,13,13,13,13,13,
13,13,13,13,13,13,13,13,
13,13,13,13,13,13,13,13,
12,12,12,12,12,12,12,12,
12,12,12,12,12,12,12,12,
12,12,12,12,12,12,12,12,
11,11,11,11,11,11,11,11,
11,11,11,11,11,11,11,11,
11,11,11,11,11,11,11,11,
11,11,11,11,11,11,11,11,
10,10,10,10,10,10,10,10,
10,10,10,10,10,10,10,10,
10,10,10,10,10,10,10,10,
10,10,10,10,10,10,10,10,
10,10,10,10,10,10,10,10,
9,9,9,9,9,9,9,9,
9,9,9,9,9,9,9,9,
9,9,9,9,9,9,9,9,
9,9,9,9,9,9,9,9,
9,9,9,9,9,9,9,9,
8,8,8,8,8,8,8,8,
8,8,8,8,8,8,8,8,
8,8,8,8,8,8,8,8,
8,8,8,8,8,8,8,8,
8,8,8,8,8,8,8,8,
8,8,8,8,8,8,8,8,
8,8,8,8,8,8,8,8,
8,8,8,8,8,8,8,8,
7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,
6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,
5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,
4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
};
void freq_equalization_NB_IoT(NB_IoT_DL_FRAME_PARMS *frame_parms,
int32_t **rxdataF_comp,
int32_t **ul_ch_mag,
int32_t **ul_ch_magb,
uint8_t symbol,
uint16_t Msc_RS,
uint8_t Qm)
{
uint16_t re;
int16_t amp;
#if defined(__x86_64__) || defined(__i386__)
__m128i *ul_ch_mag128,*ul_ch_magb128,*rxdataF_comp128;
rxdataF_comp128 = (__m128i *)&rxdataF_comp[0][symbol*frame_parms->N_RB_DL*12];
ul_ch_mag128 = (__m128i *)&ul_ch_mag[0][symbol*frame_parms->N_RB_DL*12];
ul_ch_magb128 = (__m128i *)&ul_ch_magb[0][symbol*frame_parms->N_RB_DL*12];
#elif defined(__arm__)
int16x8_t *ul_ch_mag128,*ul_ch_magb128,*rxdataF_comp128;
rxdataF_comp128 = (int16x8_t*)&rxdataF_comp[0][symbol*frame_parms->N_RB_DL*12];
ul_ch_mag128 = (int16x8_t*)&ul_ch_mag[0][symbol*frame_parms->N_RB_DL*12];
ul_ch_magb128 = (int16x8_t*)&ul_ch_magb[0][symbol*frame_parms->N_RB_DL*12];
#endif
for (re=0; re<(Msc_RS>>2); re++) {
amp=(*((int16_t*)&ul_ch_mag128[re]));
if (amp>255)
amp=255;
// printf("freq_eq: symbol %d re %d => %d,%d,%d, (%d) (%d,%d) => ",symbol,re,*((int16_t*)(&ul_ch_mag128[re])),amp,inv_ch[8*amp],*((int16_t*)(&ul_ch_mag128[re]))*inv_ch[8*amp],*(int16_t*)&(rxdataF_comp128[re]),*(1+(int16_t*)&(rxdataF_comp128[re])));
#if defined(__x86_64__) || defined(__i386__)
rxdataF_comp128[re] = _mm_mullo_epi16(rxdataF_comp128[re],*((__m128i *)&inv_ch_NB_IoT[8*amp]));
if (Qm==4)
ul_ch_mag128[re] = _mm_set1_epi16(324); // this is 512*2/sqrt(10)
else {
ul_ch_mag128[re] = _mm_set1_epi16(316); // this is 512*4/sqrt(42)
ul_ch_magb128[re] = _mm_set1_epi16(158); // this is 512*2/sqrt(42)
}
#elif defined(__arm__)
rxdataF_comp128[re] = vmulq_s16(rxdataF_comp128[re],*((int16x8_t *)&inv_ch_NB_IoT[8*amp]));
if (Qm==4)
ul_ch_mag128[re] = vdupq_n_s16(324); // this is 512*2/sqrt(10)
else {
ul_ch_mag128[re] = vdupq_n_s16(316); // this is 512*4/sqrt(42)
ul_ch_magb128[re] = vdupq_n_s16(158); // this is 512*2/sqrt(42)
}
#endif
// printf("(%d,%d)\n",*(int16_t*)&(rxdataF_comp128[re]),*(1+(int16_t*)&(rxdataF_comp128[re])));
}
}
/*
* 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.0 (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
*/
#include "PHY/defs_NB_IoT.h"
#include "PHY/extern_NB_IoT.h"
//#include "PHY/sse_intrin.h"
#include "PHY/LTE_ESTIMATION/defs_NB_IoT.h"
#include "PHY/LTE_TRANSPORT/extern_NB_IoT.h"
//#define DEBUG_CH
#include "T.h"
// For Channel Estimation in Distributed Alamouti Scheme
//static int16_t temp_out_ifft[2048*4] __attribute__((aligned(16)));
static int16_t temp_out_fft_0[2048*4] __attribute__((aligned(16)));
static int16_t temp_out_fft_1[2048*4] __attribute__((aligned(16)));
static int16_t temp_out_ifft_0[2048*4] __attribute__((aligned(16)));
static int16_t temp_out_ifft_1[2048*4] __attribute__((aligned(16)));
static int32_t temp_in_ifft_0[2048*2] __attribute__((aligned(32)));
static int32_t temp_in_ifft_1[2048*2] __attribute__((aligned(32)));
static int32_t temp_in_fft_0[2048*2] __attribute__((aligned(16)));
static int32_t temp_in_fft_1[2048*2] __attribute__((aligned(16)));
// round(exp(sqrt(-1)*(pi/2)*[0:1:N-1]/N)*pow2(15))
static int16_t ru_90[2*128] = {32767, 0,32766, 402,32758, 804,32746, 1206,32729, 1608,32706, 2009,32679, 2411,32647, 2811,32610, 3212,32568, 3612,32522, 4011,32470, 4410,32413, 4808,32352, 5205,32286, 5602,32214, 5998,32138, 6393,32058, 6787,31972, 7180,31881, 7571,31786, 7962,31686, 8351,31581, 8740,31471, 9127,31357, 9512,31238, 9896,31114, 10279,30986, 10660,30853, 11039,30715, 11417,30572, 11793,30425, 12167,30274, 12540,30118, 12910,29957, 13279,29792, 13646,29622, 14010,29448, 14373,29269, 14733,29086, 15091,28899, 15447,28707, 15800,28511, 16151,28311, 16500,28106, 16846,27897, 17190,27684, 17531,27467, 17869,27246, 18205,27020, 18538,26791, 18868,26557, 19195,26320, 19520,26078, 19841,25833, 20160,25583, 20475,25330, 20788,25073, 21097,24812, 21403,24548, 21706,24279, 22006,24008, 22302,23732, 22595,23453, 22884,23170, 23170,22884, 23453,22595, 23732,22302, 24008,22006, 24279,21706, 24548,21403, 24812,21097, 25073,20788, 25330,20475, 25583,20160, 25833,19841, 26078,19520, 26320,19195, 26557,18868, 26791,18538, 27020,18205, 27246,17869, 27467,17531, 27684,17190, 27897,16846, 28106,16500, 28311,16151, 28511,15800, 28707,15447, 28899,15091, 29086,14733, 29269,14373, 29448,14010, 29622,13646, 29792,13279, 29957,12910, 30118,12540, 30274,12167, 30425,11793, 30572,11417, 30715,11039, 30853,10660, 30986,10279, 31114,9896, 31238,9512, 31357,9127, 31471,8740, 31581,8351, 31686,7962, 31786,7571, 31881,7180, 31972,6787, 32058,6393, 32138,5998, 32214,5602, 32286,5205, 32352,4808, 32413,4410, 32470,4011, 32522,3612, 32568,3212, 32610,2811, 32647,2411, 32679,2009, 32706,1608, 32729,1206, 32746,804, 32758,402, 32766};
static int16_t ru_90c[2*128] = {32767, 0,32766, -402,32758, -804,32746, -1206,32729, -1608,32706, -2009,32679, -2411,32647, -2811,32610, -3212,32568, -3612,32522, -4011,32470, -4410,32413, -4808,32352, -5205,32286, -5602,32214, -5998,32138, -6393,32058, -6787,31972, -7180,31881, -7571,31786, -7962,31686, -8351,31581, -8740,31471, -9127,31357, -9512,31238, -9896,31114, -10279,30986, -10660,30853, -11039,30715, -11417,30572, -11793,30425, -12167,30274, -12540,30118, -12910,29957, -13279,29792, -13646,29622, -14010,29448, -14373,29269, -14733,29086, -15091,28899, -15447,28707, -15800,28511, -16151,28311, -16500,28106, -16846,27897, -17190,27684, -17531,27467, -17869,27246, -18205,27020, -18538,26791, -18868,26557, -19195,26320, -19520,26078, -19841,25833, -20160,25583, -20475,25330, -20788,25073, -21097,24812, -21403,24548, -21706,24279, -22006,24008, -22302,23732, -22595,23453, -22884,23170, -23170,22884, -23453,22595, -23732,22302, -24008,22006, -24279,21706, -24548,21403, -24812,21097, -25073,20788, -25330,20475, -25583,20160, -25833,19841, -26078,19520, -26320,19195, -26557,18868, -26791,18538, -27020,18205, -27246,17869, -27467,17531, -27684,17190, -27897,16846, -28106,16500, -28311,16151, -28511,15800, -28707,15447, -28899,15091, -29086,14733, -29269,14373, -29448,14010, -29622,13646, -29792,13279, -29957,12910, -30118,12540, -30274,12167, -30425,11793, -30572,11417, -30715,11039, -30853,10660, -30986,10279, -31114,9896, -31238,9512, -31357,9127, -31471,8740, -31581,8351, -31686,7962, -31786,7571, -31881,7180, -31972,6787, -32058,6393, -32138,5998, -32214,5602, -32286,5205, -32352,4808, -32413,4410, -32470,4011, -32522,3612, -32568,3212, -32610,2811, -32647,2411, -32679,2009, -32706,1608, -32729,1206, -32746,804, -32758,402, -32766};
#define SCALE 0x3FFF
int32_t lte_ul_channel_estimation_NB_IoT(PHY_VARS_eNB_NB_IoT *eNB,
eNB_rxtx_proc_NB_IoT_t *proc,
uint8_t eNB_id,
uint8_t UE_id,
unsigned char l,
unsigned char Ns,
uint8_t cooperation_flag)
{
NB_IoT_DL_FRAME_PARMS *frame_parms = &eNB->frame_parms;
NB_IoT_eNB_PUSCH *pusch_vars = eNB->pusch_vars[UE_id];
int32_t **ul_ch_estimates=pusch_vars->drs_ch_estimates[eNB_id];
int32_t **ul_ch_estimates_time= pusch_vars->drs_ch_estimates_time[eNB_id];
int32_t **ul_ch_estimates_0= pusch_vars->drs_ch_estimates_0[eNB_id];
int32_t **ul_ch_estimates_1= pusch_vars->drs_ch_estimates_1[eNB_id];
int32_t **rxdataF_ext= pusch_vars->rxdataF_ext[eNB_id];
int subframe = proc->subframe_rx;
//uint8_t harq_pid = subframe2harq_pid_NB_IoT(frame_parms,proc->frame_rx,subframe);
int16_t delta_phase = 0;
int16_t *ru1 = ru_90;
int16_t *ru2 = ru_90;
int16_t current_phase1,current_phase2;
uint16_t N_rb_alloc = eNB->ulsch[UE_id]->harq_process->nb_rb;
uint16_t aa,Msc_RS,Msc_RS_idx;
uint16_t * Msc_idx_ptr;
int k,pilot_pos1 = 3 - frame_parms->Ncp, pilot_pos2 = 10 - 2*frame_parms->Ncp;
int16_t alpha, beta;
int32_t *ul_ch1=NULL, *ul_ch2=NULL;
int32_t *ul_ch1_0=NULL,*ul_ch2_0=NULL,*ul_ch1_1=NULL,*ul_ch2_1=NULL;
int16_t ul_ch_estimates_re,ul_ch_estimates_im;
int32_t rx_power_correction;
//uint8_t nb_antennas_rx = frame_parms->nb_antenna_ports_eNB;
uint8_t nb_antennas_rx = frame_parms->nb_antennas_rx;
uint8_t cyclic_shift;
uint32_t alpha_ind;
uint32_t u=frame_parms->npusch_config_common.ul_ReferenceSignalsNPUSCH.grouphop[Ns+(subframe<<1)];
uint32_t v=frame_parms->npusch_config_common.ul_ReferenceSignalsNPUSCH.seqhop[Ns+(subframe<<1)];
int32_t tmp_estimates[N_rb_alloc*12] __attribute__((aligned(16)));
int symbol_offset,i,j;
//debug_msg("lte_ul_channel_estimation: cyclic shift %d\n",cyclicShift);
int16_t alpha_re[12] = {32767, 28377, 16383, 0,-16384, -28378,-32768,-28378,-16384, -1, 16383, 28377};
int16_t alpha_im[12] = {0, 16383, 28377, 32767, 28377, 16383, 0,-16384,-28378,-32768,-28378,-16384};
int32_t *in_fft_ptr_0 = (int32_t*)0,*in_fft_ptr_1 = (int32_t*)0,
*temp_out_fft_0_ptr = (int32_t*)0,*out_fft_ptr_0 = (int32_t*)0,
*temp_out_fft_1_ptr = (int32_t*)0,*out_fft_ptr_1 = (int32_t*)0,
*temp_in_ifft_ptr = (int32_t*)0;
#if defined(__x86_64__) || defined(__i386__)
__m128i *rxdataF128,*ul_ref128,*ul_ch128;
__m128i mmtmpU0,mmtmpU1,mmtmpU2,mmtmpU3;
#elif defined(__arm__)
int16x8_t *rxdataF128,*ul_ref128,*ul_ch128;
int32x4_t mmtmp0,mmtmp1,mmtmp_re,mmtmp_im;
#endif
Msc_RS = N_rb_alloc*12;
cyclic_shift = (frame_parms->npusch_config_common.ul_ReferenceSignalsNPUSCH.cyclicShift +
eNB->ulsch[UE_id]->harq_process->n_DMRS2 +
frame_parms->npusch_config_common.ul_ReferenceSignalsNPUSCH.nPRS[(subframe<<1)+Ns]) % 12;
#if defined(USER_MODE)
Msc_idx_ptr = (uint16_t*) bsearch(&Msc_RS, dftsizes, 33, sizeof(uint16_t), compareints);
if (Msc_idx_ptr)
Msc_RS_idx = Msc_idx_ptr - dftsizes;
else {
msg("lte_ul_channel_estimation: index for Msc_RS=%d not found\n",Msc_RS);
return(-1);
}
#else
uint8_t b;
for (b=0; b<33; b++)
if (Msc_RS==dftsizes[b])
Msc_RS_idx = b;
#endif
// LOG_I(PHY,"subframe %d, Ns %d, l %d, Msc_RS = %d, Msc_RS_idx = %d, u %d, v %d, cyclic_shift %d\n",subframe,Ns,l,Msc_RS, Msc_RS_idx,u,v,cyclic_shift);
#ifdef DEBUG_CH
#ifdef USER_MODE
if (Ns==0)
write_output("drs_seq0.m","drsseq0",ul_ref_sigs_rx[u][v][Msc_RS_idx],2*Msc_RS,2,1);
else
write_output("drs_seq1.m","drsseq1",ul_ref_sigs_rx[u][v][Msc_RS_idx],2*Msc_RS,2,1);
#endif
#endif
rx_power_correction = 1;
if (l == (3 - frame_parms->Ncp)) {
symbol_offset = frame_parms->N_RB_UL*12*(l+((7-frame_parms->Ncp)*(Ns&1)));
for (aa=0; aa<nb_antennas_rx; aa++) {
// msg("Componentwise prod aa %d, symbol_offset %d,ul_ch_estimates %p,ul_ch_estimates[aa] %p,ul_ref_sigs_rx[0][0][Msc_RS_idx] %p\n",aa,symbol_offset,ul_ch_estimates,ul_ch_estimates[aa],ul_ref_sigs_rx[0][0][Msc_RS_idx]);
#if defined(__x86_64__) || defined(__i386__)
rxdataF128 = (__m128i *)&rxdataF_ext[aa][symbol_offset];
ul_ch128 = (__m128i *)&ul_ch_estimates[aa][symbol_offset];
ul_ref128 = (__m128i *)ul_ref_sigs_rx[u][v][Msc_RS_idx];
#elif defined(__arm__)
rxdataF128 = (int16x8_t *)&rxdataF_ext[aa][symbol_offset];
ul_ch128 = (int16x8_t *)&ul_ch_estimates[aa][symbol_offset];
ul_ref128 = (int16x8_t *)ul_ref_sigs_rx[u][v][Msc_RS_idx];
#endif
for (i=0; i<Msc_RS/12; i++) {
#if defined(__x86_64__) || defined(__i386__)
// multiply by conjugated channel
mmtmpU0 = _mm_madd_epi16(ul_ref128[0],rxdataF128[0]);
// mmtmpU0 contains real part of 4 consecutive outputs (32-bit)
mmtmpU1 = _mm_shufflelo_epi16(ul_ref128[0],_MM_SHUFFLE(2,3,0,1));
mmtmpU1 = _mm_shufflehi_epi16(mmtmpU1,_MM_SHUFFLE(2,3,0,1));
mmtmpU1 = _mm_sign_epi16(mmtmpU1,*(__m128i*)&conjugate[0]);
mmtmpU1 = _mm_madd_epi16(mmtmpU1,rxdataF128[0]);
// mmtmpU1 contains imag part of 4 consecutive outputs (32-bit)
mmtmpU0 = _mm_srai_epi32(mmtmpU0,15);
mmtmpU1 = _mm_srai_epi32(mmtmpU1,15);
mmtmpU2 = _mm_unpacklo_epi32(mmtmpU0,mmtmpU1);
mmtmpU3 = _mm_unpackhi_epi32(mmtmpU0,mmtmpU1);
ul_ch128[0] = _mm_packs_epi32(mmtmpU2,mmtmpU3);
// printf("rb %d ch: %d %d\n",i,((int16_t*)ul_ch128)[0],((int16_t*)ul_ch128)[1]);
// multiply by conjugated channel
mmtmpU0 = _mm_madd_epi16(ul_ref128[1],rxdataF128[1]);
// mmtmpU0 contains real part of 4 consecutive outputs (32-bit)
mmtmpU1 = _mm_shufflelo_epi16(ul_ref128[1],_MM_SHUFFLE(2,3,0,1));
mmtmpU1 = _mm_shufflehi_epi16(mmtmpU1,_MM_SHUFFLE(2,3,0,1));
mmtmpU1 = _mm_sign_epi16(mmtmpU1,*(__m128i*)conjugate);
mmtmpU1 = _mm_madd_epi16(mmtmpU1,rxdataF128[1]);
// mmtmpU1 contains imag part of 4 consecutive outputs (32-bit)
mmtmpU0 = _mm_srai_epi32(mmtmpU0,15);
mmtmpU1 = _mm_srai_epi32(mmtmpU1,15);
mmtmpU2 = _mm_unpacklo_epi32(mmtmpU0,mmtmpU1);
mmtmpU3 = _mm_unpackhi_epi32(mmtmpU0,mmtmpU1);
ul_ch128[1] = _mm_packs_epi32(mmtmpU2,mmtmpU3);
mmtmpU0 = _mm_madd_epi16(ul_ref128[2],rxdataF128[2]);
// mmtmpU0 contains real part of 4 consecutive outputs (32-bit)
mmtmpU1 = _mm_shufflelo_epi16(ul_ref128[2],_MM_SHUFFLE(2,3,0,1));
mmtmpU1 = _mm_shufflehi_epi16(mmtmpU1,_MM_SHUFFLE(2,3,0,1));
mmtmpU1 = _mm_sign_epi16(mmtmpU1,*(__m128i*)conjugate);
mmtmpU1 = _mm_madd_epi16(mmtmpU1,rxdataF128[2]);
// mmtmpU1 contains imag part of 4 consecutive outputs (32-bit)
mmtmpU0 = _mm_srai_epi32(mmtmpU0,15);
mmtmpU1 = _mm_srai_epi32(mmtmpU1,15);
mmtmpU2 = _mm_unpacklo_epi32(mmtmpU0,mmtmpU1);
mmtmpU3 = _mm_unpackhi_epi32(mmtmpU0,mmtmpU1);
ul_ch128[2] = _mm_packs_epi32(mmtmpU2,mmtmpU3);
#elif defined(__arm__)
mmtmp0 = vmull_s16(((int16x4_t*)ul_ref128)[0],((int16x4_t*)rxdataF128)[0]);
mmtmp1 = vmull_s16(((int16x4_t*)ul_ref128)[1],((int16x4_t*)rxdataF128)[1]);
mmtmp_re = vcombine_s32(vpadd_s32(vget_low_s32(mmtmp0),vget_high_s32(mmtmp0)),
vpadd_s32(vget_low_s32(mmtmp1),vget_high_s32(mmtmp1)));
mmtmp0 = vmull_s16(vrev32_s16(vmul_s16(((int16x4_t*)ul_ref128)[0],*(int16x4_t*)conjugate)), ((int16x4_t*)rxdataF128)[0]);
mmtmp1 = vmull_s16(vrev32_s16(vmul_s16(((int16x4_t*)ul_ref128)[1],*(int16x4_t*)conjugate)), ((int16x4_t*)rxdataF128)[1]);
mmtmp_im = vcombine_s32(vpadd_s32(vget_low_s32(mmtmp0),vget_high_s32(mmtmp0)),
vpadd_s32(vget_low_s32(mmtmp1),vget_high_s32(mmtmp1)));
ul_ch128[0] = vcombine_s16(vmovn_s32(mmtmp_re),vmovn_s32(mmtmp_im));
ul_ch128++;
ul_ref128++;
rxdataF128++;
mmtmp0 = vmull_s16(((int16x4_t*)ul_ref128)[0],((int16x4_t*)rxdataF128)[0]);
mmtmp1 = vmull_s16(((int16x4_t*)ul_ref128)[1],((int16x4_t*)rxdataF128)[1]);
mmtmp_re = vcombine_s32(vpadd_s32(vget_low_s32(mmtmp0),vget_high_s32(mmtmp0)),
vpadd_s32(vget_low_s32(mmtmp1),vget_high_s32(mmtmp1)));
mmtmp0 = vmull_s16(vrev32_s16(vmul_s16(((int16x4_t*)ul_ref128)[0],*(int16x4_t*)conjugate)), ((int16x4_t*)rxdataF128)[0]);
mmtmp1 = vmull_s16(vrev32_s16(vmul_s16(((int16x4_t*)ul_ref128)[1],*(int16x4_t*)conjugate)), ((int16x4_t*)rxdataF128)[1]);
mmtmp_im = vcombine_s32(vpadd_s32(vget_low_s32(mmtmp0),vget_high_s32(mmtmp0)),
vpadd_s32(vget_low_s32(mmtmp1),vget_high_s32(mmtmp1)));
ul_ch128[0] = vcombine_s16(vmovn_s32(mmtmp_re),vmovn_s32(mmtmp_im));
ul_ch128++;
ul_ref128++;
rxdataF128++;
mmtmp0 = vmull_s16(((int16x4_t*)ul_ref128)[0],((int16x4_t*)rxdataF128)[0]);
mmtmp1 = vmull_s16(((int16x4_t*)ul_ref128)[1],((int16x4_t*)rxdataF128)[1]);
mmtmp_re = vcombine_s32(vpadd_s32(vget_low_s32(mmtmp0),vget_high_s32(mmtmp0)),
vpadd_s32(vget_low_s32(mmtmp1),vget_high_s32(mmtmp1)));
mmtmp0 = vmull_s16(vrev32_s16(vmul_s16(((int16x4_t*)ul_ref128)[0],*(int16x4_t*)conjugate)), ((int16x4_t*)rxdataF128)[0]);
mmtmp1 = vmull_s16(vrev32_s16(vmul_s16(((int16x4_t*)ul_ref128)[1],*(int16x4_t*)conjugate)), ((int16x4_t*)rxdataF128)[1]);
mmtmp_im = vcombine_s32(vpadd_s32(vget_low_s32(mmtmp0),vget_high_s32(mmtmp0)),
vpadd_s32(vget_low_s32(mmtmp1),vget_high_s32(mmtmp1)));
ul_ch128[0] = vcombine_s16(vmovn_s32(mmtmp_re),vmovn_s32(mmtmp_im));
ul_ch128++;
ul_ref128++;
rxdataF128++;
#endif
ul_ch128+=3;
ul_ref128+=3;
rxdataF128+=3;
}
alpha_ind = 0;
if((cyclic_shift != 0)) {
// Compensating for the phase shift introduced at the transmitte
#ifdef DEBUG_CH
write_output("drs_est_pre.m","drsest_pre",ul_ch_estimates[0],300*12,1,1);
#endif
for(i=symbol_offset; i<symbol_offset+Msc_RS; i++) {
ul_ch_estimates_re = ((int16_t*) ul_ch_estimates[aa])[i<<1];
ul_ch_estimates_im = ((int16_t*) ul_ch_estimates[aa])[(i<<1)+1];
// ((int16_t*) ul_ch_estimates[aa])[i<<1] = (i%2 == 1? 1:-1) * ul_ch_estimates_re;
((int16_t*) ul_ch_estimates[aa])[i<<1] =
(int16_t) (((int32_t) (alpha_re[alpha_ind]) * (int32_t) (ul_ch_estimates_re) +
(int32_t) (alpha_im[alpha_ind]) * (int32_t) (ul_ch_estimates_im))>>15);
//((int16_t*) ul_ch_estimates[aa])[(i<<1)+1] = (i%2 == 1? 1:-1) * ul_ch_estimates_im;
((int16_t*) ul_ch_estimates[aa])[(i<<1)+1] =
(int16_t) (((int32_t) (alpha_re[alpha_ind]) * (int32_t) (ul_ch_estimates_im) -
(int32_t) (alpha_im[alpha_ind]) * (int32_t) (ul_ch_estimates_re))>>15);
alpha_ind+=cyclic_shift;
if (alpha_ind>11)
alpha_ind-=12;
}
#ifdef DEBUG_CH
write_output("drs_est_post.m","drsest_post",ul_ch_estimates[0],300*12,1,1);
#endif
}
//copy MIMO channel estimates to temporary buffer for EMOS
//memcpy(&ul_ch_estimates_0[aa][symbol_offset],&ul_ch_estimates[aa][symbol_offset],frame_parms->ofdm_symbol_size*sizeof(int32_t)*2);
memset(temp_in_ifft_0,0,frame_parms->ofdm_symbol_size*sizeof(int32_t));
// Convert to time domain for visualization
for(i=0; i<Msc_RS; i++)
((int32_t*)temp_in_ifft_0)[i] = ul_ch_estimates[aa][symbol_offset+i];
switch(frame_parms->N_RB_DL) {
case 6:
idft128((int16_t*) temp_in_ifft_0,
(int16_t*) ul_ch_estimates_time[aa],
1);
break;
case 25:
idft512((int16_t*) temp_in_ifft_0,
(int16_t*) ul_ch_estimates_time[aa],
1);
break;
case 50:
idft1024((int16_t*) temp_in_ifft_0,
(int16_t*) ul_ch_estimates_time[aa],
1);
break;
case 100:
idft2048((int16_t*) temp_in_ifft_0,
(int16_t*) ul_ch_estimates_time[aa],
1);
break;
}
#if T_TRACER
if (aa == 0)
T(T_ENB_PHY_UL_CHANNEL_ESTIMATE, T_INT(eNB_id), T_INT(UE_id),
T_INT(proc->frame_rx), T_INT(subframe),
T_INT(0), T_BUFFER(ul_ch_estimates_time[0], 512 * 4));
#endif
#ifdef DEBUG_CH
if (aa==0) {
if (Ns == 0) {
write_output("rxdataF_ext.m","rxF_ext",&rxdataF_ext[aa][symbol_offset],512*2,2,1);
write_output("tmpin_ifft.m","drs_in",temp_in_ifft_0,512,1,1);
write_output("drs_est0.m","drs0",ul_ch_estimates_time[aa],512,1,1);
} else
write_output("drs_est1.m","drs1",ul_ch_estimates_time[aa],512,1,1);
}
#endif
if(cooperation_flag == 2) {
memset(temp_in_ifft_0,0,frame_parms->ofdm_symbol_size*sizeof(int32_t*)*2);
memset(temp_in_ifft_1,0,frame_parms->ofdm_symbol_size*sizeof(int32_t*)*2);
memset(temp_in_fft_0,0,frame_parms->ofdm_symbol_size*sizeof(int32_t*)*2);
memset(temp_in_fft_1,0,frame_parms->ofdm_symbol_size*sizeof(int32_t*)*2);
temp_in_ifft_ptr = &temp_in_ifft_0[0];
i = symbol_offset;
for(j=0; j<(frame_parms->N_RB_UL*12); j++) {
temp_in_ifft_ptr[j] = ul_ch_estimates[aa][i];
i++;
}
alpha_ind = 0;
// Compensating for the phase shift introduced at the transmitter
for(i=symbol_offset; i<symbol_offset+Msc_RS; i++) {
ul_ch_estimates_re = ((int16_t*) ul_ch_estimates[aa])[i<<1];
ul_ch_estimates_im = ((int16_t*) ul_ch_estimates[aa])[(i<<1)+1];
// ((int16_t*) ul_ch_estimates[aa])[i<<1] = (i%2 == 1? 1:-1) * ul_ch_estimates_re;
((int16_t*) ul_ch_estimates[aa])[i<<1] =
(int16_t) (((int32_t) (alpha_re[alpha_ind]) * (int32_t) (ul_ch_estimates_re) +
(int32_t) (alpha_im[alpha_ind]) * (int32_t) (ul_ch_estimates_im))>>15);
//((int16_t*) ul_ch_estimates[aa])[(i<<1)+1] = (i%2 == 1? 1:-1) * ul_ch_estimates_im;
((int16_t*) ul_ch_estimates[aa])[(i<<1)+1] =
(int16_t) (((int32_t) (alpha_re[alpha_ind]) * (int32_t) (ul_ch_estimates_im) -
(int32_t) (alpha_im[alpha_ind]) * (int32_t) (ul_ch_estimates_re))>>15);
alpha_ind+=10;
if (alpha_ind>11)
alpha_ind-=12;
}
//Extracting Channel Estimates for Distributed Alamouti Receiver Combining
temp_in_ifft_ptr = &temp_in_ifft_1[0];
i = symbol_offset;
for(j=0; j<(frame_parms->N_RB_UL*12); j++) {
temp_in_ifft_ptr[j] = ul_ch_estimates[aa][i];
i++;
}
switch (frame_parms->N_RB_DL) {
case 6:
idft128((int16_t*) &temp_in_ifft_0[0], // Performing IFFT on Combined Channel Estimates
temp_out_ifft_0,
1);
idft128((int16_t*) &temp_in_ifft_1[0], // Performing IFFT on Combined Channel Estimates
temp_out_ifft_1,
1);
break;
case 25:
idft512((int16_t*) &temp_in_ifft_0[0], // Performing IFFT on Combined Channel Estimates
temp_out_ifft_0,
1);
idft512((int16_t*) &temp_in_ifft_1[0], // Performing IFFT on Combined Channel Estimates
temp_out_ifft_1,
1);
break;
case 50:
idft1024((int16_t*) &temp_in_ifft_0[0], // Performing IFFT on Combined Channel Estimates
temp_out_ifft_0,
1);
idft1024((int16_t*) &temp_in_ifft_1[0], // Performing IFFT on Combined Channel Estimates
temp_out_ifft_1,
1);
break;
case 100:
idft2048((int16_t*) &temp_in_ifft_0[0], // Performing IFFT on Combined Channel Estimates
temp_out_ifft_0,
1);
idft2048((int16_t*) &temp_in_ifft_1[0], // Performing IFFT on Combined Channel Estimates
temp_out_ifft_1,
1);
break;
}
// because the ifft is not power preserving, we should apply the factor sqrt(power_correction) here, but we rather apply power_correction here and nothing after the next fft
in_fft_ptr_0 = &temp_in_fft_0[0];
in_fft_ptr_1 = &temp_in_fft_1[0];
for(j=0; j<(frame_parms->ofdm_symbol_size)/12; j++) {
if (j>19) {
((int16_t*)in_fft_ptr_0)[-40+(2*j)] = ((int16_t*)temp_out_ifft_0)[-80+(2*j)]*rx_power_correction;
((int16_t*)in_fft_ptr_0)[-40+(2*j)+1] = ((int16_t*)temp_out_ifft_0)[-80+(2*j+1)]*rx_power_correction;
((int16_t*)in_fft_ptr_1)[-40+(2*j)] = ((int16_t*)temp_out_ifft_1)[-80+(2*j)]*rx_power_correction;
((int16_t*)in_fft_ptr_1)[-40+(2*j)+1] = ((int16_t*)temp_out_ifft_1)[-80+(2*j)+1]*rx_power_correction;
} else {
((int16_t*)in_fft_ptr_0)[2*(frame_parms->ofdm_symbol_size-20+j)] = ((int16_t*)temp_out_ifft_0)[2*(frame_parms->ofdm_symbol_size-20+j)]*rx_power_correction;
((int16_t*)in_fft_ptr_0)[2*(frame_parms->ofdm_symbol_size-20+j)+1] = ((int16_t*)temp_out_ifft_0)[2*(frame_parms->ofdm_symbol_size-20+j)+1]*rx_power_correction;
((int16_t*)in_fft_ptr_1)[2*(frame_parms->ofdm_symbol_size-20+j)] = ((int16_t*)temp_out_ifft_1)[2*(frame_parms->ofdm_symbol_size-20+j)]*rx_power_correction;
((int16_t*)in_fft_ptr_1)[2*(frame_parms->ofdm_symbol_size-20+j)+1] = ((int16_t*)temp_out_ifft_1)[2*(frame_parms->ofdm_symbol_size-20+j)+1]*rx_power_correction;
}
}
switch (frame_parms->N_RB_DL) {
case 6:
dft128((int16_t*) &temp_in_fft_0[0],
// Performing FFT to obtain the Channel Estimates for UE0 to eNB1
temp_out_fft_0,
1);
break;
case 25:
dft512((int16_t*) &temp_in_fft_0[0],
// Performing FFT to obtain the Channel Estimates for UE0 to eNB1
temp_out_fft_0,
1);
break;
case 50:
dft1024((int16_t*) &temp_in_fft_0[0],
// Performing FFT to obtain the Channel Estimates for UE0 to eNB1
temp_out_fft_0,
1);
break;
case 100:
dft2048((int16_t*) &temp_in_fft_0[0],
// Performing FFT to obtain the Channel Estimates for UE0 to eNB1
temp_out_fft_0,
1);
break;
}
out_fft_ptr_0 = &ul_ch_estimates_0[aa][symbol_offset]; // CHANNEL ESTIMATES FOR UE0 TO eNB1
temp_out_fft_0_ptr = (int32_t*) temp_out_fft_0;
i=0;
for(j=0; j<frame_parms->N_RB_UL*12; j++) {
out_fft_ptr_0[i] = temp_out_fft_0_ptr[j];
i++;
}
switch (frame_parms->N_RB_DL) {
case 6:
dft128((int16_t*) &temp_in_fft_1[0], // Performing FFT to obtain the Channel Estimates for UE1 to eNB1
temp_out_fft_1,
1);
break;
case 25:
dft512((int16_t*) &temp_in_fft_1[0], // Performing FFT to obtain the Channel Estimates for UE1 to eNB1
temp_out_fft_1,
1);
break;
case 50:
dft1024((int16_t*) &temp_in_fft_1[0], // Performing FFT to obtain the Channel Estimates for UE1 to eNB1
temp_out_fft_1,
1);
break;
case 100:
dft2048((int16_t*) &temp_in_fft_1[0], // Performing FFT to obtain the Channel Estimates for UE1 to eNB1
temp_out_fft_1,
1);
break;
}
out_fft_ptr_1 = &ul_ch_estimates_1[aa][symbol_offset]; // CHANNEL ESTIMATES FOR UE1 TO eNB1
temp_out_fft_1_ptr = (int32_t*) temp_out_fft_1;
i=0;
for(j=0; j<frame_parms->N_RB_UL*12; j++) {
out_fft_ptr_1[i] = temp_out_fft_1_ptr[j];
i++;
}
#ifdef DEBUG_CH
#ifdef USER_MODE
if((aa == 0)&& (cooperation_flag == 2)) {
write_output("test1.m","t1",temp_in_ifft_0,512,1,1);
write_output("test2.m","t2",temp_out_ifft_0,512*2,2,1);
write_output("test3.m","t3",temp_in_fft_0,512,1,1);
write_output("test4.m","t4",temp_out_fft_0,512,1,1);
write_output("test5.m","t5",temp_in_fft_1,512,1,1);
write_output("test6.m","t6",temp_out_fft_1,512,1,1);
}
#endif
#endif
}//cooperation_flag == 2
if (Ns&1) {//we are in the second slot of the sub-frame, so do the interpolation
ul_ch1 = &ul_ch_estimates[aa][frame_parms->N_RB_UL*12*pilot_pos1];
ul_ch2 = &ul_ch_estimates[aa][frame_parms->N_RB_UL*12*pilot_pos2];
if(cooperation_flag == 2) { // For Distributed Alamouti
ul_ch1_0 = &ul_ch_estimates_0[aa][frame_parms->N_RB_UL*12*pilot_pos1];
ul_ch2_0 = &ul_ch_estimates_0[aa][frame_parms->N_RB_UL*12*pilot_pos2];
ul_ch1_1 = &ul_ch_estimates_1[aa][frame_parms->N_RB_UL*12*pilot_pos1];
ul_ch2_1 = &ul_ch_estimates_1[aa][frame_parms->N_RB_UL*12*pilot_pos2];
}
// Estimation of phase difference between the 2 channel estimates
delta_phase = lte_ul_freq_offset_estimation_NB_IoT(frame_parms,
ul_ch_estimates[aa],
N_rb_alloc);
// negative phase index indicates negative Im of ru
// msg("delta_phase: %d\n",delta_phase);
#ifdef DEBUG_CH
msg("lte_ul_channel_estimation: ul_ch1 = %p, ul_ch2 = %p, pilot_pos1=%d, pilot_pos2=%d\n",ul_ch1, ul_ch2, pilot_pos1,pilot_pos2);
#endif
for (k=0; k<frame_parms->symbols_per_tti; k++) {
// we scale alpha and beta by SCALE (instead of 0x7FFF) to avoid overflows
alpha = (int16_t) (((int32_t) SCALE * (int32_t) (pilot_pos2-k))/(pilot_pos2-pilot_pos1));
beta = (int16_t) (((int32_t) SCALE * (int32_t) (k-pilot_pos1))/(pilot_pos2-pilot_pos1));
#ifdef DEBUG_CH
msg("lte_ul_channel_estimation: k=%d, alpha = %d, beta = %d\n",k,alpha,beta);
#endif
//symbol_offset_subframe = frame_parms->N_RB_UL*12*k;
// interpolate between estimates
if ((k != pilot_pos1) && (k != pilot_pos2)) {
// multadd_complex_vector_real_scalar((int16_t*) ul_ch1,alpha,(int16_t*) &ul_ch_estimates[aa][frame_parms->N_RB_UL*12*k],1,Msc_RS);
// multadd_complex_vector_real_scalar((int16_t*) ul_ch2,beta ,(int16_t*) &ul_ch_estimates[aa][frame_parms->N_RB_UL*12*k],0,Msc_RS);
// multadd_complex_vector_real_scalar((int16_t*) ul_ch1,SCALE,(int16_t*) &ul_ch_estimates[aa][frame_parms->N_RB_UL*12*k],1,Msc_RS);
// multadd_complex_vector_real_scalar((int16_t*) ul_ch2,SCALE,(int16_t*) &ul_ch_estimates[aa][frame_parms->N_RB_UL*12*k],0,Msc_RS);
// msg("phase = %d\n",ru[2*cmax(((delta_phase/7)*(k-3)),0)]);
// the phase is linearly interpolated
current_phase1 = (delta_phase/7)*(k-pilot_pos1);
current_phase2 = (delta_phase/7)*(k-pilot_pos2);
// msg("sym: %d, current_phase1: %d, current_phase2: %d\n",k,current_phase1,current_phase2);
// set the right quadrant
(current_phase1 > 0) ? (ru1 = ru_90) : (ru1 = ru_90c);
(current_phase2 > 0) ? (ru2 = ru_90) : (ru2 = ru_90c);
// take absolute value and clip
current_phase1 = cmin(abs(current_phase1),127);
current_phase2 = cmin(abs(current_phase2),127);
// msg("sym: %d, current_phase1: %d, ru: %d + j%d, current_phase2: %d, ru: %d + j%d\n",k,current_phase1,ru1[2*current_phase1],ru1[2*current_phase1+1],current_phase2,ru2[2*current_phase2],ru2[2*current_phase2+1]);
// rotate channel estimates by estimated phase
rotate_cpx_vector((int16_t*) ul_ch1,
&ru1[2*current_phase1],
(int16_t*) &ul_ch_estimates[aa][frame_parms->N_RB_UL*12*k],
Msc_RS,
15);
rotate_cpx_vector((int16_t*) ul_ch2,
&ru2[2*current_phase2],
(int16_t*) &tmp_estimates[0],
Msc_RS,
15);
// Combine the two rotated estimates
multadd_complex_vector_real_scalar((int16_t*) &ul_ch_estimates[aa][frame_parms->N_RB_UL*12*k],SCALE,(int16_t*) &ul_ch_estimates[aa][frame_parms->N_RB_UL*12*k],1,Msc_RS);
multadd_complex_vector_real_scalar((int16_t*) &tmp_estimates[0],SCALE,(int16_t*) &ul_ch_estimates[aa][frame_parms->N_RB_UL*12*k],0,Msc_RS);
/*
if ((k<pilot_pos1) || ((k>pilot_pos2))) {
multadd_complex_vector_real_scalar((int16_t*) &ul_ch_estimates[aa][frame_parms->N_RB_UL*12*k],SCALE>>1,(int16_t*) &ul_ch_estimates[aa][frame_parms->N_RB_UL*12*k],1,Msc_RS);
multadd_complex_vector_real_scalar((int16_t*) &tmp_estimates[0],SCALE>>1,(int16_t*) &ul_ch_estimates[aa][frame_parms->N_RB_UL*12*k],0,Msc_RS);
} else {
multadd_complex_vector_real_scalar((int16_t*) &ul_ch_estimates[aa][frame_parms->N_RB_UL*12*k],SCALE>>1,(int16_t*) &ul_ch_estimates[aa][frame_parms->N_RB_UL*12*k],1,Msc_RS);
multadd_complex_vector_real_scalar((int16_t*) &tmp_estimates[0],SCALE>>1,(int16_t*) &ul_ch_estimates[aa][frame_parms->N_RB_UL*12*k],0,Msc_RS);
// multadd_complex_vector_real_scalar((int16_t*) &ul_ch_estimates[aa][frame_parms->N_RB_UL*12*k],alpha,(int16_t*) &ul_ch_estimates[aa][frame_parms->N_RB_UL*12*k],1,Msc_RS);
// multadd_complex_vector_real_scalar((int16_t*) &tmp_estimates[0],beta ,(int16_t*) &ul_ch_estimates[aa][frame_parms->N_RB_UL*12*k],0,Msc_RS);
}
*/
// memcpy(&ul_ch_estimates[aa][frame_parms->N_RB_UL*12*k],ul_ch1,Msc_RS*sizeof(int32_t));
if(cooperation_flag == 2) { // For Distributed Alamouti
multadd_complex_vector_real_scalar((int16_t*) ul_ch1_0,beta ,(int16_t*) &ul_ch_estimates_0[aa][frame_parms->N_RB_UL*12*k],1,Msc_RS);
multadd_complex_vector_real_scalar((int16_t*) ul_ch2_0,alpha,(int16_t*) &ul_ch_estimates_0[aa][frame_parms->N_RB_UL*12*k],0,Msc_RS);
multadd_complex_vector_real_scalar((int16_t*) ul_ch1_1,beta ,(int16_t*) &ul_ch_estimates_1[aa][frame_parms->N_RB_UL*12*k],1,Msc_RS);
multadd_complex_vector_real_scalar((int16_t*) ul_ch2_1,alpha,(int16_t*) &ul_ch_estimates_1[aa][frame_parms->N_RB_UL*12*k],0,Msc_RS);
}
}
} //for(k=...
// because of the scaling of alpha and beta we also need to scale the final channel estimate at the pilot positions
// multadd_complex_vector_real_scalar((int16_t*) ul_ch1,SCALE,(int16_t*) ul_ch1,1,Msc_RS);
// multadd_complex_vector_real_scalar((int16_t*) ul_ch2,SCALE,(int16_t*) ul_ch2,1,Msc_RS);
if(cooperation_flag == 2) { // For Distributed Alamouti
multadd_complex_vector_real_scalar((int16_t*) ul_ch1_0,SCALE,(int16_t*) ul_ch1_0,1,Msc_RS);
multadd_complex_vector_real_scalar((int16_t*) ul_ch2_0,SCALE,(int16_t*) ul_ch2_0,1,Msc_RS);
multadd_complex_vector_real_scalar((int16_t*) ul_ch1_1,SCALE,(int16_t*) ul_ch1_1,1,Msc_RS);
multadd_complex_vector_real_scalar((int16_t*) ul_ch2_1,SCALE,(int16_t*) ul_ch2_1,1,Msc_RS);
}
} //if (Ns&1)
} //for(aa=...
} //if(l==...
return(0);
}
int16_t lte_ul_freq_offset_estimation_NB_IoT(NB_IoT_DL_FRAME_PARMS *frame_parms,
int32_t *ul_ch_estimates,
uint16_t nb_rb)
{
#if defined(__x86_64__) || defined(__i386__)
int k, rb;
int a_idx = 64;
uint8_t conj_flag = 0;
uint8_t output_shift;
int pilot_pos1 = 3 - frame_parms->Ncp;
int pilot_pos2 = 10 - 2*frame_parms->Ncp;
__m128i *ul_ch1 = (__m128i*)&ul_ch_estimates[pilot_pos1*frame_parms->N_RB_UL*12];
__m128i *ul_ch2 = (__m128i*)&ul_ch_estimates[pilot_pos2*frame_parms->N_RB_UL*12];
int32_t avg[2];
int16_t Ravg[2];
Ravg[0]=0;
Ravg[1]=0;
int16_t iv, rv, phase_idx;
__m128i avg128U1, avg128U2, R[3], mmtmpD0,mmtmpD1,mmtmpD2,mmtmpD3;
// round(tan((pi/4)*[1:1:N]/N)*pow2(15))
int16_t alpha[128] = {201, 402, 603, 804, 1006, 1207, 1408, 1610, 1811, 2013, 2215, 2417, 2619, 2822, 3024, 3227, 3431, 3634, 3838, 4042, 4246, 4450, 4655, 4861, 5066, 5272, 5479, 5686, 5893, 6101, 6309, 6518, 6727, 6937, 7147, 7358, 7570, 7782, 7995, 8208, 8422, 8637, 8852, 9068, 9285, 9503, 9721, 9940, 10160, 10381, 10603, 10825, 11049, 11273, 11498, 11725, 11952, 12180, 12410, 12640, 12872, 13104, 13338, 13573, 13809, 14046, 14285, 14525, 14766, 15009, 15253, 15498, 15745, 15993, 16243, 16494, 16747, 17001, 17257, 17515, 17774, 18035, 18298, 18563, 18829, 19098, 19368, 19640, 19915, 20191, 20470, 20750, 21033, 21318, 21605, 21895, 22187, 22481, 22778, 23078, 23380, 23685, 23992, 24302, 24615, 24931, 25250, 25572, 25897, 26226, 26557, 26892, 27230, 27572, 27917, 28266, 28618, 28975, 29335, 29699, 30067, 30440, 30817, 31198, 31583, 31973, 32368, 32767};
// compute log2_maxh (output_shift)
avg128U1 = _mm_setzero_si128();
avg128U2 = _mm_setzero_si128();
for (rb=0; rb<nb_rb; rb++) {
avg128U1 = _mm_add_epi32(avg128U1,_mm_madd_epi16(ul_ch1[0],ul_ch1[0]));
avg128U1 = _mm_add_epi32(avg128U1,_mm_madd_epi16(ul_ch1[1],ul_ch1[1]));
avg128U1 = _mm_add_epi32(avg128U1,_mm_madd_epi16(ul_ch1[2],ul_ch1[2]));
avg128U2 = _mm_add_epi32(avg128U2,_mm_madd_epi16(ul_ch2[0],ul_ch2[0]));
avg128U2 = _mm_add_epi32(avg128U2,_mm_madd_epi16(ul_ch2[1],ul_ch2[1]));
avg128U2 = _mm_add_epi32(avg128U2,_mm_madd_epi16(ul_ch2[2],ul_ch2[2]));
ul_ch1+=3;
ul_ch2+=3;
}
avg[0] = (((int*)&avg128U1)[0] +
((int*)&avg128U1)[1] +
((int*)&avg128U1)[2] +
((int*)&avg128U1)[3])/(nb_rb*12);
avg[1] = (((int*)&avg128U2)[0] +
((int*)&avg128U2)[1] +
((int*)&avg128U2)[2] +
((int*)&avg128U2)[3])/(nb_rb*12);
// msg("avg0 = %d, avg1 = %d\n",avg[0],avg[1]);
avg[0] = cmax(avg[0],avg[1]);
avg[1] = log2_approx(avg[0]);
output_shift = cmax(0,avg[1]-10);
//output_shift = (log2_approx(avg[0])/2)+ log2_approx(frame_parms->nb_antennas_rx-1)+1;
// msg("avg= %d, shift = %d\n",avg[0],output_shift);
ul_ch1 = (__m128i*)&ul_ch_estimates[pilot_pos1*frame_parms->N_RB_UL*12];
ul_ch2 = (__m128i*)&ul_ch_estimates[pilot_pos2*frame_parms->N_RB_UL*12];
// correlate and average the 2 channel estimates ul_ch1*ul_ch2
for (rb=0; rb<nb_rb; rb++) {
mmtmpD0 = _mm_madd_epi16(ul_ch1[0],ul_ch2[0]);
mmtmpD1 = _mm_shufflelo_epi16(ul_ch1[0],_MM_SHUFFLE(2,3,0,1));
mmtmpD1 = _mm_shufflehi_epi16(mmtmpD1,_MM_SHUFFLE(2,3,0,1));
mmtmpD1 = _mm_sign_epi16(mmtmpD1,*(__m128i*)&conjugate);
mmtmpD1 = _mm_madd_epi16(mmtmpD1,ul_ch2[0]);
mmtmpD0 = _mm_srai_epi32(mmtmpD0,output_shift);
mmtmpD1 = _mm_srai_epi32(mmtmpD1,output_shift);
mmtmpD2 = _mm_unpacklo_epi32(mmtmpD0,mmtmpD1);
mmtmpD3 = _mm_unpackhi_epi32(mmtmpD0,mmtmpD1);
R[0] = _mm_packs_epi32(mmtmpD2,mmtmpD3);
mmtmpD0 = _mm_madd_epi16(ul_ch1[1],ul_ch2[1]);
mmtmpD1 = _mm_shufflelo_epi16(ul_ch1[1],_MM_SHUFFLE(2,3,0,1));
mmtmpD1 = _mm_shufflehi_epi16(mmtmpD1,_MM_SHUFFLE(2,3,0,1));
mmtmpD1 = _mm_sign_epi16(mmtmpD1,*(__m128i*)&conjugate);
mmtmpD1 = _mm_madd_epi16(mmtmpD1,ul_ch2[1]);
mmtmpD0 = _mm_srai_epi32(mmtmpD0,output_shift);
mmtmpD1 = _mm_srai_epi32(mmtmpD1,output_shift);
mmtmpD2 = _mm_unpacklo_epi32(mmtmpD0,mmtmpD1);
mmtmpD3 = _mm_unpackhi_epi32(mmtmpD0,mmtmpD1);
R[1] = _mm_packs_epi32(mmtmpD2,mmtmpD3);
mmtmpD0 = _mm_madd_epi16(ul_ch1[2],ul_ch2[2]);
mmtmpD1 = _mm_shufflelo_epi16(ul_ch1[2],_MM_SHUFFLE(2,3,0,1));
mmtmpD1 = _mm_shufflehi_epi16(mmtmpD1,_MM_SHUFFLE(2,3,0,1));
mmtmpD1 = _mm_sign_epi16(mmtmpD1,*(__m128i*)&conjugate);
mmtmpD1 = _mm_madd_epi16(mmtmpD1,ul_ch2[2]);
mmtmpD0 = _mm_srai_epi32(mmtmpD0,output_shift);
mmtmpD1 = _mm_srai_epi32(mmtmpD1,output_shift);
mmtmpD2 = _mm_unpacklo_epi32(mmtmpD0,mmtmpD1);
mmtmpD3 = _mm_unpackhi_epi32(mmtmpD0,mmtmpD1);
R[2] = _mm_packs_epi32(mmtmpD2,mmtmpD3);
R[0] = _mm_add_epi16(_mm_srai_epi16(R[0],1),_mm_srai_epi16(R[1],1));
R[0] = _mm_add_epi16(_mm_srai_epi16(R[0],1),_mm_srai_epi16(R[2],1));
Ravg[0] += (((short*)&R)[0] +
((short*)&R)[2] +
((short*)&R)[4] +
((short*)&R)[6])/(nb_rb*4);
Ravg[1] += (((short*)&R)[1] +
((short*)&R)[3] +
((short*)&R)[5] +
((short*)&R)[7])/(nb_rb*4);
ul_ch1+=3;
ul_ch2+=3;
}
// phase estimation on Ravg
// Ravg[0] = 56;
// Ravg[1] = 0;
rv = Ravg[0];
iv = Ravg[1];
if (iv<0)
iv = -Ravg[1];
if (rv<iv) {
rv = iv;
iv = Ravg[0];
conj_flag = 1;
}
// msg("rv = %d, iv = %d\n",rv,iv);
// msg("max_avg = %d, log2_approx = %d, shift = %d\n",avg[0], avg[1], output_shift);
for (k=0; k<6; k++) {
(iv<(((int32_t)(alpha[a_idx]*rv))>>15)) ? (a_idx -= 32>>k) : (a_idx += 32>>k);
}
(conj_flag==1) ? (phase_idx = 127-(a_idx>>1)) : (phase_idx = (a_idx>>1));
if (Ravg[1]<0)
phase_idx = -phase_idx;
return(phase_idx);
#elif defined(__arm__)
return(0);
#endif
}
......@@ -662,6 +662,8 @@ typedef struct {
uint32_t F;
/// Temporary h sequence to flag PUSCH_x/PUSCH_y symbols which are not scrambled
//uint8_t h[MAX_NUM_CHANNEL_BITS];
/// SRS active flag
uint8_t srs_active;
/// Pointer to the payload
uint8_t *b;
/// Current Number of Symbols
......
......@@ -32,4 +32,9 @@ extern unsigned char cs_ack_normal_NB_IoT[4];
extern unsigned char cs_ack_extended_NB_IoT[4];
extern int8_t wACK_RX_NB_IoT[5][4];
extern short conjugate[8],conjugate2[8];
extern short *ul_ref_sigs_rx[30][2][33];
extern unsigned short dftsizes[33];
#endif
\ No newline at end of file
......@@ -224,5 +224,13 @@ void rx_ulsch_NB_IoT(PHY_VARS_eNB_NB_IoT *phy_vars_eNB,
NB_IoT_eNB_ULSCH_t **ulsch,
uint8_t cooperation_flag);
void ulsch_extract_rbs_single_NB_IoT(int32_t **rxdataF,
int32_t **rxdataF_ext,
uint32_t first_rb,
uint32_t nb_rb,
uint8_t l,
uint8_t Ns,
NB_IoT_DL_FRAME_PARMS *frame_parms);
#endif
/*
* 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.0 (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/LTE_TRANSPORT/ulsch_demodulation.c
* \brief Top-level routines for demodulating the PUSCH physical channel from 36.211 V8.6 2009-03
* \author R. Knopp
* \date 2011
* \version 0.1
* \company Eurecom
* \email: knopp@eurecom.fr, florian.kaltenberger@eurecom.fr, ankit.bhamri@eurecom.fr
* \note
* \warning
*/
#include "PHY/defs_NB_IoT.h"
#include "PHY/extern_NB_IoT.h"
#include "defs_NB_IoT.h"
#include "extern_NB_IoT.h"
//#define DEBUG_ULSCH
//#include "PHY/sse_intrin.h"
#include "PHY/LTE_ESTIMATION/defs_NB_IoT.h"
#include "T.h"
//extern char* namepointer_chMag ;
//eren
//extern int **ulchmag_eren;
//eren
static short jitter[8] __attribute__ ((aligned(16))) = {1,0,0,1,0,1,1,0};
static short jitterc[8] __attribute__ ((aligned(16))) = {0,1,1,0,1,0,0,1};
#ifndef OFDMA_ULSCH
void lte_idft_NB_IoT(NB_IoT_DL_FRAME_PARMS *frame_parms,uint32_t *z, uint16_t Msc_PUSCH)
{
#if defined(__x86_64__) || defined(__i386__)
__m128i idft_in128[3][1200],idft_out128[3][1200];
__m128i norm128;
#elif defined(__arm__)
int16x8_t idft_in128[3][1200],idft_out128[3][1200];
int16x8_t norm128;
#endif
int16_t *idft_in0=(int16_t*)idft_in128[0],*idft_out0=(int16_t*)idft_out128[0];
int16_t *idft_in1=(int16_t*)idft_in128[1],*idft_out1=(int16_t*)idft_out128[1];
int16_t *idft_in2=(int16_t*)idft_in128[2],*idft_out2=(int16_t*)idft_out128[2];
uint32_t *z0,*z1,*z2,*z3,*z4,*z5,*z6,*z7,*z8,*z9,*z10=NULL,*z11=NULL;
int i,ip;
// printf("Doing lte_idft for Msc_PUSCH %d\n",Msc_PUSCH);
if (frame_parms->Ncp == 0) { // Normal prefix
z0 = z;
z1 = z0+(frame_parms->N_RB_DL*12);
z2 = z1+(frame_parms->N_RB_DL*12);
//pilot
z3 = z2+(2*frame_parms->N_RB_DL*12);
z4 = z3+(frame_parms->N_RB_DL*12);
z5 = z4+(frame_parms->N_RB_DL*12);
z6 = z5+(frame_parms->N_RB_DL*12);
z7 = z6+(frame_parms->N_RB_DL*12);
z8 = z7+(frame_parms->N_RB_DL*12);
//pilot
z9 = z8+(2*frame_parms->N_RB_DL*12);
z10 = z9+(frame_parms->N_RB_DL*12);
// srs
z11 = z10+(frame_parms->N_RB_DL*12);
} else { // extended prefix
z0 = z;
z1 = z0+(frame_parms->N_RB_DL*12);
//pilot
z2 = z1+(2*frame_parms->N_RB_DL*12);
z3 = z2+(frame_parms->N_RB_DL*12);
z4 = z3+(frame_parms->N_RB_DL*12);
z5 = z4+(frame_parms->N_RB_DL*12);
z6 = z5+(frame_parms->N_RB_DL*12);
//pilot
z7 = z6+(2*frame_parms->N_RB_DL*12);
z8 = z7+(frame_parms->N_RB_DL*12);
// srs
z9 = z8+(frame_parms->N_RB_DL*12);
}
// conjugate input
for (i=0; i<(Msc_PUSCH>>2); i++) {
#if defined(__x86_64__)||defined(__i386__)
*&(((__m128i*)z0)[i])=_mm_sign_epi16(*&(((__m128i*)z0)[i]),*(__m128i*)&conjugate2[0]);
*&(((__m128i*)z1)[i])=_mm_sign_epi16(*&(((__m128i*)z1)[i]),*(__m128i*)&conjugate2[0]);
*&(((__m128i*)z2)[i])=_mm_sign_epi16(*&(((__m128i*)z2)[i]),*(__m128i*)&conjugate2[0]);
*&(((__m128i*)z3)[i])=_mm_sign_epi16(*&(((__m128i*)z3)[i]),*(__m128i*)&conjugate2[0]);
*&(((__m128i*)z4)[i])=_mm_sign_epi16(*&(((__m128i*)z4)[i]),*(__m128i*)&conjugate2[0]);
*&(((__m128i*)z5)[i])=_mm_sign_epi16(*&(((__m128i*)z5)[i]),*(__m128i*)&conjugate2[0]);
*&(((__m128i*)z6)[i])=_mm_sign_epi16(*&(((__m128i*)z6)[i]),*(__m128i*)&conjugate2[0]);
*&(((__m128i*)z7)[i])=_mm_sign_epi16(*&(((__m128i*)z7)[i]),*(__m128i*)&conjugate2[0]);
*&(((__m128i*)z8)[i])=_mm_sign_epi16(*&(((__m128i*)z8)[i]),*(__m128i*)&conjugate2[0]);
*&(((__m128i*)z9)[i])=_mm_sign_epi16(*&(((__m128i*)z9)[i]),*(__m128i*)&conjugate2[0]);
if (frame_parms->Ncp==NORMAL_NB_IoT) {
*&(((__m128i*)z10)[i])=_mm_sign_epi16(*&(((__m128i*)z10)[i]),*(__m128i*)&conjugate2[0]);
*&(((__m128i*)z11)[i])=_mm_sign_epi16(*&(((__m128i*)z11)[i]),*(__m128i*)&conjugate2[0]);
}
#elif defined(__arm__)
*&(((int16x8_t*)z0)[i])=vmulq_s16(*&(((int16x8_t*)z0)[i]),*(int16x8_t*)&conjugate2[0]);
*&(((int16x8_t*)z1)[i])=vmulq_s16(*&(((int16x8_t*)z1)[i]),*(int16x8_t*)&conjugate2[0]);
*&(((int16x8_t*)z2)[i])=vmulq_s16(*&(((int16x8_t*)z2)[i]),*(int16x8_t*)&conjugate2[0]);
*&(((int16x8_t*)z3)[i])=vmulq_s16(*&(((int16x8_t*)z3)[i]),*(int16x8_t*)&conjugate2[0]);
*&(((int16x8_t*)z4)[i])=vmulq_s16(*&(((int16x8_t*)z4)[i]),*(int16x8_t*)&conjugate2[0]);
*&(((int16x8_t*)z5)[i])=vmulq_s16(*&(((int16x8_t*)z5)[i]),*(int16x8_t*)&conjugate2[0]);
*&(((int16x8_t*)z6)[i])=vmulq_s16(*&(((int16x8_t*)z6)[i]),*(int16x8_t*)&conjugate2[0]);
*&(((int16x8_t*)z7)[i])=vmulq_s16(*&(((int16x8_t*)z7)[i]),*(int16x8_t*)&conjugate2[0]);
*&(((int16x8_t*)z8)[i])=vmulq_s16(*&(((int16x8_t*)z8)[i]),*(int16x8_t*)&conjugate2[0]);
*&(((int16x8_t*)z9)[i])=vmulq_s16(*&(((int16x8_t*)z9)[i]),*(int16x8_t*)&conjugate2[0]);
if (frame_parms->Ncp==NORMAL_NB_IoT) {
*&(((int16x8_t*)z10)[i])=vmulq_s16(*&(((int16x8_t*)z10)[i]),*(int16x8_t*)&conjugate2[0]);
*&(((int16x8_t*)z11)[i])=vmulq_s16(*&(((int16x8_t*)z11)[i]),*(int16x8_t*)&conjugate2[0]);
}
#endif
}
for (i=0,ip=0; i<Msc_PUSCH; i++,ip+=4) {
((uint32_t*)idft_in0)[ip+0] = z0[i];
((uint32_t*)idft_in0)[ip+1] = z1[i];
((uint32_t*)idft_in0)[ip+2] = z2[i];
((uint32_t*)idft_in0)[ip+3] = z3[i];
((uint32_t*)idft_in1)[ip+0] = z4[i];
((uint32_t*)idft_in1)[ip+1] = z5[i];
((uint32_t*)idft_in1)[ip+2] = z6[i];
((uint32_t*)idft_in1)[ip+3] = z7[i];
((uint32_t*)idft_in2)[ip+0] = z8[i];
((uint32_t*)idft_in2)[ip+1] = z9[i];
if (frame_parms->Ncp==0) {
((uint32_t*)idft_in2)[ip+2] = z10[i];
((uint32_t*)idft_in2)[ip+3] = z11[i];
}
}
switch (Msc_PUSCH) {
case 12:
dft12((int16_t *)idft_in0,(int16_t *)idft_out0);
dft12((int16_t *)idft_in1,(int16_t *)idft_out1);
dft12((int16_t *)idft_in2,(int16_t *)idft_out2);
#if defined(__x86_64__)||defined(__i386__)
norm128 = _mm_set1_epi16(9459);
#elif defined(__arm__)
norm128 = vdupq_n_s16(9459);
#endif
for (i=0; i<12; i++) {
#if defined(__x86_64__)||defined(__i386__)
((__m128i*)idft_out0)[i] = _mm_slli_epi16(_mm_mulhi_epi16(((__m128i*)idft_out0)[i],norm128),1);
((__m128i*)idft_out1)[i] = _mm_slli_epi16(_mm_mulhi_epi16(((__m128i*)idft_out1)[i],norm128),1);
((__m128i*)idft_out2)[i] = _mm_slli_epi16(_mm_mulhi_epi16(((__m128i*)idft_out2)[i],norm128),1);
#elif defined(__arm__)
((int16x8_t*)idft_out0)[i] = vqdmulhq_s16(((int16x8_t*)idft_out0)[i],norm128);
((int16x8_t*)idft_out1)[i] = vqdmulhq_s16(((int16x8_t*)idft_out1)[i],norm128);
((int16x8_t*)idft_out2)[i] = vqdmulhq_s16(((int16x8_t*)idft_out2)[i],norm128);
#endif
}
break;
case 24:
dft24(idft_in0,idft_out0,1);
dft24(idft_in1,idft_out1,1);
dft24(idft_in2,idft_out2,1);
break;
case 36:
dft36(idft_in0,idft_out0,1);
dft36(idft_in1,idft_out1,1);
dft36(idft_in2,idft_out2,1);
break;
case 48:
dft48(idft_in0,idft_out0,1);
dft48(idft_in1,idft_out1,1);
dft48(idft_in2,idft_out2,1);
break;
case 60:
dft60(idft_in0,idft_out0,1);
dft60(idft_in1,idft_out1,1);
dft60(idft_in2,idft_out2,1);
break;
case 72:
dft72(idft_in0,idft_out0,1);
dft72(idft_in1,idft_out1,1);
dft72(idft_in2,idft_out2,1);
break;
case 96:
dft96(idft_in0,idft_out0,1);
dft96(idft_in1,idft_out1,1);
dft96(idft_in2,idft_out2,1);
break;
case 108:
dft108(idft_in0,idft_out0,1);
dft108(idft_in1,idft_out1,1);
dft108(idft_in2,idft_out2,1);
break;
case 120:
dft120(idft_in0,idft_out0,1);
dft120(idft_in1,idft_out1,1);
dft120(idft_in2,idft_out2,1);
break;
case 144:
dft144(idft_in0,idft_out0,1);
dft144(idft_in1,idft_out1,1);
dft144(idft_in2,idft_out2,1);
break;
case 180:
dft180(idft_in0,idft_out0,1);
dft180(idft_in1,idft_out1,1);
dft180(idft_in2,idft_out2,1);
break;
case 192:
dft192(idft_in0,idft_out0,1);
dft192(idft_in1,idft_out1,1);
dft192(idft_in2,idft_out2,1);
break;
case 216:
dft216(idft_in0,idft_out0,1);
dft216(idft_in1,idft_out1,1);
dft216(idft_in2,idft_out2,1);
break;
case 240:
dft240(idft_in0,idft_out0,1);
dft240(idft_in1,idft_out1,1);
dft240(idft_in2,idft_out2,1);
break;
case 288:
dft288(idft_in0,idft_out0,1);
dft288(idft_in1,idft_out1,1);
dft288(idft_in2,idft_out2,1);
break;
case 300:
dft300(idft_in0,idft_out0,1);
dft300(idft_in1,idft_out1,1);
dft300(idft_in2,idft_out2,1);
break;
case 324:
dft324((int16_t*)idft_in0,(int16_t*)idft_out0,1);
dft324((int16_t*)idft_in1,(int16_t*)idft_out1,1);
dft324((int16_t*)idft_in2,(int16_t*)idft_out2,1);
break;
case 360:
dft360((int16_t*)idft_in0,(int16_t*)idft_out0,1);
dft360((int16_t*)idft_in1,(int16_t*)idft_out1,1);
dft360((int16_t*)idft_in2,(int16_t*)idft_out2,1);
break;
case 384:
dft384((int16_t*)idft_in0,(int16_t*)idft_out0,1);
dft384((int16_t*)idft_in1,(int16_t*)idft_out1,1);
dft384((int16_t*)idft_in2,(int16_t*)idft_out2,1);
break;
case 432:
dft432((int16_t*)idft_in0,(int16_t*)idft_out0,1);
dft432((int16_t*)idft_in1,(int16_t*)idft_out1,1);
dft432((int16_t*)idft_in2,(int16_t*)idft_out2,1);
break;
case 480:
dft480((int16_t*)idft_in0,(int16_t*)idft_out0,1);
dft480((int16_t*)idft_in1,(int16_t*)idft_out1,1);
dft480((int16_t*)idft_in2,(int16_t*)idft_out2,1);
break;
case 540:
dft540((int16_t*)idft_in0,(int16_t*)idft_out0,1);
dft540((int16_t*)idft_in1,(int16_t*)idft_out1,1);
dft540((int16_t*)idft_in2,(int16_t*)idft_out2,1);
break;
case 576:
dft576((int16_t*)idft_in0,(int16_t*)idft_out0,1);
dft576((int16_t*)idft_in1,(int16_t*)idft_out1,1);
dft576((int16_t*)idft_in2,(int16_t*)idft_out2,1);
break;
case 600:
dft600((int16_t*)idft_in0,(int16_t*)idft_out0,1);
dft600((int16_t*)idft_in1,(int16_t*)idft_out1,1);
dft600((int16_t*)idft_in2,(int16_t*)idft_out2,1);
break;
case 648:
dft648((int16_t*)idft_in0,(int16_t*)idft_out0,1);
dft648((int16_t*)idft_in1,(int16_t*)idft_out1,1);
dft648((int16_t*)idft_in2,(int16_t*)idft_out2,1);
break;
case 720:
dft720((int16_t*)idft_in0,(int16_t*)idft_out0,1);
dft720((int16_t*)idft_in1,(int16_t*)idft_out1,1);
dft720((int16_t*)idft_in2,(int16_t*)idft_out2,1);
break;
case 864:
dft864((int16_t*)idft_in0,(int16_t*)idft_out0,1);
dft864((int16_t*)idft_in1,(int16_t*)idft_out1,1);
dft864((int16_t*)idft_in2,(int16_t*)idft_out2,1);
break;
case 900:
dft900((int16_t*)idft_in0,(int16_t*)idft_out0,1);
dft900((int16_t*)idft_in1,(int16_t*)idft_out1,1);
dft900((int16_t*)idft_in2,(int16_t*)idft_out2,1);
break;
case 960:
dft960((int16_t*)idft_in0,(int16_t*)idft_out0,1);
dft960((int16_t*)idft_in1,(int16_t*)idft_out1,1);
dft960((int16_t*)idft_in2,(int16_t*)idft_out2,1);
break;
case 972:
dft972((int16_t*)idft_in0,(int16_t*)idft_out0,1);
dft972((int16_t*)idft_in1,(int16_t*)idft_out1,1);
dft972((int16_t*)idft_in2,(int16_t*)idft_out2,1);
break;
case 1080:
dft1080((int16_t*)idft_in0,(int16_t*)idft_out0,1);
dft1080((int16_t*)idft_in1,(int16_t*)idft_out1,1);
dft1080((int16_t*)idft_in2,(int16_t*)idft_out2,1);
break;
case 1152:
dft1152((int16_t*)idft_in0,(int16_t*)idft_out0,1);
dft1152((int16_t*)idft_in1,(int16_t*)idft_out1,1);
dft1152((int16_t*)idft_in2,(int16_t*)idft_out2,1);
break;
case 1200:
dft1200(idft_in0,idft_out0,1);
dft1200(idft_in1,idft_out1,1);
dft1200(idft_in2,idft_out2,1);
break;
default:
// should not be reached
LOG_E( PHY, "Unsupported Msc_PUSCH value of %"PRIu16"\n", Msc_PUSCH );
return;
}
for (i=0,ip=0; i<Msc_PUSCH; i++,ip+=4) {
z0[i] = ((uint32_t*)idft_out0)[ip];
/*
printf("out0 (%d,%d),(%d,%d),(%d,%d),(%d,%d)\n",
((int16_t*)&idft_out0[ip])[0],((int16_t*)&idft_out0[ip])[1],
((int16_t*)&idft_out0[ip+1])[0],((int16_t*)&idft_out0[ip+1])[1],
((int16_t*)&idft_out0[ip+2])[0],((int16_t*)&idft_out0[ip+2])[1],
((int16_t*)&idft_out0[ip+3])[0],((int16_t*)&idft_out0[ip+3])[1]);
*/
z1[i] = ((uint32_t*)idft_out0)[ip+1];
z2[i] = ((uint32_t*)idft_out0)[ip+2];
z3[i] = ((uint32_t*)idft_out0)[ip+3];
z4[i] = ((uint32_t*)idft_out1)[ip+0];
z5[i] = ((uint32_t*)idft_out1)[ip+1];
z6[i] = ((uint32_t*)idft_out1)[ip+2];
z7[i] = ((uint32_t*)idft_out1)[ip+3];
z8[i] = ((uint32_t*)idft_out2)[ip];
z9[i] = ((uint32_t*)idft_out2)[ip+1];
if (frame_parms->Ncp==0) {
z10[i] = ((uint32_t*)idft_out2)[ip+2];
z11[i] = ((uint32_t*)idft_out2)[ip+3];
}
}
// conjugate output
for (i=0; i<(Msc_PUSCH>>2); i++) {
#if defined(__x86_64__) || defined(__i386__)
((__m128i*)z0)[i]=_mm_sign_epi16(((__m128i*)z0)[i],*(__m128i*)&conjugate2[0]);
((__m128i*)z1)[i]=_mm_sign_epi16(((__m128i*)z1)[i],*(__m128i*)&conjugate2[0]);
((__m128i*)z2)[i]=_mm_sign_epi16(((__m128i*)z2)[i],*(__m128i*)&conjugate2[0]);
((__m128i*)z3)[i]=_mm_sign_epi16(((__m128i*)z3)[i],*(__m128i*)&conjugate2[0]);
((__m128i*)z4)[i]=_mm_sign_epi16(((__m128i*)z4)[i],*(__m128i*)&conjugate2[0]);
((__m128i*)z5)[i]=_mm_sign_epi16(((__m128i*)z5)[i],*(__m128i*)&conjugate2[0]);
((__m128i*)z6)[i]=_mm_sign_epi16(((__m128i*)z6)[i],*(__m128i*)&conjugate2[0]);
((__m128i*)z7)[i]=_mm_sign_epi16(((__m128i*)z7)[i],*(__m128i*)&conjugate2[0]);
((__m128i*)z8)[i]=_mm_sign_epi16(((__m128i*)z8)[i],*(__m128i*)&conjugate2[0]);
((__m128i*)z9)[i]=_mm_sign_epi16(((__m128i*)z9)[i],*(__m128i*)&conjugate2[0]);
if (frame_parms->Ncp==NORMAL_NB_IoT) {
((__m128i*)z10)[i]=_mm_sign_epi16(((__m128i*)z10)[i],*(__m128i*)&conjugate2[0]);
((__m128i*)z11)[i]=_mm_sign_epi16(((__m128i*)z11)[i],*(__m128i*)&conjugate2[0]);
}
#elif defined(__arm__)
*&(((int16x8_t*)z0)[i])=vmulq_s16(*&(((int16x8_t*)z0)[i]),*(int16x8_t*)&conjugate2[0]);
*&(((int16x8_t*)z1)[i])=vmulq_s16(*&(((int16x8_t*)z1)[i]),*(int16x8_t*)&conjugate2[0]);
*&(((int16x8_t*)z2)[i])=vmulq_s16(*&(((int16x8_t*)z2)[i]),*(int16x8_t*)&conjugate2[0]);
*&(((int16x8_t*)z3)[i])=vmulq_s16(*&(((int16x8_t*)z3)[i]),*(int16x8_t*)&conjugate2[0]);
*&(((int16x8_t*)z4)[i])=vmulq_s16(*&(((int16x8_t*)z4)[i]),*(int16x8_t*)&conjugate2[0]);
*&(((int16x8_t*)z5)[i])=vmulq_s16(*&(((int16x8_t*)z5)[i]),*(int16x8_t*)&conjugate2[0]);
*&(((int16x8_t*)z6)[i])=vmulq_s16(*&(((int16x8_t*)z6)[i]),*(int16x8_t*)&conjugate2[0]);
*&(((int16x8_t*)z7)[i])=vmulq_s16(*&(((int16x8_t*)z7)[i]),*(int16x8_t*)&conjugate2[0]);
*&(((int16x8_t*)z8)[i])=vmulq_s16(*&(((int16x8_t*)z8)[i]),*(int16x8_t*)&conjugate2[0]);
*&(((int16x8_t*)z9)[i])=vmulq_s16(*&(((int16x8_t*)z9)[i]),*(int16x8_t*)&conjugate2[0]);
if (frame_parms->Ncp==NORMAL_NB_IoT) {
*&(((int16x8_t*)z10)[i])=vmulq_s16(*&(((int16x8_t*)z10)[i]),*(int16x8_t*)&conjugate2[0]);
*&(((int16x8_t*)z11)[i])=vmulq_s16(*&(((int16x8_t*)z11)[i]),*(int16x8_t*)&conjugate2[0]);
}
#endif
}
#if defined(__x86_64__) || defined(__i386__)
_mm_empty();
_m_empty();
#endif
}
#endif
int32_t ulsch_qpsk_llr_NB_IoT(NB_IoT_DL_FRAME_PARMS *frame_parms,
int32_t **rxdataF_comp,
int16_t *ulsch_llr,
uint8_t symbol,
uint16_t nb_rb,
int16_t **llrp)
{
#if defined(__x86_64__) || defined(__i386__)
__m128i *rxF=(__m128i*)&rxdataF_comp[0][(symbol*frame_parms->N_RB_DL*12)];
__m128i **llrp128 = (__m128i **)llrp;
#elif defined(__arm__)
int16x8_t *rxF= (int16x8_t*)&rxdataF_comp[0][(symbol*frame_parms->N_RB_DL*12)];
int16x8_t **llrp128 = (int16x8_t **)llrp;
#endif
int i;
// printf("qpsk llr for symbol %d (pos %d), llr offset %d\n",symbol,(symbol*frame_parms->N_RB_DL*12),llr128U-(__m128i*)ulsch_llr);
for (i=0; i<(nb_rb*3); i++) {
//printf("%d,%d,%d,%d,%d,%d,%d,%d\n",((int16_t *)rxF)[0],((int16_t *)rxF)[1],((int16_t *)rxF)[2],((int16_t *)rxF)[3],((int16_t *)rxF)[4],((int16_t *)rxF)[5],((int16_t *)rxF)[6],((int16_t *)rxF)[7]);
*(*llrp128) = *rxF;
rxF++;
(*llrp128)++;
}
#if defined(__x86_64__) || defined(__i386__)
_mm_empty();
_m_empty();
#endif
return(0);
}
void ulsch_detection_mrc_NB_IoT(NB_IoT_DL_FRAME_PARMS *frame_parms,
int32_t **rxdataF_comp,
int32_t **ul_ch_mag,
int32_t **ul_ch_magb,
uint8_t symbol,
uint16_t nb_rb)
{
#if defined(__x86_64__) || defined(__i386__)
__m128i *rxdataF_comp128_0,*ul_ch_mag128_0,*ul_ch_mag128_0b;
__m128i *rxdataF_comp128_1,*ul_ch_mag128_1,*ul_ch_mag128_1b;
#elif defined(__arm__)
int16x8_t *rxdataF_comp128_0,*ul_ch_mag128_0,*ul_ch_mag128_0b;
int16x8_t *rxdataF_comp128_1,*ul_ch_mag128_1,*ul_ch_mag128_1b;
#endif
int32_t i;
if (frame_parms->nb_antennas_rx>1) {
#if defined(__x86_64__) || defined(__i386__)
rxdataF_comp128_0 = (__m128i *)&rxdataF_comp[0][symbol*frame_parms->N_RB_DL*12];
rxdataF_comp128_1 = (__m128i *)&rxdataF_comp[1][symbol*frame_parms->N_RB_DL*12];
ul_ch_mag128_0 = (__m128i *)&ul_ch_mag[0][symbol*frame_parms->N_RB_DL*12];
ul_ch_mag128_1 = (__m128i *)&ul_ch_mag[1][symbol*frame_parms->N_RB_DL*12];
ul_ch_mag128_0b = (__m128i *)&ul_ch_magb[0][symbol*frame_parms->N_RB_DL*12];
ul_ch_mag128_1b = (__m128i *)&ul_ch_magb[1][symbol*frame_parms->N_RB_DL*12];
// MRC on each re of rb, both on MF output and magnitude (for 16QAM/64QAM llr computation)
for (i=0; i<nb_rb*3; i++) {
rxdataF_comp128_0[i] = _mm_adds_epi16(_mm_srai_epi16(rxdataF_comp128_0[i],1),_mm_srai_epi16(rxdataF_comp128_1[i],1));
ul_ch_mag128_0[i] = _mm_adds_epi16(_mm_srai_epi16(ul_ch_mag128_0[i],1),_mm_srai_epi16(ul_ch_mag128_1[i],1));
ul_ch_mag128_0b[i] = _mm_adds_epi16(_mm_srai_epi16(ul_ch_mag128_0b[i],1),_mm_srai_epi16(ul_ch_mag128_1b[i],1));
rxdataF_comp128_0[i] = _mm_add_epi16(rxdataF_comp128_0[i],(*(__m128i*)&jitterc[0]));
#elif defined(__arm__)
rxdataF_comp128_0 = (int16x8_t *)&rxdataF_comp[0][symbol*frame_parms->N_RB_DL*12];
rxdataF_comp128_1 = (int16x8_t *)&rxdataF_comp[1][symbol*frame_parms->N_RB_DL*12];
ul_ch_mag128_0 = (int16x8_t *)&ul_ch_mag[0][symbol*frame_parms->N_RB_DL*12];
ul_ch_mag128_1 = (int16x8_t *)&ul_ch_mag[1][symbol*frame_parms->N_RB_DL*12];
ul_ch_mag128_0b = (int16x8_t *)&ul_ch_magb[0][symbol*frame_parms->N_RB_DL*12];
ul_ch_mag128_1b = (int16x8_t *)&ul_ch_magb[1][symbol*frame_parms->N_RB_DL*12];
// MRC on each re of rb, both on MF output and magnitude (for 16QAM/64QAM llr computation)
for (i=0; i<nb_rb*3; i++) {
rxdataF_comp128_0[i] = vhaddq_s16(rxdataF_comp128_0[i],rxdataF_comp128_1[i]);
ul_ch_mag128_0[i] = vhaddq_s16(ul_ch_mag128_0[i],ul_ch_mag128_1[i]);
ul_ch_mag128_0b[i] = vhaddq_s16(ul_ch_mag128_0b[i],ul_ch_mag128_1b[i]);
rxdataF_comp128_0[i] = vqaddq_s16(rxdataF_comp128_0[i],(*(int16x8_t*)&jitterc[0]));
#endif
}
}
#if defined(__x86_64__) || defined(__i386__)
_mm_empty();
_m_empty();
#endif
}
void ulsch_extract_rbs_single_NB_IoT(int32_t **rxdataF,
int32_t **rxdataF_ext,
uint32_t first_rb,
uint32_t nb_rb,
uint8_t l,
uint8_t Ns,
NB_IoT_DL_FRAME_PARMS *frame_parms)
{
uint16_t nb_rb1,nb_rb2;
uint8_t aarx;
int32_t *rxF,*rxF_ext;
//uint8_t symbol = l+Ns*frame_parms->symbols_per_tti/2;
uint8_t symbol = l+((7-frame_parms->Ncp)*(Ns&1)); ///symbol within sub-frame
for (aarx=0; aarx<frame_parms->nb_antennas_rx; aarx++) {
nb_rb1 = cmin(cmax((int)(frame_parms->N_RB_UL) - (int)(2*first_rb),(int)0),(int)(2*nb_rb)); // 2 times no. RBs before the DC
nb_rb2 = 2*nb_rb - nb_rb1; // 2 times no. RBs after the DC
rxF_ext = &rxdataF_ext[aarx][(symbol*frame_parms->N_RB_UL*12)];
if (nb_rb1) {
rxF = &rxdataF[aarx][(first_rb*12 + frame_parms->first_carrier_offset + symbol*frame_parms->ofdm_symbol_size)];
memcpy(rxF_ext, rxF, nb_rb1*6*sizeof(int));
rxF_ext += nb_rb1*6;
if (nb_rb2) {
//#ifdef OFDMA_ULSCH
// rxF = &rxdataF[aarx][(1 + symbol*frame_parms->ofdm_symbol_size)*2];
//#else
rxF = &rxdataF[aarx][(symbol*frame_parms->ofdm_symbol_size)];
//#endif
memcpy(rxF_ext, rxF, nb_rb2*6*sizeof(int));
rxF_ext += nb_rb2*6;
}
} else { //there is only data in the second half
//#ifdef OFDMA_ULSCH
// rxF = &rxdataF[aarx][(1 + 6*(2*first_rb - frame_parms->N_RB_UL) + symbol*frame_parms->ofdm_symbol_size)*2];
//#else
rxF = &rxdataF[aarx][(6*(2*first_rb - frame_parms->N_RB_UL) + symbol*frame_parms->ofdm_symbol_size)];
//#endif
memcpy(rxF_ext, rxF, nb_rb2*6*sizeof(int));
rxF_ext += nb_rb2*6;
}
}
}
void ulsch_channel_compensation_NB_IoT(int32_t **rxdataF_ext,
int32_t **ul_ch_estimates_ext,
int32_t **ul_ch_mag,
int32_t **ul_ch_magb,
int32_t **rxdataF_comp,
NB_IoT_DL_FRAME_PARMS *frame_parms,
uint8_t symbol,
uint8_t Qm,
uint16_t nb_rb,
uint8_t output_shift)
{
uint16_t rb;
#if defined(__x86_64__) || defined(__i386__)
__m128i *ul_ch128,*ul_ch_mag128,*ul_ch_mag128b,*rxdataF128,*rxdataF_comp128;
uint8_t aarx;//,symbol_mod;
__m128i mmtmpU0,mmtmpU1,mmtmpU2,mmtmpU3;
#ifdef OFDMA_ULSCH
__m128i QAM_amp128U,QAM_amp128bU;
#endif
#elif defined(__arm__)
int16x4_t *ul_ch128,*rxdataF128;
int16x8_t *ul_ch_mag128,*ul_ch_mag128b,*rxdataF_comp128;
uint8_t aarx;//,symbol_mod;
int32x4_t mmtmpU0,mmtmpU1,mmtmpU0b,mmtmpU1b;
#ifdef OFDMA_ULSCH
int16x8_t mmtmpU2,mmtmpU3;
int16x8_t QAM_amp128U,QAM_amp128bU;
#endif
int16_t conj[4]__attribute__((aligned(16))) = {1,-1,1,-1};
int32x4_t output_shift128 = vmovq_n_s32(-(int32_t)output_shift);
#endif
#ifdef OFDMA_ULSCH
#if defined(__x86_64__) || defined(__i386__)
if (Qm == 4)
QAM_amp128U = _mm_set1_epi16(QAM16_n1);
else if (Qm == 6) {
QAM_amp128U = _mm_set1_epi16(QAM64_n1);
QAM_amp128bU = _mm_set1_epi16(QAM64_n2);
}
#elif defined(__arm__)
if (Qm == 4)
QAM_amp128U = vdupq_n_s16(QAM16_n1);
else if (Qm == 6) {
QAM_amp128U = vdupq_n_s16(QAM64_n1);
QAM_amp128bU = vdupq_n_s16(QAM64_n2);
}
#endif
#endif
for (aarx=0; aarx<frame_parms->nb_antennas_rx; aarx++) {
#if defined(__x86_64__) || defined(__i386__)
ul_ch128 = (__m128i *)&ul_ch_estimates_ext[aarx][symbol*frame_parms->N_RB_DL*12];
ul_ch_mag128 = (__m128i *)&ul_ch_mag[aarx][symbol*frame_parms->N_RB_DL*12];
ul_ch_mag128b = (__m128i *)&ul_ch_magb[aarx][symbol*frame_parms->N_RB_DL*12];
rxdataF128 = (__m128i *)&rxdataF_ext[aarx][symbol*frame_parms->N_RB_DL*12];
rxdataF_comp128 = (__m128i *)&rxdataF_comp[aarx][symbol*frame_parms->N_RB_DL*12];
#elif defined(__arm__)
ul_ch128 = (int16x4_t *)&ul_ch_estimates_ext[aarx][symbol*frame_parms->N_RB_DL*12];
ul_ch_mag128 = (int16x8_t *)&ul_ch_mag[aarx][symbol*frame_parms->N_RB_DL*12];
ul_ch_mag128b = (int16x8_t *)&ul_ch_magb[aarx][symbol*frame_parms->N_RB_DL*12];
rxdataF128 = (int16x4_t *)&rxdataF_ext[aarx][symbol*frame_parms->N_RB_DL*12];
rxdataF_comp128 = (int16x8_t *)&rxdataF_comp[aarx][symbol*frame_parms->N_RB_DL*12];
#endif
for (rb=0; rb<nb_rb; rb++) {
// printf("comp: symbol %d rb %d\n",symbol,rb);
#ifdef OFDMA_ULSCH
if (Qm>2) {
// get channel amplitude if not QPSK
#if defined(__x86_64__) || defined(__i386__)
mmtmpU0 = _mm_madd_epi16(ul_ch128[0],ul_ch128[0]);
mmtmpU0 = _mm_srai_epi32(mmtmpU0,output_shift);
mmtmpU1 = _mm_madd_epi16(ul_ch128[1],ul_ch128[1]);
mmtmpU1 = _mm_srai_epi32(mmtmpU1,output_shift);
mmtmpU0 = _mm_packs_epi32(mmtmpU0,mmtmpU1);
ul_ch_mag128[0] = _mm_unpacklo_epi16(mmtmpU0,mmtmpU0);
ul_ch_mag128b[0] = ul_ch_mag128[0];
ul_ch_mag128[0] = _mm_mulhi_epi16(ul_ch_mag128[0],QAM_amp128U);
ul_ch_mag128[0] = _mm_slli_epi16(ul_ch_mag128[0],2); // 2 to compensate the scale channel estimate
ul_ch_mag128[1] = _mm_unpackhi_epi16(mmtmpU0,mmtmpU0);
ul_ch_mag128b[1] = ul_ch_mag128[1];
ul_ch_mag128[1] = _mm_mulhi_epi16(ul_ch_mag128[1],QAM_amp128U);
ul_ch_mag128[1] = _mm_slli_epi16(ul_ch_mag128[1],2); // 2 to compensate the scale channel estimate
mmtmpU0 = _mm_madd_epi16(ul_ch128[2],ul_ch128[2]);
mmtmpU0 = _mm_srai_epi32(mmtmpU0,output_shift);
mmtmpU1 = _mm_packs_epi32(mmtmpU0,mmtmpU0);
ul_ch_mag128[2] = _mm_unpacklo_epi16(mmtmpU1,mmtmpU1);
ul_ch_mag128b[2] = ul_ch_mag128[2];
ul_ch_mag128[2] = _mm_mulhi_epi16(ul_ch_mag128[2],QAM_amp128U);
ul_ch_mag128[2] = _mm_slli_epi16(ul_ch_mag128[2],2); // 2 to compensate the scale channel estimate
ul_ch_mag128b[0] = _mm_mulhi_epi16(ul_ch_mag128b[0],QAM_amp128bU);
ul_ch_mag128b[0] = _mm_slli_epi16(ul_ch_mag128b[0],2); // 2 to compensate the scale channel estimate
ul_ch_mag128b[1] = _mm_mulhi_epi16(ul_ch_mag128b[1],QAM_amp128bU);
ul_ch_mag128b[1] = _mm_slli_epi16(ul_ch_mag128b[1],2); // 2 to compensate the scale channel estimate
ul_ch_mag128b[2] = _mm_mulhi_epi16(ul_ch_mag128b[2],QAM_amp128bU);
ul_ch_mag128b[2] = _mm_slli_epi16(ul_ch_mag128b[2],2);// 2 to compensate the scale channel estimate
#elif defined(__arm__)
mmtmpU0 = vmull_s16(ul_ch128[0], ul_ch128[0]);
mmtmpU0 = vqshlq_s32(vqaddq_s32(mmtmpU0,vrev64q_s32(mmtmpU0)),-output_shift128);
mmtmpU1 = vmull_s16(ul_ch128[1], ul_ch128[1]);
mmtmpU1 = vqshlq_s32(vqaddq_s32(mmtmpU1,vrev64q_s32(mmtmpU1)),-output_shift128);
mmtmpU2 = vcombine_s16(vmovn_s32(mmtmpU0),vmovn_s32(mmtmpU1));
mmtmpU0 = vmull_s16(ul_ch128[2], ul_ch128[2]);
mmtmpU0 = vqshlq_s32(vqaddq_s32(mmtmpU0,vrev64q_s32(mmtmpU0)),-output_shift128);
mmtmpU1 = vmull_s16(ul_ch128[3], ul_ch128[3]);
mmtmpU1 = vqshlq_s32(vqaddq_s32(mmtmpU1,vrev64q_s32(mmtmpU1)),-output_shift128);
mmtmpU3 = vcombine_s16(vmovn_s32(mmtmpU0),vmovn_s32(mmtmpU1));
mmtmpU0 = vmull_s16(ul_ch128[4], ul_ch128[4]);
mmtmpU0 = vqshlq_s32(vqaddq_s32(mmtmpU0,vrev64q_s32(mmtmpU0)),-output_shift128);
mmtmpU1 = vmull_s16(ul_ch128[5], ul_ch128[5]);
mmtmpU1 = vqshlq_s32(vqaddq_s32(mmtmpU1,vrev64q_s32(mmtmpU1)),-output_shift128);
mmtmpU4 = vcombine_s16(vmovn_s32(mmtmpU0),vmovn_s32(mmtmpU1));
ul_ch_mag128b[0] = vqdmulhq_s16(mmtmpU2,QAM_amp128b);
ul_ch_mag128b[1] = vqdmulhq_s16(mmtmpU3,QAM_amp128b);
ul_ch_mag128[0] = vqdmulhq_s16(mmtmpU2,QAM_amp128);
ul_ch_mag128[1] = vqdmulhq_s16(mmtmpU3,QAM_amp128);
ul_ch_mag128b[2] = vqdmulhq_s16(mmtmpU4,QAM_amp128b);
ul_ch_mag128[2] = vqdmulhq_s16(mmtmpU4,QAM_amp128);
#endif
}
#else // SC-FDMA
// just compute channel magnitude without scaling, this is done after equalization for SC-FDMA
#if defined(__x86_64__) || defined(__i386__)
mmtmpU0 = _mm_madd_epi16(ul_ch128[0],ul_ch128[0]);
mmtmpU0 = _mm_srai_epi32(mmtmpU0,output_shift);
mmtmpU1 = _mm_madd_epi16(ul_ch128[1],ul_ch128[1]);
mmtmpU1 = _mm_srai_epi32(mmtmpU1,output_shift);
mmtmpU0 = _mm_packs_epi32(mmtmpU0,mmtmpU1);
ul_ch_mag128[0] = _mm_unpacklo_epi16(mmtmpU0,mmtmpU0);
ul_ch_mag128[1] = _mm_unpackhi_epi16(mmtmpU0,mmtmpU0);
mmtmpU0 = _mm_madd_epi16(ul_ch128[2],ul_ch128[2]);
mmtmpU0 = _mm_srai_epi32(mmtmpU0,output_shift);
mmtmpU1 = _mm_packs_epi32(mmtmpU0,mmtmpU0);
ul_ch_mag128[2] = _mm_unpacklo_epi16(mmtmpU1,mmtmpU1);
// printf("comp: symbol %d rb %d => %d,%d,%d (output_shift %d)\n",symbol,rb,*((int16_t*)&ul_ch_mag128[0]),*((int16_t*)&ul_ch_mag128[1]),*((int16_t*)&ul_ch_mag128[2]),output_shift);
#elif defined(__arm__)
mmtmpU0 = vmull_s16(ul_ch128[0], ul_ch128[0]);
mmtmpU0 = vqshlq_s32(vqaddq_s32(mmtmpU0,vrev64q_s32(mmtmpU0)),-output_shift128);
mmtmpU1 = vmull_s16(ul_ch128[1], ul_ch128[1]);
mmtmpU1 = vqshlq_s32(vqaddq_s32(mmtmpU1,vrev64q_s32(mmtmpU1)),-output_shift128);
ul_ch_mag128[0] = vcombine_s16(vmovn_s32(mmtmpU0),vmovn_s32(mmtmpU1));
mmtmpU0 = vmull_s16(ul_ch128[2], ul_ch128[2]);
mmtmpU0 = vqshlq_s32(vqaddq_s32(mmtmpU0,vrev64q_s32(mmtmpU0)),-output_shift128);
mmtmpU1 = vmull_s16(ul_ch128[3], ul_ch128[3]);
mmtmpU1 = vqshlq_s32(vqaddq_s32(mmtmpU1,vrev64q_s32(mmtmpU1)),-output_shift128);
ul_ch_mag128[1] = vcombine_s16(vmovn_s32(mmtmpU0),vmovn_s32(mmtmpU1));
mmtmpU0 = vmull_s16(ul_ch128[4], ul_ch128[4]);
mmtmpU0 = vqshlq_s32(vqaddq_s32(mmtmpU0,vrev64q_s32(mmtmpU0)),-output_shift128);
mmtmpU1 = vmull_s16(ul_ch128[5], ul_ch128[5]);
mmtmpU1 = vqshlq_s32(vqaddq_s32(mmtmpU1,vrev64q_s32(mmtmpU1)),-output_shift128);
ul_ch_mag128[2] = vcombine_s16(vmovn_s32(mmtmpU0),vmovn_s32(mmtmpU1));
#endif
#endif
#if defined(__x86_64__) || defined(__i386__)
// multiply by conjugated channel
mmtmpU0 = _mm_madd_epi16(ul_ch128[0],rxdataF128[0]);
// print_ints("re",&mmtmpU0);
// mmtmpU0 contains real part of 4 consecutive outputs (32-bit)
mmtmpU1 = _mm_shufflelo_epi16(ul_ch128[0],_MM_SHUFFLE(2,3,0,1));
mmtmpU1 = _mm_shufflehi_epi16(mmtmpU1,_MM_SHUFFLE(2,3,0,1));
mmtmpU1 = _mm_sign_epi16(mmtmpU1,*(__m128i*)&conjugate[0]);
mmtmpU1 = _mm_madd_epi16(mmtmpU1,rxdataF128[0]);
// print_ints("im",&mmtmpU1);
// mmtmpU1 contains imag part of 4 consecutive outputs (32-bit)
mmtmpU0 = _mm_srai_epi32(mmtmpU0,output_shift);
// print_ints("re(shift)",&mmtmpU0);
mmtmpU1 = _mm_srai_epi32(mmtmpU1,output_shift);
// print_ints("im(shift)",&mmtmpU1);
mmtmpU2 = _mm_unpacklo_epi32(mmtmpU0,mmtmpU1);
mmtmpU3 = _mm_unpackhi_epi32(mmtmpU0,mmtmpU1);
// print_ints("c0",&mmtmpU2);
// print_ints("c1",&mmtmpU3);
rxdataF_comp128[0] = _mm_packs_epi32(mmtmpU2,mmtmpU3);
/*
print_shorts("rx:",&rxdataF128[0]);
print_shorts("ch:",&ul_ch128[0]);
print_shorts("pack:",&rxdataF_comp128[0]);
*/
// multiply by conjugated channel
mmtmpU0 = _mm_madd_epi16(ul_ch128[1],rxdataF128[1]);
// mmtmpU0 contains real part of 4 consecutive outputs (32-bit)
mmtmpU1 = _mm_shufflelo_epi16(ul_ch128[1],_MM_SHUFFLE(2,3,0,1));
mmtmpU1 = _mm_shufflehi_epi16(mmtmpU1,_MM_SHUFFLE(2,3,0,1));
mmtmpU1 = _mm_sign_epi16(mmtmpU1,*(__m128i*)conjugate);
mmtmpU1 = _mm_madd_epi16(mmtmpU1,rxdataF128[1]);
// mmtmpU1 contains imag part of 4 consecutive outputs (32-bit)
mmtmpU0 = _mm_srai_epi32(mmtmpU0,output_shift);
mmtmpU1 = _mm_srai_epi32(mmtmpU1,output_shift);
mmtmpU2 = _mm_unpacklo_epi32(mmtmpU0,mmtmpU1);
mmtmpU3 = _mm_unpackhi_epi32(mmtmpU0,mmtmpU1);
rxdataF_comp128[1] = _mm_packs_epi32(mmtmpU2,mmtmpU3);
// print_shorts("rx:",rxdataF128[1]);
// print_shorts("ch:",ul_ch128[1]);
// print_shorts("pack:",rxdataF_comp128[1]);
// multiply by conjugated channel
mmtmpU0 = _mm_madd_epi16(ul_ch128[2],rxdataF128[2]);
// mmtmpU0 contains real part of 4 consecutive outputs (32-bit)
mmtmpU1 = _mm_shufflelo_epi16(ul_ch128[2],_MM_SHUFFLE(2,3,0,1));
mmtmpU1 = _mm_shufflehi_epi16(mmtmpU1,_MM_SHUFFLE(2,3,0,1));
mmtmpU1 = _mm_sign_epi16(mmtmpU1,*(__m128i*)conjugate);
mmtmpU1 = _mm_madd_epi16(mmtmpU1,rxdataF128[2]);
// mmtmpU1 contains imag part of 4 consecutive outputs (32-bit)
mmtmpU0 = _mm_srai_epi32(mmtmpU0,output_shift);
mmtmpU1 = _mm_srai_epi32(mmtmpU1,output_shift);
mmtmpU2 = _mm_unpacklo_epi32(mmtmpU0,mmtmpU1);
mmtmpU3 = _mm_unpackhi_epi32(mmtmpU0,mmtmpU1);
rxdataF_comp128[2] = _mm_packs_epi32(mmtmpU2,mmtmpU3);
// print_shorts("rx:",rxdataF128[2]);
// print_shorts("ch:",ul_ch128[2]);
// print_shorts("pack:",rxdataF_comp128[2]);
// Add a jitter to compensate for the saturation in "packs" resulting in a bias on the DC after IDFT
rxdataF_comp128[0] = _mm_add_epi16(rxdataF_comp128[0],(*(__m128i*)&jitter[0]));
rxdataF_comp128[1] = _mm_add_epi16(rxdataF_comp128[1],(*(__m128i*)&jitter[0]));
rxdataF_comp128[2] = _mm_add_epi16(rxdataF_comp128[2],(*(__m128i*)&jitter[0]));
ul_ch128+=3;
ul_ch_mag128+=3;
ul_ch_mag128b+=3;
rxdataF128+=3;
rxdataF_comp128+=3;
#elif defined(__arm__)
mmtmpU0 = vmull_s16(ul_ch128[0], rxdataF128[0]);
//mmtmpU0 = [Re(ch[0])Re(rx[0]) Im(ch[0])Im(ch[0]) Re(ch[1])Re(rx[1]) Im(ch[1])Im(ch[1])]
mmtmpU1 = vmull_s16(ul_ch128[1], rxdataF128[1]);
//mmtmpU1 = [Re(ch[2])Re(rx[2]) Im(ch[2])Im(ch[2]) Re(ch[3])Re(rx[3]) Im(ch[3])Im(ch[3])]
mmtmpU0 = vcombine_s32(vpadd_s32(vget_low_s32(mmtmpU0),vget_high_s32(mmtmpU0)),
vpadd_s32(vget_low_s32(mmtmpU1),vget_high_s32(mmtmpU1)));
//mmtmpU0 = [Re(ch[0])Re(rx[0])+Im(ch[0])Im(ch[0]) Re(ch[1])Re(rx[1])+Im(ch[1])Im(ch[1]) Re(ch[2])Re(rx[2])+Im(ch[2])Im(ch[2]) Re(ch[3])Re(rx[3])+Im(ch[3])Im(ch[3])]
mmtmpU0b = vmull_s16(vrev32_s16(vmul_s16(ul_ch128[0],*(int16x4_t*)conj)), rxdataF128[0]);
//mmtmpU0 = [-Im(ch[0])Re(rx[0]) Re(ch[0])Im(rx[0]) -Im(ch[1])Re(rx[1]) Re(ch[1])Im(rx[1])]
mmtmpU1b = vmull_s16(vrev32_s16(vmul_s16(ul_ch128[1],*(int16x4_t*)conj)), rxdataF128[1]);
//mmtmpU0 = [-Im(ch[2])Re(rx[2]) Re(ch[2])Im(rx[2]) -Im(ch[3])Re(rx[3]) Re(ch[3])Im(rx[3])]
mmtmpU1 = vcombine_s32(vpadd_s32(vget_low_s32(mmtmpU0b),vget_high_s32(mmtmpU0b)),
vpadd_s32(vget_low_s32(mmtmpU1b),vget_high_s32(mmtmpU1b)));
//mmtmpU1 = [-Im(ch[0])Re(rx[0])+Re(ch[0])Im(rx[0]) -Im(ch[1])Re(rx[1])+Re(ch[1])Im(rx[1]) -Im(ch[2])Re(rx[2])+Re(ch[2])Im(rx[2]) -Im(ch[3])Re(rx[3])+Re(ch[3])Im(rx[3])]
mmtmpU0 = vqshlq_s32(mmtmpU0,-output_shift128);
mmtmpU1 = vqshlq_s32(mmtmpU1,-output_shift128);
rxdataF_comp128[0] = vcombine_s16(vmovn_s32(mmtmpU0),vmovn_s32(mmtmpU1));
mmtmpU0 = vmull_s16(ul_ch128[2], rxdataF128[2]);
mmtmpU1 = vmull_s16(ul_ch128[3], rxdataF128[3]);
mmtmpU0 = vcombine_s32(vpadd_s32(vget_low_s32(mmtmpU0),vget_high_s32(mmtmpU0)),
vpadd_s32(vget_low_s32(mmtmpU1),vget_high_s32(mmtmpU1)));
mmtmpU0b = vmull_s16(vrev32_s16(vmul_s16(ul_ch128[2],*(int16x4_t*)conj)), rxdataF128[2]);
mmtmpU1b = vmull_s16(vrev32_s16(vmul_s16(ul_ch128[3],*(int16x4_t*)conj)), rxdataF128[3]);
mmtmpU1 = vcombine_s32(vpadd_s32(vget_low_s32(mmtmpU0b),vget_high_s32(mmtmpU0b)),
vpadd_s32(vget_low_s32(mmtmpU1b),vget_high_s32(mmtmpU1b)));
mmtmpU0 = vqshlq_s32(mmtmpU0,-output_shift128);
mmtmpU1 = vqshlq_s32(mmtmpU1,-output_shift128);
rxdataF_comp128[1] = vcombine_s16(vmovn_s32(mmtmpU0),vmovn_s32(mmtmpU1));
mmtmpU0 = vmull_s16(ul_ch128[4], rxdataF128[4]);
mmtmpU1 = vmull_s16(ul_ch128[5], rxdataF128[5]);
mmtmpU0 = vcombine_s32(vpadd_s32(vget_low_s32(mmtmpU0),vget_high_s32(mmtmpU0)),
vpadd_s32(vget_low_s32(mmtmpU1),vget_high_s32(mmtmpU1)));
mmtmpU0b = vmull_s16(vrev32_s16(vmul_s16(ul_ch128[4],*(int16x4_t*)conj)), rxdataF128[4]);
mmtmpU1b = vmull_s16(vrev32_s16(vmul_s16(ul_ch128[5],*(int16x4_t*)conj)), rxdataF128[5]);
mmtmpU1 = vcombine_s32(vpadd_s32(vget_low_s32(mmtmpU0b),vget_high_s32(mmtmpU0b)),
vpadd_s32(vget_low_s32(mmtmpU1b),vget_high_s32(mmtmpU1b)));
mmtmpU0 = vqshlq_s32(mmtmpU0,-output_shift128);
mmtmpU1 = vqshlq_s32(mmtmpU1,-output_shift128);
rxdataF_comp128[2] = vcombine_s16(vmovn_s32(mmtmpU0),vmovn_s32(mmtmpU1));
// Add a jitter to compensate for the saturation in "packs" resulting in a bias on the DC after IDFT
rxdataF_comp128[0] = vqaddq_s16(rxdataF_comp128[0],(*(int16x8_t*)&jitter[0]));
rxdataF_comp128[1] = vqaddq_s16(rxdataF_comp128[1],(*(int16x8_t*)&jitter[0]));
rxdataF_comp128[2] = vqaddq_s16(rxdataF_comp128[2],(*(int16x8_t*)&jitter[0]));
ul_ch128+=6;
ul_ch_mag128+=3;
ul_ch_mag128b+=3;
rxdataF128+=6;
rxdataF_comp128+=3;
#endif
}
}
#if defined(__x86_64__) || defined(__i386__)
_mm_empty();
_m_empty();
#endif
}
#if defined(__x86_64__) || defined(__i386__)
__m128i QAM_amp128U_0,QAM_amp128bU_0,QAM_amp128U_1,QAM_amp128bU_1;
#endif
void ulsch_channel_compensation_alamouti_NB_IoT(int32_t **rxdataF_ext, // For Distributed Alamouti Combining
int32_t **ul_ch_estimates_ext_0,
int32_t **ul_ch_estimates_ext_1,
int32_t **ul_ch_mag_0,
int32_t **ul_ch_magb_0,
int32_t **ul_ch_mag_1,
int32_t **ul_ch_magb_1,
int32_t **rxdataF_comp_0,
int32_t **rxdataF_comp_1,
NB_IoT_DL_FRAME_PARMS *frame_parms,
uint8_t symbol,
uint8_t Qm,
uint16_t nb_rb,
uint8_t output_shift)
{
#if defined(__x86_64__) || defined(__i386__)
uint16_t rb;
__m128i *ul_ch128_0,*ul_ch128_1,*ul_ch_mag128_0,*ul_ch_mag128_1,*ul_ch_mag128b_0,*ul_ch_mag128b_1,*rxdataF128,*rxdataF_comp128_0,*rxdataF_comp128_1;
uint8_t aarx;//,symbol_mod;
__m128i mmtmpU0,mmtmpU1,mmtmpU2,mmtmpU3;
// symbol_mod = (symbol>=(7-frame_parms->Ncp)) ? symbol-(7-frame_parms->Ncp) : symbol;
// printf("comp: symbol %d\n",symbol);
if (Qm == 4) {
QAM_amp128U_0 = _mm_set1_epi16(QAM16_n1);
QAM_amp128U_1 = _mm_set1_epi16(QAM16_n1);
} else if (Qm == 6) {
QAM_amp128U_0 = _mm_set1_epi16(QAM64_n1);
QAM_amp128bU_0 = _mm_set1_epi16(QAM64_n2);
QAM_amp128U_1 = _mm_set1_epi16(QAM64_n1);
QAM_amp128bU_1 = _mm_set1_epi16(QAM64_n2);
}
for (aarx=0; aarx<frame_parms->nb_antennas_rx; aarx++) {
ul_ch128_0 = (__m128i *)&ul_ch_estimates_ext_0[aarx][symbol*frame_parms->N_RB_DL*12];
ul_ch_mag128_0 = (__m128i *)&ul_ch_mag_0[aarx][symbol*frame_parms->N_RB_DL*12];
ul_ch_mag128b_0 = (__m128i *)&ul_ch_magb_0[aarx][symbol*frame_parms->N_RB_DL*12];
ul_ch128_1 = (__m128i *)&ul_ch_estimates_ext_1[aarx][symbol*frame_parms->N_RB_DL*12];
ul_ch_mag128_1 = (__m128i *)&ul_ch_mag_1[aarx][symbol*frame_parms->N_RB_DL*12];
ul_ch_mag128b_1 = (__m128i *)&ul_ch_magb_1[aarx][symbol*frame_parms->N_RB_DL*12];
rxdataF128 = (__m128i *)&rxdataF_ext[aarx][symbol*frame_parms->N_RB_DL*12];
rxdataF_comp128_0 = (__m128i *)&rxdataF_comp_0[aarx][symbol*frame_parms->N_RB_DL*12];
rxdataF_comp128_1 = (__m128i *)&rxdataF_comp_1[aarx][symbol*frame_parms->N_RB_DL*12];
for (rb=0; rb<nb_rb; rb++) {
// printf("comp: symbol %d rb %d\n",symbol,rb);
if (Qm>2) {
// get channel amplitude if not QPSK
mmtmpU0 = _mm_madd_epi16(ul_ch128_0[0],ul_ch128_0[0]);
mmtmpU0 = _mm_srai_epi32(mmtmpU0,output_shift);
mmtmpU1 = _mm_madd_epi16(ul_ch128_0[1],ul_ch128_0[1]);
mmtmpU1 = _mm_srai_epi32(mmtmpU1,output_shift);
mmtmpU0 = _mm_packs_epi32(mmtmpU0,mmtmpU1);
ul_ch_mag128_0[0] = _mm_unpacklo_epi16(mmtmpU0,mmtmpU0);
ul_ch_mag128b_0[0] = ul_ch_mag128_0[0];
ul_ch_mag128_0[0] = _mm_mulhi_epi16(ul_ch_mag128_0[0],QAM_amp128U_0);
ul_ch_mag128_0[0] = _mm_slli_epi16(ul_ch_mag128_0[0],2); // 2 to compensate the scale channel estimate
ul_ch_mag128_0[1] = _mm_unpackhi_epi16(mmtmpU0,mmtmpU0);
ul_ch_mag128b_0[1] = ul_ch_mag128_0[1];
ul_ch_mag128_0[1] = _mm_mulhi_epi16(ul_ch_mag128_0[1],QAM_amp128U_0);
ul_ch_mag128_0[1] = _mm_slli_epi16(ul_ch_mag128_0[1],2); // 2 to scale compensate the scale channel estimate
mmtmpU0 = _mm_madd_epi16(ul_ch128_0[2],ul_ch128_0[2]);
mmtmpU0 = _mm_srai_epi32(mmtmpU0,output_shift);
mmtmpU1 = _mm_packs_epi32(mmtmpU0,mmtmpU0);
ul_ch_mag128_0[2] = _mm_unpacklo_epi16(mmtmpU1,mmtmpU1);
ul_ch_mag128b_0[2] = ul_ch_mag128_0[2];
ul_ch_mag128_0[2] = _mm_mulhi_epi16(ul_ch_mag128_0[2],QAM_amp128U_0);
ul_ch_mag128_0[2] = _mm_slli_epi16(ul_ch_mag128_0[2],2); // 2 to scale compensate the scale channel estimat
ul_ch_mag128b_0[0] = _mm_mulhi_epi16(ul_ch_mag128b_0[0],QAM_amp128bU_0);
ul_ch_mag128b_0[0] = _mm_slli_epi16(ul_ch_mag128b_0[0],2); // 2 to scale compensate the scale channel estima
ul_ch_mag128b_0[1] = _mm_mulhi_epi16(ul_ch_mag128b_0[1],QAM_amp128bU_0);
ul_ch_mag128b_0[1] = _mm_slli_epi16(ul_ch_mag128b_0[1],2); // 2 to scale compensate the scale channel estima
ul_ch_mag128b_0[2] = _mm_mulhi_epi16(ul_ch_mag128b_0[2],QAM_amp128bU_0);
ul_ch_mag128b_0[2] = _mm_slli_epi16(ul_ch_mag128b_0[2],2); // 2 to scale compensate the scale channel estima
mmtmpU0 = _mm_madd_epi16(ul_ch128_1[0],ul_ch128_1[0]);
mmtmpU0 = _mm_srai_epi32(mmtmpU0,output_shift);
mmtmpU1 = _mm_madd_epi16(ul_ch128_1[1],ul_ch128_1[1]);
mmtmpU1 = _mm_srai_epi32(mmtmpU1,output_shift);
mmtmpU0 = _mm_packs_epi32(mmtmpU0,mmtmpU1);
ul_ch_mag128_1[0] = _mm_unpacklo_epi16(mmtmpU0,mmtmpU0);
ul_ch_mag128b_1[0] = ul_ch_mag128_1[0];
ul_ch_mag128_1[0] = _mm_mulhi_epi16(ul_ch_mag128_1[0],QAM_amp128U_1);
ul_ch_mag128_1[0] = _mm_slli_epi16(ul_ch_mag128_1[0],2); // 2 to compensate the scale channel estimate
ul_ch_mag128_1[1] = _mm_unpackhi_epi16(mmtmpU0,mmtmpU0);
ul_ch_mag128b_1[1] = ul_ch_mag128_1[1];
ul_ch_mag128_1[1] = _mm_mulhi_epi16(ul_ch_mag128_1[1],QAM_amp128U_1);
ul_ch_mag128_1[1] = _mm_slli_epi16(ul_ch_mag128_1[1],2); // 2 to scale compensate the scale channel estimate
mmtmpU0 = _mm_madd_epi16(ul_ch128_1[2],ul_ch128_1[2]);
mmtmpU0 = _mm_srai_epi32(mmtmpU0,output_shift);
mmtmpU1 = _mm_packs_epi32(mmtmpU0,mmtmpU0);
ul_ch_mag128_1[2] = _mm_unpacklo_epi16(mmtmpU1,mmtmpU1);
ul_ch_mag128b_1[2] = ul_ch_mag128_1[2];
ul_ch_mag128_1[2] = _mm_mulhi_epi16(ul_ch_mag128_1[2],QAM_amp128U_0);
ul_ch_mag128_1[2] = _mm_slli_epi16(ul_ch_mag128_1[2],2); // 2 to scale compensate the scale channel estimat
ul_ch_mag128b_1[0] = _mm_mulhi_epi16(ul_ch_mag128b_1[0],QAM_amp128bU_1);
ul_ch_mag128b_1[0] = _mm_slli_epi16(ul_ch_mag128b_1[0],2); // 2 to scale compensate the scale channel estima
ul_ch_mag128b_1[1] = _mm_mulhi_epi16(ul_ch_mag128b_1[1],QAM_amp128bU_1);
ul_ch_mag128b_1[1] = _mm_slli_epi16(ul_ch_mag128b_1[1],2); // 2 to scale compensate the scale channel estima
ul_ch_mag128b_1[2] = _mm_mulhi_epi16(ul_ch_mag128b_1[2],QAM_amp128bU_1);
ul_ch_mag128b_1[2] = _mm_slli_epi16(ul_ch_mag128b_1[2],2); // 2 to scale compensate the scale channel estima
}
/************************For Computing (y)*(h0*)********************************************/
// multiply by conjugated channel
mmtmpU0 = _mm_madd_epi16(ul_ch128_0[0],rxdataF128[0]);
// print_ints("re",&mmtmpU0);
// mmtmpU0 contains real part of 4 consecutive outputs (32-bit)
mmtmpU1 = _mm_shufflelo_epi16(ul_ch128_0[0],_MM_SHUFFLE(2,3,0,1));
mmtmpU1 = _mm_shufflehi_epi16(mmtmpU1,_MM_SHUFFLE(2,3,0,1));
mmtmpU1 = _mm_sign_epi16(mmtmpU1,*(__m128i*)&conjugate[0]);
// print_ints("im",&mmtmpU1);
mmtmpU1 = _mm_madd_epi16(mmtmpU1,rxdataF128[0]);
// mmtmpU1 contains imag part of 4 consecutive outputs (32-bit)
mmtmpU0 = _mm_srai_epi32(mmtmpU0,output_shift);
// print_ints("re(shift)",&mmtmpU0);
mmtmpU1 = _mm_srai_epi32(mmtmpU1,output_shift);
// print_ints("im(shift)",&mmtmpU1);
mmtmpU2 = _mm_unpacklo_epi32(mmtmpU0,mmtmpU1);
mmtmpU3 = _mm_unpackhi_epi32(mmtmpU0,mmtmpU1);
// print_ints("c0",&mmtmpU2);
// print_ints("c1",&mmtmpU3);
rxdataF_comp128_0[0] = _mm_packs_epi32(mmtmpU2,mmtmpU3);
// print_shorts("rx:",rxdataF128[0]);
// print_shorts("ch:",ul_ch128_0[0]);
// print_shorts("pack:",rxdataF_comp128_0[0]);
// multiply by conjugated channel
mmtmpU0 = _mm_madd_epi16(ul_ch128_0[1],rxdataF128[1]);
// mmtmpU0 contains real part of 4 consecutive outputs (32-bit)
mmtmpU1 = _mm_shufflelo_epi16(ul_ch128_0[1],_MM_SHUFFLE(2,3,0,1));
mmtmpU1 = _mm_shufflehi_epi16(mmtmpU1,_MM_SHUFFLE(2,3,0,1));
mmtmpU1 = _mm_sign_epi16(mmtmpU1,*(__m128i*)conjugate);
mmtmpU1 = _mm_madd_epi16(mmtmpU1,rxdataF128[1]);
// mmtmpU1 contains imag part of 4 consecutive outputs (32-bit)
mmtmpU0 = _mm_srai_epi32(mmtmpU0,output_shift);
mmtmpU1 = _mm_srai_epi32(mmtmpU1,output_shift);
mmtmpU2 = _mm_unpacklo_epi32(mmtmpU0,mmtmpU1);
mmtmpU3 = _mm_unpackhi_epi32(mmtmpU0,mmtmpU1);
rxdataF_comp128_0[1] = _mm_packs_epi32(mmtmpU2,mmtmpU3);
// print_shorts("rx:",rxdataF128[1]);
// print_shorts("ch:",ul_ch128_0[1]);
// print_shorts("pack:",rxdataF_comp128_0[1]);
// multiply by conjugated channel
mmtmpU0 = _mm_madd_epi16(ul_ch128_0[2],rxdataF128[2]);
// mmtmpU0 contains real part of 4 consecutive outputs (32-bit)
mmtmpU1 = _mm_shufflelo_epi16(ul_ch128_0[2],_MM_SHUFFLE(2,3,0,1));
mmtmpU1 = _mm_shufflehi_epi16(mmtmpU1,_MM_SHUFFLE(2,3,0,1));
mmtmpU1 = _mm_sign_epi16(mmtmpU1,*(__m128i*)conjugate);
mmtmpU1 = _mm_madd_epi16(mmtmpU1,rxdataF128[2]);
// mmtmpU1 contains imag part of 4 consecutive outputs (32-bit)
mmtmpU0 = _mm_srai_epi32(mmtmpU0,output_shift);
mmtmpU1 = _mm_srai_epi32(mmtmpU1,output_shift);
mmtmpU2 = _mm_unpacklo_epi32(mmtmpU0,mmtmpU1);
mmtmpU3 = _mm_unpackhi_epi32(mmtmpU0,mmtmpU1);
rxdataF_comp128_0[2] = _mm_packs_epi32(mmtmpU2,mmtmpU3);
// print_shorts("rx:",rxdataF128[2]);
// print_shorts("ch:",ul_ch128_0[2]);
// print_shorts("pack:",rxdataF_comp128_0[2]);
/*************************For Computing (y*)*(h1)************************************/
// multiply by conjugated signal
mmtmpU0 = _mm_madd_epi16(ul_ch128_1[0],rxdataF128[0]);
// print_ints("re",&mmtmpU0);
// mmtmpU0 contains real part of 4 consecutive outputs (32-bit)
mmtmpU1 = _mm_shufflelo_epi16(rxdataF128[0],_MM_SHUFFLE(2,3,0,1));
mmtmpU1 = _mm_shufflehi_epi16(mmtmpU1,_MM_SHUFFLE(2,3,0,1));
mmtmpU1 = _mm_sign_epi16(mmtmpU1,*(__m128i*)&conjugate[0]);
// print_ints("im",&mmtmpU1);
mmtmpU1 = _mm_madd_epi16(mmtmpU1,ul_ch128_1[0]);
// mmtmpU1 contains imag part of 4 consecutive outputs (32-bit)
mmtmpU0 = _mm_srai_epi32(mmtmpU0,output_shift);
// print_ints("re(shift)",&mmtmpU0);
mmtmpU1 = _mm_srai_epi32(mmtmpU1,output_shift);
// print_ints("im(shift)",&mmtmpU1);
mmtmpU2 = _mm_unpacklo_epi32(mmtmpU0,mmtmpU1);
mmtmpU3 = _mm_unpackhi_epi32(mmtmpU0,mmtmpU1);
// print_ints("c0",&mmtmpU2);
// print_ints("c1",&mmtmpU3);
rxdataF_comp128_1[0] = _mm_packs_epi32(mmtmpU2,mmtmpU3);
// print_shorts("rx:",rxdataF128[0]);
// print_shorts("ch_conjugate:",ul_ch128_1[0]);
// print_shorts("pack:",rxdataF_comp128_1[0]);
// multiply by conjugated signal
mmtmpU0 = _mm_madd_epi16(ul_ch128_1[1],rxdataF128[1]);
// mmtmpU0 contains real part of 4 consecutive outputs (32-bit)
mmtmpU1 = _mm_shufflelo_epi16(rxdataF128[1],_MM_SHUFFLE(2,3,0,1));
mmtmpU1 = _mm_shufflehi_epi16(mmtmpU1,_MM_SHUFFLE(2,3,0,1));
mmtmpU1 = _mm_sign_epi16(mmtmpU1,*(__m128i*)conjugate);
mmtmpU1 = _mm_madd_epi16(mmtmpU1,ul_ch128_1[1]);
// mmtmpU1 contains imag part of 4 consecutive outputs (32-bit)
mmtmpU0 = _mm_srai_epi32(mmtmpU0,output_shift);
mmtmpU1 = _mm_srai_epi32(mmtmpU1,output_shift);
mmtmpU2 = _mm_unpacklo_epi32(mmtmpU0,mmtmpU1);
mmtmpU3 = _mm_unpackhi_epi32(mmtmpU0,mmtmpU1);
rxdataF_comp128_1[1] = _mm_packs_epi32(mmtmpU2,mmtmpU3);
// print_shorts("rx:",rxdataF128[1]);
// print_shorts("ch_conjugate:",ul_ch128_1[1]);
// print_shorts("pack:",rxdataF_comp128_1[1]);
// multiply by conjugated signal
mmtmpU0 = _mm_madd_epi16(ul_ch128_1[2],rxdataF128[2]);
// mmtmpU0 contains real part of 4 consecutive outputs (32-bit)
mmtmpU1 = _mm_shufflelo_epi16(rxdataF128[2],_MM_SHUFFLE(2,3,0,1));
mmtmpU1 = _mm_shufflehi_epi16(mmtmpU1,_MM_SHUFFLE(2,3,0,1));
mmtmpU1 = _mm_sign_epi16(mmtmpU1,*(__m128i*)conjugate);
mmtmpU1 = _mm_madd_epi16(mmtmpU1,ul_ch128_1[2]);
// mmtmpU1 contains imag part of 4 consecutive outputs (32-bit)
mmtmpU0 = _mm_srai_epi32(mmtmpU0,output_shift);
mmtmpU1 = _mm_srai_epi32(mmtmpU1,output_shift);
mmtmpU2 = _mm_unpacklo_epi32(mmtmpU0,mmtmpU1);
mmtmpU3 = _mm_unpackhi_epi32(mmtmpU0,mmtmpU1);
rxdataF_comp128_1[2] = _mm_packs_epi32(mmtmpU2,mmtmpU3);
// print_shorts("rx:",rxdataF128[2]);
// print_shorts("ch_conjugate:",ul_ch128_0[2]);
// print_shorts("pack:",rxdataF_comp128_1[2]);
ul_ch128_0+=3;
ul_ch_mag128_0+=3;
ul_ch_mag128b_0+=3;
ul_ch128_1+=3;
ul_ch_mag128_1+=3;
ul_ch_mag128b_1+=3;
rxdataF128+=3;
rxdataF_comp128_0+=3;
rxdataF_comp128_1+=3;
}
}
_mm_empty();
_m_empty();
#endif
}
void ulsch_alamouti_NB_IoT(NB_IoT_DL_FRAME_PARMS *frame_parms,// For Distributed Alamouti Receiver Combining
int32_t **rxdataF_comp,
int32_t **rxdataF_comp_0,
int32_t **rxdataF_comp_1,
int32_t **ul_ch_mag,
int32_t **ul_ch_magb,
int32_t **ul_ch_mag_0,
int32_t **ul_ch_magb_0,
int32_t **ul_ch_mag_1,
int32_t **ul_ch_magb_1,
uint8_t symbol,
uint16_t nb_rb)
{
#if defined(__x86_64__) || defined(__i386__)
int16_t *rxF,*rxF0,*rxF1;
__m128i *ch_mag,*ch_magb,*ch_mag0,*ch_mag1,*ch_mag0b,*ch_mag1b;
uint8_t rb,re,aarx;
int32_t jj=(symbol*frame_parms->N_RB_DL*12);
for (aarx=0; aarx<frame_parms->nb_antennas_rx; aarx++) {
rxF = (int16_t*)&rxdataF_comp[aarx][jj];
rxF0 = (int16_t*)&rxdataF_comp_0[aarx][jj]; // Contains (y)*(h0*)
rxF1 = (int16_t*)&rxdataF_comp_1[aarx][jj]; // Contains (y*)*(h1)
ch_mag = (__m128i *)&ul_ch_mag[aarx][jj];
ch_mag0 = (__m128i *)&ul_ch_mag_0[aarx][jj];
ch_mag1 = (__m128i *)&ul_ch_mag_1[aarx][jj];
ch_magb = (__m128i *)&ul_ch_magb[aarx][jj];
ch_mag0b = (__m128i *)&ul_ch_magb_0[aarx][jj];
ch_mag1b = (__m128i *)&ul_ch_magb_1[aarx][jj];
for (rb=0; rb<nb_rb; rb++) {
for (re=0; re<12; re+=2) {
// Alamouti RX combining
rxF[0] = rxF0[0] + rxF1[2]; // re((y0)*(h0*))+ re((y1*)*(h1)) = re(x0)
rxF[1] = rxF0[1] + rxF1[3]; // im((y0)*(h0*))+ im((y1*)*(h1)) = im(x0)
rxF[2] = rxF0[2] - rxF1[0]; // re((y1)*(h0*))- re((y0*)*(h1)) = re(x1)
rxF[3] = rxF0[3] - rxF1[1]; // im((y1)*(h0*))- im((y0*)*(h1)) = im(x1)
rxF+=4;
rxF0+=4;
rxF1+=4;
}
// compute levels for 16QAM or 64 QAM llr unit
ch_mag[0] = _mm_adds_epi16(ch_mag0[0],ch_mag1[0]);
ch_mag[1] = _mm_adds_epi16(ch_mag0[1],ch_mag1[1]);
ch_mag[2] = _mm_adds_epi16(ch_mag0[2],ch_mag1[2]);
ch_magb[0] = _mm_adds_epi16(ch_mag0b[0],ch_mag1b[0]);
ch_magb[1] = _mm_adds_epi16(ch_mag0b[1],ch_mag1b[1]);
ch_magb[2] = _mm_adds_epi16(ch_mag0b[2],ch_mag1b[2]);
ch_mag+=3;
ch_mag0+=3;
ch_mag1+=3;
ch_magb+=3;
ch_mag0b+=3;
ch_mag1b+=3;
}
}
_mm_empty();
_m_empty();
#endif
}
#if defined(__x86_64__) || defined(__i386__)
__m128i avg128U;
#elif defined(__arm__)
int32x4_t avg128U;
#endif
void ulsch_channel_level_NB_IoT(int32_t **drs_ch_estimates_ext,
NB_IoT_DL_FRAME_PARMS *frame_parms,
int32_t *avg,
uint16_t nb_rb)
{
int16_t rb;
uint8_t aarx;
#if defined(__x86_64__) || defined(__i386__)
__m128i *ul_ch128;
#elif defined(__arm__)
int16x4_t *ul_ch128;
#endif
for (aarx=0; aarx<frame_parms->nb_antennas_rx; aarx++) {
//clear average level
#if defined(__x86_64__) || defined(__i386__)
avg128U = _mm_setzero_si128();
ul_ch128=(__m128i *)drs_ch_estimates_ext[aarx];
for (rb=0; rb<nb_rb; rb++) {
avg128U = _mm_add_epi32(avg128U,_mm_madd_epi16(ul_ch128[0],ul_ch128[0]));
avg128U = _mm_add_epi32(avg128U,_mm_madd_epi16(ul_ch128[1],ul_ch128[1]));
avg128U = _mm_add_epi32(avg128U,_mm_madd_epi16(ul_ch128[2],ul_ch128[2]));
ul_ch128+=3;
}
#elif defined(__arm__)
avg128U = vdupq_n_s32(0);
ul_ch128=(int16x4_t *)drs_ch_estimates_ext[aarx];
for (rb=0; rb<nb_rb; rb++) {
avg128U = vqaddq_s32(avg128U,vmull_s16(ul_ch128[0],ul_ch128[0]));
avg128U = vqaddq_s32(avg128U,vmull_s16(ul_ch128[1],ul_ch128[1]));
avg128U = vqaddq_s32(avg128U,vmull_s16(ul_ch128[2],ul_ch128[2]));
avg128U = vqaddq_s32(avg128U,vmull_s16(ul_ch128[3],ul_ch128[3]));
avg128U = vqaddq_s32(avg128U,vmull_s16(ul_ch128[4],ul_ch128[4]));
avg128U = vqaddq_s32(avg128U,vmull_s16(ul_ch128[5],ul_ch128[5]));
ul_ch128+=6;
}
#endif
DevAssert( nb_rb );
avg[aarx] = (((int*)&avg128U)[0] +
((int*)&avg128U)[1] +
((int*)&avg128U)[2] +
((int*)&avg128U)[3])/(nb_rb*12);
}
#if defined(__x86_64__) || defined(__i386__)
_mm_empty();
_m_empty();
#endif
}
int32_t avgU[2];
int32_t avgU_0[2],avgU_1[2]; // For the Distributed Alamouti Scheme
void rx_ulsch_NB_IoT(PHY_VARS_eNB_NB_IoT *eNB,
eNB_rxtx_proc_NB_IoT_t *proc,
uint8_t eNB_id, // this is the effective sector id
uint8_t UE_id,
NB_IoT_eNB_ULSCH_t **ulsch,
uint8_t cooperation_flag)
{
// flagMag = 0;
NB_IoT_eNB_COMMON *common_vars = &eNB->common_vars;
NB_IoT_eNB_PUSCH *pusch_vars = eNB->pusch_vars[UE_id];
NB_IoT_DL_FRAME_PARMS *frame_parms = &eNB->frame_parms;
uint32_t l,i;
int32_t avgs;
uint8_t log2_maxh = 0,aarx;
int32_t avgs_0,avgs_1;
uint32_t log2_maxh_0 = 0,log2_maxh_1 = 0;
uint8_t harq_pid;
uint8_t Qm;
uint16_t rx_power_correction;
int16_t *llrp;
int subframe = proc->subframe_rx;
harq_pid = subframe2harq_pid_NB_IoT(frame_parms,proc->frame_rx,subframe);
Qm = get_Qm_ul_NB_IoT(ulsch[UE_id]->harq_process->mcs);
rx_power_correction = 1;
if (ulsch[UE_id]->harq_process->nb_rb == 0) {
LOG_E(PHY,"PUSCH (%d/%x) nb_rb=0!\n", harq_pid,ulsch[UE_id]->rnti);
return;
}
for (l=0; l<(frame_parms->symbols_per_tti-ulsch[UE_id]->harq_process->srs_active); l++) {
ulsch_extract_rbs_single_NB_IoT(common_vars->rxdataF[eNB_id],
pusch_vars->rxdataF_ext[eNB_id],
ulsch[UE_id]->harq_process->first_rb,
ulsch[UE_id]->harq_process->nb_rb,
l%(frame_parms->symbols_per_tti/2),
l/(frame_parms->symbols_per_tti/2),
frame_parms);
lte_ul_channel_estimation_NB_IoT(eNB,proc,
eNB_id,
UE_id,
l%(frame_parms->symbols_per_tti/2),
l/(frame_parms->symbols_per_tti/2),
cooperation_flag);
}
if(cooperation_flag == 2) {
for (i=0; i<frame_parms->nb_antennas_rx; i++) {
pusch_vars->ulsch_power_0[i] = signal_energy(pusch_vars->drs_ch_estimates_0[eNB_id][i],
ulsch[UE_id]->harq_process->nb_rb*12)*rx_power_correction;
pusch_vars->ulsch_power_1[i] = signal_energy(pusch_vars->drs_ch_estimates_1[eNB_id][i],
ulsch[UE_id]->harq_process->nb_rb*12)*rx_power_correction;
}
} else {
for (i=0; i<frame_parms->nb_antennas_rx; i++) {
/*
pusch_vars->ulsch_power[i] = signal_energy_nodc(pusch_vars->drs_ch_estimates[eNB_id][i],
ulsch[UE_id]->harq_processes[harq_pid]->nb_rb*12)*rx_power_correction;
*/
pusch_vars->ulsch_power[i] = signal_energy_nodc(pusch_vars->drs_ch_estimates[eNB_id][i],
ulsch[UE_id]->harq_process->nb_rb*12);
#ifdef LOCALIZATION
pusch_vars->subcarrier_power = (int32_t *)malloc(ulsch[UE_id]->harq_process->nb_rb*12*sizeof(int32_t));
pusch_vars->active_subcarrier = subcarrier_energy(pusch_vars->drs_ch_estimates[eNB_id][i],
ulsch[UE_id]->harq_process->nb_rb*12, pusch_vars->subcarrier_power, rx_power_correction);
#endif
}
}
//write_output("rxdataF_ext.m","rxF_ext",pusch_vars->rxdataF_ext[eNB_id][0],300*(frame_parms->symbols_per_tti-ulsch[UE_id]->srs_active),1,1);
//write_output("ulsch_chest.m","drs_est",pusch_vars->drs_ch_estimates[eNB_id][0],300*(frame_parms->symbols_per_tti-ulsch[UE_id]->srs_active),1,1);
if(cooperation_flag == 2) {
ulsch_channel_level_NB_IoT(pusch_vars->drs_ch_estimates_0[eNB_id],
frame_parms,
avgU_0,
ulsch[UE_id]->harq_process->nb_rb);
// printf("[ULSCH] avg_0[0] %d\n",avgU_0[0]);
avgs_0 = 0;
for (aarx=0; aarx<frame_parms->nb_antennas_rx; aarx++)
avgs_0 = cmax(avgs_0,avgU_0[(aarx<<1)]);
log2_maxh_0 = (log2_approx(avgs_0)/2)+ log2_approx(frame_parms->nb_antennas_rx-1)+3;
#ifdef DEBUG_ULSCH
printf("[ULSCH] log2_maxh_0 = %d (%d,%d)\n",log2_maxh_0,avgU_0[0],avgs_0);
#endif
ulsch_channel_level_NB_IoT(pusch_vars->drs_ch_estimates_1[eNB_id],
frame_parms,
avgU_1,
ulsch[UE_id]->harq_process->nb_rb);
// printf("[ULSCH] avg_1[0] %d\n",avgU_1[0]);
avgs_1 = 0;
for (aarx=0; aarx<frame_parms->nb_antennas_rx; aarx++)
avgs_1 = cmax(avgs_1,avgU_1[(aarx<<1)]);
log2_maxh_1 = (log2_approx(avgs_1)/2) + log2_approx(frame_parms->nb_antennas_rx-1)+3;
#ifdef DEBUG_ULSCH
printf("[ULSCH] log2_maxh_1 = %d (%d,%d)\n",log2_maxh_1,avgU_1[0],avgs_1);
#endif
log2_maxh = max(log2_maxh_0,log2_maxh_1);
} else {
ulsch_channel_level_NB_IoT(pusch_vars->drs_ch_estimates[eNB_id],
frame_parms,
avgU,
ulsch[UE_id]->harq_process->nb_rb);
// printf("[ULSCH] avg[0] %d\n",avgU[0]);
avgs = 0;
for (aarx=0; aarx<frame_parms->nb_antennas_rx; aarx++)
avgs = cmax(avgs,avgU[(aarx<<1)]);
// log2_maxh = 4+(log2_approx(avgs)/2);
log2_maxh = (log2_approx(avgs)/2)+ log2_approx(frame_parms->nb_antennas_rx-1)+4;
#ifdef DEBUG_ULSCH
printf("[ULSCH] log2_maxh = %d (%d,%d)\n",log2_maxh,avgU[0],avgs);
#endif
}
for (l=0; l<frame_parms->symbols_per_tti-ulsch[UE_id]->harq_process->srs_active; l++) {
if (((frame_parms->Ncp == 0) && ((l==3) || (l==10)))|| // skip pilots
((frame_parms->Ncp == 1) && ((l==2) || (l==8)))) {
l++;
}
if(cooperation_flag == 2) {
ulsch_channel_compensation_alamouti_NB_IoT(
pusch_vars->rxdataF_ext[eNB_id],
pusch_vars->drs_ch_estimates_0[eNB_id],
pusch_vars->drs_ch_estimates_1[eNB_id],
pusch_vars->ul_ch_mag_0[eNB_id],
pusch_vars->ul_ch_magb_0[eNB_id],
pusch_vars->ul_ch_mag_1[eNB_id],
pusch_vars->ul_ch_magb_1[eNB_id],
pusch_vars->rxdataF_comp_0[eNB_id],
pusch_vars->rxdataF_comp_1[eNB_id],
frame_parms,
l,
Qm,
ulsch[UE_id]->harq_process->nb_rb,
log2_maxh);
ulsch_alamouti_NB_IoT(frame_parms,
pusch_vars->rxdataF_comp[eNB_id],
pusch_vars->rxdataF_comp_0[eNB_id],
pusch_vars->rxdataF_comp_1[eNB_id],
pusch_vars->ul_ch_mag[eNB_id],
pusch_vars->ul_ch_magb[eNB_id],
pusch_vars->ul_ch_mag_0[eNB_id],
pusch_vars->ul_ch_magb_0[eNB_id],
pusch_vars->ul_ch_mag_1[eNB_id],
pusch_vars->ul_ch_magb_1[eNB_id],
l,
ulsch[UE_id]->harq_process->nb_rb);
} else {
ulsch_channel_compensation_NB_IoT(
pusch_vars->rxdataF_ext[eNB_id],
pusch_vars->drs_ch_estimates[eNB_id],
pusch_vars->ul_ch_mag[eNB_id],
pusch_vars->ul_ch_magb[eNB_id],
pusch_vars->rxdataF_comp[eNB_id],
frame_parms,
l,
Qm,
ulsch[UE_id]->harq_process->nb_rb,
log2_maxh); // log2_maxh+I0_shift
}
//eren
/* if(flagMag == 0){
//writing for the first time
write_output(namepointer_log2,"xxx",log2_maxh,1,1,12);
write_output(namepointer_chMag,"xxx",pusch_vars->ul_ch_mag[eNB_id][0],300,1,11);
//namepointer_chMag = NULL;
flagMag=1;
}*/
if (frame_parms->nb_antennas_rx > 1)
ulsch_detection_mrc_NB_IoT(frame_parms,
pusch_vars->rxdataF_comp[eNB_id],
pusch_vars->ul_ch_mag[eNB_id],
pusch_vars->ul_ch_magb[eNB_id],
l,
ulsch[UE_id]->harq_process->nb_rb);
#ifndef OFDMA_ULSCH
if ((eNB->measurements->n0_power_dB[0]+3)<pusch_vars->ulsch_power[0]) {
freq_equalization_NB_IoT(frame_parms,
pusch_vars->rxdataF_comp[eNB_id],
pusch_vars->ul_ch_mag[eNB_id],
pusch_vars->ul_ch_magb[eNB_id],
l,
ulsch[UE_id]->harq_process->nb_rb*12,
Qm);
}
#endif
}
#ifndef OFDMA_ULSCH
//#ifdef DEBUG_ULSCH
// Inverse-Transform equalized outputs
// printf("Doing IDFTs\n");
lte_idft_NB_IoT(frame_parms,
(uint32_t*)pusch_vars->rxdataF_comp[eNB_id][0],
ulsch[UE_id]->harq_process->nb_rb*12);
// printf("Done\n");
//#endif //DEBUG_ULSCH
#endif
llrp = (int16_t*)&pusch_vars->llr[0];
T(T_ENB_PHY_PUSCH_IQ, T_INT(eNB_id), T_INT(UE_id), T_INT(proc->frame_rx),
T_INT(subframe), T_INT(ulsch[UE_id]->harq_process->nb_rb),
T_INT(frame_parms->N_RB_UL), T_INT(frame_parms->symbols_per_tti),
T_BUFFER(pusch_vars->rxdataF_comp[eNB_id][0],
2 * /* ulsch[UE_id]->harq_processes[harq_pid]->nb_rb */ frame_parms->N_RB_UL *12*frame_parms->symbols_per_tti*2));
for (l=0; l<frame_parms->symbols_per_tti-ulsch[UE_id]->harq_process->srs_active; l++) {
if (((frame_parms->Ncp == 0) && ((l==3) || (l==10)))|| // skip pilots
((frame_parms->Ncp == 1) && ((l==2) || (l==8)))) {
l++;
}
switch (Qm) {
case 2 :
ulsch_qpsk_llr_NB_IoT(frame_parms,
pusch_vars->rxdataF_comp[eNB_id],
pusch_vars->llr,
l,
ulsch[UE_id]->harq_process->nb_rb,
&llrp);
break;
default:
#ifdef DEBUG_ULSCH
printf("ulsch_demodulation.c (rx_ulsch): Unknown Qm!!!!\n");
#endif //DEBUG_ULSCH
break;
}
}
}
......@@ -352,6 +352,14 @@ typedef struct {
uint8_t groupHoppingEnabled;
/// , see TS 36.211 (5.5.1.3). \vr{[0..29]}
uint8_t groupAssignmentNPUSCH;
/// Parameter: cyclicShift, see TS 36.211 (Table 5.5.2.1.1-2). \vr{[0..7]}
uint8_t cyclicShift;
/// nPRS for cyclic shift of DRS \note not part of offical UL-ReferenceSignalsPUSCH ASN1 specification.
uint8_t nPRS[20];
/// group hopping sequence for DRS \note not part of offical UL-ReferenceSignalsPUSCH ASN1 specification.
uint8_t grouphop[20];
/// sequence hopping sequence for DRS \note not part of offical UL-ReferenceSignalsPUSCH ASN1 specification.
uint8_t seqhop[20];
} UL_REFERENCE_SIGNALS_NPUSCH_t;
......@@ -365,6 +373,7 @@ typedef struct {
DMRS_CONFIG_t dmrs_Config;
/// Ref signals configuration
UL_REFERENCE_SIGNALS_NPUSCH_t ul_ReferenceSignalsNPUSCH;
} NPUSCH_CONFIG_COMMON;
......@@ -385,6 +394,7 @@ typedef struct {
uint16_t dl_GapDurationCoeff;
} DL_GapConfig_NB_IoT;
typedef struct {
/// Frame type (0 FDD, 1 TDD)
......
......@@ -262,15 +262,15 @@ void phy_procedures_eNB_uespec_RX_NB_IoT(PHY_VARS_eNB_NB_IoT *eNB,eNB_rxtx_proc_
eNB->pusch_stats_rb[i][(frame*10)+subframe] = eNB->nulsch[i]->harq_process->nb_rb;
eNB->pusch_stats_round[i][(frame*10)+subframe] = eNB->nulsch[i]->harq_process->round;
eNB->pusch_stats_mcs[i][(frame*10)+subframe] = eNB->nulsch[i]->harq_process->mcs;
/*
need for rx_ulsch function for NB_IoT
rx_ulsch(eNB,proc,
eNB->UE_stats[i].sector, // this is the effective sector id
i,
eNB->nulsch,
0);
*/
rx_ulsch_NB_IoT(eNB,proc,
eNB->UE_stats[i].sector, // this is the effective sector id
i,
eNB->nulsch,
0);
ret = ulsch_decoding_NB_IoT(eNB,proc,
i,
0, // control_only_flag
......
......@@ -667,7 +667,7 @@ typedef struct {
time_stats_t schedule_dlsch; // include rlc_data_req + MAC header + preprocessor
/// Delete processing time of eNB MCH scheduler
/// processing time of eNB ULSCH reception
time_stats_t rx_ulsch_sdu; // include rlc_data_ind
time_stats_t rx_ulsch_sdu_NB_IoT; // include rlc_data_ind
} eNB_MAC_INST_NB_IoT;
/*!\brief Top level UE MAC structure */
......
......@@ -160,7 +160,7 @@ void rx_sdu_NB_IoT(const module_id_t enb_mod_idP,
int crnti_rx=0;
//int old_buffer_info;
start_meas(&eNB->rx_ulsch_sdu);
start_meas(&eNB->rx_ulsch_sdu_NB_IoT);
/*if there is an error for UE_id> max or UE_id==-1, set rx_lengths to 0*/
if ((UE_id > NUMBER_OF_UE_MAX_NB_IoT) || (UE_id == -1) )
......@@ -480,7 +480,7 @@ void rx_sdu_NB_IoT(const module_id_t enb_mod_idP,
}
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RX_SDU,0);
stop_meas(&eNB->rx_ulsch_sdu);
stop_meas(&eNB->rx_ulsch_sdu_NB_IoT);
}
}
......
......@@ -100,6 +100,7 @@
/* correct Rel(8|10)/Rel14 differences
* the code is in favor of Rel14, those defines do the translation
*/
/*
#if !defined(Rel14)
# define CipheringAlgorithm_r12_t e_SecurityAlgorithmConfig__cipheringAlgorithm
# define CipheringAlgorithm_r12_t e_CipheringAlgorithm_r12 //maybe this solve the problem of the previous line
......@@ -164,7 +165,7 @@
#define SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib10 SystemInformation_r8_IEs_sib_TypeAndInfo_Member_PR_sib10
#define SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib11 SystemInformation_r8_IEs_sib_TypeAndInfo_Member_PR_sib11
#endif
*/
#ifndef NO_RRM
#include "L3_rrc_interface.h"
......
......@@ -40,22 +40,22 @@
//MP: NOTE:XXX some of the parameters defined in vars_nb_iot are called by the extern.h file so not replicated here
extern UE_RRC_INST_NB_IoT *UE_rrc_inst_NB_IoT;
extern eNB_RRC_INST_NB_IoT *eNB_rrc_inst_NB_IoT;
extern PHY_Config_t *config_INFO;
extern rlc_info_t Rlc_info_am_NB_IoT,Rlc_info_am_config_NB_IoT;
extern uint8_t DRB2LCHAN_NB_IoT[2];
extern LogicalChannelConfig_NB_r13_t SRB1bis_logicalChannelConfig_defaultValue_NB_IoT;
extern LogicalChannelConfig_NB_r13_t SRB1_logicalChannelConfig_defaultValue_NB_IoT;
extern uint16_t T300_NB_IoT[8];
extern uint16_t T301_NB_IoT[8];
extern uint16_t T310_NB_IoT[8];
extern uint16_t T311_NB_IoT[8];
extern uint16_t N310_NB_IoT[8];
extern uint16_t N311_NB_IoT[8];
extern UE_RRC_INST_NB_IoT *UE_rrc_inst_NB_IoT;
extern eNB_RRC_INST_NB_IoT *eNB_rrc_inst_NB_IoT;
extern PHY_Config_t *config_INFO;
extern rlc_info_t Rlc_info_am_NB_IoT,Rlc_info_am_config_NB_IoT;
extern uint8_t DRB2LCHAN_NB_IoT[2];
extern LogicalChannelConfig_NB_r13_t SRB1bis_logicalChannelConfig_defaultValue_NB_IoT;
extern LogicalChannelConfig_NB_r13_t SRB1_logicalChannelConfig_defaultValue_NB_IoT;
extern uint16_t T300_NB_IoT[8];
extern uint16_t T301_NB_IoT[8];
extern uint16_t T310_NB_IoT[8];
extern uint16_t T311_NB_IoT[8];
extern uint16_t N310_NB_IoT[8];
extern uint16_t N311_NB_IoT[8];
#endif
......
......@@ -31,7 +31,7 @@
//#include "defs_NB_IoT.h"
//#include "extern.h"
//#include "RRC/LITE/extern_NB_IoT.h"
//#include "common/utils/collection/tree.h"
#include "common/utils/collection/tree.h"
#include "LAYER2/MAC/extern_NB_IoT.h"
//#include "COMMON/openair_defs.h"
//#include "COMMON/platform_types.h"
......
......@@ -44,6 +44,7 @@
#include "DL-DCCH-Message-NB.h"
#include "SRB-ToAddMod-NB-r13.h"
#include "common/utils/collection/tree.h"
//#include "extern.h"
#include "extern_NB_IoT.h"
#include "assertions.h"
......
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