From ce1613ad7c73faf60500980f3c212dd4e748eced Mon Sep 17 00:00:00 2001
From: rmagueta <rmagueta@allbesmart.pt>
Date: Tue, 15 Mar 2022 18:55:50 +0000
Subject: [PATCH] Improvement in nr_get_csi_rs_signal() and
 nr_csi_rs_channel_estimation() to later be easier to extend to multiple ports

---
 openair1/PHY/INIT/nr_init_ue.c             |  16 +-
 openair1/PHY/NR_TRANSPORT/nr_csi_rs.c      |  29 ++-
 openair1/PHY/NR_UE_ESTIMATION/filt16a_32.c |   2 +-
 openair1/PHY/NR_UE_TRANSPORT/csi_rx.c      | 196 +++++++++++++--------
 openair1/PHY/defs_nr_common.h              |  15 +-
 5 files changed, 171 insertions(+), 87 deletions(-)

diff --git a/openair1/PHY/INIT/nr_init_ue.c b/openair1/PHY/INIT/nr_init_ue.c
index a8db7203c7..f4d958dae9 100644
--- a/openair1/PHY/INIT/nr_init_ue.c
+++ b/openair1/PHY/INIT/nr_init_ue.c
@@ -367,13 +367,17 @@ 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->csi_rs_generated_signal = (int32_t **)malloc16(fp->nb_antennas_rx * sizeof(int32_t *) );
     ue->nr_csi_rs_info->csi_rs_received_signal = (int32_t **)malloc16(fp->nb_antennas_rx * sizeof(int32_t *) );
-    ue->nr_csi_rs_info->csi_rs_ls_estimated_channel = (int32_t **)malloc16(fp->nb_antennas_rx * sizeof(int32_t *) );
-    ue->nr_csi_rs_info->csi_rs_estimated_channel_freq = (int32_t **)malloc16(fp->nb_antennas_rx * sizeof(int32_t *) );
+    ue->nr_csi_rs_info->csi_rs_ls_estimated_channel = (int32_t ***)malloc16(fp->nb_antennas_rx * sizeof(int32_t **) );
+    ue->nr_csi_rs_info->csi_rs_estimated_channel_freq = (int32_t ***)malloc16(fp->nb_antennas_rx * sizeof(int32_t **) );
     for (i=0; i<fp->nb_antennas_rx; i++) {
       ue->nr_csi_rs_info->csi_rs_generated_signal[i] = (int32_t *) malloc16_clear(fp->samples_per_frame_wCP * sizeof(int32_t));
       ue->nr_csi_rs_info->csi_rs_received_signal[i] = (int32_t *) malloc16_clear(fp->samples_per_frame_wCP * sizeof(int32_t));
-      ue->nr_csi_rs_info->csi_rs_ls_estimated_channel[i] = (int32_t *) malloc16_clear(fp->samples_per_frame_wCP * sizeof(int32_t));
-      ue->nr_csi_rs_info->csi_rs_estimated_channel_freq[i] = (int32_t *) malloc16_clear(fp->ofdm_symbol_size * sizeof(int32_t));
+      ue->nr_csi_rs_info->csi_rs_ls_estimated_channel[i] = (int32_t **) malloc16_clear(NR_MAX_NB_PORTS * sizeof(int32_t *));
+      ue->nr_csi_rs_info->csi_rs_estimated_channel_freq[i] = (int32_t **) malloc16_clear(NR_MAX_NB_PORTS * sizeof(int32_t *));
+      for (j=0; j<NR_MAX_NB_PORTS; j++) {
+        ue->nr_csi_rs_info->csi_rs_ls_estimated_channel[i][j] = (int32_t *) malloc16_clear(fp->samples_per_frame_wCP * sizeof(int32_t));
+        ue->nr_csi_rs_info->csi_rs_estimated_channel_freq[i][j] = (int32_t *) malloc16_clear(fp->ofdm_symbol_size * sizeof(int32_t));
+      }
     }
 
     ue->nr_srs_info = (nr_srs_info_t *)malloc16_clear(sizeof(nr_srs_info_t));
