lte_ue_measurements.c 55.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
/*
 * 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
 */
ghaddab's avatar
ghaddab committed
21

22 23 24 25 26 27
// this function fills the PHY_vars->PHY_measurement structure

#include "PHY/defs.h"
#include "PHY/extern.h"
#include "SCHED/defs.h"
#include "SCHED/extern.h"
28
#include "log.h"
29
#include "PHY/sse_intrin.h"
30 31 32 33 34

//#define k1 1000
#define k1 ((long long int) 1000)
#define k2 ((long long int) (1024-k1))

Cedric Roux's avatar
Cedric Roux committed
35 36
//#define DEBUG_MEAS_RRC
//#define DEBUG_MEAS_UE
37
//#define DEBUG_RANK_EST
38

39 40
int16_t cond_num_threshold = 0;

41
#ifdef USER_MODE
42
void print_shorts(char *s,short *x)
43
{
44 45 46


  printf("%s  : %d,%d,%d,%d,%d,%d,%d,%d\n",s,
47
         x[0],x[1],x[2],x[3],x[4],x[5],x[6],x[7]
48
        );
49 50

}
51
void print_ints(char *s,int *x)
52
{
53 54 55


  printf("%s  : %d,%d,%d,%d\n",s,
56
         x[0],x[1],x[2],x[3]
57
        );
58 59 60 61 62

}
#endif


63 64
int16_t get_PL(uint8_t Mod_id,uint8_t CC_id,uint8_t eNB_index)
{
65

66
  PHY_VARS_UE *ue = PHY_vars_UE_g[Mod_id][CC_id];
67
  /*
68
  int RSoffset;
69 70


71
  if (ue->frame_parms.mode1_flag == 1)
72 73 74
    RSoffset = 6;
  else
    RSoffset = 3;
75
  */
76

77
  LOG_D(PHY,"get_PL : Frame %d : rsrp %f dBm/RE (%f), eNB power %d dBm/RE\n", ue->proc.proc_rxtx[0].frame_rx,
78 79 80
        (1.0*dB_fixed_times10(ue->measurements.rsrp[eNB_index])-(10.0*ue->rx_total_gain_dB))/10.0,
        10*log10((double)ue->measurements.rsrp[eNB_index]),
        ue->frame_parms.pdsch_config_common.referenceSignalPower);
81

82 83 84 85
  return((int16_t)(((10*ue->rx_total_gain_dB) -
                    dB_fixed_times10(ue->measurements.rsrp[eNB_index])+
                    //        dB_fixed_times10(RSoffset*12*ue_g[Mod_id][CC_id]->frame_parms.N_RB_DL) +
                    (ue->frame_parms.pdsch_config_common.referenceSignalPower*10))/10));
86 87
}

88

89 90
uint8_t get_n_adj_cells (uint8_t Mod_id,uint8_t CC_id)
{
91

92
  PHY_VARS_UE *ue = PHY_vars_UE_g[Mod_id][CC_id];
93

94 95
  if (ue)
    return ue->measurements.n_adj_cells;
96
  else
97 98 99
    return 0;
}

100 101
uint32_t get_rx_total_gain_dB (uint8_t Mod_id,uint8_t CC_id)
{
102

103
  PHY_VARS_UE *ue = PHY_vars_UE_g[Mod_id][CC_id];
104

105 106
  if (ue)
    return ue->rx_total_gain_dB;
107

108
  return 0xFFFFFFFF;
109
}
110 111
uint32_t get_RSSI (uint8_t Mod_id,uint8_t CC_id)
{
112

113
  PHY_VARS_UE *ue = PHY_vars_UE_g[Mod_id][CC_id];
114

115 116
  if (ue)
    return ue->measurements.rssi;
117

118
  return 0xFFFFFFFF;
119
}
120 121 122
uint32_t get_RSRP(uint8_t Mod_id,uint8_t CC_id,uint8_t eNB_index)
{

123
  PHY_VARS_UE *ue = PHY_vars_UE_g[Mod_id][CC_id];
124

125 126
  if (ue)
    return ue->measurements.rsrp[eNB_index];
127

128
  return 0xFFFFFFFF;
129 130
}

131 132
uint32_t get_RSRQ(uint8_t Mod_id,uint8_t CC_id,uint8_t eNB_index)
{
133

134
  PHY_VARS_UE *ue = PHY_vars_UE_g[Mod_id][CC_id];
135

136 137
  if (ue)
    return ue->measurements.rsrq[eNB_index];
138

139
  return 0xFFFFFFFF;
140 141
}

142 143 144
int8_t set_RSRP_filtered(uint8_t Mod_id,uint8_t CC_id,uint8_t eNB_index,float rsrp)
{

145
  PHY_VARS_UE *ue = PHY_vars_UE_g[Mod_id][CC_id];
146

147 148
  if (ue) {
    ue->measurements.rsrp_filtered[eNB_index]=rsrp;
149 150
    return 0;
  }
151

152 153 154 155
  LOG_W(PHY,"[UE%d] could not set the rsrp\n",Mod_id);
  return -1;
}

156 157
int8_t set_RSRQ_filtered(uint8_t Mod_id,uint8_t CC_id,uint8_t eNB_index,float rsrq)
{
158

159
  PHY_VARS_UE *ue = PHY_vars_UE_g[Mod_id][CC_id];
160

161 162
  if (ue) {
    ue->measurements.rsrq_filtered[eNB_index]=rsrq;
163
    return 0;
164
  }
165

166 167
  LOG_W(PHY,"[UE%d] could not set the rsrq\n",Mod_id);
  return -1;
168

169
}
170

171
void ue_rrc_measurements(PHY_VARS_UE *ue,
172 173
    uint8_t slot,
    uint8_t abstraction_flag)
