csi_rx.c 41.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
/*
 * 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
 */

/***********************************************************************
*
* FILENAME    :  csi_rx.c
*
* MODULE      :
*
* DESCRIPTION :  function to receive the channel state information
*
************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

36
#include "executables/nr-softmodem-common.h"
37 38 39
#include "nr_transport_proto_ue.h"
#include "PHY/phy_extern_nr_ue.h"
#include "common/utils/nr/nr_common.h"
40
#include "PHY/NR_TRANSPORT/nr_transport_proto.h"
41
#include "PHY/NR_UE_ESTIMATION/filt16a_32.h"
42

43 44
// 10*log10(pow(2,30))
#define pow_2_30_dB 90
45 46

//#define NR_CSIRS_DEBUG
47
//#define NR_CSIIM_DEBUG
48

49 50 51 52 53
void nr_det_A_MF_2x2(int32_t *a_mf_00,
                     int32_t *a_mf_01,
                     int32_t *a_mf_10,
                     int32_t *a_mf_11,
                     int32_t *det_fin,
54
                     const unsigned short nb_rb) {
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94

  int16_t nr_conjug2[8]__attribute__((aligned(16))) = {1,-1,1,-1,1,-1,1,-1} ;

  __m128i ad_re_128, bc_re_128, det_re_128;

  __m128i *a_mf_00_128 = (__m128i *)a_mf_00;
  __m128i *a_mf_01_128 = (__m128i *)a_mf_01;
  __m128i *a_mf_10_128 = (__m128i *)a_mf_10;
  __m128i *a_mf_11_128 = (__m128i *)a_mf_11;
  __m128i *det_fin_128 = (__m128i *)det_fin;

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

    //complex multiplication (I_a+jQ_a)(I_d+jQ_d) = (I_aI_d - Q_aQ_d) + j(Q_aI_d + I_aQ_d)
    //The imag part is often zero, we compute only the real part
    ad_re_128 = _mm_sign_epi16(a_mf_00_128[0],*(__m128i*)&nr_conjug2[0]);
    ad_re_128 = _mm_madd_epi16(ad_re_128,a_mf_11_128[0]); //Re: I_a0*I_d0 - Q_a1*Q_d1

    //complex multiplication (I_b+jQ_b)(I_c+jQ_c) = (I_bI_c - Q_bQ_c) + j(Q_bI_c + I_bQ_c)
    //The imag part is often zero, we compute only the real part
    bc_re_128 = _mm_sign_epi16(a_mf_01_128[0],*(__m128i*)&nr_conjug2[0]);
    bc_re_128 = _mm_madd_epi16(bc_re_128,a_mf_10_128[0]); //Re: I_b0*I_c0 - Q_b1*Q_c1

    det_re_128 = _mm_sub_epi32(ad_re_128, bc_re_128);

    //det in Q30 format
    det_fin_128[0] = _mm_abs_epi32(det_re_128);

    det_fin_128+=1;
    a_mf_00_128+=1;
    a_mf_01_128+=1;
    a_mf_10_128+=1;
    a_mf_11_128+=1;
  }
  _mm_empty();
  _m_empty();
}

void nr_squared_matrix_element(int32_t *a,
                               int32_t *a_sq,
95
                               const unsigned short nb_rb) {
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
  __m128i *a_128 = (__m128i *)a;
  __m128i *a_sq_128 = (__m128i *)a_sq;
  for (int rb=0; rb<3*nb_rb; rb++) {
    a_sq_128[0] = _mm_madd_epi16(a_128[0], a_128[0]);
    a_sq_128+=1;
    a_128+=1;
  }
  _mm_empty();
  _m_empty();
}

void nr_numer_2x2(int32_t *a_00_sq,
                  int32_t *a_01_sq,
                  int32_t *a_10_sq,
                  int32_t *a_11_sq,
                  int32_t *num_fin,
112
                  const unsigned short nb_rb) {
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
  __m128i *a_00_sq_128 = (__m128i *)a_00_sq;
  __m128i *a_01_sq_128 = (__m128i *)a_01_sq;
  __m128i *a_10_sq_128 = (__m128i *)a_10_sq;
  __m128i *a_11_sq_128 = (__m128i *)a_11_sq;
  __m128i *num_fin_128 = (__m128i *)num_fin;
  for (int rb=0; rb<3*nb_rb; rb++) {
    __m128i sq_a_plus_sq_d_128 = _mm_add_epi32(a_00_sq_128[0], a_11_sq_128[0]);
    __m128i sq_b_plus_sq_c_128 = _mm_add_epi32(a_01_sq_128[0], a_10_sq_128[0]);
    num_fin_128[0] = _mm_add_epi32(sq_a_plus_sq_d_128, sq_b_plus_sq_c_128);
    num_fin_128+=1;
    a_00_sq_128+=1;
    a_01_sq_128+=1;
    a_10_sq_128+=1;
    a_11_sq_128+=1;
  }
  _mm_empty();
  _m_empty();
}

132
bool is_csi_rs_in_symbol(const fapi_nr_dl_config_csirs_pdu_rel15_t csirs_config_pdu, const int symbol) {
rmagueta's avatar
rmagueta committed
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179

  bool ret = false;

  // 38.211-Table 7.4.1.5.3-1: CSI-RS locations within a slot
  switch(csirs_config_pdu.row){
    case 1:
    case 2:
    case 3:
    case 4:
    case 6:
    case 9:
      if(symbol == csirs_config_pdu.symb_l0) {
        ret = true;
      }
      break;
    case 5:
    case 7:
    case 8:
    case 10:
    case 11:
    case 12:
      if(symbol == csirs_config_pdu.symb_l0 || symbol == (csirs_config_pdu.symb_l0+1) ) {
        ret = true;
      }
      break;
    case 13:
    case 14:
    case 16:
    case 17:
      if(symbol == csirs_config_pdu.symb_l0 || symbol == (csirs_config_pdu.symb_l0+1) ||
          symbol == csirs_config_pdu.symb_l1 || symbol == (csirs_config_pdu.symb_l1+1)) {
        ret = true;
      }
      break;
    case 15:
    case 18:
      if(symbol == csirs_config_pdu.symb_l0 || symbol == (csirs_config_pdu.symb_l0+1) || symbol == (csirs_config_pdu.symb_l0+2) ) {
        ret = true;
      }
      break;
    default:
      AssertFatal(0==1, "Row %d is not valid for CSI Table 7.4.1.5.3-1\n", csirs_config_pdu.row);
  }

  return ret;
}

180 181 182
int nr_get_csi_rs_signal(const PHY_VARS_NR_UE *ue,
                         const UE_nr_rxtx_proc_t *proc,
                         const fapi_nr_dl_config_csirs_pdu_rel15_t *csirs_config_pdu,
183
                         const nr_csi_info_t *nr_csi_info,
184 185 186 187
                         const uint8_t N_cdm_groups,
                         const uint8_t CDM_group_size,
                         const uint8_t k_prime,
                         const uint8_t l_prime,
188 189 190
                         const uint8_t *j_cdm,
                         const uint8_t *k_overline,
                         const uint8_t *l_overline,
191 192 193
                         int32_t csi_rs_received_signal[][ue->frame_parms.samples_per_slot_wCP],
                         uint32_t *rsrp,
                         int *rsrp_dBm) {
194

195
  int32_t **rxdataF  =  ue->common_vars.rxdataF;
196
  const NR_DL_FRAME_PARMS *frame_parms = &ue->frame_parms;
197 198
  uint16_t meas_count = 0;
  uint32_t rsrp_sum = 0;
199

200 201 202 203 204 205
  for (int ant_rx = 0; ant_rx < frame_parms->nb_antennas_rx; ant_rx++) {

    for (int rb = csirs_config_pdu->start_rb; rb < (csirs_config_pdu->start_rb+csirs_config_pdu->nr_of_rbs); rb++) {

      // for freq density 0.5 checks if even or odd RB
      if(csirs_config_pdu->freq_density <= 1 && csirs_config_pdu->freq_density != (rb % 2)) {
rmagueta's avatar
rmagueta committed
206 207
        continue;
      }
208

209 210
      for (int cdm_id = 0; cdm_id < N_cdm_groups; cdm_id++) {
        for (int s = 0; s < CDM_group_size; s++)  {
211 212

          // loop over frequency resource elements within a group
213
          for (int kp = 0; kp <= k_prime; kp++) {
214

215
            uint16_t k = (frame_parms->first_carrier_offset + (rb*NR_NB_SC_PER_RB)+k_overline[cdm_id] + kp) % frame_parms->ofdm_symbol_size;
216 217

            // loop over time resource elements within a group
218
            for (int lp = 0; lp <= l_prime; lp++) {
219
              uint16_t symb = lp + l_overline[cdm_id];
220
              uint64_t symbol_offset = symb*frame_parms->ofdm_symbol_size;
221 222 223 224
              c16_t *rx_signal = (c16_t*)&rxdataF[ant_rx][symbol_offset];
              c16_t *rx_csi_rs_signal = (c16_t*)&csi_rs_received_signal[ant_rx][symbol_offset];
              rx_csi_rs_signal[k].r = rx_signal[k].r;
              rx_csi_rs_signal[k].i = rx_signal[k].i;
225

226 227 228 229 230
              rsrp_sum += (((int32_t)(rx_csi_rs_signal[k].r)*rx_csi_rs_signal[k].r) +
                           ((int32_t)(rx_csi_rs_signal[k].i)*rx_csi_rs_signal[k].i));

              meas_count++;

231
#ifdef NR_CSIRS_DEBUG
232
              int dataF_offset = proc->nr_slot_rx*ue->frame_parms.samples_per_slot_wCP;
233
              uint16_t port_tx = s+j_cdm[cdm_id]*CDM_group_size;
234
              c16_t *tx_csi_rs_signal = (c16_t*)&nr_csi_info->csi_rs_generated_signal[port_tx][symbol_offset+dataF_offset];
235
              LOG_I(NR_PHY, "l,k (%2d,%4d) |\tport_tx %d (%4d,%4d)\tant_rx %d (%4d,%4d)\n",
236 237 238
                    symb,
                    k,
                    port_tx+3000,
239 240
                    tx_csi_rs_signal[k].r,
                    tx_csi_rs_signal[k].i,
241
                    ant_rx,
242 243
                    rx_csi_rs_signal[k].r,
                    rx_csi_rs_signal[k].i);
244
#endif
245 246 247
            }
          }
        }
248 249 250 251
      }
    }
  }

252 253 254 255 256 257 258 259 260

  *rsrp = rsrp_sum/meas_count;
  *rsrp_dBm = dB_fixed(*rsrp) + 30 - pow_2_30_dB
      - ((int)openair0_cfg[0].rx_gain[0] - (int)openair0_cfg[0].rx_gain_offset[0]) - dB_fixed(ue->frame_parms.ofdm_symbol_size);

#ifdef NR_CSIRS_DEBUG
  LOG_I(NR_PHY, "RSRP = %i (%i dBm)\n", *rsrp, *rsrp_dBm);
#endif

261 262 263
  return 0;
}

264 265
uint32_t calc_power_csirs(const uint16_t *x, const fapi_nr_dl_config_csirs_pdu_rel15_t *csirs_config_pdu)
{
266 267 268
  uint64_t sum_x = 0;
  uint64_t sum_x2 = 0;
  uint16_t size = 0;
269 270
  for (int rb = 0; rb < csirs_config_pdu->nr_of_rbs; rb++) {
    if (csirs_config_pdu->freq_density <= 1 && csirs_config_pdu->freq_density != ((rb + csirs_config_pdu->start_rb) % 2)) {
271 272
      continue;
    }
273 274
    sum_x = sum_x + x[rb];
    sum_x2 = sum_x2 + x[rb] * x[rb];
275 276
    size++;
  }
277
  return sum_x2 / size - (sum_x / size) * (sum_x / size);
278 279
}

280 281 282
int nr_csi_rs_channel_estimation(const PHY_VARS_NR_UE *ue,
                                 const UE_nr_rxtx_proc_t *proc,
                                 const fapi_nr_dl_config_csirs_pdu_rel15_t *csirs_config_pdu,
283
                                 const nr_csi_info_t *nr_csi_info,
284
                                 const int32_t **csi_rs_generated_signal,
285
                                 const int32_t csi_rs_received_signal[][ue->frame_parms.samples_per_slot_wCP],
286 287 288 289 290
                                 const uint8_t N_cdm_groups,
                                 const uint8_t CDM_group_size,
                                 const uint8_t k_prime,
                                 const uint8_t l_prime,
                                 const uint8_t N_ports,
291 292 293
                                 const uint8_t *j_cdm,
                                 const uint8_t *k_overline,
                                 const uint8_t *l_overline,
294 295
                                 int32_t csi_rs_ls_estimated_channel[][N_ports][ue->frame_parms.ofdm_symbol_size],
                                 int32_t csi_rs_estimated_channel_freq[][N_ports][ue->frame_parms.ofdm_symbol_size],
296 297
                                 int16_t *log2_re,
                                 int16_t *log2_maxh,
298 299
                                 uint32_t *noise_power) {

300 301
  const NR_DL_FRAME_PARMS *frame_parms = &ue->frame_parms;
  const int dataF_offset = proc->nr_slot_rx*ue->frame_parms.samples_per_slot_wCP;
302
  *noise_power = 0;
303
  int maxh = 0;
304
  int count = 0;
305

306
  for (int ant_rx = 0; ant_rx < frame_parms->nb_antennas_rx; ant_rx++) {
307

rmagueta's avatar
rmagueta committed
308 309
    /// LS channel estimation

310
    for(uint16_t port_tx = 0; port_tx<N_ports; port_tx++) {
311
      memset(csi_rs_ls_estimated_channel[ant_rx][port_tx], 0, frame_parms->ofdm_symbol_size*sizeof(int32_t));
312 313 314 315 316 317
    }

    for (int rb = csirs_config_pdu->start_rb; rb < (csirs_config_pdu->start_rb+csirs_config_pdu->nr_of_rbs); rb++) {

      // for freq density 0.5 checks if even or odd RB
      if(csirs_config_pdu->freq_density <= 1 && csirs_config_pdu->freq_density != (rb % 2)) {
rmagueta's avatar
rmagueta committed
318 319
        continue;
      }
320

321 322
      for (int cdm_id = 0; cdm_id < N_cdm_groups; cdm_id++) {
        for (int s = 0; s < CDM_group_size; s++)  {
323

324
          uint16_t port_tx = s+j_cdm[cdm_id]*CDM_group_size;
325 326

          // loop over frequency resource elements within a group
327
          for (int kp = 0; kp <= k_prime; kp++) {
328

329
            uint16_t kinit = (frame_parms->first_carrier_offset + rb*NR_NB_SC_PER_RB) % frame_parms->ofdm_symbol_size;
330
            uint16_t k = kinit + k_overline[cdm_id] + kp;
331 332

            // loop over time resource elements within a group
333
            for (int lp = 0; lp <= l_prime; lp++) {
334
              uint16_t symb = lp + l_overline[cdm_id];
335
              uint64_t symbol_offset = symb*frame_parms->ofdm_symbol_size;
336 337 338
              c16_t *tx_csi_rs_signal = (c16_t*)&csi_rs_generated_signal[port_tx][symbol_offset+dataF_offset];
              c16_t *rx_csi_rs_signal = (c16_t*)&csi_rs_received_signal[ant_rx][symbol_offset];
              c16_t *csi_rs_ls_estimated_channel16 = (c16_t*)&csi_rs_ls_estimated_channel[ant_rx][port_tx][0];
339

340 341
              int16_t csi_rs_ls_estimated_channel_re = (int16_t)(((int32_t)tx_csi_rs_signal[k].r*rx_csi_rs_signal[k].r + (int32_t)tx_csi_rs_signal[k].i*rx_csi_rs_signal[k].i)>>nr_csi_info->csi_rs_generated_signal_bits);
              int16_t csi_rs_ls_estimated_channel_im = (int16_t)(((int32_t)tx_csi_rs_signal[k].r*rx_csi_rs_signal[k].i - (int32_t)tx_csi_rs_signal[k].i*rx_csi_rs_signal[k].r)>>nr_csi_info->csi_rs_generated_signal_bits);
342

343 344
              // This is not just the LS estimation for each (k,l), but also the sum of the different contributions
              // for the sake of optimizing the memory used.
345 346
              csi_rs_ls_estimated_channel16[kinit].r += csi_rs_ls_estimated_channel_re;
              csi_rs_ls_estimated_channel16[kinit].i += csi_rs_ls_estimated_channel_im;
347 348 349
            }
          }
        }
350 351
      }
    }
352

353 354 355 356 357 358 359
#ifdef NR_CSIRS_DEBUG
    for(int symb = 0; symb < NR_SYMBOLS_PER_SLOT; symb++) {
      if(!is_csi_rs_in_symbol(*csirs_config_pdu,symb)) {
        continue;
      }
      for(int k = 0; k<frame_parms->ofdm_symbol_size; k++) {
        LOG_I(NR_PHY, "l,k (%2d,%4d) | ", symb, k);
360
        for(uint16_t port_tx = 0; port_tx<N_ports; port_tx++) {
361
          uint64_t symbol_offset = symb*frame_parms->ofdm_symbol_size;
362 363 364
          c16_t *tx_csi_rs_signal = (c16_t*)&csi_rs_generated_signal[port_tx][symbol_offset+dataF_offset];
          c16_t *rx_csi_rs_signal = (c16_t*)&csi_rs_received_signal[ant_rx][symbol_offset];
          c16_t *csi_rs_ls_estimated_channel16 = (c16_t*)&csi_rs_ls_estimated_channel[ant_rx][port_tx][0];
365 366
          printf("port_tx %d --> ant_rx %d, tx (%4d,%4d), rx (%4d,%4d), ls (%4d,%4d) | ",
                 port_tx+3000, ant_rx,
367 368 369
                 tx_csi_rs_signal[k].r, tx_csi_rs_signal[k].i,
                 rx_csi_rs_signal[k].r, rx_csi_rs_signal[k].i,
                 csi_rs_ls_estimated_channel16[k].r, csi_rs_ls_estimated_channel16[k].i);
370 371 372 373 374 375
        }
        printf("\n");
      }
    }
#endif

376 377
    /// Channel interpolation

378
    for(uint16_t port_tx = 0; port_tx<N_ports; port_tx++) {
379 380 381 382 383 384 385 386
      memset(csi_rs_estimated_channel_freq[ant_rx][port_tx], 0, frame_parms->ofdm_symbol_size*sizeof(int32_t));
    }

    for (int rb = csirs_config_pdu->start_rb; rb < (csirs_config_pdu->start_rb+csirs_config_pdu->nr_of_rbs); rb++) {

      // for freq density 0.5 checks if even or odd RB
      if(csirs_config_pdu->freq_density <= 1 && csirs_config_pdu->freq_density != (rb % 2)) {
        continue;
387
      }
388

389 390
      count++;

391
      uint16_t k = (frame_parms->first_carrier_offset + rb*NR_NB_SC_PER_RB) % frame_parms->ofdm_symbol_size;
392
      for(uint16_t port_tx = 0; port_tx<N_ports; port_tx++) {
393
        int16_t *csi_rs_ls_estimated_channel16 = (int16_t*)&csi_rs_ls_estimated_channel[ant_rx][port_tx][k];
394 395
        int16_t *csi_rs_estimated_channel16 = (int16_t *)&csi_rs_estimated_channel_freq[ant_rx][port_tx][k];
        if( (k == 0) || (k == frame_parms->first_carrier_offset) ) { // Start of OFDM symbol case or first occupied subcarrier case
396
          multadd_real_vector_complex_scalar(filt24_start, csi_rs_ls_estimated_channel16, csi_rs_estimated_channel16, 24);
397
        } else if( ( (k + NR_NB_SC_PER_RB) >= frame_parms->ofdm_symbol_size) ||
398
                   (rb == (csirs_config_pdu->start_rb+csirs_config_pdu->nr_of_rbs-1)) ) { // End of OFDM symbol case or Last occupied subcarrier case
399
          multadd_real_vector_complex_scalar(filt24_end, csi_rs_ls_estimated_channel16, csi_rs_estimated_channel16 - 3*sizeof(uint64_t), 24);
400
        } else { // Middle case
401
          multadd_real_vector_complex_scalar(filt24_middle, csi_rs_ls_estimated_channel16, csi_rs_estimated_channel16 - 3*sizeof(uint64_t), 24);
402
        }
403
      }
404
    }
405

406
    /// Power noise estimation
407 408
    uint16_t noise_real[frame_parms->nb_antennas_rx][N_ports][csirs_config_pdu->nr_of_rbs];
    uint16_t noise_imag[frame_parms->nb_antennas_rx][N_ports][csirs_config_pdu->nr_of_rbs];
409 410 411 412 413
    for (int rb = csirs_config_pdu->start_rb; rb < (csirs_config_pdu->start_rb+csirs_config_pdu->nr_of_rbs); rb++) {
      if (csirs_config_pdu->freq_density <= 1 && csirs_config_pdu->freq_density != (rb % 2)) {
        continue;
      }
      uint16_t k = (frame_parms->first_carrier_offset + rb*NR_NB_SC_PER_RB) % frame_parms->ofdm_symbol_size;
414
      for(uint16_t port_tx = 0; port_tx<N_ports; port_tx++) {
415 416 417 418 419
        c16_t *csi_rs_ls_estimated_channel16 = (c16_t*)&csi_rs_ls_estimated_channel[ant_rx][port_tx][k];
        c16_t *csi_rs_estimated_channel16 = (c16_t *)&csi_rs_estimated_channel_freq[ant_rx][port_tx][k];
        noise_real[ant_rx][port_tx][rb-csirs_config_pdu->start_rb] = abs(csi_rs_ls_estimated_channel16->r-csi_rs_estimated_channel16->r);
        noise_imag[ant_rx][port_tx][rb-csirs_config_pdu->start_rb] = abs(csi_rs_ls_estimated_channel16->i-csi_rs_estimated_channel16->i);
        maxh = cmax3(maxh, abs(csi_rs_estimated_channel16->r), abs(csi_rs_estimated_channel16->i));
420 421
      }
    }
422
    for(uint16_t port_tx = 0; port_tx<N_ports; port_tx++) {
423 424 425
      *noise_power += (calc_power_csirs(noise_real[ant_rx][port_tx], csirs_config_pdu) + calc_power_csirs(noise_imag[ant_rx][port_tx],csirs_config_pdu));
    }

426 427
#ifdef NR_CSIRS_DEBUG
    for(int k = 0; k<frame_parms->ofdm_symbol_size; k++) {
428 429 430
      int rb = k >= frame_parms->first_carrier_offset ?
               (k - frame_parms->first_carrier_offset)/NR_NB_SC_PER_RB :
               (k + frame_parms->ofdm_symbol_size - frame_parms->first_carrier_offset)/NR_NB_SC_PER_RB;
431
      LOG_I(NR_PHY, "(k = %4d) |\t", k);
432
      for(uint16_t port_tx = 0; port_tx<N_ports; port_tx++) {
433 434
        c16_t *csi_rs_ls_estimated_channel16 = (c16_t*)&csi_rs_ls_estimated_channel[ant_rx][port_tx][0];
        c16_t *csi_rs_estimated_channel16 = (c16_t *)&csi_rs_estimated_channel_freq[ant_rx][port_tx][0];
rmagueta's avatar
rmagueta committed
435
        printf("Channel port_tx %d --> ant_rx %d : ls (%4d,%4d), int (%4d,%4d), noise (%4d,%4d) | ",
436
               port_tx+3000, ant_rx,
437 438
               csi_rs_ls_estimated_channel16[k].r, csi_rs_ls_estimated_channel16[k].i,
               csi_rs_estimated_channel16[k].r, csi_rs_estimated_channel16[k].i,
439 440
               rb >= csirs_config_pdu->start_rb+csirs_config_pdu->nr_of_rbs ? 0 : noise_real[ant_rx][port_tx][rb-csirs_config_pdu->start_rb],
               rb >= csirs_config_pdu->start_rb+csirs_config_pdu->nr_of_rbs ? 0 : noise_imag[ant_rx][port_tx][rb-csirs_config_pdu->start_rb]);
441 442
      }
      printf("\n");
443 444 445
    }
#endif

446 447
  }

448
  *noise_power /= (frame_parms->nb_antennas_rx*N_ports);
449 450
  *log2_maxh = log2_approx(maxh-1);
  *log2_re = log2_approx(count-1);
451 452 453 454 455

#ifdef NR_CSIRS_DEBUG
  LOG_I(NR_PHY, "Noise power estimation based on CSI-RS: %i\n", *noise_power);
#endif

456 457 458
  return 0;
}

459 460
int nr_csi_rs_ri_estimation(const PHY_VARS_NR_UE *ue,
                            const fapi_nr_dl_config_csirs_pdu_rel15_t *csirs_config_pdu,
461
                            const nr_csi_info_t *nr_csi_info,
462 463
                            const uint8_t N_ports,
                            int32_t csi_rs_estimated_channel_freq[][N_ports][ue->frame_parms.ofdm_symbol_size],
464
                            const int16_t log2_maxh,
465 466
                            uint8_t *rank_indicator) {

467 468
  const NR_DL_FRAME_PARMS *frame_parms = &ue->frame_parms;
  const int16_t cond_dB_threshold = 5;
rmagueta's avatar
rmagueta committed
469
  int count = 0;
470 471
  *rank_indicator = 0;

472
  if (ue->frame_parms.nb_antennas_rx == 1 || N_ports == 1) {
rmagueta's avatar
rmagueta committed
473
    return 0;
474
  } else if( !(ue->frame_parms.nb_antennas_rx == 2 && N_ports == 2) ) {
rmagueta's avatar
rmagueta committed
475
    LOG_W(NR_PHY, "Rank indicator computation is not implemented for %i x %i system\n",
476
          ue->frame_parms.nb_antennas_rx, N_ports);
rmagueta's avatar
rmagueta committed
477 478 479
    return -1;
  }

480 481 482 483 484
  /* Example 2x2: Hh x H =
  *            | conjch00 conjch10 | x | ch00 ch01 | = | conjch00*ch00+conjch10*ch10 conjch00*ch01+conjch10*ch11 |
  *            | conjch01 conjch11 |   | ch10 ch11 |   | conjch01*ch00+conjch11*ch10 conjch01*ch01+conjch11*ch11 |
  */

