From c7a54269de4dd75bf94765b2fe9f71fe48cd9ae2 Mon Sep 17 00:00:00 2001
From: rmagueta <rmagueta@allbesmart.pt>
Date: Wed, 30 Mar 2022 16:16:58 +0100
Subject: [PATCH] First version of rank indicator computation at UE

---
 openair1/PHY/INIT/nr_init_ue.c        |   2 +
 openair1/PHY/NR_UE_TRANSPORT/csi_rx.c | 123 ++++++++++++++++++++++++++
 openair1/PHY/defs_nr_common.h         |   7 ++
 3 files changed, 132 insertions(+)

diff --git a/openair1/PHY/INIT/nr_init_ue.c b/openair1/PHY/INIT/nr_init_ue.c
index 6d2655cb932..033ea2eec60 100644
--- a/openair1/PHY/INIT/nr_init_ue.c
+++ b/openair1/PHY/INIT/nr_init_ue.c
@@ -351,6 +351,7 @@ int init_nr_ue_signal(PHY_VARS_NR_UE *ue, int nb_connected_gNB)
       }
     }
     ue->nr_csi_rs_info->noise_power = (uint32_t*)malloc16_clear(sizeof(uint32_t));
+    ue->nr_csi_rs_info->rank_indicator = (uint8_t*)malloc16_clear(sizeof(uint8_t));
     ue->nr_csi_rs_info->csi_rs_generated_signal = (int32_t **)malloc16(NR_MAX_NB_PORTS * sizeof(int32_t *) );
     for (i=0; i<NR_MAX_NB_PORTS; i++) {
       ue->nr_csi_rs_info->csi_rs_generated_signal[i] = (int32_t *) malloc16_clear(fp->samples_per_frame_wCP * sizeof(int32_t));
@@ -642,6 +643,7 @@ void term_nr_ue_signal(PHY_VARS_NR_UE *ue, int nb_connected_gNB)
       free_and_zero(ue->nr_csi_rs_info->nr_gold_csi_rs[slot]);
     }
     free_and_zero(ue->nr_csi_rs_info->noise_power);
+    free_and_zero(ue->nr_csi_rs_info->rank_indicator);
     free_and_zero(ue->nr_csi_rs_info->nr_gold_csi_rs);
     free_and_zero(ue->nr_csi_rs_info->csi_rs_generated_signal);
     free_and_zero(ue->nr_csi_rs_info->csi_rs_received_signal);
diff --git a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c
index fd33398f5cd..138d5ff7cac 100644
--- a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c
+++ b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c
@@ -355,6 +355,114 @@ int nr_csi_rs_channel_estimation(PHY_VARS_NR_UE *ue,
   return 0;
 }
 