174
{
175

176
  uint8_t subframe = slot>>1;
177
  int aarx,rb;
Bilel's avatar
Bilel committed
178 179 180 181
  uint8_t pss_symb;
  uint8_t sss_symb;

  int32_t **rxdataF;
182
  int16_t *rxF,*rxF_pss,*rxF_sss;
183

184
  uint16_t Nid_cell = ue->frame_parms.Nid_cell;
185 186
  uint8_t eNB_offset,nu,l,nushift,k;
  uint16_t off;
187
  uint8_t previous_thread_id = ue->current_thread_id[subframe]==0 ? (RX_NB_TH-1):(ue->current_thread_id[subframe]-1);
188

189
   //uint8_t isPss; // indicate if this is a slot for extracting PSS
190 191 192 193 194
  //uint8_t isSss; // indicate if this is a slot for extracting SSS
  //int32_t pss_ext[4][72]; // contain the extracted 6*12 REs for mapping the PSS
  //int32_t sss_ext[4][72]; // contain the extracted 6*12 REs for mapping the SSS
  //int32_t (*xss_ext)[72]; // point to either pss_ext or sss_ext for common calculation
  //int16_t *re,*im; // real and imag part of each 32-bit xss_ext[][] value
195

196
  //LOG_I(PHY,"UE RRC MEAS Start Subframe %d Frame Type %d slot %d \n",subframe,ue->frame_parms.frame_type,slot);
197
  for (eNB_offset = 0; eNB_offset<1+ue->measurements.n_adj_cells; eNB_offset++) {
198

199
    if (eNB_offset==0) {
200
      ue->measurements.rssi = 0;
201
      //ue->measurements.n0_power_tot = 0;
202

knopp's avatar
knopp committed
203
      if (abstraction_flag == 0) {
Bilel's avatar
Bilel committed
204 205 206 207
        if ( ((ue->frame_parms.frame_type == FDD) && ((subframe == 0) || (subframe == 5))) ||
             ((ue->frame_parms.frame_type == TDD) && ((subframe == 1) || (subframe == 6)))
                )
        {  // FDD PSS/SSS, compute noise in DTX REs
208

209 210
          if (ue->frame_parms.Ncp==NORMAL) {
            for (aarx=0; aarx<ue->frame_parms.nb_antennas_rx; aarx++) {
211

Bilel's avatar
Bilel committed
212 213
          if(ue->frame_parms.frame_type == FDD)
          {
214 215
	      rxF_sss = (int16_t *)&ue->common_vars.common_vars_rx_data_per_thread[ue->current_thread_id[subframe]].rxdataF[aarx][(5*ue->frame_parms.ofdm_symbol_size)];
	      rxF_pss = (int16_t *)&ue->common_vars.common_vars_rx_data_per_thread[ue->current_thread_id[subframe]].rxdataF[aarx][(6*ue->frame_parms.ofdm_symbol_size)];
Bilel's avatar
Bilel committed
216 217 218
          }
          else
          {
219 220
              rxF_sss = (int16_t *)&ue->common_vars.common_vars_rx_data_per_thread[previous_thread_id].rxdataF[aarx][(13*ue->frame_parms.ofdm_symbol_size)];
              rxF_pss = (int16_t *)&ue->common_vars.common_vars_rx_data_per_thread[ue->current_thread_id[subframe]].rxdataF[aarx][(2*ue->frame_parms.ofdm_symbol_size)];
Bilel's avatar
Bilel committed
221
          }
222
              //-ve spectrum from SSS
223

224
              //+ve spectrum from SSS
225
              ue->measurements.n0_power[aarx] += (((int32_t)rxF_sss[2+70]*rxF_sss[2+70])+((int32_t)rxF_sss[2+69]*rxF_sss[2+69]));
226 227
              ue->measurements.n0_power[aarx] += (((int32_t)rxF_sss[2+68]*rxF_sss[2+68])+((int32_t)rxF_sss[2+67]*rxF_sss[2+67]));
              ue->measurements.n0_power[aarx] += (((int32_t)rxF_sss[2+66]*rxF_sss[2+66])+((int32_t)rxF_sss[2+65]*rxF_sss[2+65]));
228 229
              //              ue->measurements.n0_power[aarx] += (((int32_t)rxF_sss[2+64]*rxF_sss[2+64])+((int32_t)rxF_sss[2+63]*rxF_sss[2+63]));
              //              printf("sssp32 %d\n",ue->measurements.n0_power[aarx]);
230
              //+ve spectrum from PSS
231 232 233
              ue->measurements.n0_power[aarx] += (((int32_t)rxF_pss[2+70]*rxF_pss[2+70])+((int32_t)rxF_pss[2+69]*rxF_pss[2+69]));
              ue->measurements.n0_power[aarx] += (((int32_t)rxF_pss[2+68]*rxF_pss[2+68])+((int32_t)rxF_pss[2+67]*rxF_pss[2+67]));
              ue->measurements.n0_power[aarx] += (((int32_t)rxF_pss[2+66]*rxF_pss[2+66])+((int32_t)rxF_pss[2+65]*rxF_pss[2+65]));
234 235
          //              ue->measurements.n0_power[aarx] += (((int32_t)rxF_pss[2+64]*rxF_pss[2+64])+((int32_t)rxF_pss[2+63]*rxF_pss[2+63]));
          //          printf("pss32 %d\n",ue->measurements.n0_power[aarx]);              //-ve spectrum from PSS
Bilel's avatar
Bilel committed
236 237
              if(ue->frame_parms.frame_type == FDD)
              {
238 239
                  rxF_sss = (int16_t *)&ue->common_vars.common_vars_rx_data_per_thread[ue->current_thread_id[subframe]].rxdataF[aarx][(6*ue->frame_parms.ofdm_symbol_size)];
                  rxF_pss = (int16_t *)&ue->common_vars.common_vars_rx_data_per_thread[ue->current_thread_id[subframe]].rxdataF[aarx][(7*ue->frame_parms.ofdm_symbol_size)];
Bilel's avatar
Bilel committed
240 241 242
              }
              else
              {
243 244
                  rxF_sss = (int16_t *)&ue->common_vars.common_vars_rx_data_per_thread[previous_thread_id].rxdataF[aarx][(14*ue->frame_parms.ofdm_symbol_size)];
                  rxF_pss = (int16_t *)&ue->common_vars.common_vars_rx_data_per_thread[ue->current_thread_id[subframe]].rxdataF[aarx][(3*ue->frame_parms.ofdm_symbol_size)];
Bilel's avatar
Bilel committed
245
              }
246 247
          //              ue->measurements.n0_power[aarx] += (((int32_t)rxF_pss[-72]*rxF_pss[-72])+((int32_t)rxF_pss[-71]*rxF_pss[-71]));
          //          printf("pssm36 %d\n",ue->measurements.n0_power[aarx]);
248 249 250
              ue->measurements.n0_power[aarx] += (((int32_t)rxF_pss[-70]*rxF_pss[-70])+((int32_t)rxF_pss[-69]*rxF_pss[-69]));
              ue->measurements.n0_power[aarx] += (((int32_t)rxF_pss[-68]*rxF_pss[-68])+((int32_t)rxF_pss[-67]*rxF_pss[-67]));
              ue->measurements.n0_power[aarx] += (((int32_t)rxF_pss[-66]*rxF_pss[-66])+((int32_t)rxF_pss[-65]*rxF_pss[-65]));
251

Bilel's avatar
Bilel committed
252 253 254 255
              ue->measurements.n0_power[aarx] = (((int32_t)rxF_sss[-70]*rxF_sss[-70])+((int32_t)rxF_sss[-69]*rxF_sss[-69]));
              ue->measurements.n0_power[aarx] += (((int32_t)rxF_sss[-68]*rxF_sss[-68])+((int32_t)rxF_sss[-67]*rxF_sss[-67]));
              ue->measurements.n0_power[aarx] += (((int32_t)rxF_sss[-66]*rxF_sss[-66])+((int32_t)rxF_sss[-65]*rxF_sss[-65]));

256 257
          //              ue->measurements.n0_power[aarx] += (((int32_t)rxF_pss[-64]*rxF_pss[-64])+((int32_t)rxF_pss[-63]*rxF_pss[-63]));
          //          printf("pssm32 %d\n",ue->measurements.n0_power[aarx]);
258
              ue->measurements.n0_power_dB[aarx] = (unsigned short) dB_fixed(ue->measurements.n0_power[aarx]/12);
259
              ue->measurements.n0_power_tot /*+=*/ = ue->measurements.n0_power[aarx];
260
        }
261

262 263
            //LOG_I(PHY,"Subframe %d RRC UE MEAS Noise Level %d \n", subframe, ue->measurements.n0_power_tot);

264 265 266
        ue->measurements.n0_power_tot_dB = (unsigned short) dB_fixed(ue->measurements.n0_power_tot/(12*aarx));
        ue->measurements.n0_power_tot_dBm = ue->measurements.n0_power_tot_dB - ue->rx_total_gain_dB - dB_fixed(ue->frame_parms.ofdm_symbol_size);
        } else {
267
            LOG_E(PHY, "Not yet implemented: noise power calculation when prefix length = EXTENDED\n");
268
        }
269
        }
270
        else if ((ue->frame_parms.frame_type == TDD) &&
Bilel's avatar
Bilel committed
271
                 ((subframe == 1) || (subframe == 6))) {  // TDD PSS/SSS, compute noise in DTX REs // 2016-09-29 wilson fix incorrect noise power calculation
272 273


Bilel's avatar
Bilel committed
274 275
          pss_symb = 2;
          sss_symb = ue->frame_parms.symbols_per_tti-1;
276 277
          if (ue->frame_parms.Ncp==NORMAL) {
            for (aarx=0; aarx<ue->frame_parms.nb_antennas_rx; aarx++) {
278

279
                rxdataF  =  ue->common_vars.common_vars_rx_data_per_thread[(ue->current_thread_id[subframe])].rxdataF;
Bilel's avatar
Bilel committed
280 281
                rxF_pss  = (int16_t *) &rxdataF[aarx][((pss_symb*(ue->frame_parms.ofdm_symbol_size)))];

282
                rxdataF  =  ue->common_vars.common_vars_rx_data_per_thread[previous_thread_id].rxdataF;
Bilel's avatar
Bilel committed
283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306
                rxF_sss  = (int16_t *) &rxdataF[aarx][((sss_symb*(ue->frame_parms.ofdm_symbol_size)))];

                //-ve spectrum from SSS
            //          printf("slot %d: SSS DTX: %d,%d, non-DTX %d,%d\n",slot,rxF_pss[-72],rxF_pss[-71],rxF_pss[-36],rxF_pss[-35]);

            //              ue->measurements.n0_power[aarx] = (((int32_t)rxF_pss[-72]*rxF_pss[-72])+((int32_t)rxF_pss[-71]*rxF_pss[-71]));
            //          printf("sssn36 %d\n",ue->measurements.n0_power[aarx]);
                ue->measurements.n0_power[aarx] = (((int32_t)rxF_pss[-70]*rxF_pss[-70])+((int32_t)rxF_pss[-69]*rxF_pss[-69]));
                ue->measurements.n0_power[aarx] += (((int32_t)rxF_pss[-68]*rxF_pss[-68])+((int32_t)rxF_pss[-67]*rxF_pss[-67]));
                ue->measurements.n0_power[aarx] += (((int32_t)rxF_pss[-66]*rxF_pss[-66])+((int32_t)rxF_pss[-65]*rxF_pss[-65]));
            //              ue->measurements.n0_power[aarx] += (((int32_t)rxF_pss[-64]*rxF_pss[-64])+((int32_t)rxF_pss[-63]*rxF_pss[-63]));
            //          printf("sssm32 %d\n",ue->measurements.n0_power[aarx]);
                //+ve spectrum from SSS
            ue->measurements.n0_power[aarx] += (((int32_t)rxF_sss[2+70]*rxF_sss[2+70])+((int32_t)rxF_sss[2+69]*rxF_sss[2+69]));
                ue->measurements.n0_power[aarx] += (((int32_t)rxF_sss[2+68]*rxF_sss[2+68])+((int32_t)rxF_sss[2+67]*rxF_sss[2+67]));
                ue->measurements.n0_power[aarx] += (((int32_t)rxF_sss[2+66]*rxF_sss[2+66])+((int32_t)rxF_sss[2+65]*rxF_sss[2+65]));
            //          ue->measurements.n0_power[aarx] += (((int32_t)rxF_sss[2+64]*rxF_sss[2+64])+((int32_t)rxF_sss[2+63]*rxF_sss[2+63]));
            //          printf("sssp32 %d\n",ue->measurements.n0_power[aarx]);
                //+ve spectrum from PSS
                ue->measurements.n0_power[aarx] += (((int32_t)rxF_pss[2+70]*rxF_pss[2+70])+((int32_t)rxF_pss[2+69]*rxF_pss[2+69]));
                ue->measurements.n0_power[aarx] += (((int32_t)rxF_pss[2+68]*rxF_pss[2+68])+((int32_t)rxF_pss[2+67]*rxF_pss[2+67]));
                ue->measurements.n0_power[aarx] += (((int32_t)rxF_pss[2+66]*rxF_pss[2+66])+((int32_t)rxF_pss[2+65]*rxF_pss[2+65]));
            //              ue->measurements.n0_power[aarx] += (((int32_t)rxF_pss[2+64]*rxF_pss[2+64])+((int32_t)rxF_pss[2+63]*rxF_pss[2+63]));
            //          printf("pss32 %d\n",ue->measurements.n0_power[aarx]);              //-ve spectrum from PSS
307
                rxF_pss = (int16_t *)&ue->common_vars.common_vars_rx_data_per_thread[ue->current_thread_id[subframe]].rxdataF[aarx][(7*ue->frame_parms.ofdm_symbol_size)];
Bilel's avatar
Bilel committed
308 309 310 311 312 313 314 315 316
            //              ue->measurements.n0_power[aarx] += (((int32_t)rxF_pss[-72]*rxF_pss[-72])+((int32_t)rxF_pss[-71]*rxF_pss[-71]));
            //          printf("pssm36 %d\n",ue->measurements.n0_power[aarx]);
                ue->measurements.n0_power[aarx] += (((int32_t)rxF_pss[-70]*rxF_pss[-70])+((int32_t)rxF_pss[-69]*rxF_pss[-69]));
                ue->measurements.n0_power[aarx] += (((int32_t)rxF_pss[-68]*rxF_pss[-68])+((int32_t)rxF_pss[-67]*rxF_pss[-67]));
                ue->measurements.n0_power[aarx] += (((int32_t)rxF_pss[-66]*rxF_pss[-66])+((int32_t)rxF_pss[-65]*rxF_pss[-65]));
            //              ue->measurements.n0_power[aarx] += (((int32_t)rxF_pss[-64]*rxF_pss[-64])+((int32_t)rxF_pss[-63]*rxF_pss[-63]));
            //          printf("pssm32 %d\n",ue->measurements.n0_power[aarx]);
                ue->measurements.n0_power_dB[aarx] = (unsigned short) dB_fixed(ue->measurements.n0_power[aarx]/12);
                ue->measurements.n0_power_tot /*+=*/ = ue->measurements.n0_power[aarx];
317
        }
318

Bilel's avatar
Bilel committed
319 320
        ue->measurements.n0_power_tot_dB = (unsigned short) dB_fixed(ue->measurements.n0_power_tot/(12*aarx));
        ue->measurements.n0_power_tot_dBm = ue->measurements.n0_power_tot_dB - ue->rx_total_gain_dB - dB_fixed(ue->frame_parms.ofdm_symbol_size);
321

322
        //LOG_I(PHY,"Subframe %d RRC UE MEAS Noise Level %d \n", subframe, ue->measurements.n0_power_tot);
323

324 325
          }
        }
326 327
      }
    }
328
    // recompute nushift with eNB_offset corresponding to adjacent eNB on which to perform channel estimation
329
    //    printf("[PHY][UE %d] Frame %d slot %d Doing ue_rrc_measurements rsrp/rssi (Nid_cell %d, Nid2 %d, nushift %d, eNB_offset %d)\n",ue->Mod_id,ue->frame,slot,Nid_cell,Nid2,nushift,eNB_offset);
330
    if (eNB_offset > 0)
331
      Nid_cell = ue->measurements.adj_cell_id[eNB_offset-1];
332 333 334 335 336 337


    nushift =  Nid_cell%6;



338
    ue->measurements.rsrp[eNB_offset] = 0;
339 340 341


    if (abstraction_flag == 0) {
342

343 344
      // compute RSRP using symbols 0 and 4-frame_parms->Ncp

345
      for (l=0,nu=0; l<=(4-ue->frame_parms.Ncp); l+=(4-ue->frame_parms.Ncp),nu=3) {
346
        k = (nu + nushift)%6;
347
#ifdef DEBUG_MEAS_RRC
348
        LOG_I(PHY,"[UE %d] Frame %d subframe %d Doing ue_rrc_measurements rsrp/rssi (Nid_cell %d, nushift %d, eNB_offset %d, k %d, l %d)\n",ue->Mod_id,ue->proc.proc_rxtx[subframe&1].frame_rx,subframe,Nid_cell,nushift,
349
              eNB_offset,k,l);
350 351
#endif

352
        for (aarx=0; aarx<ue->frame_parms.nb_antennas_rx; aarx++) {
353
          rxF = (int16_t *)&ue->common_vars.common_vars_rx_data_per_thread[ue->current_thread_id[subframe]].rxdataF[aarx][(l*ue->frame_parms.ofdm_symbol_size)];
354
          off  = (ue->frame_parms.first_carrier_offset+k)<<1;
355

356 357
          if (l==(4-ue->frame_parms.Ncp)) {
            for (rb=0; rb<ue->frame_parms.N_RB_DL; rb++) {
358 359 360

              //    printf("rb %d, off %d, off2 %d\n",rb,off,off2);

361
              ue->measurements.rsrp[eNB_offset] += (((int32_t)(rxF[off])*rxF[off])+((int32_t)(rxF[off+1])*rxF[off+1]));
362
              //        printf("rb %d, off %d : %d\n",rb,off,((((int32_t)rxF[off])*rxF[off])+((int32_t)(rxF[off+1])*rxF[off+1])));
363 364
              //              if ((ue->frame_rx&0x3ff) == 0)
              //                printf("rb %d, off %d : %d\n",rb,off,((rxF[off]*rxF[off])+(rxF[off+1]*rxF[off+1])));
365

366

367 368
              off+=12;

369
              if (off>=(ue->frame_parms.ofdm_symbol_size<<1))
370 371
                off = (1+k)<<1;

372
              ue->measurements.rsrp[eNB_offset] += (((int32_t)(rxF[off])*rxF[off])+((int32_t)(rxF[off+1])*rxF[off+1]));
373 374
              //    printf("rb %d, off %d : %d\n",rb,off,(((int32_t)(rxF[off])*rxF[off])+((int32_t)(rxF[off+1])*rxF[off+1])));
              /*
375
                if ((ue->frame_rx&0x3ff) == 0)
376 377 378 379
                printf("rb %d, off %d : %d\n",rb,off,((rxF[off]*rxF[off])+(rxF[off+1]*rxF[off+1])));
              */
              off+=12;

380
              if (off>=(ue->frame_parms.ofdm_symbol_size<<1))
381 382 383 384 385 386 387
                off = (1+k)<<1;

            }

            /*
            if ((eNB_offset==0)&&(l==0)) {
            for (i=0;i<6;i++,off2+=4)
388 389
            ue->measurements.rssi += ((rxF[off2]*rxF[off2])+(rxF[off2+1]*rxF[off2+1]));
            if (off2==(ue->frame_parms.ofdm_symbol_size<<2))
390 391
            off2=4;
            for (i=0;i<6;i++,off2+=4)
392
            ue->measurements.rssi += ((rxF[off2]*rxF[off2])+(rxF[off2+1]*rxF[off2+1]));
393 394
            }
            */
395
            //    printf("slot %d, rb %d => rsrp %d, rssi %d\n",slot,rb,ue->measurements.rsrp[eNB_offset],ue->measurements.rssi);
396 397
          }
        }
398
      }
399

400
      // 2 RE per PRB
401 402 403
      //      ue->measurements.rsrp[eNB_offset]/=(24*ue->frame_parms.N_RB_DL);
      ue->measurements.rsrp[eNB_offset]/=(2*ue->frame_parms.N_RB_DL*ue->frame_parms.ofdm_symbol_size);
      //      LOG_I(PHY,"eNB: %d, RSRP: %d \n",eNB_offset,ue->measurements.rsrp[eNB_offset]);
404
      if (eNB_offset == 0) {
405 406 407 408
        //  ue->measurements.rssi/=(24*ue->frame_parms.N_RB_DL);
        //  ue->measurements.rssi*=rx_power_correction;
        //  ue->measurements.rssi=ue->measurements.rsrp[0]*24/2;
        ue->measurements.rssi=ue->measurements.rsrp[0]*(12*ue->frame_parms.N_RB_DL);
409
      }
410

411 412
      if (ue->measurements.rssi>0)
        ue->measurements.rsrq[eNB_offset] = 100*ue->measurements.rsrp[eNB_offset]*ue->frame_parms.N_RB_DL/ue->measurements.rssi;
413
      else
414
        ue->measurements.rsrq[eNB_offset] = -12000;
415

416
      //((200*ue->measurements.rsrq[eNB_offset]) + ((1024-200)*100*ue->measurements.rsrp[eNB_offset]*ue->frame_parms.N_RB_DL/ue->measurements.rssi))>>10;
417
    } else { // Do abstraction of RSRP and RSRQ
418
      ue->measurements.rssi = ue->measurements.rx_power_avg[0];
419
      // dummay value for the moment
420 421
      ue->measurements.rsrp[eNB_offset] = -93 ;
      ue->measurements.rsrq[eNB_offset] = 3;
422 423

    }
424

425
#ifdef DEBUG_MEAS_RRC
426

427
    //    if (slot == 0) {
428

429
      if (eNB_offset == 0)
Elena Lukashova's avatar
Elena Lukashova committed
430
       LOG_I(PHY,"[UE %d] Frame %d, subframe %d RRC Measurements => rssi %3.1f dBm (digital: %3.1f dB, gain %d), N0 %d dBm\n",ue->Mod_id,
431
              ue->proc.proc_rxtx[subframe&1].frame_rx,subframe,10*log10(ue->measurements.rssi)-ue->rx_total_gain_dB,
432 433 434
              10*log10(ue->measurements.rssi),
              ue->rx_total_gain_dB,
              ue->measurements.n0_power_tot_dBm);
435

436
      LOG_I(PHY,"[UE %d] Frame %d, subframe %d RRC Measurements (idx %d, Cell id %d) => rsrp: %3.1f dBm/RE (%d), rsrq: %3.1f dB\n",
437
            ue->Mod_id,
438
            ue->proc.proc_rxtx[subframe&1].frame_rx,subframe,eNB_offset,
439 440 441 442 443 444 445 446 447
            (eNB_offset>0) ? ue->measurements.adj_cell_id[eNB_offset-1] : ue->frame_parms.Nid_cell,
            10*log10(ue->measurements.rsrp[eNB_offset])-ue->rx_total_gain_dB,
            ue->measurements.rsrp[eNB_offset],
            (10*log10(ue->measurements.rsrq[eNB_offset])));
      //LOG_D(PHY,"RSRP_total_dB: %3.2f \n",(dB_fixed_times10(ue->measurements.rsrp[eNB_offset])/10.0)-ue->rx_total_gain_dB-dB_fixed(ue->frame_parms.N_RB_DL*12));

      //LOG_D(PHY,"RSRP_dB: %3.2f \n",(dB_fixed_times10(ue->measurements.rsrp[eNB_offset])/10.0));
      //LOG_D(PHY,"gain_loss_dB: %d \n",ue->rx_total_gain_dB);
      //LOG_D(PHY,"gain_fixed_dB: %d \n",dB_fixed(ue->frame_parms.N_RB_DL*12));
448

449
      //    }
450

451 452 453
#endif
  }

454 455
}

