nr_ue_measurements.c 11.7 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.1  (the "License"); you may not use this file
 * except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.openairinterface.org/?page_id=698
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *-------------------------------------------------------------------------------
 * For more information about the OpenAirInterface (OAI) Software Alliance:
 *      contact@openairinterface.org
 */
Hongzhi Wang's avatar
Hongzhi Wang committed
21

cig's avatar
cig committed
22 23
/*! \file nr_ue_measurements.c
 * \brief UE measurements routines
cig's avatar
cig committed
24
 * \author  R. Knopp, G. Casati, K. Saaifan
cig's avatar
cig committed
25 26 27
 * \date 2020
 * \version 0.1
 * \company Eurecom, Fraunhofer IIS
cig's avatar
cig committed
28
 * \email: knopp@eurecom.fr, guido.casati@iis.fraunhofer.de, khodr.saaifan@iis.fraunhofer.de
cig's avatar
cig committed
29 30 31 32
 * \note
 * \warning
 */

cig's avatar
cig committed
33
#include "executables/softmodem-common.h"
cig's avatar
cig committed
34
#include "executables/nr-softmodem-common.h"
35
#include "PHY/defs_nr_UE.h"
36
#include "PHY/INIT/nr_phy_init.h"
Hongzhi Wang's avatar
Hongzhi Wang committed
37 38 39
#include "PHY/phy_extern_nr_ue.h"
#include "common/utils/LOG/log.h"
#include "PHY/sse_intrin.h"
40

Hongzhi Wang's avatar
Hongzhi Wang committed
41 42 43 44 45 46 47 48
//#define k1 1000
#define k1 ((long long int) 1000)
#define k2 ((long long int) (1024-k1))

//#define DEBUG_MEAS_RRC
//#define DEBUG_MEAS_UE
//#define DEBUG_RANK_EST

49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
uint32_t get_nr_rx_total_gain_dB (module_id_t Mod_id,uint8_t CC_id)
{

  PHY_VARS_NR_UE *ue = PHY_vars_UE_g[Mod_id][CC_id];

  if (ue)
    return ue->rx_total_gain_dB;

  return 0xFFFFFFFF;
}


float_t get_nr_RSRP(module_id_t Mod_id,uint8_t CC_id,uint8_t gNB_index)
{

  AssertFatal(PHY_vars_UE_g!=NULL,"PHY_vars_UE_g is null\n");
  AssertFatal(PHY_vars_UE_g[Mod_id]!=NULL,"PHY_vars_UE_g[%d] is null\n",Mod_id);
  AssertFatal(PHY_vars_UE_g[Mod_id][CC_id]!=NULL,"PHY_vars_UE_g[%d][%d] is null\n",Mod_id,CC_id);

  PHY_VARS_NR_UE *ue = PHY_vars_UE_g[Mod_id][CC_id];

  if (ue)
    return (10*log10(ue->measurements.rsrp[gNB_index])-
	    get_nr_rx_total_gain_dB(Mod_id,0) -
	    10*log10(20*12));
  return -140.0;
}

Hongzhi Wang's avatar
Hongzhi Wang committed
77
void nr_ue_measurements(PHY_VARS_NR_UE *ue,
78
                        const UE_nr_rxtx_proc_t *proc,
79 80 81
                        NR_UE_DLSCH_t *dlsch,
                        uint32_t pdsch_est_size,
                        int32_t dl_ch_estimates[][pdsch_est_size])