485 486 487
  int32_t csi_rs_estimated_conjch_ch[frame_parms->nb_antennas_rx][N_ports][frame_parms->nb_antennas_rx][N_ports][frame_parms->ofdm_symbol_size] __attribute__((aligned(32)));
  int32_t csi_rs_estimated_A_MF[N_ports][N_ports][frame_parms->ofdm_symbol_size] __attribute__((aligned(32)));
  int32_t csi_rs_estimated_A_MF_sq[N_ports][N_ports][frame_parms->ofdm_symbol_size] __attribute__((aligned(32)));
488 489
  int32_t csi_rs_estimated_determ_fin[frame_parms->ofdm_symbol_size] __attribute__((aligned(32)));
  int32_t csi_rs_estimated_numer_fin[frame_parms->ofdm_symbol_size] __attribute__((aligned(32)));
490

491 492
  const uint8_t sum_shift = 1; // log2(2x2) = 2, which is a shift of 1 bit
  
493 494 495 496 497 498 499 500
  for (int rb = csirs_config_pdu->start_rb; rb < (csirs_config_pdu->start_rb+csirs_config_pdu->nr_of_rbs); rb++) {

    if (csirs_config_pdu->freq_density <= 1 && csirs_config_pdu->freq_density != (rb % 2)) {
      continue;
    }
    uint16_t k = (frame_parms->first_carrier_offset + rb*NR_NB_SC_PER_RB) % frame_parms->ofdm_symbol_size;

    for (int ant_rx_conjch = 0; ant_rx_conjch < frame_parms->nb_antennas_rx; ant_rx_conjch++) {
501
      for(uint16_t port_tx_conjch = 0; port_tx_conjch < N_ports; port_tx_conjch++) {
502
        for (int ant_rx_ch = 0; ant_rx_ch < frame_parms->nb_antennas_rx; ant_rx_ch++) {
503
          for(uint16_t port_tx_ch = 0; port_tx_ch < N_ports; port_tx_ch++) {
504 505

            // conjch x ch computation
506 507
            nr_conjch0_mult_ch1(&csi_rs_estimated_channel_freq[ant_rx_conjch][port_tx_conjch][k],
                                &csi_rs_estimated_channel_freq[ant_rx_ch][port_tx_ch][k],
508
                                &csi_rs_estimated_conjch_ch[ant_rx_conjch][port_tx_conjch][ant_rx_ch][port_tx_ch][k],
509
                                1,
510
                                log2_maxh);
511 512 513

            // construct Hh x H elements
            if(ant_rx_conjch == ant_rx_ch) {
514 515
              nr_a_sum_b((__m128i *)&csi_rs_estimated_A_MF[port_tx_conjch][port_tx_ch][k],
                         (__m128i *)&csi_rs_estimated_conjch_ch[ant_rx_conjch][port_tx_conjch][ant_rx_ch][port_tx_ch][k],
516 517
                         1);
            }
518 519 520 521 522 523
          }
        }
      }
    }

    // compute the determinant of A_MF (denominator)
524 525 526 527 528
    nr_det_A_MF_2x2(&csi_rs_estimated_A_MF[0][0][k],
                    &csi_rs_estimated_A_MF[0][1][k],
                    &csi_rs_estimated_A_MF[1][0][k],
                    &csi_rs_estimated_A_MF[1][1][k],
                    &csi_rs_estimated_determ_fin[k],
529
                    1);
530 531

    // compute the square of A_MF (numerator)
532 533 534 535 536 537 538 539 540
    nr_squared_matrix_element(&csi_rs_estimated_A_MF[0][0][k], &csi_rs_estimated_A_MF_sq[0][0][k], 1);
    nr_squared_matrix_element(&csi_rs_estimated_A_MF[0][1][k], &csi_rs_estimated_A_MF_sq[0][1][k], 1);
    nr_squared_matrix_element(&csi_rs_estimated_A_MF[1][0][k], &csi_rs_estimated_A_MF_sq[1][0][k], 1);
    nr_squared_matrix_element(&csi_rs_estimated_A_MF[1][1][k], &csi_rs_estimated_A_MF_sq[1][1][k], 1);
    nr_numer_2x2(&csi_rs_estimated_A_MF_sq[0][0][k],
                 &csi_rs_estimated_A_MF_sq[0][1][k],
                 &csi_rs_estimated_A_MF_sq[1][0][k],
                 &csi_rs_estimated_A_MF_sq[1][1][k],
                 &csi_rs_estimated_numer_fin[k],
541
                 1);
542

543
#ifdef NR_CSIRS_DEBUG
544 545
    for(uint16_t port_tx_conjch = 0; port_tx_conjch < N_ports; port_tx_conjch++) {
      for(uint16_t port_tx_ch = 0; port_tx_ch < N_ports; port_tx_ch++) {
546
        c16_t *csi_rs_estimated_A_MF_k = (c16_t *) &csi_rs_estimated_A_MF[port_tx_conjch][port_tx_ch][k];
547
        LOG_I(NR_PHY, "(%i) csi_rs_estimated_A_MF[%i][%i] = (%i, %i)\n",
548 549
              k, port_tx_conjch, port_tx_ch, csi_rs_estimated_A_MF_k->r, csi_rs_estimated_A_MF_k->i);
        c16_t *csi_rs_estimated_A_MF_sq_k = (c16_t *) &csi_rs_estimated_A_MF_sq[port_tx_conjch][port_tx_ch][k];
550
        LOG_I(NR_PHY, "(%i) csi_rs_estimated_A_MF_sq[%i][%i] = (%i, %i)\n",
551
              k, port_tx_conjch, port_tx_ch, csi_rs_estimated_A_MF_sq_k->r, csi_rs_estimated_A_MF_sq_k->i);
552 553
      }
    }
554 555
    LOG_I(NR_PHY, "(%i) csi_rs_estimated_determ_fin = %i\n", k, csi_rs_estimated_determ_fin[k]);
    LOG_I(NR_PHY, "(%i) csi_rs_estimated_numer_fin = %i\n", k, csi_rs_estimated_numer_fin[k]>>sum_shift);
556 557
#endif

558 559
    // compute the conditional number
    for (int sc_idx=0; sc_idx < NR_NB_SC_PER_RB; sc_idx++) {
560 561
      int8_t csi_rs_estimated_denum_db = dB_fixed(csi_rs_estimated_determ_fin[k + sc_idx]);
      int8_t csi_rs_estimated_numer_db = dB_fixed(csi_rs_estimated_numer_fin[k + sc_idx]>>sum_shift);
562
      int8_t cond_db = csi_rs_estimated_numer_db - csi_rs_estimated_denum_db;
563 564 565 566 567 568 569

#ifdef NR_CSIRS_DEBUG
      LOG_I(NR_PHY, "csi_rs_estimated_denum_db = %i\n", csi_rs_estimated_denum_db);
      LOG_I(NR_PHY, "csi_rs_estimated_numer_db = %i\n", csi_rs_estimated_numer_db);
      LOG_I(NR_PHY, "cond_db = %i\n", cond_db);
#endif

570 571 572 573 574 575 576 577 578 579 580 581 582
      if (cond_db < cond_dB_threshold) {
        count++;
      } else {
        count--;
      }
    }
  }

  // conditional number is lower than cond_dB_threshold in half on more REs
  if (count > 0) {
    *rank_indicator = 1;
  }