456
void lte_ue_measurements(PHY_VARS_UE *ue,
457 458
                         unsigned int subframe_offset,
                         unsigned char N0_symbol,
459
                         unsigned char abstraction_flag,
460
                         unsigned char rank_adaptation,
461
                         uint8_t subframe)
462 463 464
{


465
  int aarx,aatx,eNB_id=0; //,gain_offset=0;
466 467 468
  //int rx_power[NUMBER_OF_CONNECTED_eNB_MAX];
  int i;
  unsigned int limit,subband;
469
#if defined(__x86_64__) || defined(__i386__)
470
  __m128i *dl_ch0_128,*dl_ch1_128;
471 472
#elif defined(__arm__)
  int16x8_t *dl_ch0_128, *dl_ch1_128;
473
#endif
474
  int *dl_ch0,*dl_ch1;
475

476
  LTE_DL_FRAME_PARMS *frame_parms = &ue->frame_parms;
477 478
  int nb_subbands,subband_size,last_subband_size;
  int N_RB_DL = frame_parms->N_RB_DL;
479 480


481
  int rank_tm3_tm4;
482 483


484
  ue->measurements.nb_antennas_rx = frame_parms->nb_antennas_rx;
485

486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512

  switch (N_RB_DL) {
  case 6:
    nb_subbands = 6;
    subband_size = 12;
    last_subband_size = 0;
    break;

  default:
  case 25:
    nb_subbands = 7;
    subband_size = 4*12;
    last_subband_size = 12;
    break;

  case 50:
    nb_subbands = 9;
    subband_size = 6*12;
    last_subband_size = 2*12;
    break;

  case 100:
    nb_subbands = 13;
    subband_size = 8*12;
    last_subband_size = 4*12;
    break;
  }
513

514
  // signal measurements
515
  for (eNB_id=0; eNB_id<ue->n_connected_eNB; eNB_id++) {
516
    for (aarx=0; aarx<frame_parms->nb_antennas_rx; aarx++) {
Xiwen JIANG's avatar
Xiwen JIANG committed
517
      for (aatx=0; aatx<frame_parms->nb_antenna_ports_eNB; aatx++) {
518
        ue->measurements.rx_spatial_power[eNB_id][aatx][aarx] =
519
          (signal_energy_nodc(&ue->common_vars.common_vars_rx_data_per_thread[ue->current_thread_id[subframe]].dl_ch_estimates[eNB_id][(aatx<<1) + aarx][0],
520
                              (N_RB_DL*12)));
521
        //- ue->measurements.n0_power[aarx];
522

523 524
        if (ue->measurements.rx_spatial_power[eNB_id][aatx][aarx]<0)
          ue->measurements.rx_spatial_power[eNB_id][aatx][aarx] = 0; //ue->measurements.n0_power[aarx];
525

526
        ue->measurements.rx_spatial_power_dB[eNB_id][aatx][aarx] = (unsigned short) dB_fixed(ue->measurements.rx_spatial_power[eNB_id][aatx][aarx]);
527 528

        if (aatx==0)
529
          ue->measurements.rx_power[eNB_id][aarx] = ue->measurements.rx_spatial_power[eNB_id][aatx][aarx];
530
        else
531
          ue->measurements.rx_power[eNB_id][aarx] += ue->measurements.rx_spatial_power[eNB_id][aatx][aarx];
532 533
      } //aatx

534
      ue->measurements.rx_power_dB[eNB_id][aarx] = (unsigned short) dB_fixed(ue->measurements.rx_power[eNB_id][aarx]);
535 536

      if (aarx==0)
537
        ue->measurements.rx_power_tot[eNB_id] = ue->measurements.rx_power[eNB_id][aarx];
538
      else
539
        ue->measurements.rx_power_tot[eNB_id] += ue->measurements.rx_power[eNB_id][aarx];
540 541
    } //aarx

542
    ue->measurements.rx_power_tot_dB[eNB_id] = (unsigned short) dB_fixed(ue->measurements.rx_power_tot[eNB_id]);
543 544 545

  } //eNB_id

546
  eNB_id=0;
547
  if (ue->transmission_mode[0]==4 || ue->transmission_mode[0]==3){
548 549 550 551 552 553 554 555
    if (rank_adaptation == 1)
      rank_tm3_tm4 = rank_estimation_tm3_tm4(&ue->common_vars.common_vars_rx_data_per_thread[subframe&0x1].dl_ch_estimates[eNB_id][0][4],
                                             &ue->common_vars.common_vars_rx_data_per_thread[subframe&0x1].dl_ch_estimates[eNB_id][2][4],
                                             &ue->common_vars.common_vars_rx_data_per_thread[subframe&0x1].dl_ch_estimates[eNB_id][1][4],
                                             &ue->common_vars.common_vars_rx_data_per_thread[subframe&0x1].dl_ch_estimates[eNB_id][3][4],
                                             N_RB_DL);
    else
      rank_tm3_tm4=1;
556
#ifdef DEBUG_RANK_EST
Elena Lukashova's avatar
Elena Lukashova committed
557
  printf("rank tm3 or tm4 %d\n", rank_tm3_tm4);
558
#endif
559
  }
560

561 562 563 564 565 566 567
  if (ue->transmission_mode[eNB_id]!=4 && ue->transmission_mode[eNB_id]!=3)
    ue->measurements.rank[eNB_id] = 0;
  else
    ue->measurements.rank[eNB_id] = rank_tm3_tm4;
  //  printf ("tx mode %d\n", ue->transmission_mode[eNB_id]);
  //  printf ("rank %d\n", ue->PHY_measurements.rank[eNB_id]);

568
  // filter to remove jitter
569 570 571 572 573 574
  if (ue->init_averaging == 0) {
    for (eNB_id = 0; eNB_id < ue->n_connected_eNB; eNB_id++)
      ue->measurements.rx_power_avg[eNB_id] = (int)
          (((k1*((long long int)(ue->measurements.rx_power_avg[eNB_id]))) +
            (k2*((long long int)(ue->measurements.rx_power_tot[eNB_id]))))>>10);

575
    //LOG_I(PHY,"Noise Power Computation: k1 %d k2 %d n0 avg %d n0 tot %d\n", k1, k2, ue->measurements.n0_power_avg,
576
    //    ue->measurements.n0_power_tot);
577 578 579
    ue->measurements.n0_power_avg = (int)
        (((k1*((long long int) (ue->measurements.n0_power_avg))) +
          (k2*((long long int) (ue->measurements.n0_power_tot))))>>10);
580
  } else {
581 582
    for (eNB_id = 0; eNB_id < ue->n_connected_eNB; eNB_id++)
      ue->measurements.rx_power_avg[eNB_id] = ue->measurements.rx_power_tot[eNB_id];
583

584 585
    ue->measurements.n0_power_avg = ue->measurements.n0_power_tot;
    ue->init_averaging = 0;
586 587
  }

588 589 590 591 592
  for (eNB_id = 0; eNB_id < ue->n_connected_eNB; eNB_id++) {
    ue->measurements.rx_power_avg_dB[eNB_id] = dB_fixed( ue->measurements.rx_power_avg[eNB_id]);
    ue->measurements.wideband_cqi_tot[eNB_id] = dB_fixed2(ue->measurements.rx_power_tot[eNB_id],ue->measurements.n0_power_tot);
    ue->measurements.wideband_cqi_avg[eNB_id] = dB_fixed2(ue->measurements.rx_power_avg[eNB_id],ue->measurements.n0_power_avg);
    ue->measurements.rx_rssi_dBm[eNB_id] = ue->measurements.rx_power_avg_dB[eNB_id] - ue->rx_total_gain_dB;
593
#ifdef DEBUG_MEAS_UE
Bilel's avatar
Bilel committed
594
      LOG_I(PHY,"[eNB %d] Subframe %d, RSSI %d dBm, RSSI (digital) %d dB, WBandCQI %d dB, rxPwrAvg %d, n0PwrAvg %d\n",
595
            eNB_id,
596
            subframe,
597 598 599 600
            ue->measurements.rx_rssi_dBm[eNB_id],
            ue->measurements.rx_power_avg_dB[eNB_id],
            ue->measurements.wideband_cqi_avg[eNB_id],
            ue->measurements.rx_power_avg[eNB_id],
601
            ue->measurements.n0_power_tot);
knopp's avatar
knopp committed
602
#endif
603 604
  }

605
  ue->measurements.n0_power_avg_dB = dB_fixed( ue->measurements.n0_power_avg);
606

607
  for (eNB_id = 0; eNB_id < ue->n_connected_eNB; eNB_id++) {
608 609 610 611
    if (frame_parms->mode1_flag==0) {
      // cqi/pmi information

      for (aarx=0; aarx<frame_parms->nb_antennas_rx; aarx++) {
612 613
        dl_ch0    = &ue->common_vars.common_vars_rx_data_per_thread[ue->current_thread_id[subframe]].dl_ch_estimates[eNB_id][aarx][4];
        dl_ch1    = &ue->common_vars.common_vars_rx_data_per_thread[ue->current_thread_id[subframe]].dl_ch_estimates[eNB_id][2+aarx][4];
614 615 616 617 618

        for (subband=0; subband<nb_subbands; subband++) {

          // cqi
          if (aarx==0)
619
            ue->measurements.subband_cqi_tot[eNB_id][subband]=0;
620 621 622 623 624

          if ((subband<(nb_subbands-1))||(N_RB_DL==6)) {
            /*for (i=0;i<48;i++)
            msg("subband %d (%d) : %d,%d\n",subband,i,((short *)dl_ch0)[2*i],((short *)dl_ch0)[1+(2*i)]);
            */
625
            ue->measurements.subband_cqi[eNB_id][aarx][subband] =
626 627
              (signal_energy_nodc(dl_ch0,subband_size) + signal_energy_nodc(dl_ch1,subband_size));

628 629
            if ( ue->measurements.subband_cqi[eNB_id][aarx][subband] < 0)
              ue->measurements.subband_cqi[eNB_id][aarx][subband]=0;
630 631 632

            /*
            else
633
            ue->measurements.subband_cqi[eNB_id][aarx][subband]-=ue->measurements.n0_power[aarx];
634 635
            */

636 637 638
            ue->measurements.subband_cqi_tot[eNB_id][subband] += ue->measurements.subband_cqi[eNB_id][aarx][subband];
            ue->measurements.subband_cqi_dB[eNB_id][aarx][subband] = dB_fixed2(ue->measurements.subband_cqi[eNB_id][aarx][subband],
                ue->measurements.n0_power[aarx]);
639 640 641
          } else { // this is for the last subband which is smaller in size
            //      for (i=0;i<12;i++)
            //        printf("subband %d (%d) : %d,%d\n",subband,i,((short *)dl_ch0)[2*i],((short *)dl_ch0)[1+(2*i)]);
642 643 644 645 646
            ue->measurements.subband_cqi[eNB_id][aarx][subband] = (signal_energy_nodc(dl_ch0,last_subband_size) +
                signal_energy_nodc(dl_ch1,last_subband_size)); // - ue->measurements.n0_power[aarx];
            ue->measurements.subband_cqi_tot[eNB_id][subband] += ue->measurements.subband_cqi[eNB_id][aarx][subband];
            ue->measurements.subband_cqi_dB[eNB_id][aarx][subband] = dB_fixed2(ue->measurements.subband_cqi[eNB_id][aarx][subband],
                ue->measurements.n0_power[aarx]);
647 648 649 650
          }

          dl_ch1+=subband_size;
          dl_ch0+=subband_size;
651
          //    msg("subband_cqi[%d][%d][%d] => %d (%d dB)\n",eNB_id,aarx,subband,ue->measurements.subband_cqi[eNB_id][aarx][subband],ue->measurements.subband_cqi_dB[eNB_id][aarx][subband]);
652 653 654 655 656
        }

      }

      for (subband=0; subband<nb_subbands; subband++) {
657 658
        ue->measurements.subband_cqi_tot_dB[eNB_id][subband] = dB_fixed2(ue->measurements.subband_cqi_tot[eNB_id][subband],ue->measurements.n0_power_tot);
        //    msg("subband_cqi_tot[%d][%d] => %d dB (n0 %d)\n",eNB_id,subband,ue->measurements.subband_cqi_tot_dB[eNB_id][subband],ue->measurements.n0_power_tot);
659 660 661
      }

      for (aarx=0; aarx<frame_parms->nb_antennas_rx; aarx++) {
662
        //printf("aarx=%d", aarx);
663
        // skip the first 4 RE due to interpolation filter length of 5 (not possible to skip 5 due to 128i alignment, must be multiple of 128bit)
664 665

#if defined(__x86_64__) || defined(__i386__)
666
       __m128i pmi128_re,pmi128_im,mmtmpPMI0,mmtmpPMI1 /* ,mmtmpPMI2,mmtmpPMI3 */ ;
667

668 669
        dl_ch0_128    = (__m128i *)&ue->common_vars.common_vars_rx_data_per_thread[ue->current_thread_id[subframe]].dl_ch_estimates[eNB_id][aarx][4];
        dl_ch1_128    = (__m128i *)&ue->common_vars.common_vars_rx_data_per_thread[ue->current_thread_id[subframe]].dl_ch_estimates[eNB_id][2+aarx][4];
670 671
#elif defined(__arm__)
        int32x4_t pmi128_re,pmi128_im,mmtmpPMI0,mmtmpPMI1,mmtmpPMI0b,mmtmpPMI1b;
672

673 674
        dl_ch0_128    = (int16x8_t *)&ue->common_vars.common_vars_rx_data_per_thread[ue->current_thread_id[subframe]].dl_ch_estimates[eNB_id][aarx][4];
        dl_ch1_128    = (int16x8_t *)&ue->common_vars.common_vars_rx_data_per_thread[ue->current_thread_id[subframe]].dl_ch_estimates[eNB_id][2+aarx][4];
675 676

#endif
677 678 679 680
        for (subband=0; subband<nb_subbands; subband++) {


          // pmi
681
#if defined(__x86_64__) || defined(__i386__)
682

683
          pmi128_re = _mm_xor_si128(pmi128_re,pmi128_re);
Elena Lukashova's avatar
Elena Lukashova committed
684
          pmi128_im = _mm_xor_si128(pmi128_im,pmi128_im);
685
#elif defined(__arm__)
Elena Lukashova's avatar
Elena Lukashova committed
686

687
          pmi128_re = vdupq_n_s32(0);
688
          pmi128_im = vdupq_n_s32(0);
689
#endif
690 691 692 693 694 695 696 697
          // limit is the number of groups of 4 REs in a subband (12 = 4 RBs, 3 = 1 RB)
          // for 5 MHz channelization, there are 7 subbands, 6 of size 4 RBs and 1 of size 1 RB
          if ((N_RB_DL==6) || (subband<(nb_subbands-1)))
            limit = subband_size>>2;
          else
            limit = last_subband_size>>2;

          for (i=0; i<limit; i++) {
698 699

#if defined(__x86_64__) || defined(__i386__)
700
              mmtmpPMI0 = _mm_xor_si128(mmtmpPMI0,mmtmpPMI0);
701
              mmtmpPMI1 = _mm_xor_si128(mmtmpPMI1,mmtmpPMI1);
702 703 704

            // For each RE in subband perform ch0 * conj(ch1)
            // multiply by conjugated channel
705 706
                //  print_ints("ch0",&dl_ch0_128[0]);
                //  print_ints("ch1",&dl_ch1_128[0]);
Elena Lukashova's avatar
Elena Lukashova committed
707

708 709
            mmtmpPMI0 = _mm_madd_epi16(dl_ch0_128[0],dl_ch1_128[0]);
                 //  print_ints("re",&mmtmpPMI0);
Elena Lukashova's avatar
Elena Lukashova committed
710 711
            mmtmpPMI1 = _mm_shufflelo_epi16(dl_ch1_128[0],_MM_SHUFFLE(2,3,0,1));
              //  print_ints("_mm_shufflelo_epi16",&mmtmpPMI1);
712
            mmtmpPMI1 = _mm_shufflehi_epi16(mmtmpPMI1,_MM_SHUFFLE(2,3,0,1));
713
                //  print_ints("_mm_shufflehi_epi16",&mmtmpPMI1);
714
            mmtmpPMI1 = _mm_sign_epi16(mmtmpPMI1,*(__m128i*)&conjugate[0]);
715
               //  print_ints("_mm_sign_epi16",&mmtmpPMI1);
716
            mmtmpPMI1 = _mm_madd_epi16(mmtmpPMI1,dl_ch0_128[0]);
717
               //   print_ints("mm_madd_epi16",&mmtmpPMI1);
718 719
            // mmtmpPMI1 contains imag part of 4 consecutive outputs (32-bit)
            pmi128_re = _mm_add_epi32(pmi128_re,mmtmpPMI0);
720
             //   print_ints(" pmi128_re 0",&pmi128_re);
721
            pmi128_im = _mm_add_epi32(pmi128_im,mmtmpPMI1);
722
               //   print_ints(" pmi128_im 0 ",&pmi128_im);
723

724
          /*  mmtmpPMI0 = _mm_xor_si128(mmtmpPMI0,mmtmpPMI0);
725
            mmtmpPMI1 = _mm_xor_si128(mmtmpPMI1,mmtmpPMI1);
726

727 728
            mmtmpPMI0 = _mm_madd_epi16(dl_ch0_128[1],dl_ch1_128[1]);
                 //  print_ints("re",&mmtmpPMI0);
729 730 731
            mmtmpPMI1 = _mm_shufflelo_epi16(dl_ch1_128[1],_MM_SHUFFLE(2,3,0,1));
              //  print_ints("_mm_shufflelo_epi16",&mmtmpPMI1);
            mmtmpPMI1 = _mm_shufflehi_epi16(mmtmpPMI1,_MM_SHUFFLE(2,3,0,1));
732
                //  print_ints("_mm_shufflehi_epi16",&mmtmpPMI1);
733
            mmtmpPMI1 = _mm_sign_epi16(mmtmpPMI1,*(__m128i*)&conjugate);
734
               //  print_ints("_mm_sign_epi16",&mmtmpPMI1);
735
            mmtmpPMI1 = _mm_madd_epi16(mmtmpPMI1,dl_ch0_128[1]);
736
               //   print_ints("mm_madd_epi16",&mmtmpPMI1);
737 738
            // mmtmpPMI1 contains imag part of 4 consecutive outputs (32-bit)
            pmi128_re = _mm_add_epi32(pmi128_re,mmtmpPMI0);
739
                //  print_ints(" pmi128_re 1",&pmi128_re);
740
            pmi128_im = _mm_add_epi32(pmi128_im,mmtmpPMI1);
741
            //print_ints(" pmi128_im 1 ",&pmi128_im);*/
742

743
#elif defined(__arm__)
Elena Lukashova's avatar
Elena Lukashova committed
744

745 746 747 748 749 750 751 752 753
            mmtmpPMI0 = vmull_s16(((int16x4_t*)dl_ch0_128)[0], ((int16x4_t*)dl_ch1_128)[0]);
            mmtmpPMI1 = vmull_s16(((int16x4_t*)dl_ch0_128)[1], ((int16x4_t*)dl_ch1_128)[1]);
            pmi128_re = vqaddq_s32(pmi128_re,vcombine_s32(vpadd_s32(vget_low_s32(mmtmpPMI0),vget_high_s32(mmtmpPMI0)),vpadd_s32(vget_low_s32(mmtmpPMI1),vget_high_s32(mmtmpPMI1))));

            mmtmpPMI0b = vmull_s16(vrev32_s16(vmul_s16(((int16x4_t*)dl_ch0_128)[0],*(int16x4_t*)conjugate)), ((int16x4_t*)dl_ch1_128)[0]);
            mmtmpPMI1b = vmull_s16(vrev32_s16(vmul_s16(((int16x4_t*)dl_ch0_128)[1],*(int16x4_t*)conjugate)), ((int16x4_t*)dl_ch1_128)[1]);
            pmi128_im = vqaddq_s32(pmi128_im,vcombine_s32(vpadd_s32(vget_low_s32(mmtmpPMI0b),vget_high_s32(mmtmpPMI0b)),vpadd_s32(vget_low_s32(mmtmpPMI1b),vget_high_s32(mmtmpPMI1b))));

#endif
754 755 756 757
            dl_ch0_128++;
            dl_ch1_128++;
          }

758 759 760 761
          ue->measurements.subband_pmi_re[eNB_id][subband][aarx] = (((int *)&pmi128_re)[0] + ((int *)&pmi128_re)[1] + ((int *)&pmi128_re)[2] + ((int *)&pmi128_re)[3])>>2;
          ue->measurements.subband_pmi_im[eNB_id][subband][aarx] = (((int *)&pmi128_im)[0] + ((int *)&pmi128_im)[1] + ((int *)&pmi128_im)[2] + ((int *)&pmi128_im)[3])>>2;
          ue->measurements.wideband_pmi_re[eNB_id][aarx] += ue->measurements.subband_pmi_re[eNB_id][subband][aarx];
          ue->measurements.wideband_pmi_im[eNB_id][aarx] += ue->measurements.subband_pmi_im[eNB_id][subband][aarx];
762 763 764
        } // subband loop
      } // rx antenna loop
    }  // if frame_parms->mode1_flag == 0
765
    else {
766 767
      // cqi information only for mode 1
      for (aarx=0; aarx<frame_parms->nb_antennas_rx; aarx++) {
768
        dl_ch0    = &ue->common_vars.common_vars_rx_data_per_thread[ue->current_thread_id[subframe]].dl_ch_estimates[eNB_id][aarx][4];
769 770 771 772 773

        for (subband=0; subband<7; subband++) {

          // cqi
          if (aarx==0)
774
            ue->measurements.subband_cqi_tot[eNB_id][subband]=0;
775 776 777 778

          if (subband<6) {
            //      for (i=0;i<48;i++)
            //        printf("subband %d (%d) : %d,%d\n",subband,i,((short *)dl_ch0)[2*i],((short *)dl_ch0)[1+(2*i)]);
779 780
            ue->measurements.subband_cqi[eNB_id][aarx][subband] =
              (signal_energy_nodc(dl_ch0,48) ) - ue->measurements.n0_power[aarx];
781

782 783 784
            ue->measurements.subband_cqi_tot[eNB_id][subband] += ue->measurements.subband_cqi[eNB_id][aarx][subband];
            ue->measurements.subband_cqi_dB[eNB_id][aarx][subband] = dB_fixed2(ue->measurements.subband_cqi[eNB_id][aarx][subband],
                ue->measurements.n0_power[aarx]);
785 786 787
          } else {
            //      for (i=0;i<12;i++)
            //        printf("subband %d (%d) : %d,%d\n",subband,i,((short *)dl_ch0)[2*i],((short *)dl_ch0)[1+(2*i)]);
788 789 790 791
            ue->measurements.subband_cqi[eNB_id][aarx][subband] = (signal_energy_nodc(dl_ch0,12) ) - ue->measurements.n0_power[aarx];
            ue->measurements.subband_cqi_tot[eNB_id][subband] += ue->measurements.subband_cqi[eNB_id][aarx][subband];
            ue->measurements.subband_cqi_dB[eNB_id][aarx][subband] = dB_fixed2(ue->measurements.subband_cqi[eNB_id][aarx][subband],
                ue->measurements.n0_power[aarx]);
792 793 794
          }

          dl_ch1+=48;
795
          //    msg("subband_cqi[%d][%d][%d] => %d (%d dB)\n",eNB_id,aarx,subband,ue->measurements.subband_cqi[eNB_id][aarx][subband],ue->measurements.subband_cqi_dB[eNB_id][aarx][subband]);
796
        }
797 798
      }

799
      for (subband=0; subband<nb_subbands; subband++) {
800
        ue->measurements.subband_cqi_tot_dB[eNB_id][subband] = dB_fixed2(ue->measurements.subband_cqi_tot[eNB_id][subband],ue->measurements.n0_power_tot);
801 802 803
      }
    }

804
    //ue->measurements.rank[eNB_id] = 0;
805

806
    for (i=0; i<nb_subbands; i++) {
807
      ue->measurements.selected_rx_antennas[eNB_id][i] = 0;
808

809
      if (frame_parms->nb_antennas_rx>1) {
810 811
        if (ue->measurements.subband_cqi_dB[eNB_id][0][i] >= ue->measurements.subband_cqi_dB[eNB_id][1][i])
          ue->measurements.selected_rx_antennas[eNB_id][i] = 0;
812
        else
813
          ue->measurements.selected_rx_antennas[eNB_id][i] = 1;
814
      } else
815
        ue->measurements.selected_rx_antennas[eNB_id][i] = 0;
816 817
    }

818
    // if(eNB_id==0)
819
    // printf("in lte_ue_measurements: selected rx_antenna[eNB_id==0]:%u\n", ue->measurements.selected_rx_antennas[eNB_id][i]);
820
  }  // eNB_id loop
821

822
#if defined(__x86_64__) || defined(__i386__)
823 824
  _mm_empty();
  _m_empty();
825
#endif
826
}
827 828