Hongzhi Wang's avatar
Hongzhi Wang committed
82
{
83
  int slot = proc->nr_slot_rx;
cig's avatar
cig committed
84
  int aarx, aatx, gNB_id = 0;
Hongzhi Wang's avatar
Hongzhi Wang committed
85
  NR_DL_FRAME_PARMS *frame_parms = &ue->frame_parms;
cig's avatar
cig committed
86
  int ch_offset = frame_parms->ofdm_symbol_size*2;
87
  int N_RB_DL = dlsch->dlsch_config.number_rbs;
Hongzhi Wang's avatar
Hongzhi Wang committed
88 89 90

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

91 92 93 94
  allocCast3D(rx_spatial_power,
              int,
              ue->measurements.rx_spatial_power,
              NUMBER_OF_CONNECTED_gNB_MAX,
95 96
              cmax(frame_parms->nb_antenna_ports_gNB, 1),
              cmax(frame_parms->nb_antennas_rx, 1),
laurent's avatar
laurent committed
97
              false);
98 99 100 101
  allocCast3D(rx_spatial_power_dB,
              unsigned short,
              ue->measurements.rx_spatial_power_dB,
              NUMBER_OF_CONNECTED_gNB_MAX,
102 103
              cmax(frame_parms->nb_antenna_ports_gNB, 1),
              cmax(frame_parms->nb_antennas_rx, 1),
laurent's avatar
laurent committed
104
              false);
105

Hongzhi Wang's avatar
Hongzhi Wang committed
106
  // signal measurements
107
  for (gNB_id = 0; gNB_id < ue->n_connected_gNB; gNB_id++){
Hongzhi Wang's avatar
Hongzhi Wang committed
108

cig's avatar
cig committed
109
    ue->measurements.rx_power_tot[gNB_id] = 0;
Hongzhi Wang's avatar
Hongzhi Wang committed
110

cig's avatar
cig committed
111
    for (aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++){
Hongzhi Wang's avatar
Hongzhi Wang committed
112

cig's avatar
cig committed
113
      ue->measurements.rx_power[gNB_id][aarx] = 0;
Hongzhi Wang's avatar
Hongzhi Wang committed
114

cig's avatar
cig committed
115
      for (aatx = 0; aatx < frame_parms->nb_antenna_ports_gNB; aatx++){
laurent's avatar
laurent committed
116 117
        const int z=signal_energy_nodc(&dl_ch_estimates[gNB_id][ch_offset], N_RB_DL * NR_NB_SC_PER_RB);
        rx_spatial_power[gNB_id][aatx][aarx] = z;
Hongzhi Wang's avatar
Hongzhi Wang committed
118

119 120
        if (rx_spatial_power[gNB_id][aatx][aarx] < 0)
          rx_spatial_power[gNB_id][aatx][aarx] = 0;
Hongzhi Wang's avatar
Hongzhi Wang committed
121

122 123
        rx_spatial_power_dB[gNB_id][aatx][aarx] = (unsigned short)dB_fixed(rx_spatial_power[gNB_id][aatx][aarx]);
        ue->measurements.rx_power[gNB_id][aarx] += rx_spatial_power[gNB_id][aatx][aarx];
cig's avatar
cig committed
124
      }
Hongzhi Wang's avatar
Hongzhi Wang committed
125

cig's avatar
cig committed
126 127
      ue->measurements.rx_power_dB[gNB_id][aarx] = (unsigned short) dB_fixed(ue->measurements.rx_power[gNB_id][aarx]);
      ue->measurements.rx_power_tot[gNB_id] += ue->measurements.rx_power[gNB_id][aarx];
Hongzhi Wang's avatar
Hongzhi Wang committed
128

cig's avatar
cig committed
129
    }
Hongzhi Wang's avatar
Hongzhi Wang committed
130

cig's avatar
cig committed
131 132 133
    ue->measurements.rx_power_tot_dB[gNB_id] = (unsigned short) dB_fixed(ue->measurements.rx_power_tot[gNB_id]);

  }
Hongzhi Wang's avatar
Hongzhi Wang committed
134 135 136

  // filter to remove jitter
  if (ue->init_averaging == 0) {
cig's avatar
cig committed
137

138
    for (gNB_id = 0; gNB_id < ue->n_connected_gNB; gNB_id++)
cig's avatar
cig committed
139 140 141 142
      ue->measurements.rx_power_avg[gNB_id] = (int)(((k1*((long long int)(ue->measurements.rx_power_avg[gNB_id]))) + (k2*((long long int)(ue->measurements.rx_power_tot[gNB_id])))) >> 10);

    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);

Thomas Schlichter's avatar
Thomas Schlichter committed
143
    LOG_D(PHY, "Noise Power Computation: k1 %lld k2 %lld n0 avg %u n0 tot %u\n", k1, k2, ue->measurements.n0_power_avg, ue->measurements.n0_power_tot);
cig's avatar
cig committed
144

Hongzhi Wang's avatar
Hongzhi Wang committed
145
  } else {
cig's avatar
cig committed
146

147
    for (gNB_id = 0; gNB_id < ue->n_connected_gNB; gNB_id++)
cig's avatar
cig committed
148
      ue->measurements.rx_power_avg[gNB_id] = ue->measurements.rx_power_tot[gNB_id];
Hongzhi Wang's avatar
Hongzhi Wang committed
149 150 151

    ue->measurements.n0_power_avg = ue->measurements.n0_power_tot;
    ue->init_averaging = 0;
cig's avatar
cig committed
152

Hongzhi Wang's avatar
Hongzhi Wang committed
153 154
  }