583 584 585 586 587
#ifdef NR_CSIRS_DEBUG
  LOG_I(NR_PHY, "count = %i\n", count);
  LOG_I(NR_PHY, "rank = %i\n", (*rank_indicator)+1);
#endif

588 589 590
  return 0;
}

591 592
int nr_csi_rs_pmi_estimation(const PHY_VARS_NR_UE *ue,
                             const fapi_nr_dl_config_csirs_pdu_rel15_t *csirs_config_pdu,
593
                             const nr_csi_info_t *nr_csi_info,
594 595
                             const uint8_t N_ports,
                             const int32_t csi_rs_estimated_channel_freq[][N_ports][ue->frame_parms.ofdm_symbol_size],
596 597 598
                             const uint32_t interference_plus_noise_power,
                             const uint8_t rank_indicator,
                             const int16_t log2_re,
rmagueta's avatar
rmagueta committed
599
                             uint8_t *i1,
600
                             uint8_t *i2,
rmagueta's avatar
rmagueta committed
601
                             uint32_t *precoded_sinr_dB) {
rmagueta's avatar
rmagueta committed
602

603
  const NR_DL_FRAME_PARMS *frame_parms = &ue->frame_parms;
rmagueta's avatar
rmagueta committed
604 605 606 607 608 609 610 611 612
  memset(i1,0,3*sizeof(uint8_t));
  i2[0] = 0;

  // i1 is a three-element vector in the form of [i11 i12 i13], when CodebookType is specified as 'Type1SinglePanel'.
  // Note that i13 is not applicable when the number of transmission layers is one of {1, 5, 6, 7, 8}.
  // i2, for 'Type1SinglePanel' codebook type, it is a scalar when PMIMode is specified as 'wideband', and when PMIMode
  // is specified as 'subband' or when PRGSize, the length of the i2 vector equals to the number of subbands or PRGs.
  // Note that when the number of CSI-RS ports is 2, the applicable codebook type is 'Type1SinglePanel'. In this case,
  // the precoding matrix is obtained by a single index (i2 field here) based on TS 38.214 Table 5.2.2.2.1-1.
613 614 615
  // The first column is applicable if the UE is reporting a Rank = 1, whereas the second column is applicable if the
  // UE is reporting a Rank = 2.

616
  if(N_ports == 1 || interference_plus_noise_power == 0) {
617 618 619
    return 0;
  }

rmagueta's avatar
rmagueta committed
620
  if(rank_indicator == 0 || rank_indicator == 1) {
621

622 623 624 625 626 627
    int32_t sum_re[4] = {0};
    int32_t sum_im[4] = {0};
    int32_t sum2_re[4] = {0};
    int32_t sum2_im[4] = {0};
    int32_t tested_precoded_sinr[4] = {0};

rmagueta's avatar
rmagueta committed
628 629 630 631 632 633 634 635
    for (int rb = csirs_config_pdu->start_rb; rb < (csirs_config_pdu->start_rb+csirs_config_pdu->nr_of_rbs); rb++) {

      if (csirs_config_pdu->freq_density <= 1 && csirs_config_pdu->freq_density != (rb % 2)) {
        continue;
      }
      uint16_t k = (frame_parms->first_carrier_offset + rb * NR_NB_SC_PER_RB) % frame_parms->ofdm_symbol_size;

      for (int ant_rx = 0; ant_rx < frame_parms->nb_antennas_rx; ant_rx++) {
636

637 638
        c16_t *csi_rs_estimated_channel_p0 = (c16_t *) &csi_rs_estimated_channel_freq[ant_rx][0][k];
        c16_t *csi_rs_estimated_channel_p1 = (c16_t *) &csi_rs_estimated_channel_freq[ant_rx][1][k];
rmagueta's avatar
rmagueta committed
639 640

        // H_p0 + 1*H_p1 = (H_p0_re + H_p1_re) + 1j*(H_p0_im + H_p1_im)
641 642 643 644
        sum_re[0] += (csi_rs_estimated_channel_p0->r+csi_rs_estimated_channel_p1->r);
        sum_im[0] += (csi_rs_estimated_channel_p0->i+csi_rs_estimated_channel_p1->i);
        sum2_re[0] += ((csi_rs_estimated_channel_p0->r+csi_rs_estimated_channel_p1->r)*(csi_rs_estimated_channel_p0->r+csi_rs_estimated_channel_p1->r))>>log2_re;
        sum2_im[0] += ((csi_rs_estimated_channel_p0->i+csi_rs_estimated_channel_p1->i)*(csi_rs_estimated_channel_p0->i+csi_rs_estimated_channel_p1->i))>>log2_re;
rmagueta's avatar
rmagueta committed
645 646

        // H_p0 + 1j*H_p1 = (H_p0_re - H_p1_im) + 1j*(H_p0_im + H_p1_re)
647 648 649 650
        sum_re[1] += (csi_rs_estimated_channel_p0->r-csi_rs_estimated_channel_p1->i);
        sum_im[1] += (csi_rs_estimated_channel_p0->i+csi_rs_estimated_channel_p1->r);
        sum2_re[1] += ((csi_rs_estimated_channel_p0->r-csi_rs_estimated_channel_p1->i)*(csi_rs_estimated_channel_p0->r-csi_rs_estimated_channel_p1->i))>>log2_re;
        sum2_im[1] += ((csi_rs_estimated_channel_p0->i+csi_rs_estimated_channel_p1->r)*(csi_rs_estimated_channel_p0->i+csi_rs_estimated_channel_p1->r))>>log2_re;
rmagueta's avatar
rmagueta committed
651 652

        // H_p0 - 1*H_p1 = (H_p0_re - H_p1_re) + 1j*(H_p0_im - H_p1_im)
653 654 655 656
        sum_re[2] += (csi_rs_estimated_channel_p0->r-csi_rs_estimated_channel_p1->r);
        sum_im[2] += (csi_rs_estimated_channel_p0->i-csi_rs_estimated_channel_p1->i);
        sum2_re[2] += ((csi_rs_estimated_channel_p0->r-csi_rs_estimated_channel_p1->r)*(csi_rs_estimated_channel_p0->r-csi_rs_estimated_channel_p1->r))>>log2_re;
        sum2_im[2] += ((csi_rs_estimated_channel_p0->i-csi_rs_estimated_channel_p1->i)*(csi_rs_estimated_channel_p0->i-csi_rs_estimated_channel_p1->i))>>log2_re;
rmagueta's avatar
rmagueta committed
657 658

        // H_p0 - 1j*H_p1 = (H_p0_re + H_p1_im) + 1j*(H_p0_im - H_p1_re)
659 660 661 662
        sum_re[3] += (csi_rs_estimated_channel_p0->r+csi_rs_estimated_channel_p1->i);
        sum_im[3] += (csi_rs_estimated_channel_p0->i-csi_rs_estimated_channel_p1->r);
        sum2_re[3] += ((csi_rs_estimated_channel_p0->r+csi_rs_estimated_channel_p1->i)*(csi_rs_estimated_channel_p0->r+csi_rs_estimated_channel_p1->i))>>log2_re;
        sum2_im[3] += ((csi_rs_estimated_channel_p0->i-csi_rs_estimated_channel_p1->r)*(csi_rs_estimated_channel_p0->i-csi_rs_estimated_channel_p1->r))>>log2_re;
rmagueta's avatar
rmagueta committed
663 664 665
      }
    }

666
    // We should perform >>nr_csi_info->log2_re here for all terms, but since sum2_re and sum2_im can be high values,
667 668
    // we performed this above.
    for(int p = 0; p<4; p++) {
669 670
      int32_t power_re = sum2_re[p] - (sum_re[p]>>log2_re)*(sum_re[p]>>log2_re);
      int32_t power_im = sum2_im[p] - (sum_im[p]>>log2_re)*(sum_im[p]>>log2_re);
671
      tested_precoded_sinr[p] = (power_re+power_im)/(int32_t)interference_plus_noise_power;
672 673
    }

rmagueta's avatar
rmagueta committed
674 675
    if(rank_indicator == 0) {
      for(int tested_i2 = 0; tested_i2 < 4; tested_i2++) {
676
        if(tested_precoded_sinr[tested_i2] > tested_precoded_sinr[i2[0]]) {
rmagueta's avatar
rmagueta committed
677 678
          i2[0] = tested_i2;
        }
rmagueta's avatar
rmagueta committed
679
      }
rmagueta's avatar
rmagueta committed
680
      *precoded_sinr_dB = dB_fixed(tested_precoded_sinr[i2[0]]);
rmagueta's avatar
rmagueta committed
681
    } else {
682
      i2[0] = tested_precoded_sinr[0]+tested_precoded_sinr[2] > tested_precoded_sinr[1]+tested_precoded_sinr[3] ? 0 : 1;
683
      *precoded_sinr_dB = dB_fixed((tested_precoded_sinr[i2[0]] + tested_precoded_sinr[i2[0]+2])>>1);
rmagueta's avatar
rmagueta committed
684 685
    }

686
  } else {
rmagueta's avatar
rmagueta committed
687 688
    LOG_W(NR_PHY, "PMI computation is not implemented for rank indicator %i\n", rank_indicator+1);
    return -1;
689 690 691 692 693
  }

  return 0;
}