829
void lte_ue_measurements_emul(PHY_VARS_UE *ue,uint8_t subframe,uint8_t eNB_id)
830
{
831

832
  msg("[PHY] EMUL UE lte_ue_measurements_emul subframe %d, eNB_id %d\n",subframe,eNB_id);
833
}
834

835

836 837 838 839
uint8_t rank_estimation_tm3_tm4 (int *dl_ch_estimates_00, // please respect the order of channel estimates
                                 int *dl_ch_estimates_01,
                                 int *dl_ch_estimates_10,
                                 int *dl_ch_estimates_11,
Elena Lukashova's avatar
Elena Lukashova committed
840 841
                                 unsigned short nb_rb)
{
842 843

  int i=0;
844
  int rank=0;
845 846 847 848 849 850 851 852 853
  int N_RB=nb_rb;
  int *ch00_rank, *ch01_rank, *ch10_rank, *ch11_rank;

  int32_t shift;
  int avg_0[2];
  int avg_1[2];

  int count=0;

854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877
  /* we need at least alignment to 16 bytes, let's put 32 to be sure
   * (maybe not necessary but doesn't hurt)
   */
  int32_t conjch00_ch01[12*N_RB] __attribute__((aligned(32)));
  int32_t conjch01_ch00[12*N_RB] __attribute__((aligned(32)));
  int32_t conjch10_ch11[12*N_RB] __attribute__((aligned(32)));
  int32_t conjch11_ch10[12*N_RB] __attribute__((aligned(32)));
  int32_t conjch00_ch00[12*N_RB] __attribute__((aligned(32)));
  int32_t conjch01_ch01[12*N_RB] __attribute__((aligned(32)));
  int32_t conjch10_ch10[12*N_RB] __attribute__((aligned(32)));
  int32_t conjch11_ch11[12*N_RB] __attribute__((aligned(32)));
  int32_t af_mf_00[12*N_RB] __attribute__((aligned(32)));
  int32_t af_mf_00_sq[12*N_RB] __attribute__((aligned(32)));
  int32_t af_mf_01_sq[12*N_RB] __attribute__((aligned(32)));
  int32_t af_mf_10_sq[12*N_RB] __attribute__((aligned(32)));
  int32_t af_mf_11_sq[12*N_RB] __attribute__((aligned(32)));
  int32_t af_mf_01[12*N_RB] __attribute__((aligned(32)));
  int32_t af_mf_10[12*N_RB] __attribute__((aligned(32)));
  int32_t af_mf_11[12*N_RB] __attribute__((aligned(32)));
  int32_t determ_fin[12*N_RB] __attribute__((aligned(32)));
  int32_t denum_db[12*N_RB] __attribute__((aligned(32)));
  int32_t numer_fin[12*N_RB] __attribute__((aligned(32)));
  int32_t numer_db[12*N_RB] __attribute__((aligned(32)));
  int32_t cond_db[12*N_RB] __attribute__((aligned(32)));
878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036

  ch00_rank = dl_ch_estimates_00;
  ch01_rank = dl_ch_estimates_01;
  ch10_rank = dl_ch_estimates_10;
  ch11_rank = dl_ch_estimates_11;

  dlsch_channel_level_TM34_meas(ch00_rank,
                                ch01_rank,
                                ch10_rank,
                                ch11_rank,
                                avg_0,
                                avg_1,
                                N_RB);

  avg_0[0] = (log2_approx(avg_0[0])/2);
  shift = cmax(avg_0[0],0);

#ifdef DEBUG_RANK_EST
  printf("\n shift %d \n" , shift);
  printf("\n conj(ch00)ch01 \n");
#endif

  conjch0_mult_ch1(ch00_rank,
                   ch01_rank,
                   conjch00_ch01,
                   N_RB,
                   shift); // this is an arbitrary shift to avoid overflow. can be changed.

#ifdef DEBUG_RANK_EST
  printf("\n conj(ch01)ch00 \n");
#endif

  conjch0_mult_ch1(ch01_rank,
                   ch00_rank,
                   conjch01_ch00,
                   N_RB,
                   shift);

#ifdef DEBUG_RANK_EST
  printf("\n conj(ch10)ch11 \n");
#endif


  conjch0_mult_ch1(ch10_rank,
                   ch11_rank,
                   conjch10_ch11,
                   N_RB,
                   shift);

#ifdef DEBUG_RANK_EST
  printf("\n conj(ch11)ch10 \n");
#endif

  conjch0_mult_ch1(ch11_rank,
                   ch10_rank,
                   conjch11_ch10,
                   N_RB,
                   shift);

#ifdef DEBUG_RANK_EST
  printf("\n conj(ch00)ch00 \n");
#endif

  conjch0_mult_ch1(ch00_rank,
                   ch00_rank,
                   conjch00_ch00,
                   N_RB,
                   shift);

#ifdef DEBUG_RANK_EST
  printf("\n conj(ch01)ch01 \n");
#endif

  conjch0_mult_ch1(ch01_rank,
                   ch01_rank,
                   conjch01_ch01,
                   N_RB,
                   shift);

#ifdef DEBUG_RANK_EST
  printf("\n conj(ch10)ch10 \n");
#endif

  conjch0_mult_ch1(ch10_rank,
                   ch10_rank,
                   conjch10_ch10,
                   N_RB,
                   shift);
#ifdef DEBUG_RANK_EST
  printf("\n conj(ch11)ch11 \n");
#endif

  conjch0_mult_ch1(ch11_rank,
                   ch11_rank,
                   conjch11_ch11,
                   N_RB,
                   shift);

  construct_HhH_elements(conjch00_ch00,
                         conjch01_ch01,
                         conjch11_ch11,
                         conjch10_ch10,
                         conjch00_ch01,
                         conjch01_ch00,
                         conjch10_ch11,
                         conjch11_ch10,
                         af_mf_00,
                         af_mf_01,
                         af_mf_10,
                         af_mf_11,
                         N_RB);
#ifdef DEBUG_RANK_EST
  printf("\n |HhH00|^2 \n");
#endif

  squared_matrix_element(af_mf_00,
                         af_mf_00_sq,
                         N_RB);

#ifdef DEBUG_RANK_EST
  printf("\n |HhH01|^2 \n");
#endif

  squared_matrix_element(af_mf_01,
                         af_mf_01_sq,
                         N_RB);

#ifdef DEBUG_RANK_EST
  printf("\n |HhH10|^2 \n");
#endif

  squared_matrix_element(af_mf_10,
                         af_mf_10_sq,
                         N_RB);

#ifdef DEBUG_RANK_EST
  printf("\n |HhH11|^2 \n");
#endif

  squared_matrix_element(af_mf_11,
                         af_mf_11_sq,
                         N_RB);

  det_HhH(af_mf_00,
          af_mf_01,
          af_mf_10,
          af_mf_11,
          determ_fin,
          N_RB);

  numer(af_mf_00_sq,
        af_mf_01_sq,
        af_mf_10_sq,
        af_mf_11_sq,
        numer_fin,
        N_RB);

  for (i=1; i<12*N_RB; i++)
  {
1037 1038
    denum_db[i]=dB_fixed(determ_fin[i]);
    numer_db[i]=dB_fixed(numer_fin[i]);
1039
    cond_db[i]=(numer_db[i]-denum_db[i]);
1040
    if (cond_db[i] < cond_num_threshold)
1041 1042
      count++;
#ifdef DEBUG_RANK_EST
1043
    printf("cond_num_threshold =%d \n", cond_num_threshold);
1044 1045 1046 1047 1048 1049 1050 1051
    printf("i %d  numer_db[i] = %d \n", i, numer_db[i]);
    printf("i %d  denum_db[i] = %d \n", i, denum_db[i]);
    printf("i %d  cond_db[i] =  %d \n", i, cond_db[i]);
    printf("i %d counter = %d \n", i, count);
#endif
  }

  if (count >= 6*N_RB) // conditional number is lower 10dB in half on more Res Blocks
1052
    rank=1;
1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137

#ifdef DEBUG_RANK_EST
    printf(" rank = %d \n", rank);
#endif
   return(rank);
}