155
  for (gNB_id = 0; gNB_id < ue->n_connected_gNB; gNB_id++) {
cig's avatar
cig committed
156 157

    ue->measurements.rx_power_avg_dB[gNB_id] = dB_fixed( ue->measurements.rx_power_avg[gNB_id]);
158 159
    ue->measurements.wideband_cqi_tot[gNB_id] = ue->measurements.rx_power_tot_dB[gNB_id] - ue->measurements.n0_power_tot_dB;
    ue->measurements.wideband_cqi_avg[gNB_id] = ue->measurements.rx_power_avg_dB[gNB_id] - dB_fixed(ue->measurements.n0_power_avg);
cig's avatar
cig committed
160
    ue->measurements.rx_rssi_dBm[gNB_id] = ue->measurements.rx_power_avg_dB[gNB_id] + 30 - 10*log10(pow(2, 30)) - ((int)openair0_cfg[0].rx_gain[0] - (int)openair0_cfg[0].rx_gain_offset[0]) - dB_fixed(ue->frame_parms.ofdm_symbol_size);
cig's avatar
cig committed
161

luis_pereira87's avatar
luis_pereira87 committed
162
    LOG_D(PHY, "[gNB %d] Slot %d, RSSI %d dB (%d dBm/RE), WBandCQI %d dB, rxPwrAvg %d, n0PwrAvg %d\n",
cig's avatar
cig committed
163 164 165
      gNB_id,
      slot,
      ue->measurements.rx_power_avg_dB[gNB_id],
luis_pereira87's avatar
luis_pereira87 committed
166
      ue->measurements.rx_rssi_dBm[gNB_id],
cig's avatar
cig committed
167 168 169
      ue->measurements.wideband_cqi_avg[gNB_id],
      ue->measurements.rx_power_avg[gNB_id],
      ue->measurements.n0_power_tot);
Hongzhi Wang's avatar
Hongzhi Wang committed
170
  }
171 172
}