694
int nr_csi_rs_cqi_estimation(const uint32_t precoded_sinr,
rmagueta's avatar
rmagueta committed
695 696 697 698
                             uint8_t *cqi) {

  *cqi = 0;

rmagueta's avatar
rmagueta committed
699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725
  // Default SINR table for an AWGN channel for SISO scenario, considering 0.1 BLER condition and TS 38.214 Table 5.2.2.1-2
  if(precoded_sinr>0 && precoded_sinr<=2) {
    *cqi = 4;
  } else if(precoded_sinr==3) {
    *cqi = 5;
  } else if(precoded_sinr>3 && precoded_sinr<=5) {
    *cqi = 6;
  } else if(precoded_sinr>5 && precoded_sinr<=7) {
    *cqi = 7;
  } else if(precoded_sinr>7 && precoded_sinr<=9) {
    *cqi = 8;
  } else if(precoded_sinr==10) {
    *cqi = 9;
  } else if(precoded_sinr>10 && precoded_sinr<=12) {
    *cqi = 10;
  } else if(precoded_sinr>12 && precoded_sinr<=15) {
    *cqi = 11;
  } else if(precoded_sinr==16) {
    *cqi = 12;
  } else if(precoded_sinr>16 && precoded_sinr<=18) {
    *cqi = 13;
  } else if(precoded_sinr==19) {
    *cqi = 14;
  } else if(precoded_sinr>19) {
    *cqi = 15;
  }

rmagueta's avatar
rmagueta committed
726 727 728
  return 0;
}

