lte_ue_measurements.c 54.8 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

188 189 190 191 192 193
  //uint8_t isPss; // indicate if this is a slot for extracting PSS
  //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
194

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

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

knopp's avatar
knopp committed
202
      if (abstraction_flag == 0) {
Bilel's avatar
Bilel committed
203 204 205 206
        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
207

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

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

223
              //+ve spectrum from SSS
224
              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]));
225 226
              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]));
227 228
              //              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]);
229
              //+ve spectrum from PSS
230 231 232
              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]));
233 234
          //              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
235 236
              if(ue->frame_parms.frame_type == FDD)
              {
237 238
                  rxF_sss = (int16_t *)&ue->common_vars.common_vars_rx_data_per_thread[subframe%RX_NB_TH].rxdataF[aarx][(6*ue->frame_parms.ofdm_symbol_size)];
                  rxF_pss = (int16_t *)&ue->common_vars.common_vars_rx_data_per_thread[subframe%RX_NB_TH].rxdataF[aarx][(7*ue->frame_parms.ofdm_symbol_size)];
Bilel's avatar
Bilel committed
239 240 241
              }
              else
              {
242
                  rxF_sss = (int16_t *)&ue->common_vars.common_vars_rx_data_per_thread[(subframe-1)%RX_NB_TH].rxdataF[aarx][(14*ue->frame_parms.ofdm_symbol_size)];
243
                  rxF_pss = (int16_t *)&ue->common_vars.common_vars_rx_data_per_thread[subframe%RX_NB_TH].rxdataF[aarx][(3*ue->frame_parms.ofdm_symbol_size)];
Bilel's avatar
Bilel committed
244
              }
245 246
          //              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]);
247 248 249
              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]));
250

Bilel's avatar
Bilel committed
251 252 253 254
              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]));

255 256
          //              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]);
257
              ue->measurements.n0_power_dB[aarx] = (unsigned short) dB_fixed(ue->measurements.n0_power[aarx]/12);
258
              ue->measurements.n0_power_tot /*+=*/ = ue->measurements.n0_power[aarx];
259
        }
260

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

263 264 265
        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 {
266
            LOG_E(PHY, "Not yet implemented: noise power calculation when prefix length = EXTENDED\n");
267
        }
268
        }
269
        else if ((ue->frame_parms.frame_type == TDD) &&
Bilel's avatar
Bilel committed
270
                 ((subframe == 1) || (subframe == 6))) {  // TDD PSS/SSS, compute noise in DTX REs // 2016-09-29 wilson fix incorrect noise power calculation
271 272


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

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

281
                rxdataF  =  ue->common_vars.common_vars_rx_data_per_thread[(subframe-1)%RX_NB_TH].rxdataF;
Bilel's avatar
Bilel committed
282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305
                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
306
                rxF_pss = (int16_t *)&ue->common_vars.common_vars_rx_data_per_thread[subframe%RX_NB_TH].rxdataF[aarx][(7*ue->frame_parms.ofdm_symbol_size)];
Bilel's avatar
Bilel committed
307 308 309 310 311 312 313 314 315
            //              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];
316
        }
317

Bilel's avatar
Bilel committed
318 319
        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);
320

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

323 324
          }
        }
325 326
      }
    }
327
    // recompute nushift with eNB_offset corresponding to adjacent eNB on which to perform channel estimation
328
    //    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);
329
    if (eNB_offset > 0)
330
      Nid_cell = ue->measurements.adj_cell_id[eNB_offset-1];
331 332 333 334 335 336


    nushift =  Nid_cell%6;



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


    if (abstraction_flag == 0) {
341

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

344
      for (l=0,nu=0; l<=(4-ue->frame_parms.Ncp); l+=(4-ue->frame_parms.Ncp),nu=3) {
345
        k = (nu + nushift)%6;
346
#ifdef DEBUG_MEAS_RRC
347
        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,
348
              eNB_offset,k,l);
349 350
#endif

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

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

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

360
              ue->measurements.rsrp[eNB_offset] += (((int32_t)(rxF[off])*rxF[off])+((int32_t)(rxF[off+1])*rxF[off+1]));
361
              //        printf("rb %d, off %d : %d\n",rb,off,((((int32_t)rxF[off])*rxF[off])+((int32_t)(rxF[off+1])*rxF[off+1])));
362 363
              //              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])));
364

365

366 367
              off+=12;

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

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

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

            }

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

399
      // 2 RE per PRB
400 401 402
      //      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]);
403
      if (eNB_offset == 0) {
404 405 406 407
        //  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);
408
      }
409

410 411
      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;
412
      else
413
        ue->measurements.rsrq[eNB_offset] = -12000;
414

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

    }
423

424
#ifdef DEBUG_MEAS_RRC
425

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

428
      if (eNB_offset == 0)
Elena Lukashova's avatar
Elena Lukashova committed
429
       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,
430
              ue->proc.proc_rxtx[subframe&1].frame_rx,subframe,10*log10(ue->measurements.rssi)-ue->rx_total_gain_dB,
431 432 433
              10*log10(ue->measurements.rssi),
              ue->rx_total_gain_dB,
              ue->measurements.n0_power_tot_dBm);
434

435
      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",
436
            ue->Mod_id,
437
            ue->proc.proc_rxtx[subframe&1].frame_rx,subframe,eNB_offset,
438 439 440 441 442 443 444 445 446
            (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));
447

448
      //    }
449

450 451 452
#endif
  }

453 454
}

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


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

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


480
  int rank_tm3_tm4;
481 482


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

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

  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;
  }
512

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

522 523
        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];
524

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

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

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

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

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

  } //eNB_id

545
  eNB_id=0;