cig's avatar
cig committed
173 174 175 176 177 178 179 180
// This function implements:
// - SS reference signal received power (SS-RSRP) as per clause 5.1.1 of 3GPP TS 38.215 version 16.3.0 Release 16
// - no Layer 3 filtering implemented (no filterCoefficient provided from RRC)
// Todo:
// - Layer 3 filtering according to clause 5.5.3.2 of 3GPP TS 38.331 version 16.2.0 Release 16
// Measurement units:
// - RSRP:    W (dBW)
// - RX Gain  dB
181 182
void nr_ue_ssb_rsrp_measurements(PHY_VARS_NR_UE *ue,
                                 int ssb_index,
183 184 185
                                 const UE_nr_rxtx_proc_t *proc,
                                 c16_t rxdataF[][ue->frame_parms.samples_per_slot_wCP])
{
francescomani's avatar
francescomani committed
186
  int k_start = 56;
cig's avatar
cig committed
187
  int k_end   = 183;
188
  int slot = proc->nr_slot_rx;
cig's avatar
cig committed
189
  unsigned int ssb_offset = ue->frame_parms.first_carrier_offset + ue->frame_parms.ssb_start_subcarrier;
francescomani's avatar
francescomani committed
190 191 192 193 194 195
  int symbol_offset = nr_get_ssb_start_symbol(&ue->frame_parms,ssb_index);

  if (ue->frame_parms.half_frame_bit)
    symbol_offset += (ue->frame_parms.slots_per_frame>>1)*ue->frame_parms.symbols_per_slot;

  uint8_t l_sss = (symbol_offset + 2) % ue->frame_parms.symbols_per_slot;
196

197
  uint32_t rsrp = 0;
198

199 200
  LOG_D(PHY, "In %s: [UE %d] slot %d l_sss %d ssb_offset %d\n", __FUNCTION__, ue->Mod_id, slot, l_sss, ssb_offset);
  int nb_re = 0;
201

202
  for (int aarx = 0; aarx < ue->frame_parms.nb_antennas_rx; aarx++) {
203

204
    int16_t *rxF_sss = (int16_t *)&rxdataF[aarx][l_sss*ue->frame_parms.ofdm_symbol_size];
205

206
    for(int k = k_start; k < k_end; k++){
207

208 209
      int re = (ssb_offset + k) % ue->frame_parms.ofdm_symbol_size;

210
#ifdef DEBUG_MEAS_UE
211
      LOG_I(PHY, "In %s rxF_sss %d %d\n", __FUNCTION__, rxF_sss[re*2], rxF_sss[re*2 + 1]);
212
#endif
213

214
      rsrp += (((int32_t)rxF_sss[re*2]*rxF_sss[re*2]) + ((int32_t)rxF_sss[re*2 + 1]*rxF_sss[re*2 + 1]));
215
      nb_re++;
216 217

    }
cig's avatar
cig committed
218
  }
219

220 221 222 223 224
  rsrp /= nb_re;
  ue->measurements.ssb_rsrp_dBm[ssb_index] = 10*log10(rsrp) +
                                             30 - 10*log10(pow(2,30)) -
                                             ((int)openair0_cfg[0].rx_gain[0] - (int)openair0_cfg[0].rx_gain_offset[0]) -
                                             dB_fixed(ue->frame_parms.ofdm_symbol_size);
cig's avatar
cig committed
225

226
  LOG_D(PHY, "In %s: [UE %d] ssb %d SS-RSRP: %d dBm/RE (%d)\n",
cig's avatar
cig committed
227 228
    __FUNCTION__,
    ue->Mod_id,
229 230 231
    ssb_index,
    ue->measurements.ssb_rsrp_dBm[ssb_index],
    rsrp);
232
}
cig's avatar
cig committed
233