729 730 731
int nr_csi_im_power_estimation(const PHY_VARS_NR_UE *ue,
                               const UE_nr_rxtx_proc_t *proc,
                               const fapi_nr_dl_config_csiim_pdu_rel15_t *csiim_config_pdu,
732 733
                               uint32_t *interference_plus_noise_power) {

734
  int32_t **rxdataF = ue->common_vars.rxdataF;
735
  const NR_DL_FRAME_PARMS *frame_parms = &ue->frame_parms;
736

737 738
  const uint16_t end_rb = csiim_config_pdu->start_rb + csiim_config_pdu->nr_of_rbs > csiim_config_pdu->bwp_size ?
                          csiim_config_pdu->bwp_size : csiim_config_pdu->start_rb + csiim_config_pdu->nr_of_rbs;
739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802

  int32_t count = 0;
  int32_t sum_re = 0;
  int32_t sum_im = 0;
  int32_t sum2_re = 0;
  int32_t sum2_im = 0;

  int l_csiim[4] = {-1, -1, -1, -1};

  for(int symb_idx = 0; symb_idx < 4; symb_idx++) {

    uint8_t symb = csiim_config_pdu->l_csiim[symb_idx];
    bool done = false;
    for (int symb_idx2 = 0; symb_idx2 < symb_idx; symb_idx2++) {
      if (l_csiim[symb_idx2] == symb) {
        done = true;
      }
    }

    if (done) {
      continue;
    }

    l_csiim[symb_idx] = symb;
    uint64_t symbol_offset = symb*frame_parms->ofdm_symbol_size;

    for (int ant_rx = 0; ant_rx < frame_parms->nb_antennas_rx; ant_rx++) {

      c16_t *rx_signal = (c16_t*)&rxdataF[ant_rx][symbol_offset];

      for (int rb = csiim_config_pdu->start_rb; rb < end_rb; rb++) {

        uint16_t sc0_offset = (frame_parms->first_carrier_offset + rb*NR_NB_SC_PER_RB) % frame_parms->ofdm_symbol_size;

        for (int sc_idx = 0; sc_idx<4; sc_idx++) {

          uint16_t sc = sc0_offset + csiim_config_pdu->k_csiim[sc_idx];

#ifdef NR_CSIIM_DEBUG
          LOG_I(NR_PHY, "(ant_rx %i, sc %i) real %i, imag %i\n", ant_rx, rb, rx_signal[sc].r, rx_signal[sc].i);
#endif

          sum_re += rx_signal[sc].r;
          sum_im += rx_signal[sc].i;
          sum2_re += rx_signal[sc].r*rx_signal[sc].r;
          sum2_im += rx_signal[sc].i*rx_signal[sc].i;
          count++;
        }
      }
    }
  }

  int32_t power_re = sum2_re/count - (sum_re/count)*(sum_re/count);
  int32_t power_im = sum2_im/count - (sum_im/count)*(sum_im/count);

  *interference_plus_noise_power = power_re + power_im;

#ifdef NR_CSIIM_DEBUG
  LOG_I(NR_PHY, "interference_plus_noise_power based on CSI-IM = %i\n", *interference_plus_noise_power);
#endif

  return 0;
}