546
  if (ue->transmission_mode[0]==4 || ue->transmission_mode[0]==3){
547 548 549 550 551 552 553 554
    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;
555
#ifdef DEBUG_RANK_EST
Elena Lukashova's avatar
Elena Lukashova committed
556
  printf("rank tm3 or tm4 %d\n", rank_tm3_tm4);
557
#endif
558
  }
559

560 561 562 563 564 565 566
  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]);

567
  // filter to remove jitter
568 569 570 571 572 573
  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);

574
    //LOG_I(PHY,"Noise Power Computation: k1 %d k2 %d n0 avg %d n0 tot %d\n", k1, k2, ue->measurements.n0_power_avg,
575
    //    ue->measurements.n0_power_tot);
576 577 578
    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);
579
  } else {
580 581
    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];
582

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

587 588 589 590 591
  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;
592
#ifdef DEBUG_MEAS_UE
Bilel's avatar
Bilel committed
593
      LOG_I(PHY,"[eNB %d] Subframe %d, RSSI %d dBm, RSSI (digital) %d dB, WBandCQI %d dB, rxPwrAvg %d, n0PwrAvg %d\n",
594
            eNB_id,
595
            subframe,
596 597 598 599
            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],
600
            ue->measurements.n0_power_tot);
knopp's avatar
knopp committed
601
#endif
602 603
  }

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

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

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

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

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

          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)]);
            */
624
            ue->measurements.subband_cqi[eNB_id][aarx][subband] =
625 626
              (signal_energy_nodc(dl_ch0,subband_size) + signal_energy_nodc(dl_ch1,subband_size));

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

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

635 636 637
            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]);
638 639 640
          } 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)]);
641 642 643 644 645
            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]);
646 647 648 649
          }

          dl_ch1+=subband_size;
          dl_ch0+=subband_size;
650
          //    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]);
651 652 653 654 655
        }

      }

      for (subband=0; subband<nb_subbands; subband++) {
656 657
        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);
658 659 660
      }

      for (aarx=0; aarx<frame_parms->nb_antennas_rx; aarx++) {
661
        //printf("aarx=%d", aarx);
662
        // 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)
663 664

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

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

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

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


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

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

686
          pmi128_re = vdupq_n_s32(0);
687
          pmi128_im = vdupq_n_s32(0);
688
#endif
689 690 691 692 693 694 695 696
          // 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++) {
697 698

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

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

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

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

726 727
            mmtmpPMI0 = _mm_madd_epi16(dl_ch0_128[1],dl_ch1_128[1]);
                 //  print_ints("re",&mmtmpPMI0);
728 729 730
            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));
731
                //  print_ints("_mm_shufflehi_epi16",&mmtmpPMI1);
732
            mmtmpPMI1 = _mm_sign_epi16(mmtmpPMI1,*(__m128i*)&conjugate);
733
               //  print_ints("_mm_sign_epi16",&mmtmpPMI1);
734
            mmtmpPMI1 = _mm_madd_epi16(mmtmpPMI1,dl_ch0_128[1]);
735
               //   print_ints("mm_madd_epi16",&mmtmpPMI1);
736 737
            // mmtmpPMI1 contains imag part of 4 consecutive outputs (32-bit)
            pmi128_re = _mm_add_epi32(pmi128_re,mmtmpPMI0);
738
                //  print_ints(" pmi128_re 1",&pmi128_re);
739
            pmi128_im = _mm_add_epi32(pmi128_im,mmtmpPMI1);
740
            //print_ints(" pmi128_im 1 ",&pmi128_im);*/
741

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

744 745 746 747 748 749 750 751 752
            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
753 754 755 756
            dl_ch0_128++;
            dl_ch1_128++;
          }

757 758 759 760
          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];
761 762 763
        } // subband loop
      } // rx antenna loop
    }  // if frame_parms->mode1_flag == 0
764
    else {
765 766
      // cqi information only for mode 1
      for (aarx=0; aarx<frame_parms->nb_antennas_rx; aarx++) {
767
        dl_ch0    = &ue->common_vars.common_vars_rx_data_per_thread[subframe%RX_NB_TH].dl_ch_estimates[eNB_id][aarx][4];
768 769 770 771 772

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

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

          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)]);
778 779
            ue->measurements.subband_cqi[eNB_id][aarx][subband] =
              (signal_energy_nodc(dl_ch0,48) ) - ue->measurements.n0_power[aarx];
780

781 782 783
            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]);
784 785 786
          } 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)]);
787 788 789 790
            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]);
791 792 793
          }

          dl_ch1+=48;
794
          //    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]);
795
        }
796 797
      }

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

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

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

808
      if (frame_parms->nb_antennas_rx>1) {
809 810
        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;
811
        else
812
          ue->measurements.selected_rx_antennas[eNB_id][i] = 1;
813
      } else
814
        ue->measurements.selected_rx_antennas[eNB_id][i] = 0;
815 816
    }

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

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


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

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

834

835 836 837 838
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
839 840
                                 unsigned short nb_rb)
{
841 842

  int i=0;
843
  int rank=0;
844 845 846 847 848 849 850 851 852
  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;

853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876
  /* 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)));
877 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

  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++)
  {
1036 1037
    denum_db[i]=dB_fixed(determ_fin[i]);
    numer_db[i]=dB_fixed(numer_fin[i]);
1038
    cond_db[i]=(numer_db[i]-denum_db[i]);
1039
    if (cond_db[i] < cond_num_threshold)
1040 1041
      count++;
#ifdef DEBUG_RANK_EST
1042
    printf("cond_num_threshold =%d \n", cond_num_threshold);
1043 1044 1045 1046 1047 1048 1049 1050
    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
1051
    rank=1;
1052 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

#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++) {

1137
    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
1138 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 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259