cig's avatar
cig committed
234 235
// This function computes the received noise power
// Measurement units:
Thomas Schlichter's avatar
Thomas Schlichter committed
236
// - psd_awgn (AWGN power spectral density):     dBm/Hz
cig's avatar
cig committed
237
void nr_ue_rrc_measurements(PHY_VARS_NR_UE *ue,
238 239 240
                            const UE_nr_rxtx_proc_t *proc,
                            c16_t rxdataF[][ue->frame_parms.samples_per_slot_wCP])
{
cig's avatar
cig committed
241
  uint8_t k;
242
  int slot = proc->nr_slot_rx;
243
  int aarx;
cig's avatar
cig committed
244
  int16_t *rxF_sss;
245 246 247
  const uint8_t k_left = 48;
  const uint8_t k_right = 183;
  const uint8_t k_length = 8;
248
  uint8_t l_sss = (ue->symbol_offset + 2) % ue->frame_parms.symbols_per_slot;
cig's avatar
cig committed
249
  unsigned int ssb_offset = ue->frame_parms.first_carrier_offset + ue->frame_parms.ssb_start_subcarrier;
cig's avatar
cig committed
250 251 252
  double rx_gain = openair0_cfg[0].rx_gain[0];
  double rx_gain_offset = openair0_cfg[0].rx_gain_offset[0];

cig's avatar
cig committed
253 254 255 256 257 258 259
  ue->measurements.n0_power_tot = 0;

  LOG_D(PHY, "In %s doing measurements for ssb_offset %d l_sss %d \n", __FUNCTION__, ssb_offset, l_sss);

  for (aarx = 0; aarx<ue->frame_parms.nb_antennas_rx; aarx++) {

    ue->measurements.n0_power[aarx] = 0;
260
    rxF_sss = (int16_t *)&rxdataF[aarx][l_sss*ue->frame_parms.ofdm_symbol_size];
cig's avatar
cig committed
261 262 263 264

    //-ve spectrum from SSS
    for(k = k_left; k < k_left + k_length; k++){

265 266
      int re = (ssb_offset + k) % ue->frame_parms.ofdm_symbol_size;

cig's avatar
cig committed
267
      #ifdef DEBUG_MEAS_RRC
268
      LOG_I(PHY, "In %s -rxF_sss %d %d\n", __FUNCTION__, rxF_sss[re*2], rxF_sss[re*2 + 1]);
cig's avatar
cig committed
269 270
      #endif

271
      ue->measurements.n0_power[aarx] += (((int32_t)rxF_sss[re*2]*rxF_sss[re*2]) + ((int32_t)rxF_sss[re*2 + 1]*rxF_sss[re*2 + 1]));
cig's avatar
cig committed
272 273 274 275 276 277

    }

    //+ve spectrum from SSS
    for(k = k_right; k < k_right + k_length; k++){

278 279
      int re = (ssb_offset + k) % ue->frame_parms.ofdm_symbol_size;

cig's avatar
cig committed
280
      #ifdef DEBUG_MEAS_RRC
281
      LOG_I(PHY, "In %s +rxF_sss %d %d\n", __FUNCTION__, rxF_sss[re*2], rxF_sss[re*2 + 1]);
cig's avatar
cig committed
282 283
      #endif

284
      ue->measurements.n0_power[aarx] += (((int32_t)rxF_sss[re*2]*rxF_sss[re*2]) + ((int32_t)rxF_sss[re*2 + 1]*rxF_sss[re*2 + 1]));
cig's avatar
cig committed
285 286 287

    }

288
    ue->measurements.n0_power[aarx] /= 2*k_length;
cig's avatar
cig committed
289 290 291 292 293
    ue->measurements.n0_power_dB[aarx] = (unsigned short) dB_fixed(ue->measurements.n0_power[aarx]);
    ue->measurements.n0_power_tot += ue->measurements.n0_power[aarx];

  }

294
  ue->measurements.n0_power_tot_dB = (unsigned short) dB_fixed(ue->measurements.n0_power_tot);
295 296

  #ifdef DEBUG_MEAS_RRC
Thomas Schlichter's avatar
Thomas Schlichter committed
297 298 299
  const int psd_awgn = -174;
  const int scs = 15000 * (1 << ue->frame_parms.numerology_index);
  const int nf_usrp = ue->measurements.n0_power_tot_dB + 3 + 30 - ((int)rx_gain - (int)rx_gain_offset) - 10 * log10(pow(2, 30)) - (psd_awgn + dB_fixed(scs) + dB_fixed(ue->frame_parms.ofdm_symbol_size));
cig's avatar
cig committed
300
  LOG_D(PHY, "In [%s][slot:%d] NF USRP %d dB\n", __FUNCTION__, slot, nf_usrp);
301 302
  #endif

303 304 305 306 307 308 309 310
  LOG_D(PHY,
        "In [%s][slot:%d] Noise Level %d (digital level %d dB, noise power spectral density %f dBm/RE)\n",
        __FUNCTION__,
        slot,
        ue->measurements.n0_power_tot,
        ue->measurements.n0_power_tot_dB,
        ue->measurements.n0_power_tot_dB + 30 - 10 * log10(pow(2, 30)) - dB_fixed(ue->frame_parms.ofdm_symbol_size)
            - ((int)rx_gain - (int)rx_gain_offset));
cig's avatar
cig committed
311
}