803
int nr_ue_csi_im_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t gNB_id) {
804 805 806 807 808

  if(!ue->csiim_vars[gNB_id]->active) {
    return -1;
  }

809
  const fapi_nr_dl_config_csiim_pdu_rel15_t *csiim_config_pdu = (fapi_nr_dl_config_csiim_pdu_rel15_t*)&ue->csiim_vars[gNB_id]->csiim_config_pdu;
810 811 812 813 814 815 816 817 818 819 820

#ifdef NR_CSIIM_DEBUG
  LOG_I(NR_PHY, "csiim_config_pdu->bwp_size = %i\n", csiim_config_pdu->bwp_size);
  LOG_I(NR_PHY, "csiim_config_pdu->bwp_start = %i\n", csiim_config_pdu->bwp_start);
  LOG_I(NR_PHY, "csiim_config_pdu->subcarrier_spacing = %i\n", csiim_config_pdu->subcarrier_spacing);
  LOG_I(NR_PHY, "csiim_config_pdu->start_rb = %i\n", csiim_config_pdu->start_rb);
  LOG_I(NR_PHY, "csiim_config_pdu->nr_of_rbs = %i\n", csiim_config_pdu->nr_of_rbs);
  LOG_I(NR_PHY, "csiim_config_pdu->k_csiim = %i.%i.%i.%i\n", csiim_config_pdu->k_csiim[0], csiim_config_pdu->k_csiim[1], csiim_config_pdu->k_csiim[2], csiim_config_pdu->k_csiim[3]);
  LOG_I(NR_PHY, "csiim_config_pdu->l_csiim = %i.%i.%i.%i\n", csiim_config_pdu->l_csiim[0], csiim_config_pdu->l_csiim[1], csiim_config_pdu->l_csiim[2], csiim_config_pdu->l_csiim[3]);
#endif

821 822
  nr_csi_im_power_estimation(ue, proc, csiim_config_pdu, &ue->nr_csi_info->interference_plus_noise_power);
  ue->nr_csi_info->csi_im_meas_computed = true;
823

824 825 826 827 828 829 830 831 832
  return 0;
}