+int nr_csi_rs_ri_estimation(PHY_VARS_NR_UE *ue,
+                            UE_nr_rxtx_proc_t *proc,
+                            fapi_nr_dl_config_csirs_pdu_rel15_t *csirs_config_pdu,
+                            nr_csi_rs_info_t *nr_csi_rs_info,
+                            int32_t ***csi_rs_estimated_channel_freq,
+                            uint8_t *rank_indicator) {
+
+  NR_DL_FRAME_PARMS *frame_parms = &ue->frame_parms;
+  int16_t cond_dB_threshold = 0;
+  int count=0;
+  *rank_indicator = 0;
+
+  /* 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 |
+  */
+
+  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;
+
+    // conjch x ch computation
+    for (int ant_rx_conjch = 0; ant_rx_conjch < frame_parms->nb_antennas_rx; ant_rx_conjch++) {
+      for(uint16_t port_tx_conjch = 0; port_tx_conjch < nr_csi_rs_info->N_ports; port_tx_conjch++) {
+        for (int ant_rx_ch = 0; ant_rx_ch < frame_parms->nb_antennas_rx; ant_rx_ch++) {
+          for(uint16_t port_tx_ch = 0; port_tx_ch < nr_csi_rs_info->N_ports; port_tx_ch++) {
+            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],
+                                &nr_csi_rs_info->csi_rs_estimated_conjch_ch[ant_rx_conjch][port_tx_conjch][ant_rx_ch][port_tx_ch][k],
+                                1,
+                                0);
+          }
+        }
+      }
+    }
+
+    // construct Hh x H elements
+    nr_construct_HhH_elements(0 < frame_parms->nb_antennas_rx && 0 < nr_csi_rs_info->N_ports ? &nr_csi_rs_info->csi_rs_estimated_conjch_ch[0][0][0][0][k] : NULL,
+                              0 < frame_parms->nb_antennas_rx && 1 < nr_csi_rs_info->N_ports ? &nr_csi_rs_info->csi_rs_estimated_conjch_ch[0][1][0][1][k] : NULL,
+                              1 < frame_parms->nb_antennas_rx && 1 < nr_csi_rs_info->N_ports ? &nr_csi_rs_info->csi_rs_estimated_conjch_ch[1][1][1][1][k] : NULL,
+                              1 < frame_parms->nb_antennas_rx && 0 < nr_csi_rs_info->N_ports ? &nr_csi_rs_info->csi_rs_estimated_conjch_ch[1][0][1][0][k] : NULL,
+                              2 < frame_parms->nb_antennas_rx && 0 < nr_csi_rs_info->N_ports ? &nr_csi_rs_info->csi_rs_estimated_conjch_ch[2][0][2][0][k] : NULL,
+                              2 < frame_parms->nb_antennas_rx && 1 < nr_csi_rs_info->N_ports ? &nr_csi_rs_info->csi_rs_estimated_conjch_ch[2][1][2][1][k] : NULL,
+                              3 < frame_parms->nb_antennas_rx && 0 < nr_csi_rs_info->N_ports ? &nr_csi_rs_info->csi_rs_estimated_conjch_ch[3][0][3][0][k] : NULL,
+                              3 < frame_parms->nb_antennas_rx && 1 < nr_csi_rs_info->N_ports ? &nr_csi_rs_info->csi_rs_estimated_conjch_ch[3][1][3][1][k] : NULL,
+                              0 < frame_parms->nb_antennas_rx && 1 < nr_csi_rs_info->N_ports ? &nr_csi_rs_info->csi_rs_estimated_conjch_ch[0][0][0][1][k] : NULL,
+                              0 < frame_parms->nb_antennas_rx && 1 < nr_csi_rs_info->N_ports ? &nr_csi_rs_info->csi_rs_estimated_conjch_ch[0][1][0][0][k] : NULL,
+                              1 < frame_parms->nb_antennas_rx && 1 < nr_csi_rs_info->N_ports ? &nr_csi_rs_info->csi_rs_estimated_conjch_ch[1][0][1][1][k] : NULL,
+                              1 < frame_parms->nb_antennas_rx && 1 < nr_csi_rs_info->N_ports ? &nr_csi_rs_info->csi_rs_estimated_conjch_ch[1][1][1][0][k] : NULL,
+                              2 < frame_parms->nb_antennas_rx && 1 < nr_csi_rs_info->N_ports ? &nr_csi_rs_info->csi_rs_estimated_conjch_ch[2][0][2][1][k] : NULL,
+                              2 < frame_parms->nb_antennas_rx && 1 < nr_csi_rs_info->N_ports ? &nr_csi_rs_info->csi_rs_estimated_conjch_ch[2][1][2][0][k] : NULL,
+                              3 < frame_parms->nb_antennas_rx && 1 < nr_csi_rs_info->N_ports ? &nr_csi_rs_info->csi_rs_estimated_conjch_ch[3][0][3][1][k] : NULL,
+                              3 < frame_parms->nb_antennas_rx && 1 < nr_csi_rs_info->N_ports ? &nr_csi_rs_info->csi_rs_estimated_conjch_ch[3][1][3][0][k] : NULL,
+                              &nr_csi_rs_info->csi_rs_estimated_A_MF[0][0][k],
+                              &nr_csi_rs_info->csi_rs_estimated_A_MF[0][1][k],
+                              &nr_csi_rs_info->csi_rs_estimated_A_MF[1][0][k],
+                              &nr_csi_rs_info->csi_rs_estimated_A_MF[1][1][k],
+                              1,
+                              0);
+
+    // compute the determinant of A_MF (denominator)
+    nr_det_HhH(&nr_csi_rs_info->csi_rs_estimated_A_MF[0][0][k],
+               &nr_csi_rs_info->csi_rs_estimated_A_MF[0][1][k],
+               &nr_csi_rs_info->csi_rs_estimated_A_MF[1][0][k],
+               &nr_csi_rs_info->csi_rs_estimated_A_MF[1][1][k],
+               &nr_csi_rs_info->csi_rs_estimated_determ_fin[k],
+               1,
+               0,
+               0);
+
+    // compute the square of A_MF (numerator)
+    squared_matrix_element(&nr_csi_rs_info->csi_rs_estimated_A_MF[0][0][k], &nr_csi_rs_info->csi_rs_estimated_A_MF_sq[0][0][k], 1);
+    squared_matrix_element(&nr_csi_rs_info->csi_rs_estimated_A_MF[0][1][k], &nr_csi_rs_info->csi_rs_estimated_A_MF_sq[0][1][k], 1);
+    squared_matrix_element(&nr_csi_rs_info->csi_rs_estimated_A_MF[1][0][k], &nr_csi_rs_info->csi_rs_estimated_A_MF_sq[1][0][k], 1);
+    squared_matrix_element(&nr_csi_rs_info->csi_rs_estimated_A_MF[1][1][k], &nr_csi_rs_info->csi_rs_estimated_A_MF_sq[1][1][k], 1);
+    numer(&nr_csi_rs_info->csi_rs_estimated_A_MF_sq[0][0][k],
+          &nr_csi_rs_info->csi_rs_estimated_A_MF_sq[0][1][k],
+          &nr_csi_rs_info->csi_rs_estimated_A_MF_sq[1][0][k],
+          &nr_csi_rs_info->csi_rs_estimated_A_MF_sq[1][1][k],
+          &nr_csi_rs_info->csi_rs_estimated_numer_fin[k],
+          1);
+
+    // compute the conditional number
+    for (int sc_idx=0; sc_idx < NR_NB_SC_PER_RB; sc_idx++) {
+      int8_t csi_rs_estimated_denum_db = dB_fixed(nr_csi_rs_info->csi_rs_estimated_determ_fin[k + sc_idx]);
+      int8_t csi_rs_estimated_numer_db = dB_fixed(nr_csi_rs_info->csi_rs_estimated_numer_fin[k + k]);
+      int8_t cond_db = csi_rs_estimated_numer_db - csi_rs_estimated_denum_db;
+      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;
+  }
+
+  LOG_I(NR_PHY, "count %i, RI = %i\n", *rank_indicator + 1);
+
+  return 0;
+}
+
 int nr_ue_csi_im_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t gNB_id) {
   return 0;
 }