@@ -655,6 +659,10 @@ void term_nr_ue_signal(PHY_VARS_NR_UE *ue, int nb_connected_gNB)
     for (int i = 0; i < fp->nb_antennas_rx; i++) {
       free_and_zero(ue->nr_csi_rs_info->csi_rs_generated_signal[i]);
       free_and_zero(ue->nr_csi_rs_info->csi_rs_received_signal[i]);
+      for (int j=0; j<NR_MAX_NB_PORTS; j++) {
+        free_and_zero(ue->nr_csi_rs_info->csi_rs_ls_estimated_channel[i][j]);
+        free_and_zero(ue->nr_csi_rs_info->csi_rs_estimated_channel_freq[i][j]);
+      }
       free_and_zero(ue->nr_csi_rs_info->csi_rs_ls_estimated_channel[i]);
       free_and_zero(ue->nr_csi_rs_info->csi_rs_estimated_channel_freq[i]);
     }
diff --git a/openair1/PHY/NR_TRANSPORT/nr_csi_rs.c b/openair1/PHY/NR_TRANSPORT/nr_csi_rs.c
index 0f687d6878..64198e1318 100644
--- a/openair1/PHY/NR_TRANSPORT/nr_csi_rs.c
+++ b/openair1/PHY/NR_TRANSPORT/nr_csi_rs.c
@@ -592,7 +592,7 @@ void nr_generate_csi_rs(NR_DL_FRAME_PARMS frame_parms,
     }
   }
 
-  nr_csi_rs_info->k_list_length = 0;
+  nr_csi_rs_info->N_ports = 0;
   uint16_t start_sc = frame_parms.first_carrier_offset;
 
   // resource mapping according to 38.211 7.4.1.5.3
@@ -600,11 +600,14 @@ void nr_generate_csi_rs(NR_DL_FRAME_PARMS frame_parms,
    if ( (csi_params->freq_density > 1) || (csi_params->freq_density == (n%2))) {  // for freq density 0.5 checks if even or odd RB
     for (int ji=0; ji<size; ji++) { // loop over CDM groups
       for (int s=0 ; s<gs; s++)  { // loop over each CDM group size
+
         p = s+j[ji]*gs; // port index
+        if(nr_csi_rs_info->N_ports<(p+1)) {
+          nr_csi_rs_info->N_ports = p+1;
+        }
+
         for (kp=0; kp<=kprime; kp++) { // loop over frequency resource elements within a group
           k = (start_sc+(n*NR_NB_SC_PER_RB)+koverline[ji]+kp)%(frame_parms.ofdm_symbol_size);  // frequency index of current resource element
-          nr_csi_rs_info->map_list[nr_csi_rs_info->k_list_length] = k;
-          nr_csi_rs_info->k_list_length++;
           // wf according to tables 7.4.5.3-2 to 7.4.5.3-5
           if (kp == 0)
             wf = 1;
@@ -648,5 +651,23 @@ void nr_generate_csi_rs(NR_DL_FRAME_PARMS frame_parms,
       }    
     }
    }
-  } 
+  }
+  nr_csi_rs_info->N_cdm_groups = size;
+  nr_csi_rs_info->CDM_group_size = gs;
+  nr_csi_rs_info->kprime = kprime;
+  nr_csi_rs_info->lprime = lprime;
+  memcpy(nr_csi_rs_info->j,j,16*sizeof(uint8_t));
+  memcpy(nr_csi_rs_info->koverline,koverline,16*sizeof(uint8_t));
+  memcpy(nr_csi_rs_info->loverline,loverline,16*sizeof(uint8_t));
+
+#ifdef NR_CSIRS_DEBUG
+  LOG_I(NR_PHY, "nr_csi_rs_info->N_ports = %d\n", nr_csi_rs_info->N_ports);
+  LOG_I(NR_PHY, "nr_csi_rs_info->N_cdm_groups = %d\n", nr_csi_rs_info->N_cdm_groups);
+  LOG_I(NR_PHY, "nr_csi_rs_info->CDM_group_size = %d\n", nr_csi_rs_info->CDM_group_size);
+  LOG_I(NR_PHY, "nr_csi_rs_info->kprime = %d\n", nr_csi_rs_info->kprime);
+  LOG_I(NR_PHY, "nr_csi_rs_info->lprime = %d\n", nr_csi_rs_info->lprime);
+  for(int ji=0; ji<nr_csi_rs_info->N_cdm_groups; ji++) {
+    LOG_I(NR_PHY, "(CDM group %d) j = %d, koverline = %d, loverline = %d\n", ji, nr_csi_rs_info->j[ji], nr_csi_rs_info->koverline[ji], nr_csi_rs_info->loverline[ji]);
+  }
+#endif
 }