int nr_ue_csi_rs_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t gNB_id) {

  if(!ue->csirs_vars[gNB_id]->active) {
    return -1;
  }

833
  const fapi_nr_dl_config_csirs_pdu_rel15_t *csirs_config_pdu = (fapi_nr_dl_config_csirs_pdu_rel15_t*)&ue->csirs_vars[gNB_id]->csirs_config_pdu;
834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851

#ifdef NR_CSIRS_DEBUG
  LOG_I(NR_PHY, "csirs_config_pdu->subcarrier_spacing = %i\n", csirs_config_pdu->subcarrier_spacing);
  LOG_I(NR_PHY, "csirs_config_pdu->cyclic_prefix = %i\n", csirs_config_pdu->cyclic_prefix);
  LOG_I(NR_PHY, "csirs_config_pdu->start_rb = %i\n", csirs_config_pdu->start_rb);
  LOG_I(NR_PHY, "csirs_config_pdu->nr_of_rbs = %i\n", csirs_config_pdu->nr_of_rbs);
  LOG_I(NR_PHY, "csirs_config_pdu->csi_type = %i (0:TRS, 1:CSI-RS NZP, 2:CSI-RS ZP)\n", csirs_config_pdu->csi_type);
  LOG_I(NR_PHY, "csirs_config_pdu->row = %i\n", csirs_config_pdu->row);
  LOG_I(NR_PHY, "csirs_config_pdu->freq_domain = %i\n", csirs_config_pdu->freq_domain);
  LOG_I(NR_PHY, "csirs_config_pdu->symb_l0 = %i\n", csirs_config_pdu->symb_l0);
  LOG_I(NR_PHY, "csirs_config_pdu->symb_l1 = %i\n", csirs_config_pdu->symb_l1);
  LOG_I(NR_PHY, "csirs_config_pdu->cdm_type = %i\n", csirs_config_pdu->cdm_type);
  LOG_I(NR_PHY, "csirs_config_pdu->freq_density = %i (0: dot5 (even RB), 1: dot5 (odd RB), 2: one, 3: three)\n", csirs_config_pdu->freq_density);
  LOG_I(NR_PHY, "csirs_config_pdu->scramb_id = %i\n", csirs_config_pdu->scramb_id);
  LOG_I(NR_PHY, "csirs_config_pdu->power_control_offset = %i\n", csirs_config_pdu->power_control_offset);
  LOG_I(NR_PHY, "csirs_config_pdu->power_control_offset_ss = %i\n", csirs_config_pdu->power_control_offset_ss);
#endif

852 853
  const NR_DL_FRAME_PARMS *frame_parms = &ue->frame_parms;
  int32_t csi_rs_received_signal[frame_parms->nb_antennas_rx][frame_parms->samples_per_slot_wCP];
854 855 856 857 858
  uint8_t N_cdm_groups = 0;
  uint8_t CDM_group_size = 0;
  uint8_t k_prime = 0;
  uint8_t l_prime = 0;
  uint8_t N_ports = 0;
859 860 861
  uint8_t j_cdm[16];
  uint8_t k_overline[16];
  uint8_t l_overline[16];
862 863
  int16_t log2_re = 0;
  int16_t log2_maxh = 0;
864 865
  uint32_t rsrp = 0;
  int rsrp_dBm = 0;
866 867 868 869 870 871 872
  uint32_t noise_power = 0;
  uint8_t rank_indicator = 0;
  uint32_t precoded_sinr_dB = 0;
  uint8_t cqi = 0;
  uint8_t i1[3];
  uint8_t i2[1];

873
  nr_generate_csi_rs(frame_parms,
874
                     ue->nr_csi_info->csi_rs_generated_signal,
875
                     AMP,
876
                     ue->nr_csi_info,
877
                     (nfapi_nr_dl_tti_csi_rs_pdu_rel15_t *) csirs_config_pdu,
878 879 880 881 882
                     proc->nr_slot_rx,
                     &N_cdm_groups,
                     &CDM_group_size,
                     &k_prime,
                     &l_prime,
883 884 885 886
                     &N_ports,
                     j_cdm,
                     k_overline,
                     l_overline);
887

888 889
  int32_t csi_rs_ls_estimated_channel[frame_parms->nb_antennas_rx][N_ports][frame_parms->ofdm_symbol_size];
  int32_t csi_rs_estimated_channel_freq[frame_parms->nb_antennas_rx][N_ports][frame_parms->ofdm_symbol_size];
890

rmagueta's avatar
rmagueta committed
891 892 893
  nr_get_csi_rs_signal(ue,
                       proc,
                       csirs_config_pdu,
894
                       ue->nr_csi_info,
895 896 897 898
                       N_cdm_groups,
                       CDM_group_size,
                       k_prime,
                       l_prime,
899 900 901
                       j_cdm,
                       k_overline,
                       l_overline,
902 903 904
                       csi_rs_received_signal,
                       &rsrp,
                       &rsrp_dBm);
905

906 907
  nr_csi_rs_channel_estimation(ue,
                               proc,
rmagueta's avatar
rmagueta committed
908
                               csirs_config_pdu,
909 910
                               ue->nr_csi_info,
                               (const int32_t **) ue->nr_csi_info->csi_rs_generated_signal,
911
                               csi_rs_received_signal,
912 913 914 915 916
                               N_cdm_groups,
                               CDM_group_size,
                               k_prime,
                               l_prime,
                               N_ports,
917 918 919
                               j_cdm,
                               k_overline,
                               l_overline,
920 921
                               csi_rs_ls_estimated_channel,
                               csi_rs_estimated_channel_freq,
922 923 924
                               &log2_re,
                               &log2_maxh,
                               &noise_power);
925

rmagueta's avatar
rmagueta committed
926 927
  nr_csi_rs_ri_estimation(ue,
                          csirs_config_pdu,
928
                          ue->nr_csi_info,
929
                          N_ports,
930
                          csi_rs_estimated_channel_freq,
931 932
                          log2_maxh,
                          &rank_indicator);
933

934 935
  nr_csi_rs_pmi_estimation(ue,
                           csirs_config_pdu,
936
                           ue->nr_csi_info,
937
                           N_ports,
938
                           csi_rs_estimated_channel_freq,
939
                           ue->nr_csi_info->csi_im_meas_computed ? ue->nr_csi_info->interference_plus_noise_power : noise_power,
940 941 942 943 944
                           rank_indicator,
                           log2_re,
                           i1,
                           i2,
                           &precoded_sinr_dB);
rmagueta's avatar
rmagueta committed
945

946
  nr_csi_rs_cqi_estimation(precoded_sinr_dB, &cqi);
rmagueta's avatar
rmagueta committed
947

948 949
  LOG_I(NR_PHY, "RSRP = %i dBm, RI = %i, i1 = %i.%i.%i, i2 = %i, SINR = %i dB, CQI = %i\n",
        rsrp_dBm, rank_indicator+1, i1[0], i1[1], i1[2], i2[0], precoded_sinr_dB, cqi);
950

951 952
  // Send CSI measurements to MAC
  fapi_nr_csirs_measurements_t csirs_measurements;
953 954
  csirs_measurements.rsrp = rsrp;
  csirs_measurements.rsrp_dBm = rsrp_dBm;
955 956 957 958
  csirs_measurements.rank_indicator = rank_indicator;
  csirs_measurements.i1 = *i1;
  csirs_measurements.i2 = *i2;
  csirs_measurements.cqi = cqi;
Roberto Louro Magueta's avatar
Roberto Louro Magueta committed
959
  nr_downlink_indication_t dl_indication;
960
  fapi_nr_rx_indication_t *rx_ind = calloc(sizeof(*rx_ind),1);
Roberto Louro Magueta's avatar
Roberto Louro Magueta committed
961
  nr_fill_dl_indication(&dl_indication, NULL, rx_ind, proc, ue, gNB_id, NULL);
962 963
  nr_fill_rx_indication(rx_ind, FAPI_NR_CSIRS_IND, gNB_id, ue, NULL, NULL, 1, proc, (void *)&csirs_measurements);
  if (ue->if_inst && ue->if_inst->dl_indication) {
Roberto Louro Magueta's avatar
Roberto Louro Magueta committed
964
    ue->if_inst->dl_indication(&dl_indication, NULL);
965 966 967 968
  } else {
    free(rx_ind);
  }

969 970
  return 0;
}