@@ -406,5 +514,20 @@ int nr_ue_csi_rs_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t
                                ue->nr_csi_rs_info->csi_rs_received_signal,
                                ue->nr_csi_rs_info->csi_rs_estimated_channel_freq,
                                ue->nr_csi_rs_info->noise_power);
+
+  if(ue->frame_parms.nb_antennas_rx == 1 || ue->nr_csi_rs_info->N_ports == 1) {
+    *ue->nr_csi_rs_info->rank_indicator = 0;
+  } else if(ue->frame_parms.nb_antennas_rx == 2 && ue->nr_csi_rs_info->N_ports == 2) {
+    nr_csi_rs_ri_estimation(ue,
+                            proc,
+                            csirs_config_pdu,
+                            ue->nr_csi_rs_info,
+                            ue->nr_csi_rs_info->csi_rs_estimated_channel_freq,
+                            ue->nr_csi_rs_info->rank_indicator);
+  } else {
+    LOG_D(NR_PHY, "Rank indicator computation is not implemented for %i x %i system\n",
+          ue->frame_parms.nb_antennas_rx, ue->nr_csi_rs_info->N_ports);
+  }
+
   return 0;
 }
diff --git a/openair1/PHY/defs_nr_common.h b/openair1/PHY/defs_nr_common.h
index 87eed8c4fcf..1ed5eee07c8 100644
--- a/openair1/PHY/defs_nr_common.h
+++ b/openair1/PHY/defs_nr_common.h
@@ -43,6 +43,7 @@
 #define nr_slot_t lte_subframe_t
 
 #define MAX_NUM_SUBCARRIER_SPACING 5
+#define NR_MAX_OFDM_SYMBOL_SIZE 4096
 
 #define NR_NB_SC_PER_RB 12
 #define NR_NB_REG_PER_CCE 6
@@ -260,7 +261,13 @@ typedef struct {
   int32_t **csi_rs_received_signal;
   int32_t ***csi_rs_ls_estimated_channel;
   int32_t ***csi_rs_estimated_channel_freq;
+  int32_t csi_rs_estimated_conjch_ch[4][4][4][4][NR_MAX_OFDM_SYMBOL_SIZE] __attribute__((aligned(32)));
+  int32_t csi_rs_estimated_A_MF[2][2][NR_MAX_OFDM_SYMBOL_SIZE] __attribute__((aligned(32)));
+  int32_t csi_rs_estimated_A_MF_sq[2][2][NR_MAX_OFDM_SYMBOL_SIZE] __attribute__((aligned(32)));
+  int32_t csi_rs_estimated_determ_fin[NR_MAX_OFDM_SYMBOL_SIZE] __attribute__((aligned(32)));
+  int32_t csi_rs_estimated_numer_fin[NR_MAX_OFDM_SYMBOL_SIZE] __attribute__((aligned(32)));
   uint32_t *noise_power;
+  uint8_t *rank_indicator;
 } nr_csi_rs_info_t;
 
 typedef struct NR_DL_FRAME_PARMS NR_DL_FRAME_PARMS;
-- 
GitLab