void conjch0_mult_ch1(int *ch0,
                      int *ch1,
                      int32_t *ch0conj_ch1,
                      unsigned short nb_rb,
                      unsigned char output_shift0)
{
  //This function is used to compute multiplications in Hhermitian * H matrix
  unsigned short rb;
  __m128i *dl_ch0_128,*dl_ch1_128, *ch0conj_ch1_128, mmtmpD0,mmtmpD1,mmtmpD2,mmtmpD3;

  dl_ch0_128 = (__m128i *)ch0;
  dl_ch1_128 = (__m128i *)ch1;

  ch0conj_ch1_128 = (__m128i *)ch0conj_ch1;

  for (rb=0; rb<3*nb_rb; rb++) {

    mmtmpD0 = _mm_madd_epi16(dl_ch0_128[0],dl_ch1_128[0]);
    mmtmpD1 = _mm_shufflelo_epi16(dl_ch0_128[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[0]);
    mmtmpD1 = _mm_madd_epi16(mmtmpD1,dl_ch1_128[0]);
    mmtmpD0 = _mm_srai_epi32(mmtmpD0,output_shift0);
    mmtmpD1 = _mm_srai_epi32(mmtmpD1,output_shift0);
    mmtmpD2 = _mm_unpacklo_epi32(mmtmpD0,mmtmpD1);
    mmtmpD3 = _mm_unpackhi_epi32(mmtmpD0,mmtmpD1);

    ch0conj_ch1_128[0] = _mm_packs_epi32(mmtmpD2,mmtmpD3);

#ifdef DEBUG_RANK_EST
    printf("\n Computing conjugates \n");
    print_shorts("ch0:",(int16_t*)&dl_ch0_128[0]);
    print_shorts("ch1:",(int16_t*)&dl_ch1_128[0]);
    print_shorts("pack:",(int16_t*)&ch0conj_ch1_128[0]);
#endif

    dl_ch0_128+=1;
    dl_ch1_128+=1;
    ch0conj_ch1_128+=1;
  }
  _mm_empty();
  _m_empty();
}

void construct_HhH_elements(int *ch0conj_ch0, //00_00
                            int *ch1conj_ch1,//01_01
                            int *ch2conj_ch2,//11_11
                            int *ch3conj_ch3,//10_10
                            int *ch0conj_ch1,//00_01
                            int *ch1conj_ch0,//01_00
                            int *ch2conj_ch3,//10_11
                            int *ch3conj_ch2,//11_10
                            int32_t *after_mf_00,
                            int32_t *after_mf_01,
                            int32_t *after_mf_10,
                            int32_t *after_mf_11,
                            unsigned short nb_rb)
{
  unsigned short rb;
  __m128i *ch0conj_ch0_128, *ch1conj_ch1_128, *ch2conj_ch2_128, *ch3conj_ch3_128;
  __m128i *ch0conj_ch1_128, *ch1conj_ch0_128, *ch2conj_ch3_128, *ch3conj_ch2_128;
  __m128i *after_mf_00_128, *after_mf_01_128, *after_mf_10_128, *after_mf_11_128;

  ch0conj_ch0_128 = (__m128i *)ch0conj_ch0;
  ch1conj_ch1_128 = (__m128i *)ch1conj_ch1;
  ch2conj_ch2_128 = (__m128i *)ch2conj_ch2;
  ch3conj_ch3_128 = (__m128i *)ch3conj_ch3;
  ch0conj_ch1_128 = (__m128i *)ch0conj_ch1;
  ch1conj_ch0_128 = (__m128i *)ch1conj_ch0;
  ch2conj_ch3_128 = (__m128i *)ch2conj_ch3;
  ch3conj_ch2_128 = (__m128i *)ch3conj_ch2;
  after_mf_00_128 = (__m128i *)after_mf_00;
  after_mf_01_128 = (__m128i *)after_mf_01;
  after_mf_10_128 = (__m128i *)after_mf_10;
  after_mf_11_128 = (__m128i *)after_mf_11;

  for (rb=0; rb<3*nb_rb; rb++) {

1138
    after_mf_00_128[0] =_mm_adds_epi16(ch0conj_ch0_128[0],ch3conj_ch3_128[0]);// _mm_adds_epi32(ch0conj_ch0_128[0], ch3conj_ch3_128[0]); //00_00 + 10_10
1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 124