diff --git a/openair1/PHY/NR_UE_ESTIMATION/filt16a_32.c b/openair1/PHY/NR_UE_ESTIMATION/filt16a_32.c
index 5d3362a8c7..85084deae5 100644
--- a/openair1/PHY/NR_UE_ESTIMATION/filt16a_32.c
+++ b/openair1/PHY/NR_UE_ESTIMATION/filt16a_32.c
@@ -287,7 +287,7 @@ short filt16_end[16] = {
 // CSI-RS
 short filt24_start[24] = {
     12288,11605,10923,10240,9557,8875,8192,7509,6827,6144,5461,4779,
-    4096,0,0,0,0,0,0,0,0,0,0,0};
+    0,0,0,0,0,0,0,0,0,0,0,0};
 
 short filt24_end[24] = {
     4096,4779,5461,6144,6827,7509,8192,8875,9557,10240,10923,11605,
diff --git a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c
index cc7906fabf..0ae52ec62d 100644
--- a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c
+++ b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c
@@ -99,31 +99,50 @@ int nr_get_csi_rs_signal(PHY_VARS_NR_UE *ue,
   int32_t **rxdataF  =  ue->common_vars.common_vars_rx_data_per_thread[proc->thread_id].rxdataF;
   NR_DL_FRAME_PARMS *frame_parms = &ue->frame_parms;
 
-  for (int ant = 0; ant < frame_parms->nb_antennas_rx; ant++) {
-    memset(csi_rs_received_signal[ant], 0, frame_parms->samples_per_frame_wCP*sizeof(int32_t));
-    for(int symb = 0; symb < NR_SYMBOLS_PER_SLOT; symb++) {
-      if(!is_csi_rs_in_symbol(*csirs_config_pdu,  symb)) {
+  for (int ant_rx = 0; ant_rx < frame_parms->nb_antennas_rx; ant_rx++) {
+    memset(csi_rs_received_signal[ant_rx], 0, frame_parms->samples_per_frame_wCP*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;
       }
-      uint64_t symbol_offset = symb*frame_parms->ofdm_symbol_size;
-      int16_t *rx_signal = (int16_t*)&rxdataF[ant][symbol_offset];
-      int16_t *rx_csi_rs_signal = (int16_t*)&csi_rs_received_signal[ant][symbol_offset];
-      for(int k_id = 0; k_id<nr_csi_rs_info->k_list_length; k_id++) {
-        uint16_t k = nr_csi_rs_info->map_list[k_id];
-        rx_csi_rs_signal[k<<1] = rx_signal[k<<1];
-        rx_csi_rs_signal[(k<<1)+1] = rx_signal[(k<<1)+1];
+
+      for (int cdm_id = 0; cdm_id < nr_csi_rs_info->N_cdm_groups; cdm_id++) {
+        for (int s = 0; s < nr_csi_rs_info->CDM_group_size; s++)  {
+
+          // loop over frequency resource elements within a group
+          for (int kp = 0; kp <= nr_csi_rs_info->kprime; kp++) {
+
+            uint16_t k = (frame_parms->first_carrier_offset + (rb*NR_NB_SC_PER_RB)+nr_csi_rs_info->koverline[cdm_id] + kp) % frame_parms->ofdm_symbol_size;
+
+            // loop over time resource elements within a group
+            for (int lp = 0; lp <= nr_csi_rs_info->lprime; lp++) {
+              uint16_t symb = lp + nr_csi_rs_info->loverline[cdm_id];
+              uint64_t symbol_offset = symb*frame_parms->ofdm_symbol_size;
+              int16_t *rx_signal = (int16_t*)&rxdataF[ant_rx][symbol_offset];
+              int16_t *rx_csi_rs_signal = (int16_t*)&csi_rs_received_signal[ant_rx][symbol_offset];
+              rx_csi_rs_signal[k<<1] = rx_signal[k<<1];
+              rx_csi_rs_signal[(k<<1)+1] = rx_signal[(k<<1)+1];
 
 #ifdef NR_CSIRS_DEBUG
-        int dataF_offset = proc->nr_slot_rx*ue->frame_parms.samples_per_slot_wCP;
-        int16_t *tx_csi_rs_signal = (int16_t*)&nr_csi_rs_info->csi_rs_generated_signal[ant][symbol_offset+dataF_offset];
-        LOG_I(NR_PHY, "l,k (%2d,%3d) |\ttx (%4d,%4d)\trx (%4d,%4d)\n",
-              symb,
-              nr_csi_rs_info->map_list[k_id],
-              tx_csi_rs_signal[k<<1],
-              tx_csi_rs_signal[(k<<1)+1],
-              rx_csi_rs_signal[k<<1],
-              rx_csi_rs_signal[(k<<1)+1]);
+              int dataF_offset = proc->nr_slot_rx*ue->frame_parms.samples_per_slot_wCP;
+              uint16_t port_tx = s+nr_csi_rs_info->j[cdm_id]*nr_csi_rs_info->CDM_group_size;
+              int16_t *tx_csi_rs_signal = (int16_t*)&nr_csi_rs_info->csi_rs_generated_signal[port_tx][symbol_offset+dataF_offset];
+              LOG_I(NR_PHY, "l,k (%2d,%3d) |\tport_tx %d (%4d,%4d)\tant_rx %d (%4d,%4d)\n",
+                    symb,
+                    k,
+                    port_tx+3000,
+                    tx_csi_rs_signal[k<<1],
+                    tx_csi_rs_signal[(k<<1)+1],
+                    ant_rx,
+                    rx_csi_rs_signal[k<<1],
+                    rx_csi_rs_signal[(k<<1)+1]);
 #endif
+            }
+          }
+        }
       }
     }
   }
@@ -137,80 +156,104 @@ int nr_csi_rs_channel_estimation(PHY_VARS_NR_UE *ue,
                                  nr_csi_rs_info_t *nr_csi_rs_info,
                                  int32_t **csi_rs_generated_signal,
                                  int32_t **csi_rs_received_signal,
-                                 int32_t **csi_rs_estimated_channel_freq,
+                                 int32_t ***csi_rs_estimated_channel_freq,
                                  uint32_t *noise_power) {
 
   NR_DL_FRAME_PARMS *frame_parms = &ue->frame_parms;
   int dataF_offset = proc->nr_slot_rx*ue->frame_parms.samples_per_slot_wCP;
 
-  for (int ant = 0; ant < frame_parms->nb_antennas_rx; ant++) {
+  for (int ant_rx = 0; ant_rx < frame_parms->nb_antennas_rx; ant_rx++) {
 
     /// LS channel estimation
 
-    for(int symb = 0; symb < NR_SYMBOLS_PER_SLOT; symb++) {
-      if(!is_csi_rs_in_symbol(*csirs_config_pdu,  symb)) {
+    for(uint16_t port_tx = 0; port_tx<nr_csi_rs_info->N_ports; port_tx++) {
+      memset(nr_csi_rs_info->csi_rs_ls_estimated_channel[ant_rx][port_tx], 0, frame_parms->samples_per_frame_wCP*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;
       }
-      uint64_t symbol_offset = symb*frame_parms->ofdm_symbol_size;
-      int16_t *tx_csi_rs_signal = (int16_t*)&nr_csi_rs_info->csi_rs_generated_signal[ant][symbol_offset+dataF_offset];
-      int16_t *rx_csi_rs_signal = (int16_t*)&csi_rs_received_signal[ant][symbol_offset];
-      int16_t *csi_rs_ls_estimated_channel = (int16_t*)&nr_csi_rs_info->csi_rs_ls_estimated_channel[ant][symbol_offset];
 
-      for(int k_id = 0; k_id<nr_csi_rs_info->k_list_length; k_id++) {
-        uint16_t k = nr_csi_rs_info->map_list[k_id];
-        csi_rs_ls_estimated_channel[k<<1] = (int16_t)(((int32_t)tx_csi_rs_signal[k<<1]*rx_csi_rs_signal[k<<1] + (int32_t)tx_csi_rs_signal[(k<<1)+1]*rx_csi_rs_signal[(k<<1)+1])>>nr_csi_rs_info->csi_rs_generated_signal_bits);
-        csi_rs_ls_estimated_channel[(k<<1)+1] = (int16_t)(((int32_t)tx_csi_rs_signal[k<<1]*rx_csi_rs_signal[(k<<1)+1] - (int32_t)tx_csi_rs_signal[(k<<1)+1]*rx_csi_rs_signal[k<<1])>>nr_csi_rs_info->csi_rs_generated_signal_bits);
+      for (int cdm_id = 0; cdm_id < nr_csi_rs_info->N_cdm_groups; cdm_id++) {
+        for (int s = 0; s < nr_csi_rs_info->CDM_group_size; s++)  {
+
+          uint16_t port_tx = s+nr_csi_rs_info->j[cdm_id]*nr_csi_rs_info->CDM_group_size;
+
+          // loop over frequency resource elements within a group
+          for (int kp = 0; kp <= nr_csi_rs_info->kprime; kp++) {
+
+            uint16_t k = (frame_parms->first_carrier_offset + (rb*NR_NB_SC_PER_RB)+nr_csi_rs_info->koverline[cdm_id] + kp) % frame_parms->ofdm_symbol_size;
+
+            // loop over time resource elements within a group
+            for (int lp = 0; lp <= nr_csi_rs_info->lprime; lp++) {
+              uint16_t symb = lp + nr_csi_rs_info->loverline[cdm_id];
+              uint64_t symbol_offset = symb*frame_parms->ofdm_symbol_size;
+              int16_t *tx_csi_rs_signal = (int16_t*)&nr_csi_rs_info->csi_rs_generated_signal[port_tx][symbol_offset+dataF_offset];
+              int16_t *rx_csi_rs_signal = (int16_t*)&csi_rs_received_signal[ant_rx][symbol_offset];
+              int16_t *csi_rs_ls_estimated_channel = (int16_t*)&nr_csi_rs_info->csi_rs_ls_estimated_channel[ant_rx][port_tx][symbol_offset];
+
+              csi_rs_ls_estimated_channel[k<<1] = (int16_t)(((int32_t)tx_csi_rs_signal[k<<1]*rx_csi_rs_signal[k<<1] + (int32_t)tx_csi_rs_signal[(k<<1)+1]*rx_csi_rs_signal[(k<<1)+1])>>nr_csi_rs_info->csi_rs_generated_signal_bits);
+              csi_rs_ls_estimated_channel[(k<<1)+1] = (int16_t)(((int32_t)tx_csi_rs_signal[k<<1]*rx_csi_rs_signal[(k<<1)+1] - (int32_t)tx_csi_rs_signal[(k<<1)+1]*rx_csi_rs_signal[k<<1])>>nr_csi_rs_info->csi_rs_generated_signal_bits);
 
 #ifdef NR_CSIRS_DEBUG
-        LOG_I(NR_PHY, "l,k (%2d,%3d) |\ttx (%4d,%4d)\trx (%4d,%4d)\tls (%4d,%4d)\n",
-              symb,
-              nr_csi_rs_info->map_list[k_id],
-              tx_csi_rs_signal[k<<1],
-              tx_csi_rs_signal[(k<<1)+1],
-              rx_csi_rs_signal[k<<1],
-              rx_csi_rs_signal[(k<<1)+1],
-              csi_rs_ls_estimated_channel[k<<1],
-              csi_rs_ls_estimated_channel[(k<<1)+1]);
+              LOG_I(NR_PHY, "l,k (%2d,%4d) |\tport_tx %d (%4d,%4d)\tant_rx %d (%4d,%4d)\tls (%4d,%4d)\n",
+                    symb,
+                    k,
+                    port_tx+3000,
+                    tx_csi_rs_signal[k<<1],
+                    tx_csi_rs_signal[(k<<1)+1],
+                    ant_rx,
+                    rx_csi_rs_signal[k<<1],
+                    rx_csi_rs_signal[(k<<1)+1],
+                    csi_rs_ls_estimated_channel[k<<1],
+                    csi_rs_ls_estimated_channel[(k<<1)+1]);
 #endif
+            }
+          }
+        }
       }
     }
 
     /// Channel interpolation
 
+    for(uint16_t port_tx = 0; port_tx<nr_csi_rs_info->N_ports; port_tx++) {
+      memset(csi_rs_estimated_channel_freq[ant_rx][port_tx], 0, frame_parms->ofdm_symbol_size*sizeof(int32_t));
+    }
+
     int16_t ls_estimated[2];
-    memset(csi_rs_estimated_channel_freq[ant], 0, frame_parms->ofdm_symbol_size*sizeof(int32_t));
-
-    for (int k_id = 0; k_id < nr_csi_rs_info->k_list_length; k_id++) {
-
-      uint16_t k = nr_csi_rs_info->map_list[k_id];
-      int16_t *csi_rs_estimated_channel16 = (int16_t *)&csi_rs_estimated_channel_freq[ant][k];
-
-      // There are many possibilities to allocate the CSI-RS in time, which would take the implementation of many filters.
-      // In this approach, the LS for each symbol would be different, and it would be necessary to interpolate each symbol
-      // on the frequency as well. To reduce this complexity, and lower the processing time, we will assume that the
-      // slot duration is less than the channel coherence time. Therefore, the LS of each symbol (for the same subcarrier)
-      // would be the same, and it will only be necessary to do the frequency interpolation for 1 symbol, as the result
-      // for the others would be the same.
-      int Nsymb = 0;
-      int32_t sum_csi_rs_ls_real = 0;
-      int32_t sum_csi_rs_ls_imag = 0;
-      for (int symb = 0; symb < NR_SYMBOLS_PER_SLOT; symb++) {
-        if (!is_csi_rs_in_symbol(*csirs_config_pdu, symb)) {
-          continue;
-        }
-        Nsymb++;
-        uint64_t symbol_offset = symb * frame_parms->ofdm_symbol_size;
-        int16_t *csi_rs_ls_estimated_channel = (int16_t *) &nr_csi_rs_info->csi_rs_ls_estimated_channel[ant][symbol_offset];
-        sum_csi_rs_ls_real += csi_rs_ls_estimated_channel[k << 1];
-        sum_csi_rs_ls_imag += csi_rs_ls_estimated_channel[(k << 1) + 1];
+
+    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;
       }
-      ls_estimated[0] = (int16_t) (sum_csi_rs_ls_real / Nsymb);
-      ls_estimated[1] = (int16_t) (sum_csi_rs_ls_imag / Nsymb);
 
-      if( (k_id == 0) || (k_id > 0 && k < nr_csi_rs_info->map_list[k_id-1]) ) { // First occupied subcarrier case or Start of OFDM symbol case
+      // TODO: Extend this to multiple antenna ports
+      int cdm_id = 0;
+      int s = 0;
+      int kp = 0;
+      int lp = 0;
+
+      uint16_t port_tx = s+nr_csi_rs_info->j[cdm_id]*nr_csi_rs_info->CDM_group_size;
+
+      uint16_t k = (frame_parms->first_carrier_offset + (rb*NR_NB_SC_PER_RB)+nr_csi_rs_info->koverline[cdm_id] + kp) % frame_parms->ofdm_symbol_size;
+      uint16_t symb = lp + nr_csi_rs_info->loverline[cdm_id];
+      uint64_t symbol_offset = symb*frame_parms->ofdm_symbol_size;
+
+      int16_t *csi_rs_ls_estimated_channel = (int16_t*)&nr_csi_rs_info->csi_rs_ls_estimated_channel[ant_rx][port_tx][symbol_offset];
+      int16_t *csi_rs_estimated_channel16 = (int16_t *)&csi_rs_estimated_channel_freq[ant_rx][port_tx][k];
+
+      ls_estimated[0] = (int16_t) csi_rs_ls_estimated_channel[k<<1];
+      ls_estimated[1] = (int16_t) csi_rs_ls_estimated_channel[(k<<1)+1];
+
+      if( (k == 0) || (k == frame_parms->first_carrier_offset) ) { // Start of OFDM symbol case or first occupied subcarrier case
         multadd_real_vector_complex_scalar(filt24_start, ls_estimated, csi_rs_estimated_channel16, 24);
-      } else if( (k_id < nr_csi_rs_info->k_list_length-1 && nr_csi_rs_info->map_list[k_id+1] < k) ||
-                 (k_id == nr_csi_rs_info->k_list_length-1) ) { // End of OFDM symbol case or Last occupied subcarrier case
+      } else if( ( (k + NR_NB_SC_PER_RB) >= frame_parms->ofdm_symbol_size) ||
+                   (rb == (csirs_config_pdu->start_rb+csirs_config_pdu->nr_of_rbs-1)) ) { // End of OFDM symbol case or Last occupied subcarrier case
         multadd_real_vector_complex_scalar(filt24_end, ls_estimated, csi_rs_estimated_channel16 - 3*sizeof(uint64_t), 24);
       } else { // Middle case
         multadd_real_vector_complex_scalar(filt24_middle, ls_estimated, csi_rs_estimated_channel16 - 3*sizeof(uint64_t), 24);
@@ -219,9 +262,14 @@ int nr_csi_rs_channel_estimation(PHY_VARS_NR_UE *ue,
 
 #ifdef NR_CSIRS_DEBUG
 
-    uint64_t symbol_offset = csirs_config_pdu->symb_l0*frame_parms->ofdm_symbol_size;
-    int16_t *csi_rs_ls_estimated_channel = (int16_t*)&nr_csi_rs_info->csi_rs_ls_estimated_channel[ant][symbol_offset];
-    int16_t *csi_rs_estimated_channel16 = (int16_t*)&nr_csi_rs_info->csi_rs_estimated_channel_freq[ant][0];
+    int cdm_id = 0;
+    int s = 0;
+    int lp = 0;
+    uint16_t port_tx = s+nr_csi_rs_info->j[cdm_id]*nr_csi_rs_info->CDM_group_size;
+    uint16_t symb = lp + nr_csi_rs_info->loverline[cdm_id];
+    uint64_t symbol_offset = symb*frame_parms->ofdm_symbol_size;
+    int16_t *csi_rs_ls_estimated_channel = (int16_t*)&nr_csi_rs_info->csi_rs_ls_estimated_channel[ant_rx][port_tx][symbol_offset];
+    int16_t *csi_rs_estimated_channel16 = (int16_t *)&csi_rs_estimated_channel_freq[ant_rx][port_tx][0];
 
     for(int k = 0; k<frame_parms->ofdm_symbol_size; k++) {
       LOG_I(NR_PHY, "(%4d) |\tls (%4d,%4d)\tint (%4d,%4d)\n",
diff --git a/openair1/PHY/defs_nr_common.h b/openair1/PHY/defs_nr_common.h
index cbc8bc8508..cfe5e8b9df 100644
--- a/openair1/PHY/defs_nr_common.h
+++ b/openair1/PHY/defs_nr_common.h
@@ -94,6 +94,7 @@
 
 #define NR_MAX_NB_RBG 18
 #define NR_MAX_NB_LAYERS 2 // 8 // SU-MIMO (3GPP TS 38.211 V15.4.0 section 7.3.1.3)
+#define NR_MAX_NB_PORTS 32
 #define NR_MAX_NB_CODEWORDS 2
 #define NR_MAX_NB_HARQ_PROCESSES 16
 #define NR_MAX_PDSCH_ENCODED_LENGTH (NR_MAX_NB_RB*NR_SYMBOLS_PER_SLOT*NR_NB_SC_PER_RB*8*NR_MAX_NB_LAYERS) // 8 is the maximum modulation order (it was 950984 before !!)
@@ -265,14 +266,20 @@ typedef struct {
 } nr_srs_info_t;
 
 typedef struct {
+  uint8_t N_cdm_groups;
+  uint8_t CDM_group_size;
+  uint8_t kprime;
+  uint8_t lprime;
+  uint8_t N_ports;
+  uint8_t j[16];
+  uint8_t koverline[16];
+  uint8_t loverline[16];
   uint32_t ***nr_gold_csi_rs;
-  uint16_t k_list_length;
-  uint16_t map_list[NR_MAX_CSI_RS_LENGTH];
   uint8_t csi_rs_generated_signal_bits;
   int32_t **csi_rs_generated_signal;
   int32_t **csi_rs_received_signal;
-  int32_t **csi_rs_ls_estimated_channel;
-  int32_t **csi_rs_estimated_channel_freq;
+  int32_t ***csi_rs_ls_estimated_channel;
+  int32_t ***csi_rs_estimated_channel_freq;
   uint32_t *noise_power;
 } nr_csi_rs_info_t;
 
-- 
2.26.2