diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt
index ff4a452866e0ecba89e2a0e6a74a10fe303344c6..c7836e7a7f96c47e854a516ecefaac665daf1599 100644
--- a/cmake_targets/CMakeLists.txt
+++ b/cmake_targets/CMakeLists.txt
@@ -515,12 +515,12 @@ set (CONFIG_SOURCES
     ${CONFIG_ROOTDIR}/config_load_configmodule.c
     ${CONFIG_ROOTDIR}/config_userapi.c
     ${CONFIG_ROOTDIR}/config_cmdline.c
-   ) 
+   )
 set (CONFIG_LIBCONFIG_SOURCES
     ${CONFIG_ROOTDIR}/libconfig/config_libconfig.c
-   )   
+   )
 add_library(params_libconfig MODULE ${CONFIG_LIBCONFIG_SOURCES} )
-target_link_libraries(params_libconfig config)  
+target_link_libraries(params_libconfig config)
 # shared library loader
 set (SHLIB_LOADER_SOURCES
     ${OPENAIR_DIR}/common/utils/load_module_shlib.c
@@ -665,6 +665,7 @@ add_boolean_option(SMBV                    False "Rohde&Schwarz SMBV100A vector
 add_boolean_option(DEBUG_PHY               False "Enable PHY layer debugging options")
 add_boolean_option(DEBUG_PHY_PROC          False "Enable debugging of PHY layer procedures")
 add_boolean_option(DEBUG_DLSCH             False "Enable debugging of DLSCH physical layer channel")
+add_boolean_option(MEX                     False "Enabling compilation with mex")
 
 ##########################
 # NAS LAYER OPTIONS
@@ -984,7 +985,7 @@ set(SECU_CN_SRC
   )
 add_library(SECU_CN ${SECU_CN_SRC})
 
-# Physical Channel Procedures Scheduling  
+# Physical Channel Procedures Scheduling
 ################################"
 set(SCHED_SRC
   ${OPENAIR1_DIR}/SCHED/fapi_l1.c
@@ -1084,6 +1085,7 @@ set(PHY_SRC_COMMON
 #  ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/slss.c
 #  ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/sldch.c
 #  ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/slsch.c
+  ${OPENAIR1_DIR}/PHY/LTE_UE_TRANSPORT/get_pmi.c
   ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/group_hopping.c
   ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/phich_common.c
   ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/pcfich_common.c
@@ -1172,6 +1174,7 @@ set(PHY_SRC_UE
   ${OPENAIR1_DIR}/PHY/LTE_UE_TRANSPORT/sss_ue.c
   ${OPENAIR1_DIR}/PHY/LTE_UE_TRANSPORT/dlsch_demodulation.c
   ${OPENAIR1_DIR}/PHY/LTE_UE_TRANSPORT/dlsch_llr_computation.c
+  ${OPENAIR1_DIR}/PHY/LTE_UE_TRANSPORT/linear_preprocessing_rec.c
   ${OPENAIR1_DIR}/PHY/LTE_UE_TRANSPORT/dlsch_decoding.c
   ${OPENAIR1_DIR}/PHY/LTE_UE_TRANSPORT/dci_tools_ue.c
   ${OPENAIR1_DIR}/PHY/LTE_UE_TRANSPORT/uci_tools_ue.c
@@ -1219,6 +1222,27 @@ add_library(PHY ${PHY_SRC})
 add_library(PHY_UE ${PHY_SRC_UE})
 add_library(PHY_RU ${PHY_SRC_RU})
 
+#Library for mex functions
+#########################3
+set(PHY_MEX_UE
+  ${OPENAIR1_DIR}/PHY/LTE_UE_TRANSPORT/linear_preprocessing_rec.c
+  ${OPENAIR1_DIR}/PHY/LTE_UE_TRANSPORT/dlsch_llr_computation.c
+  ${OPENAIR1_DIR}/PHY/LTE_UE_TRANSPORT/dlsch_demodulation.c
+  ${OPENAIR1_DIR}/PHY/TOOLS/log2_approx.c
+  ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/lte_mcs.c
+  ${OPENAIR1_DIR}/PHY/LTE_UE_TRANSPORT/get_pmi.c
+  ${OPENAIR1_DIR}/PHY/TOOLS/dB_routines.c
+  ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/pmch_common.c
+  ${OPENAIR1_DIR}/PHY/TOOLS/cadd_vv.c
+  ${OPENAIR1_DIR}/PHY/TOOLS/cmult_sv.c
+  ${OPENAIR1_DIR}/PHY/TOOLS/cmult_vv.c
+  ${OPENAIR1_DIR}/PHY/LTE_UE_TRANSPORT/dlsch_llr_computation_avx2.c
+  ${OPENAIR1_DIR}/PHY/TOOLS/signal_energy.c
+  ${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/lte_ue_measurements.c
+  ${OPENAIR2_DIR}/UTIL/LOG/log.c
+  )
+add_library(PHY_MEX ${PHY_MEX_UE})
+
 #Layer 2 library
 #####################
 set(MAC_DIR ${OPENAIR2_DIR}/LAYER2/MAC)
@@ -1814,11 +1838,13 @@ endif()
 # So, here are some hacks here. Hope this gets fixed in future!
 if(EXISTS "/usr/include/atlas/cblas.h" OR EXISTS "/usr/include/cblas.h")
   include_directories("/usr/include/atlas")
+  LINK_DIRECTORIES("/usr/lib/lapack")
   LINK_DIRECTORIES("/usr/lib64")
   LINK_DIRECTORIES("/usr/lib64/atlas") #Added because atlas libraries in CentOS 7 are here!
-  
+
   if(EXISTS "/usr/lib64/libblas.so" OR EXISTS "/usr/lib/libblas.so") #Case for CentOS7
      list(APPEND ATLAS_LIBRARIES blas)
+
   else() # Case for Ubuntu
      list(APPEND ATLAS_LIBRARIES cblas)
   endif()
@@ -1844,6 +1870,8 @@ else()
   message("No Blas/Atlas libs found, some targets will fail")
 endif()
 
+list(APPEND ATLAS_LIBRARIES lapack lapacke)
+
 if (${XFORMS})
   include_directories ("/usr/include/X11")
   set(XFORMS_SOURCE
@@ -1926,7 +1954,7 @@ add_executable(lte-softmodem
 
 target_link_libraries (lte-softmodem
   -Wl,--start-group
-  RRC_LIB S1AP_LIB S1AP_ENB GTPV1U SECU_CN SECU_OSA UTIL HASHTABLE SCTP_CLIENT UDP SCHED_LIB SCHED_RU_LIB PHY_COMMON PHY PHY_RU LFDS L2 
+  RRC_LIB S1AP_LIB S1AP_ENB GTPV1U SECU_CN SECU_OSA UTIL HASHTABLE SCTP_CLIENT UDP SCHED_LIB SCHED_RU_LIB PHY_COMMON PHY PHY_RU LFDS L2
   ${MSC_LIB} ${RAL_LIB} ${NAS_UE_LIB} ${ITTI_LIB} ${FLPT_MSG_LIB} ${ASYNC_IF_LIB} ${FLEXRAN_AGENT_LIB} LFDS7
   NFAPI_COMMON_LIB NFAPI_LIB NFAPI_VNF_LIB NFAPI_PNF_LIB NFAPI_USER_LIB
   -Wl,--end-group z dl)
@@ -1964,7 +1992,7 @@ add_executable(lte-softmodem-nos1
   )
 target_link_libraries (lte-softmodem-nos1
   -Wl,--start-group
-  RRC_LIB SECU_CN SECU_OSA UTIL HASHTABLE SCHED_LIB SCHED_RU_LIB PHY_COMMON PHY PHY_RU LFDS L2 ${MSC_LIB} ${RAL_LIB} ${ITTI_LIB} 
+  RRC_LIB SECU_CN SECU_OSA UTIL HASHTABLE SCHED_LIB SCHED_RU_LIB PHY_COMMON PHY PHY_RU LFDS L2 ${MSC_LIB} ${RAL_LIB} ${ITTI_LIB}
   ${MIH_LIB} ${FLPT_MSG_LIB} ${ASYNC_IF_LIB} ${FLEXRAN_AGENT_LIB} LFDS7
   NFAPI_COMMON_LIB NFAPI_LIB NFAPI_VNF_LIB NFAPI_PNF_LIB NFAPI_USER_LIB
   -Wl,--end-group z dl )
@@ -2004,8 +2032,8 @@ add_executable(lte-uesoftmodem
 
 target_link_libraries (lte-uesoftmodem
   -Wl,--start-group
-  RRC_LIB S1AP_LIB S1AP_ENB GTPV1U SECU_CN SECU_OSA UTIL HASHTABLE SCTP_CLIENT UDP SCHED_RU_LIB SCHED_UE_LIB PHY_COMMON PHY_UE PHY_RU LFDS L2_UE SIMU 
-  ${MSC_LIB} ${RAL_LIB} ${NAS_UE_LIB} ${ITTI_LIB} ${FLPT_MSG_LIB} ${ASYNC_IF_LIB} LFDS7
+  RRC_LIB S1AP_LIB S1AP_ENB GTPV1U SECU_CN SECU_OSA UTIL HASHTABLE SCTP_CLIENT UDP SCHED_RU_LIB SCHED_UE_LIB PHY_COMMON PHY_UE PHY_RU LFDS L2_UE SIMU
+  ${MSC_LIB} ${RAL_LIB} ${NAS_UE_LIB} ${ITTI_LIB} ${FLPT_MSG_LIB} ${ASYNC_IF_LIB} LFDS7 ${ATLAS_LIBRARIES}
   NFAPI_COMMON_LIB NFAPI_LIB NFAPI_PNF_LIB NFAPI_USER_LIB
   -Wl,--end-group z dl)
 
@@ -2044,8 +2072,8 @@ add_executable(lte-uesoftmodem-nos1
 
 target_link_libraries (lte-uesoftmodem-nos1
   -Wl,--start-group
-  RRC_LIB SECU_CN SECU_OSA UTIL HASHTABLE SCHED_RU_LIB SCHED_UE_LIB PHY_COMMON PHY_UE PHY_RU LFDS L2_UE SIMU ${MSC_LIB} ${RAL_LIB} ${ITTI_LIB} 
-  ${MIH_LIB} ${FLPT_MSG_LIB} ${ASYNC_IF_LIB} LFDS7
+  RRC_LIB SECU_CN SECU_OSA UTIL HASHTABLE SCHED_RU_LIB SCHED_UE_LIB PHY_COMMON PHY_UE PHY_RU LFDS L2_UE SIMU ${MSC_LIB} ${RAL_LIB} ${ITTI_LIB}
+  ${MIH_LIB} ${FLPT_MSG_LIB} ${ASYNC_IF_LIB} LFDS7 ${ATLAS_LIBRARIES}
   NFAPI_COMMON_LIB NFAPI_LIB NFAPI_PNF_LIB NFAPI_USER_LIB
   -Wl,--end-group z dl )
 
diff --git a/cmake_targets/tools/build_helper b/cmake_targets/tools/build_helper
index d5a2d9412c05e5b22c5415281271d1a67a315c9c..f51d3656a1f53bff18c6f9cd7c207741d78f41a0 100755
--- a/cmake_targets/tools/build_helper
+++ b/cmake_targets/tools/build_helper
@@ -56,7 +56,7 @@ white='\E[37m'
 reset_color='\E[00m'
 COLORIZE=1
 
-cecho()  {  
+cecho()  {
     # Color-echo
     # arg1 = message
     # arg2 = color
@@ -147,10 +147,10 @@ clean_kernel() {
 clean_all_files() {
  set_openair_env
  dir=$OPENAIR_DIR/cmake_targets
- rm -rf $dir/log $OPENAIR_DIR/targets/bin/* 
+ rm -rf $dir/log $OPENAIR_DIR/targets/bin/*
  rm -rf $dir/lte_build_oai $dir/lte-simulators/build
  rm -rf $dir/oaisim_build_oai/build $dir/oaisim_build_oai/CMakeLists.txt
- rm -rf $dir/autotests/bin $dir/autotests/log $dir/autotests/*/build 
+ rm -rf $dir/autotests/bin $dir/autotests/log $dir/autotests/*/build
 }
 
 ###################################
@@ -272,7 +272,7 @@ check_install_usrp_uhd_driver(){
         v=$(lsb_release -cs)
         $SUDO apt-add-repository --remove "deb http://files.ettus.com/binaries/uhd/repo/uhd/ubuntu/$v $v main"
         # The new USRP repository
-        # Raphael Defosseux: Adding a loop on adding PPA because in CI the gpg key retrieve may 
+        # Raphael Defosseux: Adding a loop on adding PPA because in CI the gpg key retrieve may
         # timeout due to proxy / network latencies in Eurecom on VM
         echo_info "\nAdding PPA repository ettusresearch/uhd\n"
         x=0
@@ -352,7 +352,7 @@ check_install_bladerf_driver(){
         fi
         $SUDO apt-get install -y --allow-unauthenticated  bladerf libbladerf-dev
         $SUDO apt-get install -y --allow-unauthenticated bladerf-firmware-fx3
-        $SUDO apt-get install -y --allow-unauthenticated bladerf-fpga-hostedx40	
+        $SUDO apt-get install -y --allow-unauthenticated bladerf-fpga-hostedx40
    elif [[ "$OS_BASEDISTRO" == "fedora" ]]; then
         install_bladerf_driver_from_source
    else
@@ -373,7 +373,7 @@ check_install_lmssdr_driver(){
                 echo_error "lmssdr support implies installing lmssdr drivers and tools" \
                            " from sources. check:"
                 echo_info "https://open-cells.com/index.php/2017/05/10/limesdr-installation/"
-                echo_fatal "Cannot compile lmssdr device" 
+                echo_fatal "Cannot compile lmssdr device"
 	fi
 
 
@@ -470,7 +470,7 @@ check_install_additional_tools (){
       python2-matplotlib"
   fi
     $SUDO $INSTALLER install -y $PACKAGE_LIST
-    
+
     $SUDO rm -fr /opt/ssh
     $SUDO GIT_SSL_NO_VERIFY=true git clone https://gitlab.eurecom.fr/oai/ssh.git /opt/ssh
 
@@ -549,6 +549,8 @@ check_install_oai_software() {
 	iptables-dev \
 	libatlas-base-dev \
 	libblas-dev \
+  liblapack-dev\
+  liblapacke-dev\
 	libffi-dev \
 	libforms-bin \
 	libforms-dev \
@@ -602,7 +604,7 @@ check_install_oai_software() {
       # Fedora repos already contain gccxml's successor castxml.
       $SUDO $INSTALLER install -y castxml
     fi
-    
+
     $SUDO $INSTALLER install -y \
       autoconf \
       automake \
@@ -689,7 +691,7 @@ install_asn1c_from_source(){
 }
 
 #################################################
-# 2. compile 
+# 2. compile
 ################################################
 
 install_nas_tools() {
@@ -718,7 +720,7 @@ set_openair_env(){
     [ -f "/.$fullpath" ] || fullpath=`readlink -f $PWD/$fullpath`
     openair_path=${fullpath%/cmake_targets/*}
     openair_path=${openair_path%/targets/*}
-    openair_path=${openair_path%/openair[123]/*}    
+    openair_path=${openair_path%/openair[123]/*}
     export OPENAIR_DIR=$openair_path
     export OPENAIR1_DIR=$openair_path/openair1
     export OPENAIR2_DIR=$openair_path/openair2
@@ -735,7 +737,7 @@ ppid=$$
 arraycounter=1
 echo_info "** Trapped CTRL-C. Killing all subprocesses now..."
 echo_info "** Calling sync now..."
-sync 
+sync
 while true
 do
         FORLOOP=FALSE
@@ -753,7 +755,7 @@ do
            arraycounter=`expr $arraycounter - 1`
            ## We want to kill child process id first and then parent id's
            while [ $arraycounter -ne 0 ]
-           do  
+           do
              echo "first we send ctrl-c to program"
              $SUDO kill -INT "${procid[$arraycounter]}"
              sleep 5
diff --git a/openair1/PHY/LTE_TRANSPORT/dci_tools_common.c b/openair1/PHY/LTE_TRANSPORT/dci_tools_common.c
index 842fb376a05c60349ef2674a6e2e3569f7ac87f2..6cb2ae47386c88e4234e6d157c5cc805223ad8f9 100644
--- a/openair1/PHY/LTE_TRANSPORT/dci_tools_common.c
+++ b/openair1/PHY/LTE_TRANSPORT/dci_tools_common.c
@@ -165,49 +165,6 @@ int8_t delta_PUSCH_acc[4] = {-1,0,1,3};
 
 int8_t *delta_PUCCH_lut = delta_PUSCH_acc;
 
-uint8_t get_pmi(uint8_t N_RB_DL, MIMO_mode_t mode, uint32_t pmi_alloc,uint16_t rb)
-{
-  /*
-  MIMO_mode_t mode   = dlsch_harq->mimo_mode;
-  uint32_t pmi_alloc = dlsch_harq->pmi_alloc;
-  */
-
-  switch (N_RB_DL) {
-    case 6:   // 1 PRB per subband
-      if (mode <= PUSCH_PRECODING1)
-        return((pmi_alloc>>(rb<<1))&3);
-      else
-        return((pmi_alloc>>rb)&1);
-
-      break;
-
-    default:
-    case 25:  // 4 PRBs per subband
-      if (mode <= PUSCH_PRECODING1)
-        return((pmi_alloc>>((rb>>2)<<1))&3);
-      else
-        return((pmi_alloc>>(rb>>2))&1);
-
-      break;
-
-    case 50: // 6 PRBs per subband
-      if (mode <= PUSCH_PRECODING1)
-        return((pmi_alloc>>((rb/6)<<1))&3);
-      else
-        return((pmi_alloc>>(rb/6))&1);
-
-      break;
-
-    case 100: // 8 PRBs per subband
-      if (mode <= PUSCH_PRECODING1)
-        return((pmi_alloc>>((rb>>3)<<1))&3);
-      else
-        return((pmi_alloc>>(rb>>3))&1);
-
-      break;
-  }
-}
-
 uint32_t check_phich_reg(LTE_DL_FRAME_PARMS *frame_parms,uint32_t kprime,uint8_t lprime,uint8_t mi)
 {
 
@@ -330,7 +287,7 @@ void conv_eMTC_rballoc(uint16_t resource_block_coding,
 		       uint32_t N_RB_DL,
 		       uint32_t *rb_alloc) {
 
-   
+
   int narrowband = resource_block_coding>>5;
   int RIV        = resource_block_coding&31;
   int N_NB_DL    = N_RB_DL/6;
@@ -346,7 +303,7 @@ void conv_eMTC_rballoc(uint16_t resource_block_coding,
   rb_alloc[2]                        = 0;
   rb_alloc[3]                        = 0;
   rb_alloc[ind]                      = alloc<<ind_mod;
-  if (ind_mod > 26)  rb_alloc[ind+1] = alloc>>(6-(ind_mod-26)); 
+  if (ind_mod > 26)  rb_alloc[ind+1] = alloc>>(6-(ind_mod-26));
 }
 
 void conv_rballoc(uint8_t ra_header,uint32_t rb_alloc,uint32_t N_RB_DL,uint32_t *rb_alloc2)
@@ -410,7 +367,7 @@ void conv_rballoc(uint8_t ra_header,uint32_t rb_alloc,uint32_t N_RB_DL,uint32_t
     // bit mask across
     if ((rb_alloc2[0]>>31)==1)
       rb_alloc2[1] |= 1;
-    
+
     if ((rb_alloc&1) != 0)
       rb_alloc2[1] |= (3<<16);
     break;
@@ -420,7 +377,7 @@ void conv_rballoc(uint8_t ra_header,uint32_t rb_alloc,uint32_t N_RB_DL,uint32_t
     for (i=0; i<25; i++) {
       if ((rb_alloc&(1<<(24-i))) != 0)
 	rb_alloc2[(4*i)>>5] |= (0xf<<((4*i)%32));
-      
+
       //  printf("rb_alloc2[%d] (type 0) %x (%d)\n",(4*i)>>5,rb_alloc2[(4*i)>>5],rb_alloc&(1<<i));
     }
 
diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c b/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c
index ce30aff04238767b8d800f8ccedcc1925c52a89b..5bf6f073d86180cc41a5acdf6d025aa194c16c79 100644
--- a/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c
+++ b/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c
@@ -37,7 +37,7 @@
 #include "PHY/LTE_TRANSPORT/transport_eNB.h"
 #include "UTIL/LOG/vcd_signal_dumper.h"
 #include "PHY/LTE_TRANSPORT/transport_proto.h"
-
+#include "PHY/LTE_TRANSPORT/transport_common_proto.h"
 //#define DEBUG_DLSCH_MODULATION
 #define NEW_ALLOC_RE
 
@@ -714,8 +714,8 @@ int allocate_REs_in_RB(PHY_VARS_eNB* phy_vars_eNB,
 
   int first_layer0 = -1; //= dlsch0_harq->first_layer;
   int Nlayers0 = -1; //  = dlsch0_harq->Nlayers;
-  uint8_t mod_order0=0; 
-  uint8_t mod_order1=0; 
+  uint8_t mod_order0=0;
+  uint8_t mod_order1=0;
   uint8_t precoder_index0,precoder_index1;
 
   uint8_t *x1=NULL;
diff --git a/openair1/PHY/LTE_UE_TRANSPORT/dlsch_demodulation.c b/openair1/PHY/LTE_UE_TRANSPORT/dlsch_demodulation.c
index 81347085539ef01ace695a7eb85e891fee79f0a9..9750656a4fe736590b56add4a60625c6e54e0dcc 100644
--- a/openair1/PHY/LTE_UE_TRANSPORT/dlsch_demodulation.c
+++ b/openair1/PHY/LTE_UE_TRANSPORT/dlsch_demodulation.c
@@ -36,8 +36,18 @@
 #include "transport_proto_ue.h"
 #include "PHY/sse_intrin.h"
 #include "T.h"
+#include<stdio.h>
+#include<math.h>
+#include <stdlib.h>
+#include <string.h>
+#include <lapacke_utils.h>
+#include <lapacke.h>
+#include <cblas.h>
+#include "linear_preprocessing_rec.h"
 
 #define NOCYGWIN_STATIC
+//#define DEBUG_MMSE
+
 
 /* dynamic shift for LLR computation for TM3/4
  * set as command line argument, see lte-softmodem.c
@@ -103,6 +113,7 @@ int rx_pdsch(PHY_VARS_UE *ue,
   int avg[4];
   int avg_0[2];
   int avg_1[2];
+  unsigned short mmse_flag=0;
 
 #if UE_TIMING_TRACE
   uint8_t slot = 0;
@@ -440,14 +451,15 @@ int rx_pdsch(PHY_VARS_UE *ue,
            ((dlsch0_harq->mimo_mode >=DUALSTREAM_UNIFORM_PRECODING1) &&
             (dlsch0_harq->mimo_mode <=DUALSTREAM_PUSCH_PRECODING)))
      {
-      dlsch_channel_level_TM34(pdsch_vars[eNB_id]->dl_ch_estimates_ext,
-                                 frame_parms,
-                                 pdsch_vars[eNB_id]->pmi_ext,
-                                 avg_0,
-                                 avg_1,
-                                 symbol,
-                                 nb_rb,
-                                 dlsch0_harq->mimo_mode);
+       dlsch_channel_level_TM34(pdsch_vars[eNB_id]->dl_ch_estimates_ext,
+                                  frame_parms,
+                                  pdsch_vars[eNB_id]->pmi_ext,
+                                  avg_0,
+                                  avg_1,
+                                  symbol,
+                                  nb_rb,
+                                  mmse_flag,
+                                  dlsch0_harq->mimo_mode);
 
       LOG_D(PHY,"Channel Level TM34  avg_0 %d, avg_1 %d, rx_type %d, rx_standard %d, dlsch_demod_shift %d \n", avg_0[0],
               avg_1[0], rx_type, rx_standard, dlsch_demod_shift);
@@ -546,6 +558,27 @@ int rx_pdsch(PHY_VARS_UE *ue,
 #if UE_TIMING_TRACE
     start_meas(&ue->generic_stat_bis[ue->current_thread_id[subframe]][slot]);
 #endif
+
+  if (rx_type==rx_IC_dual_stream && mmse_flag==1){
+
+    precode_channel_est(pdsch_vars[eNB_id]->dl_ch_estimates_ext,
+                        frame_parms,
+                        pdsch_vars[eNB_id],
+                        symbol,
+                        nb_rb,
+                        dlsch0_harq->mimo_mode);
+
+   mmse_processing_oai(pdsch_vars[eNB_id],
+                        frame_parms,
+                        measurements,
+                        first_symbol_flag,
+                        dlsch0_harq->mimo_mode,
+                        mmse_flag,
+                        0.0,
+                        symbol,
+                        nb_rb);
+  }
+
 // Now channel compensation
   if (dlsch0_harq->mimo_mode<LARGE_CDD) {
     dlsch_channel_compensation(pdsch_vars[eNB_id]->rxdataF_ext,
@@ -564,7 +597,7 @@ int rx_pdsch(PHY_VARS_UE *ue,
     if (symbol == 5) {
      LOG_M("rxF_comp_d.m","rxF_c_d",&pdsch_vars[eNB_id]->rxdataF_comp0[0][symbol*frame_parms->N_RB_DL*12],frame_parms->N_RB_DL*12,1,1);
     }
-    
+
     if ((rx_type==rx_IC_single_stream) &&
         (eNB_id_i<ue->n_connected_eNB)) {
          dlsch_channel_compensation(pdsch_vars[eNB_id_i]->rxdataF_ext,
@@ -606,6 +639,7 @@ int rx_pdsch(PHY_VARS_UE *ue,
                                      dlsch0_harq->round,
                                      dlsch0_harq->mimo_mode,
                                      nb_rb,
+                                     mmse_flag,
                                      pdsch_vars[eNB_id]->log2_maxh0,
                                      pdsch_vars[eNB_id]->log2_maxh1);
       if (symbol == 5) {
@@ -1279,15 +1313,14 @@ void dlsch_channel_compensation(int **rxdataF_ext,
       QAM_amp128b = _mm_set1_epi16(QAM64_n2);
     }
 
-    //    printf("comp: rxdataF_comp %p, symbol %d\n",rxdataF_comp[0],symbol);
-
     for (aarx=0; aarx<frame_parms->nb_antennas_rx; aarx++) {
 
-      dl_ch128          = (__m128i *)&dl_ch_estimates_ext[(aatx<<1)+aarx][symbol*frame_parms->N_RB_DL*12];
-      dl_ch_mag128      = (__m128i *)&dl_ch_mag[(aatx<<1)+aarx][symbol*frame_parms->N_RB_DL*12];
-      dl_ch_mag128b     = (__m128i *)&dl_ch_magb[(aatx<<1)+aarx][symbol*frame_parms->N_RB_DL*12];
+      dl_ch128          = (__m128i *)&dl_ch_estimates_ext[aatx*frame_parms->nb_antennas_rx + aarx][symbol*frame_parms->N_RB_DL*12];
+      //print_shorts("dl_ch128[0]=",&dl_ch128[0]);*/
+      dl_ch_mag128      = (__m128i *)&dl_ch_mag[aatx*frame_parms->nb_antennas_rx + aarx][symbol*frame_parms->N_RB_DL*12];
+      dl_ch_mag128b     = (__m128i *)&dl_ch_magb[aatx*frame_parms->nb_antennas_rx + aarx][symbol*frame_parms->N_RB_DL*12];
       rxdataF128        = (__m128i *)&rxdataF_ext[aarx][symbol*frame_parms->N_RB_DL*12];
-      rxdataF_comp128   = (__m128i *)&rxdataF_comp[(aatx<<1)+aarx][symbol*frame_parms->N_RB_DL*12];
+      rxdataF_comp128   = (__m128i *)&rxdataF_comp[aatx*frame_parms->nb_antennas_rx + aarx][symbol*frame_parms->N_RB_DL*12];
 
 
       for (rb=0; rb<nb_rb; rb++) {
@@ -1308,9 +1341,9 @@ void dlsch_channel_compensation(int **rxdataF_ext,
           dl_ch_mag128b[0] = dl_ch_mag128[0];
           dl_ch_mag128[0] = _mm_mulhi_epi16(dl_ch_mag128[0],QAM_amp128);
           dl_ch_mag128[0] = _mm_slli_epi16(dl_ch_mag128[0],1);
-    //print_ints("Re(ch):",(int16_t*)&mmtmpD0);
-    //print_shorts("QAM_amp:",(int16_t*)&QAM_amp128);
-    //print_shorts("mag:",(int16_t*)&dl_ch_mag128[0]);
+          //print_ints("Re(ch):",(int16_t*)&mmtmpD0);
+          //print_shorts("QAM_amp:",(int16_t*)&QAM_amp128);
+          //print_shorts("mag:",(int16_t*)&dl_ch_mag128[0]);
           dl_ch_mag128[1] = _mm_unpackhi_epi16(mmtmpD0,mmtmpD0);
           dl_ch_mag128b[1] = dl_ch_mag128[1];
           dl_ch_mag128[1] = _mm_mulhi_epi16(dl_ch_mag128[1],QAM_amp128);
@@ -1343,7 +1376,6 @@ void dlsch_channel_compensation(int **rxdataF_ext,
 
         // multiply by conjugated channel
         mmtmpD0 = _mm_madd_epi16(dl_ch128[0],rxdataF128[0]);
-        //  print_ints("re",&mmtmpD0);
 
         // mmtmpD0 contains real part of 4 consecutive outputs (32-bit)
         mmtmpD1 = _mm_shufflelo_epi16(dl_ch128[0],_MM_SHUFFLE(2,3,0,1));
@@ -1400,7 +1432,7 @@ void dlsch_channel_compensation(int **rxdataF_ext,
           rxdataF_comp128[2] = _mm_packs_epi32(mmtmpD2,mmtmpD3);
           //  print_shorts("rx:",rxdataF128+2);
           //  print_shorts("ch:",dl_ch128+2);
-          //        print_shorts("pack:",rxdataF_comp128+2);
+               // print_shorts("pack:",rxdataF_comp128+2);
 
           dl_ch128+=3;
           dl_ch_mag128+=3;
@@ -1541,11 +1573,11 @@ void dlsch_channel_compensation(int **rxdataF_ext,
     //    printf("comp: rxdataF_comp %p, symbol %d\n",rxdataF_comp[0],symbol);
 
     for (aarx=0; aarx<frame_parms->nb_antennas_rx; aarx++) {
-      dl_ch128          = (int16x4_t*)&dl_ch_estimates_ext[(aatx<<1)+aarx][symbol*frame_parms->N_RB_DL*12];
-      dl_ch_mag128      = (int16x8_t*)&dl_ch_mag[(aatx<<1)+aarx][symbol*frame_parms->N_RB_DL*12];
-      dl_ch_mag128b     = (int16x8_t*)&dl_ch_magb[(aatx<<1)+aarx][symbol*frame_parms->N_RB_DL*12];
+      dl_ch128          = (int16x4_t*)&dl_ch_estimates_ext[aatx*frame_parms->nb_antennas_rx + aarx][symbol*frame_parms->N_RB_DL*12];
+      dl_ch_mag128      = (int16x8_t*)&dl_ch_mag[aatx*frame_parms->nb_antennas_rx + aarx][symbol*frame_parms->N_RB_DL*12];
+      dl_ch_mag128b     = (int16x8_t*)&dl_ch_magb[aatx*frame_parms->nb_antennas_rx + aarx][symbol*frame_parms->N_RB_DL*12];
       rxdataF128        = (int16x4_t*)&rxdataF_ext[aarx][symbol*frame_parms->N_RB_DL*12];
-      rxdataF_comp128   = (int16x4x2_t*)&rxdataF_comp[(aatx<<1)+aarx][symbol*frame_parms->N_RB_DL*12];
+      rxdataF_comp128   = (int16x4x2_t*)&rxdataF_comp[aatx*frame_parms->nb_antennas_rx + aarx][symbol*frame_parms->N_RB_DL*12];
 
       for (rb=0; rb<nb_rb; rb++) {
   if (mod_order>2) {
@@ -1706,6 +1738,204 @@ void dlsch_channel_compensation(int **rxdataF_ext,
 #endif
 }
 
+void dlsch_channel_compensation_core(int **rxdataF_ext,
+                                     int **dl_ch_estimates_ext,
+                                     int **dl_ch_mag,
+                                     int **dl_ch_magb,
+                                     int **rxdataF_comp,
+                                     int **rho,
+                                     unsigned char n_tx,
+                                     unsigned char n_rx,
+                                     unsigned char mod_order,
+                                     unsigned char output_shift,
+                                     int length,
+                                     int start_point)
+
+{
+
+  unsigned short ii;
+  int length_mod8 = 0;
+  int length2;
+  __m128i *dl_ch128,*dl_ch_mag128,*dl_ch_mag128b, *dl_ch128_2, *rxdataF128,*rxdataF_comp128,*rho128;
+  __m128i mmtmpD0,mmtmpD1,mmtmpD2,mmtmpD3,QAM_amp128,QAM_amp128b;
+  int aatx = 0, aarx = 0;
+
+  for (aatx=0; aatx<n_tx; aatx++) {
+
+    if (mod_order == 4) {
+      QAM_amp128 = _mm_set1_epi16(QAM16_n1);  // 2/sqrt(10)
+      QAM_amp128b = _mm_setzero_si128();
+    } else if (mod_order == 6) {
+      QAM_amp128  = _mm_set1_epi16(QAM64_n1); //
+      QAM_amp128b = _mm_set1_epi16(QAM64_n2);
+    }
+
+    for (aarx=0; aarx<n_rx; aarx++) {
+
+    dl_ch128          = (__m128i *)&dl_ch_estimates_ext[aatx*n_rx + aarx][start_point];
+    dl_ch_mag128      = (__m128i *)&dl_ch_mag[aatx*n_rx + aarx][start_point];
+    dl_ch_mag128b     = (__m128i *)&dl_ch_magb[aatx*n_rx + aarx][start_point];
+    rxdataF128        = (__m128i *)&rxdataF_ext[aarx][start_point];
+    rxdataF_comp128   = (__m128i *)&rxdataF_comp[aatx*n_rx + aarx][start_point];
+
+      length_mod8 = length&7;
+      if (length_mod8 == 0){
+        length2 = length>>3;
+
+        for (ii=0; ii<length2; ++ii) {
+          if (mod_order>2) {
+            // get channel amplitude if not QPSK
+
+            mmtmpD0 = _mm_madd_epi16(dl_ch128[0],dl_ch128[0]);
+            mmtmpD0 = _mm_srai_epi32(mmtmpD0,output_shift);
+
+            mmtmpD1 = _mm_madd_epi16(dl_ch128[1],dl_ch128[1]);
+            mmtmpD1 = _mm_srai_epi32(mmtmpD1,output_shift);
+
+            mmtmpD0 = _mm_packs_epi32(mmtmpD0,mmtmpD1);
+
+            // store channel magnitude here in a new field of dlsch
+
+            dl_ch_mag128[0] = _mm_unpacklo_epi16(mmtmpD0,mmtmpD0);
+            dl_ch_mag128b[0] = dl_ch_mag128[0];
+            dl_ch_mag128[0] = _mm_mulhi_epi16(dl_ch_mag128[0],QAM_amp128);
+            dl_ch_mag128[0] = _mm_slli_epi16(dl_ch_mag128[0],1);
+            //print_ints("Re(ch):",(int16_t*)&mmtmpD0);
+            //print_shorts("QAM_amp:",(int16_t*)&QAM_amp128);
+            //print_shorts("mag:",(int16_t*)&dl_ch_mag128[0]);
+            dl_ch_mag128[1] = _mm_unpackhi_epi16(mmtmpD0,mmtmpD0);
+            dl_ch_mag128b[1] = dl_ch_mag128[1];
+            dl_ch_mag128[1] = _mm_mulhi_epi16(dl_ch_mag128[1],QAM_amp128);
+            dl_ch_mag128[1] = _mm_slli_epi16(dl_ch_mag128[1],1);
+
+            dl_ch_mag128b[0] = _mm_mulhi_epi16(dl_ch_mag128b[0],QAM_amp128b);
+            dl_ch_mag128b[0] = _mm_slli_epi16(dl_ch_mag128b[0],1);
+
+            dl_ch_mag128b[1] = _mm_mulhi_epi16(dl_ch_mag128b[1],QAM_amp128b);
+            dl_ch_mag128b[1] = _mm_slli_epi16(dl_ch_mag128b[1],1);
+
+          }
+
+          // multiply by conjugated channel
+          mmtmpD0 = _mm_madd_epi16(dl_ch128[0],rxdataF128[0]);
+
+          // mmtmpD0 contains real part of 4 consecutive outputs (32-bit)
+          mmtmpD1 = _mm_shufflelo_epi16(dl_ch128[0],_MM_SHUFFLE(2,3,0,1));
+          mmtmpD1 = _mm_shufflehi_epi16(mmtmpD1,_MM_SHUFFLE(2,3,0,1));
+          mmtmpD1 = _mm_sign_epi16(mmtmpD1,*(__m128i*)&conjugate[0]);
+          //  print_ints("im",&mmtmpD1);
+          mmtmpD1 = _mm_madd_epi16(mmtmpD1,rxdataF128[0]);
+          // mmtmpD1 contains imag part of 4 consecutive outputs (32-bit)
+          mmtmpD0 = _mm_srai_epi32(mmtmpD0,output_shift);
+          //  print_ints("re(shift)",&mmtmpD0);
+          mmtmpD1 = _mm_srai_epi32(mmtmpD1,output_shift);
+          //  print_ints("im(shift)",&mmtmpD1);
+          mmtmpD2 = _mm_unpacklo_epi32(mmtmpD0,mmtmpD1);
+          mmtmpD3 = _mm_unpackhi_epi32(mmtmpD0,mmtmpD1);
+          //        print_ints("c0",&mmtmpD2);
+          //  print_ints("c1",&mmtmpD3);
+          rxdataF_comp128[0] = _mm_packs_epi32(mmtmpD2,mmtmpD3);
+          //  print_shorts("rx:",rxdataF128);
+          //  print_shorts("ch:",dl_ch128);
+          //  print_shorts("pack:",rxdataF_comp128);
+
+          // multiply by conjugated channel
+          mmtmpD0 = _mm_madd_epi16(dl_ch128[1],rxdataF128[1]);
+          // mmtmpD0 contains real part of 4 consecutive outputs (32-bit)
+          mmtmpD1 = _mm_shufflelo_epi16(dl_ch128[1],_MM_SHUFFLE(2,3,0,1));
+          mmtmpD1 = _mm_shufflehi_epi16(mmtmpD1,_MM_SHUFFLE(2,3,0,1));
+          mmtmpD1 = _mm_sign_epi16(mmtmpD1,*(__m128i*)conjugate);
+          mmtmpD1 = _mm_madd_epi16(mmtmpD1,rxdataF128[1]);
+          // mmtmpD1 contains imag part of 4 consecutive outputs (32-bit)
+          mmtmpD0 = _mm_srai_epi32(mmtmpD0,output_shift);
+          mmtmpD1 = _mm_srai_epi32(mmtmpD1,output_shift);
+          mmtmpD2 = _mm_unpacklo_epi32(mmtmpD0,mmtmpD1);
+          mmtmpD3 = _mm_unpackhi_epi32(mmtmpD0,mmtmpD1);
+
+          rxdataF_comp128[1] = _mm_packs_epi32(mmtmpD2,mmtmpD3);
+          //  print_shorts("rx:",rxdataF128+1);
+          //  print_shorts("ch:",dl_ch128+1);
+          //print_shorts("pack:",rxdataF_comp128+1);
+
+          dl_ch128+=2;
+          dl_ch_mag128+=2;
+          dl_ch_mag128b+=2;
+          rxdataF128+=2;
+          rxdataF_comp128+=2;
+        }
+      }else {
+        printf ("Channel Compensation: Received number of subcarriers is not multiple of 8, \n"
+                 "need to adapt the code!\n");
+      }
+    }
+  }
+
+/*This part of code makes sense only for processing in 2x2 blocks*/
+  if (rho) {
+
+
+    for (aarx=0; aarx<n_rx; aarx++) {
+      rho128        = (__m128i *)&rho[aarx][start_point];
+      dl_ch128      = (__m128i *)&dl_ch_estimates_ext[aarx][start_point];
+      dl_ch128_2    = (__m128i *)&dl_ch_estimates_ext[2+aarx][start_point];
+
+      if (length_mod8 == 0){
+        length2 = length>>3;
+
+        for (ii=0; ii<length2; ++ii) {
+          // multiply by conjugated channel
+          mmtmpD0 = _mm_madd_epi16(dl_ch128[0],dl_ch128_2[0]);
+          //  print_ints("re",&mmtmpD0);
+
+          // mmtmpD0 contains real part of 4 consecutive outputs (32-bit)
+          mmtmpD1 = _mm_shufflelo_epi16(dl_ch128[0],_MM_SHUFFLE(2,3,0,1));
+          mmtmpD1 = _mm_shufflehi_epi16(mmtmpD1,_MM_SHUFFLE(2,3,0,1));
+          mmtmpD1 = _mm_sign_epi16(mmtmpD1,*(__m128i*)&conjugate[0]);
+          //  print_ints("im",&mmtmpD1);
+          mmtmpD1 = _mm_madd_epi16(mmtmpD1,dl_ch128_2[0]);
+          // mmtmpD1 contains imag part of 4 consecutive outputs (32-bit)
+          mmtmpD0 = _mm_srai_epi32(mmtmpD0,output_shift);
+          //  print_ints("re(shift)",&mmtmpD0);
+          mmtmpD1 = _mm_srai_epi32(mmtmpD1,output_shift);
+          //  print_ints("im(shift)",&mmtmpD1);
+          mmtmpD2 = _mm_unpacklo_epi32(mmtmpD0,mmtmpD1);
+          mmtmpD3 = _mm_unpackhi_epi32(mmtmpD0,mmtmpD1);
+          //        print_ints("c0",&mmtmpD2);
+          //  print_ints("c1",&mmtmpD3);
+          rho128[0] = _mm_packs_epi32(mmtmpD2,mmtmpD3);
+
+          //print_shorts("rx:",dl_ch128_2);
+          //print_shorts("ch:",dl_ch128);
+          //print_shorts("pack:",rho128);
+
+          // multiply by conjugated channel
+          mmtmpD0 = _mm_madd_epi16(dl_ch128[1],dl_ch128_2[1]);
+          // mmtmpD0 contains real part of 4 consecutive outputs (32-bit)
+          mmtmpD1 = _mm_shufflelo_epi16(dl_ch128[1],_MM_SHUFFLE(2,3,0,1));
+          mmtmpD1 = _mm_shufflehi_epi16(mmtmpD1,_MM_SHUFFLE(2,3,0,1));
+          mmtmpD1 = _mm_sign_epi16(mmtmpD1,*(__m128i*)conjugate);
+          mmtmpD1 = _mm_madd_epi16(mmtmpD1,dl_ch128_2[1]);
+          // mmtmpD1 contains imag part of 4 consecutive outputs (32-bit)
+          mmtmpD0 = _mm_srai_epi32(mmtmpD0,output_shift);
+          mmtmpD1 = _mm_srai_epi32(mmtmpD1,output_shift);
+          mmtmpD2 = _mm_unpacklo_epi32(mmtmpD0,mmtmpD1);
+          mmtmpD3 = _mm_unpackhi_epi32(mmtmpD0,mmtmpD1);
+
+          rho128[1] =_mm_packs_epi32(mmtmpD2,mmtmpD3);
+          dl_ch128+=2;
+          dl_ch128_2+=2;
+          rho128+=2;
+        }
+      }else {
+        printf ("Channel Compensation: Received number of subcarriers is not multiple of 8, \n"
+                 "need to adapt the code!\n");
+      }
+    }
+  }
+  _mm_empty();
+  _m_empty();
+}
+
 #if defined(__x86_64__) || defined(__i386__)
 
 void prec2A_TM56_128(unsigned char pmi,__m128i *ch0,__m128i *ch1)
@@ -2282,6 +2512,69 @@ void dlsch_channel_compensation_TM56(int **rxdataF_ext,
   _m_empty();
 }
 
+void precode_channel_est(int32_t **dl_ch_estimates_ext,
+                        LTE_DL_FRAME_PARMS *frame_parms,
+                        LTE_UE_PDSCH *pdsch_vars,
+                        unsigned char symbol,
+                        unsigned short nb_rb,
+                        MIMO_mode_t mimo_mode){
+
+  unsigned short rb;
+  __m128i *dl_ch0_128,*dl_ch1_128;
+  unsigned char aarx=0,symbol_mod,pilots=0;
+  unsigned char *pmi_ext = pdsch_vars->pmi_ext;
+
+  symbol_mod = (symbol>=(7-frame_parms->Ncp)) ? symbol-(7-frame_parms->Ncp) : symbol;
+
+  if ((symbol_mod == 0) || (symbol_mod == (4-frame_parms->Ncp)))
+    pilots=1;
+
+  for (aarx=0;aarx<frame_parms->nb_antennas_rx;aarx++) {
+
+    dl_ch0_128          = (__m128i *)&dl_ch_estimates_ext[aarx][symbol*frame_parms->N_RB_DL*12]; // this is h11
+    dl_ch1_128          = (__m128i *)&dl_ch_estimates_ext[2+aarx][symbol*frame_parms->N_RB_DL*12]; // this is h12
+
+    for (rb=0; rb<nb_rb; rb++) {
+      if (mimo_mode==LARGE_CDD) {
+            prec2A_TM3_128(&dl_ch0_128[0],&dl_ch1_128[0]);
+            prec2A_TM3_128(&dl_ch0_128[1],&dl_ch1_128[1]);
+            if (pilots==0) {
+              prec2A_TM3_128(&dl_ch0_128[2],&dl_ch1_128[2]);
+            }
+          }else if (mimo_mode==DUALSTREAM_UNIFORM_PRECODING1) {
+            prec2A_TM4_128(0,&dl_ch0_128[0],&dl_ch1_128[0]);
+            prec2A_TM4_128(0,&dl_ch0_128[1],&dl_ch1_128[1]);
+            if (pilots==0) {
+              prec2A_TM4_128(0,&dl_ch0_128[2],&dl_ch1_128[2]);
+            }
+          }else if (mimo_mode==DUALSTREAM_UNIFORM_PRECODINGj) {
+            prec2A_TM4_128(1,&dl_ch0_128[0],&dl_ch1_128[0]);
+            prec2A_TM4_128(1,&dl_ch0_128[1],&dl_ch1_128[1]);
+            if (pilots==0) {
+              prec2A_TM4_128(1,&dl_ch0_128[2],&dl_ch1_128[2]);
+            }
+          }else if (mimo_mode==DUALSTREAM_PUSCH_PRECODING) {
+            prec2A_TM4_128(pmi_ext[rb],&dl_ch0_128[0],&dl_ch1_128[0]);
+            prec2A_TM4_128(pmi_ext[rb],&dl_ch0_128[1],&dl_ch1_128[1]);
+            if (pilots==0) {
+              prec2A_TM4_128(pmi_ext[rb],&dl_ch0_128[2],&dl_ch1_128[2]);
+            }
+          }else {
+            LOG_E(PHY,"Unknown MIMO mode\n");
+            return;
+          }
+          if (pilots==0){
+            dl_ch0_128+=3;
+            dl_ch1_128+=3;
+          }else {
+            dl_ch0_128+=2;
+            dl_ch1_128+=2;
+          }
+        }
+
+      }
+}
+
 void dlsch_channel_compensation_TM34(LTE_DL_FRAME_PARMS *frame_parms,
                                     LTE_UE_PDSCH *pdsch_vars,
                                     PHY_MEASUREMENTS *measurements,
@@ -2293,6 +2586,7 @@ void dlsch_channel_compensation_TM34(LTE_DL_FRAME_PARMS *frame_parms,
                                     int round,
                                     MIMO_mode_t mimo_mode,
                                     unsigned short nb_rb,
+                                    unsigned short mmse_flag,
                                     unsigned char output_shift0,
                                     unsigned char output_shift1) {
 
@@ -2342,20 +2636,8 @@ void dlsch_channel_compensation_TM34(LTE_DL_FRAME_PARMS *frame_parms,
 
   for (aarx=0;aarx<frame_parms->nb_antennas_rx;aarx++) {
 
-   /* if (aarx==0) {
-      output_shift=output_shift0;
-    }
-      else {
-        output_shift=output_shift1;
-      } */
-
-     // printf("antenna %d\n", aarx);
-   // printf("symbol %d, rx antenna %d\n", symbol, aarx);
-
     dl_ch0_128          = (__m128i *)&dl_ch_estimates_ext[aarx][symbol*frame_parms->N_RB_DL*12]; // this is h11
     dl_ch1_128          = (__m128i *)&dl_ch_estimates_ext[2+aarx][symbol*frame_parms->N_RB_DL*12]; // this is h12
-
-
     dl_ch_mag0_128      = (__m128i *)&dl_ch_mag0[aarx][symbol*frame_parms->N_RB_DL*12]; //responsible for x1
     dl_ch_mag0_128b     = (__m128i *)&dl_ch_magb0[aarx][symbol*frame_parms->N_RB_DL*12];//responsible for x1
     dl_ch_mag1_128      = (__m128i *)&dl_ch_mag1[aarx][symbol*frame_parms->N_RB_DL*12];   //responsible for x2. always coming from tx2
@@ -2365,50 +2647,39 @@ void dlsch_channel_compensation_TM34(LTE_DL_FRAME_PARMS *frame_parms,
     rxdataF_comp1_128   = (__m128i *)&rxdataF_comp1[aarx][symbol*frame_parms->N_RB_DL*12]; //result of multipl with MF x2 on antenna of interest
 
     for (rb=0; rb<nb_rb; rb++) {
-
+      if (mmse_flag == 0) {
       // combine TX channels using precoder from pmi
-      if (mimo_mode==LARGE_CDD) {
-        prec2A_TM3_128(&dl_ch0_128[0],&dl_ch1_128[0]);
-        prec2A_TM3_128(&dl_ch0_128[1],&dl_ch1_128[1]);
-
-
-        if (pilots==0) {
-          prec2A_TM3_128(&dl_ch0_128[2],&dl_ch1_128[2]);
-        }
-      }
-      else if (mimo_mode==DUALSTREAM_UNIFORM_PRECODING1) {
-        prec2A_TM4_128(0,&dl_ch0_128[0],&dl_ch1_128[0]);
-        prec2A_TM4_128(0,&dl_ch0_128[1],&dl_ch1_128[1]);
-
-        if (pilots==0) {
-          prec2A_TM4_128(0,&dl_ch0_128[2],&dl_ch1_128[2]);
-        }
-      }
-      else if (mimo_mode==DUALSTREAM_UNIFORM_PRECODINGj) {
-        prec2A_TM4_128(1,&dl_ch0_128[0],&dl_ch1_128[0]);
-        prec2A_TM4_128(1,&dl_ch0_128[1],&dl_ch1_128[1]);
-
-        if (pilots==0) {
-          prec2A_TM4_128(1,&dl_ch0_128[2],&dl_ch1_128[2]);
-        }
-      }
-
-        else if (mimo_mode==DUALSTREAM_PUSCH_PRECODING) {
-        prec2A_TM4_128(pmi_ext[rb],&dl_ch0_128[0],&dl_ch1_128[0]);
-        prec2A_TM4_128(pmi_ext[rb],&dl_ch0_128[1],&dl_ch1_128[1]);
-
-        if (pilots==0) {
-          prec2A_TM4_128(pmi_ext[rb],&dl_ch0_128[2],&dl_ch1_128[2]);
+        if (mimo_mode==LARGE_CDD) {
+          prec2A_TM3_128(&dl_ch0_128[0],&dl_ch1_128[0]);
+          prec2A_TM3_128(&dl_ch0_128[1],&dl_ch1_128[1]);
+          if (pilots==0) {
+            prec2A_TM3_128(&dl_ch0_128[2],&dl_ch1_128[2]);
+          }
+        }else if (mimo_mode==DUALSTREAM_UNIFORM_PRECODING1) {
+          prec2A_TM4_128(0,&dl_ch0_128[0],&dl_ch1_128[0]);
+          prec2A_TM4_128(0,&dl_ch0_128[1],&dl_ch1_128[1]);
+          if (pilots==0) {
+            prec2A_TM4_128(0,&dl_ch0_128[2],&dl_ch1_128[2]);
+          }
+        }else if (mimo_mode==DUALSTREAM_UNIFORM_PRECODINGj) {
+          prec2A_TM4_128(1,&dl_ch0_128[0],&dl_ch1_128[0]);
+          prec2A_TM4_128(1,&dl_ch0_128[1],&dl_ch1_128[1]);
+          if (pilots==0) {
+            prec2A_TM4_128(1,&dl_ch0_128[2],&dl_ch1_128[2]);
+          }
+        }else if (mimo_mode==DUALSTREAM_PUSCH_PRECODING) {
+          prec2A_TM4_128(pmi_ext[rb],&dl_ch0_128[0],&dl_ch1_128[0]);
+          prec2A_TM4_128(pmi_ext[rb],&dl_ch0_128[1],&dl_ch1_128[1]);
+          if (pilots==0) {
+            prec2A_TM4_128(pmi_ext[rb],&dl_ch0_128[2],&dl_ch1_128[2]);
+          }
+        }else {
+          LOG_E(PHY,"Unknown MIMO mode\n");
+          return;
         }
       }
 
 
-      else {
-        LOG_E(PHY,"Unknown MIMO mode\n");
-        return;
-      }
-
-
       if (mod_order0>2) {
         // get channel amplitude if not QPSK
 
@@ -2535,7 +2806,7 @@ void dlsch_channel_compensation_TM34(LTE_DL_FRAME_PARMS *frame_parms,
 
            // print_shorts("rx:",rxdataF128);
            // print_shorts("ch:",dl_ch0_128);
-        // print_shorts("pack:",rxdataF_comp0_128);
+      //print_shorts("pack:",rxdataF_comp0_128);
 
       // multiply by conjugated channel
       mmtmpD0 = _mm_madd_epi16(dl_ch0_128[1],rxdataF128[1]);
@@ -2754,36 +3025,31 @@ void dlsch_channel_compensation_TM34(LTE_DL_FRAME_PARMS *frame_parms,
     rxdataF_comp1_128   = (int16x8_t*)&rxdataF_comp1[aarx][symbol*frame_parms->N_RB_DL*12];
 
     for (rb=0; rb<nb_rb; rb++) {
-      // combine TX channels using precoder from pmi
-      if (mimo_mode==LARGE_CDD) {
-        prec2A_TM3_128(&dl_ch0_128[0],&dl_ch1_128[0]);
-        prec2A_TM3_128(&dl_ch0_128[1],&dl_ch1_128[1]);
-
-
-        if (pilots==0) {
-          prec2A_TM3_128(&dl_ch0_128[2],&dl_ch1_128[2]);
-        }
-      }
-      else if (mimo_mode==DUALSTREAM_UNIFORM_PRECODING1) {
-        prec2A_TM4_128(0,&dl_ch0_128[0],&dl_ch1_128[0]);
-        prec2A_TM4_128(0,&dl_ch0_128[1],&dl_ch1_128[1]);
-
-        if (pilots==0) {
-          prec2A_TM4_128(0,&dl_ch0_128[2],&dl_ch1_128[2]);
-        }
-      }
-      else if (mimo_mode==DUALSTREAM_UNIFORM_PRECODINGj) {
-        prec2A_TM4_128(1,&dl_ch0_128[0],&dl_ch1_128[0]);
-        prec2A_TM4_128(1,&dl_ch0_128[1],&dl_ch1_128[1]);
-
-        if (pilots==0) {
-          prec2A_TM4_128(1,&dl_ch0_128[2],&dl_ch1_128[2]);
+      if (mmse_flag == 0) {
+        // combine TX channels using precoder from pmi
+        if (mimo_mode==LARGE_CDD) {
+          prec2A_TM3_128(&dl_ch0_128[0],&dl_ch1_128[0]);
+          prec2A_TM3_128(&dl_ch0_128[1],&dl_ch1_128[1]);
+          if (pilots==0) {
+            prec2A_TM3_128(&dl_ch0_128[2],&dl_ch1_128[2]);
+          }
+        }else if (mimo_mode==DUALSTREAM_UNIFORM_PRECODING1) {
+          prec2A_TM4_128(0,&dl_ch0_128[0],&dl_ch1_128[0]);
+          prec2A_TM4_128(0,&dl_ch0_128[1],&dl_ch1_128[1]);
+          if (pilots==0) {
+            prec2A_TM4_128(0,&dl_ch0_128[2],&dl_ch1_128[2]);
+          }
+        }else if (mimo_mode==DUALSTREAM_UNIFORM_PRECODINGj) {
+          prec2A_TM4_128(1,&dl_ch0_128[0],&dl_ch1_128[0]);
+          prec2A_TM4_128(1,&dl_ch0_128[1],&dl_ch1_128[1]);
+          if (pilots==0) {
+            prec2A_TM4_128(1,&dl_ch0_128[2],&dl_ch1_128[2]);
+          }
+        }else {
+          LOG_E(PHY,"Unknown MIMO mode\n");
+          return;
         }
       }
-      else {
-        LOG_E(PHY,"Unknown MIMO mode\n");
-        return;
-      }
 
 
       if (mod_order0>2) {
@@ -3008,19 +3274,15 @@ void dlsch_dual_stream_correlation(LTE_DL_FRAME_PARMS *frame_parms,
 
   for (aarx=0; aarx<frame_parms->nb_antennas_rx; aarx++) {
 
-
-
- //printf ("antenna %d", aarx);
     dl_ch128          = (__m128i *)&dl_ch_estimates_ext[aarx][symbol*frame_parms->N_RB_DL*12];
 
     if (dl_ch_estimates_ext_i == NULL) // TM3/4
-      dl_ch128i         = (__m128i *)&dl_ch_estimates_ext[2+aarx][symbol*frame_parms->N_RB_DL*12];
+      dl_ch128i         = (__m128i *)&dl_ch_estimates_ext[aarx + frame_parms->nb_antennas_rx][symbol*frame_parms->N_RB_DL*12];
     else
       dl_ch128i         = (__m128i *)&dl_ch_estimates_ext_i[aarx][symbol*frame_parms->N_RB_DL*12];
 
     dl_ch_rho128      = (__m128i *)&dl_ch_rho_ext[aarx][symbol*frame_parms->N_RB_DL*12];
 
-
     for (rb=0; rb<nb_rb; rb++) {
       // multiply by conjugated channel
       mmtmpD0 = _mm_madd_epi16(dl_ch128[0],dl_ch128i[0]);
@@ -3095,158 +3357,37 @@ void dlsch_dual_stream_correlation(LTE_DL_FRAME_PARMS *frame_parms,
 }
 
 
-/*void dlsch_dual_stream_correlationTM34(LTE_DL_FRAME_PARMS *frame_parms,
-                                   unsigned char symbol,
-                                   unsigned short nb_rb,
-                                   int **dl_ch_estimates_ext,
-                                   int **dl_ch_estimates_ext_i,
-                                   int **dl_ch_rho_ext,
-                                   unsigned char output_shift0,
-                                   unsigned char output_shift1)
+void dlsch_detection_mrc(LTE_DL_FRAME_PARMS *frame_parms,
+                         int **rxdataF_comp,
+                         int **rxdataF_comp_i,
+                         int **rho,
+                         int **rho_i,
+                         int **dl_ch_mag,
+                         int **dl_ch_magb,
+                         int **dl_ch_mag_i,
+                         int **dl_ch_magb_i,
+                         unsigned char symbol,
+                         unsigned short nb_rb,
+                         unsigned char dual_stream_UE)
 {
 
 #if defined(__x86_64__)||defined(__i386__)
 
-  unsigned short rb;
-  __m128i *dl_ch128,*dl_ch128i,*dl_ch_rho128,mmtmpD0,mmtmpD1,mmtmpD2,mmtmpD3;
-  unsigned char aarx,symbol_mod,pilots=0;
-  int output_shift;
-
-  //    printf("dlsch_dual_stream_correlation: symbol %d\n",symbol);
-
-  symbol_mod = (symbol>=(7-frame_parms->Ncp)) ? symbol-(7-frame_parms->Ncp) : symbol;
-
-  if ((symbol_mod == 0) || (symbol_mod == (4-frame_parms->Ncp))) {
-    pilots=1;
-  }
+  unsigned char aatx;
+  int i;
+  __m128i *rxdataF_comp128_0,*rxdataF_comp128_1,*rxdataF_comp128_i0,*rxdataF_comp128_i1,*dl_ch_mag128_0,*dl_ch_mag128_1,*dl_ch_mag128_0b,*dl_ch_mag128_1b,*rho128_0,*rho128_1,*rho128_i0,*rho128_i1,
+    *dl_ch_mag128_i0,*dl_ch_mag128_i1,*dl_ch_mag128_i0b,*dl_ch_mag128_i1b;
 
-  //  printf("Dual stream correlation (%p)\n",dl_ch_estimates_ext_i);
+  if (frame_parms->nb_antennas_rx>1) {
 
-  for (aarx=0; aarx<frame_parms->nb_antennas_rx; aarx++) {
+    for (aatx=0; aatx<frame_parms->nb_antenna_ports_eNB; aatx++) {
 
-       if (aarx==0) {
-      output_shift=output_shift0;
-    }
-      else {
-        output_shift=output_shift1;
-      }
-
- //printf ("antenna %d", aarx);
-    dl_ch128          = (__m128i *)&dl_ch_estimates_ext[aarx][symbol*frame_parms->N_RB_DL*12];
-
-    if (dl_ch_estimates_ext_i == NULL) // TM3/4
-      dl_ch128i         = (__m128i *)&dl_ch_estimates_ext[2+aarx][symbol*frame_parms->N_RB_DL*12];
-    else
-      dl_ch128i         = (__m128i *)&dl_ch_estimates_ext_i[aarx][symbol*frame_parms->N_RB_DL*12];
-
-    dl_ch_rho128      = (__m128i *)&dl_ch_rho_ext[aarx][symbol*frame_parms->N_RB_DL*12];
-
-
-    for (rb=0; rb<nb_rb; rb++) {
-      // multiply by conjugated channel
-      mmtmpD0 = _mm_madd_epi16(dl_ch128[0],dl_ch128i[0]);
-      //      print_ints("re",&mmtmpD0);
-      // mmtmpD0 contains real part of 4 consecutive outputs (32-bit)
-      mmtmpD1 = _mm_shufflelo_epi16(dl_ch128[0],_MM_SHUFFLE(2,3,0,1));
-      mmtmpD1 = _mm_shufflehi_epi16(mmtmpD1,_MM_SHUFFLE(2,3,0,1));
-      mmtmpD1 = _mm_sign_epi16(mmtmpD1,*(__m128i*)&conjugate[0]);
-      mmtmpD1 = _mm_madd_epi16(mmtmpD1,dl_ch128i[0]);
-      //      print_ints("im",&mmtmpD1);
-      // mmtmpD1 contains imag part of 4 consecutive outputs (32-bit)
-      mmtmpD0 = _mm_srai_epi32(mmtmpD0,output_shift);
-      //      print_ints("re(shift)",&mmtmpD0);
-      mmtmpD1 = _mm_srai_epi32(mmtmpD1,output_shift);
-      //      print_ints("im(shift)",&mmtmpD1);
-      mmtmpD2 = _mm_unpacklo_epi32(mmtmpD0,mmtmpD1);
-      mmtmpD3 = _mm_unpackhi_epi32(mmtmpD0,mmtmpD1);
-      //      print_ints("c0",&mmtmpD2);
-      //      print_ints("c1",&mmtmpD3);
-      dl_ch_rho128[0] = _mm_packs_epi32(mmtmpD2,mmtmpD3);
-    // print_shorts("rho 0:",dl_ch_rho128);
-      // multiply by conjugated channel
-      mmtmpD0 = _mm_madd_epi16(dl_ch128[1],dl_ch128i[1]);
-      // mmtmpD0 contains real part of 4 consecutive outputs (32-bit)
-      mmtmpD1 = _mm_shufflelo_epi16(dl_ch128[1],_MM_SHUFFLE(2,3,0,1));
-      mmtmpD1 = _mm_shufflehi_epi16(mmtmpD1,_MM_SHUFFLE(2,3,0,1));
-      mmtmpD1 = _mm_sign_epi16(mmtmpD1,*(__m128i*)conjugate);
-      mmtmpD1 = _mm_madd_epi16(mmtmpD1,dl_ch128i[1]);
-      // mmtmpD1 contains imag part of 4 consecutive outputs (32-bit)
-      mmtmpD0 = _mm_srai_epi32(mmtmpD0,output_shift);
-      mmtmpD1 = _mm_srai_epi32(mmtmpD1,output_shift);
-      mmtmpD2 = _mm_unpacklo_epi32(mmtmpD0,mmtmpD1);
-      mmtmpD3 = _mm_unpackhi_epi32(mmtmpD0,mmtmpD1);
-      dl_ch_rho128[1] =_mm_packs_epi32(mmtmpD2,mmtmpD3);
-
-
-      if (pilots==0) {
-
-        // multiply by conjugated channel
-        mmtmpD0 = _mm_madd_epi16(dl_ch128[2],dl_ch128i[2]);
-        // mmtmpD0 contains real part of 4 consecutive outputs (32-bit)
-        mmtmpD1 = _mm_shufflelo_epi16(dl_ch128[2],_MM_SHUFFLE(2,3,0,1));
-        mmtmpD1 = _mm_shufflehi_epi16(mmtmpD1,_MM_SHUFFLE(2,3,0,1));
-        mmtmpD1 = _mm_sign_epi16(mmtmpD1,*(__m128i*)conjugate);
-        mmtmpD1 = _mm_madd_epi16(mmtmpD1,dl_ch128i[2]);
-        // mmtmpD1 contains imag part of 4 consecutive outputs (32-bit)
-        mmtmpD0 = _mm_srai_epi32(mmtmpD0,output_shift);
-        mmtmpD1 = _mm_srai_epi32(mmtmpD1,output_shift);
-        mmtmpD2 = _mm_unpacklo_epi32(mmtmpD0,mmtmpD1);
-        mmtmpD3 = _mm_unpackhi_epi32(mmtmpD0,mmtmpD1);
-        dl_ch_rho128[2] = _mm_packs_epi32(mmtmpD2,mmtmpD3);
-
-       dl_ch128+=3;
-        dl_ch128i+=3;
-        dl_ch_rho128+=3;
-      } else {
-
-        dl_ch128+=2;
-        dl_ch128i+=2;
-        dl_ch_rho128+=2;
-      }
-    }
-
-  }
-
-  _mm_empty();
-  _m_empty();
-
-#elif defined(__arm__)
-
-#endif
-}
-*/
-
-void dlsch_detection_mrc(LTE_DL_FRAME_PARMS *frame_parms,
-                         int **rxdataF_comp,
-                         int **rxdataF_comp_i,
-                         int **rho,
-                         int **rho_i,
-                         int **dl_ch_mag,
-                         int **dl_ch_magb,
-                         int **dl_ch_mag_i,
-                         int **dl_ch_magb_i,
-                         unsigned char symbol,
-                         unsigned short nb_rb,
-                         unsigned char dual_stream_UE)
-{
-
-#if defined(__x86_64__)||defined(__i386__)
-
-  unsigned char aatx;
-  int i;
-  __m128i *rxdataF_comp128_0,*rxdataF_comp128_1,*rxdataF_comp128_i0,*rxdataF_comp128_i1,*dl_ch_mag128_0,*dl_ch_mag128_1,*dl_ch_mag128_0b,*dl_ch_mag128_1b,*rho128_0,*rho128_1,*rho128_i0,*rho128_i1,
-    *dl_ch_mag128_i0,*dl_ch_mag128_i1,*dl_ch_mag128_i0b,*dl_ch_mag128_i1b;
-
-  if (frame_parms->nb_antennas_rx>1) {
-
-    for (aatx=0; aatx<frame_parms->nb_antenna_ports_eNB; aatx++) {
-
-      rxdataF_comp128_0   = (__m128i *)&rxdataF_comp[(aatx<<1)][symbol*frame_parms->N_RB_DL*12];
-      rxdataF_comp128_1   = (__m128i *)&rxdataF_comp[(aatx<<1)+1][symbol*frame_parms->N_RB_DL*12];
-      dl_ch_mag128_0      = (__m128i *)&dl_ch_mag[(aatx<<1)][symbol*frame_parms->N_RB_DL*12];
-      dl_ch_mag128_1      = (__m128i *)&dl_ch_mag[(aatx<<1)+1][symbol*frame_parms->N_RB_DL*12];
-      dl_ch_mag128_0b     = (__m128i *)&dl_ch_magb[(aatx<<1)][symbol*frame_parms->N_RB_DL*12];
-      dl_ch_mag128_1b     = (__m128i *)&dl_ch_magb[(aatx<<1)+1][symbol*frame_parms->N_RB_DL*12];
+      rxdataF_comp128_0   = (__m128i *)&rxdataF_comp[(aatx<<1)][symbol*frame_parms->N_RB_DL*12];
+      rxdataF_comp128_1   = (__m128i *)&rxdataF_comp[(aatx<<1)+1][symbol*frame_parms->N_RB_DL*12];
+      dl_ch_mag128_0      = (__m128i *)&dl_ch_mag[(aatx<<1)][symbol*frame_parms->N_RB_DL*12];
+      dl_ch_mag128_1      = (__m128i *)&dl_ch_mag[(aatx<<1)+1][symbol*frame_parms->N_RB_DL*12];
+      dl_ch_mag128_0b     = (__m128i *)&dl_ch_magb[(aatx<<1)][symbol*frame_parms->N_RB_DL*12];
+      dl_ch_mag128_1b     = (__m128i *)&dl_ch_magb[(aatx<<1)+1][symbol*frame_parms->N_RB_DL*12];
 
       // MRC on each re of rb, both on MF output and magnitude (for 16QAM/64QAM llr computation)
       for (i=0;i<nb_rb*3;i++) {
@@ -3356,7 +3497,6 @@ void dlsch_detection_mrc(LTE_DL_FRAME_PARMS *frame_parms,
 #endif
 }
 
-
 void dlsch_detection_mrc_TM34(LTE_DL_FRAME_PARMS *frame_parms,
                               LTE_UE_PDSCH *pdsch_vars,
                               int harq_pid,
@@ -3366,7 +3506,11 @@ void dlsch_detection_mrc_TM34(LTE_DL_FRAME_PARMS *frame_parms,
                               unsigned char dual_stream_UE) {
 
   int i;
-  __m128i *rxdataF_comp128_0,*rxdataF_comp128_1,*rxdataF_comp128_i0,*rxdataF_comp128_i1,*dl_ch_mag128_0,*dl_ch_mag128_1,*dl_ch_mag128_0b,*dl_ch_mag128_1b,*rho128_0,*rho128_1,*rho128_i0,*rho128_i1,*dl_ch_mag128_i0,*dl_ch_mag128_i1,*dl_ch_mag128_i0b,*dl_ch_mag128_i1b;
+  __m128i *rxdataF_comp128_0,*rxdataF_comp128_1;
+  __m128i *dl_ch_mag128_0,*dl_ch_mag128_1;
+  __m128i *dl_ch_mag128_0b,*dl_ch_mag128_1b;
+  __m128i *rho128_0, *rho128_1;
+
 
   int **rxdataF_comp0           = pdsch_vars->rxdataF_comp0;
   int **rxdataF_comp1           = pdsch_vars->rxdataF_comp1[harq_pid][round];
@@ -3377,66 +3521,120 @@ void dlsch_detection_mrc_TM34(LTE_DL_FRAME_PARMS *frame_parms,
   int **dl_ch_magb0             = pdsch_vars->dl_ch_magb0;
   int **dl_ch_magb1             = pdsch_vars->dl_ch_magb1[harq_pid][round];
 
-  if (frame_parms->nb_antennas_rx>1) {
-
-      rxdataF_comp128_0   = (__m128i *)&rxdataF_comp0[0][symbol*frame_parms->N_RB_DL*12];
-      rxdataF_comp128_1   = (__m128i *)&rxdataF_comp0[1][symbol*frame_parms->N_RB_DL*12];
-      dl_ch_mag128_0      = (__m128i *)&dl_ch_mag0[0][symbol*frame_parms->N_RB_DL*12];
-      dl_ch_mag128_1      = (__m128i *)&dl_ch_mag0[1][symbol*frame_parms->N_RB_DL*12];
-      dl_ch_mag128_0b     = (__m128i *)&dl_ch_magb0[0][symbol*frame_parms->N_RB_DL*12];
-      dl_ch_mag128_1b     = (__m128i *)&dl_ch_magb0[1][symbol*frame_parms->N_RB_DL*12];
+  rxdataF_comp128_0   = (__m128i *)&rxdataF_comp0[0][symbol*frame_parms->N_RB_DL*12];
+  rxdataF_comp128_1   = (__m128i *)&rxdataF_comp0[1][symbol*frame_parms->N_RB_DL*12];
+  dl_ch_mag128_0      = (__m128i *)&dl_ch_mag0[0][symbol*frame_parms->N_RB_DL*12];
+  dl_ch_mag128_1      = (__m128i *)&dl_ch_mag0[1][symbol*frame_parms->N_RB_DL*12];
+  dl_ch_mag128_0b     = (__m128i *)&dl_ch_magb0[0][symbol*frame_parms->N_RB_DL*12];
+  dl_ch_mag128_1b     = (__m128i *)&dl_ch_magb0[1][symbol*frame_parms->N_RB_DL*12];
+  rho128_0 = (__m128i *) &dl_ch_rho2_ext[0][symbol*frame_parms->N_RB_DL*12];
+  rho128_1 = (__m128i *) &dl_ch_rho2_ext[1][symbol*frame_parms->N_RB_DL*12];
 
       // MRC on each re of rb, both on MF output and magnitude (for 16QAM/64QAM llr computation)
-      for (i=0;i<nb_rb*3;i++) {
-        rxdataF_comp128_0[i] = _mm_adds_epi16(_mm_srai_epi16(rxdataF_comp128_0[i],1),_mm_srai_epi16(rxdataF_comp128_1[i],1));
-        dl_ch_mag128_0[i]    = _mm_adds_epi16(_mm_srai_epi16(dl_ch_mag128_0[i],1),_mm_srai_epi16(dl_ch_mag128_1[i],1));
-        dl_ch_mag128_0b[i]   = _mm_adds_epi16(_mm_srai_epi16(dl_ch_mag128_0b[i],1),_mm_srai_epi16(dl_ch_mag128_1b[i],1));
-
-        // print_shorts("mrc compens0:",&rxdataF_comp128_0[i]);
-        // print_shorts("mrc mag128_0:",&dl_ch_mag128_0[i]);
-        // print_shorts("mrc mag128_0b:",&dl_ch_mag128_0b[i]);
-      }    }
+  for (i=0;i<nb_rb*3;i++) {
+    rxdataF_comp128_0[i] = _mm_adds_epi16(_mm_srai_epi16(rxdataF_comp128_0[i],1),_mm_srai_epi16(rxdataF_comp128_1[i],1));
+    dl_ch_mag128_0[i]    = _mm_adds_epi16(_mm_srai_epi16(dl_ch_mag128_0[i],1),_mm_srai_epi16(dl_ch_mag128_1[i],1));
+    dl_ch_mag128_0b[i]   = _mm_adds_epi16(_mm_srai_epi16(dl_ch_mag128_0b[i],1),_mm_srai_epi16(dl_ch_mag128_1b[i],1));
+    rho128_0[i] = _mm_adds_epi16(_mm_srai_epi16(rho128_0[i],1),_mm_srai_epi16(rho128_1[i],1));
+
+    if (frame_parms->nb_antennas_rx>2) {
+
+      __m128i *rxdataF_comp128_2 = NULL;
+      __m128i *rxdataF_comp128_3 = NULL;
+      __m128i *dl_ch_mag128_2 = NULL;
+      __m128i *dl_ch_mag128_3 = NULL;
+      __m128i *dl_ch_mag128_2b = NULL;
+      __m128i *dl_ch_mag128_3b = NULL;
+      __m128i *rho128_2 = NULL;
+      __m128i *rho128_3 = NULL;
+
+      rxdataF_comp128_2   = (__m128i *)&rxdataF_comp0[2][symbol*frame_parms->N_RB_DL*12];
+      rxdataF_comp128_3   = (__m128i *)&rxdataF_comp0[3][symbol*frame_parms->N_RB_DL*12];
+      dl_ch_mag128_2      = (__m128i *)&dl_ch_mag0[2][symbol*frame_parms->N_RB_DL*12];
+      dl_ch_mag128_3      = (__m128i *)&dl_ch_mag0[3][symbol*frame_parms->N_RB_DL*12];
+      dl_ch_mag128_2b     = (__m128i *)&dl_ch_magb0[2][symbol*frame_parms->N_RB_DL*12];
+      dl_ch_mag128_3b     = (__m128i *)&dl_ch_magb0[3][symbol*frame_parms->N_RB_DL*12];
+      rho128_2 = (__m128i *) &dl_ch_rho2_ext[2][symbol*frame_parms->N_RB_DL*12];
+      rho128_3 = (__m128i *) &dl_ch_rho2_ext[3][symbol*frame_parms->N_RB_DL*12];
+      /*rxdataF_comp*/
+      rxdataF_comp128_2[i] = _mm_adds_epi16(_mm_srai_epi16(rxdataF_comp128_2[i],1),_mm_srai_epi16(rxdataF_comp128_3[i],1));
+      rxdataF_comp128_0[i] = _mm_adds_epi16(_mm_srai_epi16(rxdataF_comp128_0[i],1),_mm_srai_epi16(rxdataF_comp128_2[i],1));
+      /*dl_ch_mag*/
+      dl_ch_mag128_2[i] = _mm_adds_epi16(_mm_srai_epi16(dl_ch_mag128_2[i],1),_mm_srai_epi16(dl_ch_mag128_3[i],1));
+      dl_ch_mag128_0[i] = _mm_adds_epi16(_mm_srai_epi16(dl_ch_mag128_0[i],1),_mm_srai_epi16(dl_ch_mag128_2[i],1));
+      /*dl_ch_mag*/
+      dl_ch_mag128_2b[i] = _mm_adds_epi16(_mm_srai_epi16(dl_ch_mag128_2b[i],1),_mm_srai_epi16(dl_ch_mag128_3b[i],1));
+      dl_ch_mag128_0b[i] = _mm_adds_epi16(_mm_srai_epi16(dl_ch_mag128_0b[i],1),_mm_srai_epi16(dl_ch_mag128_2b[i],1));
+      /*rho*/
+      rho128_2[i] = _mm_adds_epi16(_mm_srai_epi16(rho128_2[i],1),_mm_srai_epi16(rho128_3[i],1));
+      rho128_0[i] = _mm_adds_epi16(_mm_srai_epi16(rho128_0[i],1),_mm_srai_epi16(rho128_2[i],1));
+    }
+  }
 
-   // if (rho) {
-      rho128_0 = (__m128i *) &dl_ch_rho2_ext[0][symbol*frame_parms->N_RB_DL*12];
-      rho128_1 = (__m128i *) &dl_ch_rho2_ext[1][symbol*frame_parms->N_RB_DL*12];
-      for (i=0;i<nb_rb*3;i++) {
-           //  print_shorts("mrc rho0:",&rho128_0[i]);
-            //  print_shorts("mrc rho1:",&rho128_1[i]);
-        rho128_0[i] = _mm_adds_epi16(_mm_srai_epi16(rho128_0[i],1),_mm_srai_epi16(rho128_1[i],1));
-      }
-   //}
+    if (dual_stream_UE == 1) {
 
+      __m128i *dl_ch_mag128_i0, *dl_ch_mag128_i1;
+      __m128i *dl_ch_mag128_i0b, *dl_ch_mag128_i1b;
+      __m128i *rho128_i0, *rho128_i1;
+      __m128i *rxdataF_comp128_i0, *rxdataF_comp128_i1;
 
-    if (dual_stream_UE == 1) {
-      rho128_i0 = (__m128i *) &dl_ch_rho_ext[0][symbol*frame_parms->N_RB_DL*12];
-      rho128_i1 = (__m128i *) &dl_ch_rho_ext[1][symbol*frame_parms->N_RB_DL*12];
       rxdataF_comp128_i0   = (__m128i *)&rxdataF_comp1[0][symbol*frame_parms->N_RB_DL*12];
       rxdataF_comp128_i1   = (__m128i *)&rxdataF_comp1[1][symbol*frame_parms->N_RB_DL*12];
       dl_ch_mag128_i0      = (__m128i *)&dl_ch_mag1[0][symbol*frame_parms->N_RB_DL*12];
       dl_ch_mag128_i1      = (__m128i *)&dl_ch_mag1[1][symbol*frame_parms->N_RB_DL*12];
       dl_ch_mag128_i0b     = (__m128i *)&dl_ch_magb1[0][symbol*frame_parms->N_RB_DL*12];
       dl_ch_mag128_i1b     = (__m128i *)&dl_ch_magb1[1][symbol*frame_parms->N_RB_DL*12];
+      rho128_i0 = (__m128i *) &dl_ch_rho_ext[0][symbol*frame_parms->N_RB_DL*12];
+      rho128_i1 = (__m128i *) &dl_ch_rho_ext[1][symbol*frame_parms->N_RB_DL*12];
+
+
       for (i=0;i<nb_rb*3;i++) {
         rxdataF_comp128_i0[i] = _mm_adds_epi16(_mm_srai_epi16(rxdataF_comp128_i0[i],1),_mm_srai_epi16(rxdataF_comp128_i1[i],1));
-        rho128_i0[i]           = _mm_adds_epi16(_mm_srai_epi16(rho128_i0[i],1),_mm_srai_epi16(rho128_i1[i],1));
-
         dl_ch_mag128_i0[i]    = _mm_adds_epi16(_mm_srai_epi16(dl_ch_mag128_i0[i],1),_mm_srai_epi16(dl_ch_mag128_i1[i],1));
         dl_ch_mag128_i0b[i]    = _mm_adds_epi16(_mm_srai_epi16(dl_ch_mag128_i0b[i],1),_mm_srai_epi16(dl_ch_mag128_i1b[i],1));
+        rho128_i0[i]           = _mm_adds_epi16(_mm_srai_epi16(rho128_i0[i],1),_mm_srai_epi16(rho128_i1[i],1));
 
-        //print_shorts("mrc compens1:",&rxdataF_comp128_i0[i]);
-        //print_shorts("mrc mag128_i0:",&dl_ch_mag128_i0[i]);
-        //print_shorts("mrc mag128_i0b:",&dl_ch_mag128_i0b[i]);
+        if (frame_parms->nb_antennas_rx>2) {
+
+          __m128i *rxdataF_comp128_i2 = NULL;
+          __m128i *rxdataF_comp128_i3 = NULL;
+          __m128i *dl_ch_mag128_i2 = NULL;
+          __m128i *dl_ch_mag128_i3 = NULL;
+          __m128i *dl_ch_mag128_i2b = NULL;
+          __m128i *dl_ch_mag128_i3b = NULL;
+          __m128i *rho128_i2 = NULL;
+          __m128i *rho128_i3 = NULL;
+
+          rxdataF_comp128_i2   = (__m128i *)&rxdataF_comp1[2][symbol*frame_parms->N_RB_DL*12];
+          rxdataF_comp128_i3   = (__m128i *)&rxdataF_comp1[3][symbol*frame_parms->N_RB_DL*12];
+          dl_ch_mag128_i2      = (__m128i *)&dl_ch_mag1[2][symbol*frame_parms->N_RB_DL*12];
+          dl_ch_mag128_i3      = (__m128i *)&dl_ch_mag1[3][symbol*frame_parms->N_RB_DL*12];
+          dl_ch_mag128_i2b     = (__m128i *)&dl_ch_magb1[2][symbol*frame_parms->N_RB_DL*12];
+          dl_ch_mag128_i3b     = (__m128i *)&dl_ch_magb1[3][symbol*frame_parms->N_RB_DL*12];
+          rho128_i2 = (__m128i *) &dl_ch_rho_ext[2][symbol*frame_parms->N_RB_DL*12];
+          rho128_i3 = (__m128i *) &dl_ch_rho_ext[3][symbol*frame_parms->N_RB_DL*12];
+
+
+         /*rxdataF_comp*/
+          rxdataF_comp128_i2[i] = _mm_adds_epi16(_mm_srai_epi16(rxdataF_comp128_i2[i],1),_mm_srai_epi16(rxdataF_comp128_i3[i],1));
+          rxdataF_comp128_i0[i] = _mm_adds_epi16(_mm_srai_epi16(rxdataF_comp128_i0[i],1),_mm_srai_epi16(rxdataF_comp128_i2[i],1));
+          /*dl_ch_mag*/
+          dl_ch_mag128_i2[i] = _mm_adds_epi16(_mm_srai_epi16(dl_ch_mag128_i2[i],1),_mm_srai_epi16(dl_ch_mag128_i3[i],1));
+          dl_ch_mag128_i0[i] = _mm_adds_epi16(_mm_srai_epi16(dl_ch_mag128_i0[i],1),_mm_srai_epi16(dl_ch_mag128_i2[i],1));
+          /*dl_ch_mag*/
+          dl_ch_mag128_i2b[i] = _mm_adds_epi16(_mm_srai_epi16(dl_ch_mag128_i2b[i],1),_mm_srai_epi16(dl_ch_mag128_i3b[i],1));
+          dl_ch_mag128_i0b[i] = _mm_adds_epi16(_mm_srai_epi16(dl_ch_mag128_i0b[i],1),_mm_srai_epi16(dl_ch_mag128_i2b[i],1));
+          /*rho*/
+          rho128_i2[i] = _mm_adds_epi16(_mm_srai_epi16(rho128_i2[i],1),_mm_srai_epi16(rho128_i3[i],1));
+          rho128_i0[i] = _mm_adds_epi16(_mm_srai_epi16(rho128_i0[i],1),_mm_srai_epi16(rho128_i2[i],1));
+        }
       }
     }
 
-
   _mm_empty();
   _m_empty();
 }
 
-
-
 void dlsch_scale_channel(int **dl_ch_estimates_ext,
                          LTE_DL_FRAME_PARMS *frame_parms,
                          LTE_UE_DLSCH_t **dlsch_ue,
@@ -3462,7 +3660,7 @@ void dlsch_scale_channel(int **dl_ch_estimates_ext,
   // Determine scaling amplitude based the symbol
 
   ch_amp = ((pilots) ? (dlsch_ue[0]->sqrt_rho_b) : (dlsch_ue[0]->sqrt_rho_a));
-  
+
   LOG_D(PHY,"Scaling PDSCH Chest in OFDM symbol %d by %d, pilots %d nb_rb %d NCP %d symbol %d\n",symbol_mod,ch_amp,pilots,nb_rb,frame_parms->Ncp,symbol);
    // printf("Scaling PDSCH Chest in OFDM symbol %d by %d\n",symbol_mod,ch_amp);
 
@@ -3498,7 +3696,6 @@ void dlsch_scale_channel(int **dl_ch_estimates_ext,
 #endif
 }
 
-
 //compute average channel_level on each (TX,RX) antenna pair
 void dlsch_channel_level(int **dl_ch_estimates_ext,
                          LTE_DL_FRAME_PARMS *frame_parms,
@@ -3508,6 +3705,7 @@ void dlsch_channel_level(int **dl_ch_estimates_ext,
 {
 
 #if defined(__x86_64__)||defined(__i386__)
+  //printf("symbol = %d\n", symbol);
 
   short rb;
   unsigned char aatx,aarx,nre=12,symbol_mod;
@@ -3525,21 +3723,23 @@ void dlsch_channel_level(int **dl_ch_estimates_ext,
   //nb_rb*nre = y * 2^x
   int16_t x = factor2(nb_rb*nre);
   int16_t y = (nb_rb*nre)>>x;
-  //printf("nb_rb*nre = %d = %d * 2^(%d)\n",nb_rb*nre,y,x);
 
   for (aatx=0; aatx<frame_parms->nb_antenna_ports_eNB; aatx++)
     for (aarx=0; aarx<frame_parms->nb_antennas_rx; aarx++) {
-      //clear average level
+       //clear average level
+      //printf("aatx = %d, aarx = %d, aatx*frame_parms->nb_antennas_rx + aarx] = %d \n", aatx, aarx, aatx*frame_parms->nb_antennas_rx + aarx);
+
       avg128D = _mm_setzero_si128();
       // 5 is always a symbol with no pilots for both normal and extended prefix
 
-      dl_ch128=(__m128i *)&dl_ch_estimates_ext[(aatx<<1)+aarx][symbol*frame_parms->N_RB_DL*12];
+
+      dl_ch128=(__m128i *)&dl_ch_estimates_ext[aatx*frame_parms->nb_antennas_rx + aarx][symbol*frame_parms->N_RB_DL*12];
 
       for (rb=0;rb<nb_rb;rb++) {
-        //      printf("rb %d : ",rb);
-        //      print_shorts("ch",&dl_ch128[0]);
-	avg128D = _mm_add_epi32(avg128D,_mm_srai_epi16(_mm_madd_epi16(dl_ch128[0],dl_ch128[0]),x));
-	avg128D = _mm_add_epi32(avg128D,_mm_srai_epi16(_mm_madd_epi16(dl_ch128[1],dl_ch128[1]),x));
+
+        //printf("rb %d : ",rb);
+        avg128D = _mm_add_epi32(avg128D,_mm_srai_epi16(_mm_madd_epi16(dl_ch128[0],dl_ch128[0]),x));
+        avg128D = _mm_add_epi32(avg128D,_mm_srai_epi16(_mm_madd_epi16(dl_ch128[1],dl_ch128[1]),x));
 
         //avg128D = _mm_add_epi32(avg128D,_mm_madd_epi16(dl_ch128[0],_mm_srai_epi16(_mm_mulhi_epi16(dl_ch128[0], coeff128),15)));
         //avg128D = _mm_add_epi32(avg128D,_mm_madd_epi16(dl_ch128[1],_mm_srai_epi16(_mm_mulhi_epi16(dl_ch128[1], coeff128),15)));
@@ -3548,25 +3748,24 @@ void dlsch_channel_level(int **dl_ch_estimates_ext,
           dl_ch128+=2;
         }
         else {
-	  avg128D = _mm_add_epi32(avg128D,_mm_srai_epi16(_mm_madd_epi16(dl_ch128[2],dl_ch128[2]),x));
+           avg128D = _mm_add_epi32(avg128D,_mm_srai_epi16(_mm_madd_epi16(dl_ch128[2],dl_ch128[2]),x));
           //avg128D = _mm_add_epi32(avg128D,_mm_madd_epi16(dl_ch128[2],_mm_srai_epi16(_mm_mulhi_epi16(dl_ch128[2], coeff128),15)));
           dl_ch128+=3;
         }
-        /*
-          if (rb==0) {
-          print_shorts("dl_ch128",&dl_ch128[0]);
-          print_shorts("dl_ch128",&dl_ch128[1]);
-          print_shorts("dl_ch128",&dl_ch128[2]);
-          }
-        */
+
+          /*if(rb==0){
+            print_shorts("dl_ch128",&dl_ch128[0]);
+            print_shorts("dl_ch128",&dl_ch128[1]);
+            print_shorts("dl_ch128",&dl_ch128[2]);
+          }*/
+
       }
 
-      avg[(aatx<<1)+aarx] =(((int32_t*)&avg128D)[0] +
-                            ((int32_t*)&avg128D)[1] +
-                            ((int32_t*)&avg128D)[2] +
-			      ((int32_t*)&avg128D)[3])/y;
-                //  printf("Channel level : %d\n",avg[(aatx<<1)+aarx]);
-    }
+      avg[aatx*frame_parms->nb_antennas_rx + aarx] =(((int32_t*)&avg128D)[0] +
+                                                     ((int32_t*)&avg128D)[1] +
+                                                     ((int32_t*)&avg128D)[2] +
+                                                     ((int32_t*)&avg128D)[3])/y;
+      }
 
   _mm_empty();
   _m_empty();
@@ -3586,7 +3785,7 @@ void dlsch_channel_level(int **dl_ch_estimates_ext,
       avg128D = vdupq_n_s32(0);
       // 5 is always a symbol with no pilots for both normal and extended prefix
 
-      dl_ch128=(int16x4_t *)&dl_ch_estimates_ext[(aatx<<1)+aarx][symbol*frame_parms->N_RB_DL*12];
+      dl_ch128=(int16x4_t *)&dl_ch_estimates_ext[aatx*frame_parms->nb_antennas_rx + aarx][symbol*frame_parms->N_RB_DL*12];
 
       for (rb=0; rb<nb_rb; rb++) {
         //  printf("rb %d : ",rb);
@@ -3596,7 +3795,7 @@ void dlsch_channel_level(int **dl_ch_estimates_ext,
         avg128D = vqaddq_s32(avg128D,vmull_s16(dl_ch128[2],dl_ch128[2]));
         avg128D = vqaddq_s32(avg128D,vmull_s16(dl_ch128[3],dl_ch128[3]));
 
-        if (((symbol_mod == 0) || (symbol_mod == (frame_parms->Ncp-1)))&&(frame_parms->nb_antenna_ports_eNB!=1)) {
+        if (((symbol_mod == 0) || (symbol_mod == (frame_parms->Ncp-1)))&&(frame_parms->mode1_flag==0)) {
           dl_ch128+=4;
         } else {
           avg128D = vqaddq_s32(avg128D,vmull_s16(dl_ch128[4],dl_ch128[4]));
@@ -3613,187 +3812,745 @@ void dlsch_channel_level(int **dl_ch_estimates_ext,
         */
       }
 
-
-      if (((symbol_mod == 0) || (symbol_mod == (frame_parms->Ncp-1)))&&(frame_parms->nb_antenna_ports_eNB!=1))
+      if (((symbol_mod == 0) || (symbol_mod == (frame_parms->Ncp-1)))&&(frame_parms->mode1_flag==0))
         nre=8;
-      else if (((symbol_mod == 0) || (symbol_mod == (frame_parms->Ncp-1)))&&(frame_parms->nb_antenna_ports_eNB==1))
+      else if (((symbol_mod == 0) || (symbol_mod == (frame_parms->Ncp-1)))&&(frame_parms->mode1_flag==1))
         nre=10;
       else
         nre=12;
 
-      avg[(aatx<<1)+aarx] = (((int32_t*)&avg128D)[0] +
-                             ((int32_t*)&avg128D)[1] +
-                             ((int32_t*)&avg128D)[2] +
-                             ((int32_t*)&avg128D)[3])/(nb_rb*nre);
+      avg[aatx*frame_parms->nb_antennas_rx + aarx] = (((int32_t*)&avg128D)[0] +
+                                                          ((int32_t*)&avg128D)[1] +
+                                                          ((int32_t*)&avg128D)[2] +
+                                                          ((int32_t*)&avg128D)[3])/(nb_rb*nre);
 
-      //            printf("Channel level : %d\n",avg[(aatx<<1)+aarx]);
+      //printf("Channel level : %d\n",avg[aatx*(frame_parms->nb_antennas_rx-1) + aarx]);
     }
-
-
 #endif
-}
 
-//compute average channel_level of effective (precoded) channel
+}
 
-//compute average channel_level of effective (precoded) channel
-void dlsch_channel_level_TM34(int **dl_ch_estimates_ext,
-                              LTE_DL_FRAME_PARMS *frame_parms,
-                              unsigned char *pmi_ext,
-                              int *avg_0,
-                              int *avg_1,
-                              uint8_t symbol,
-                              unsigned short nb_rb,
-                              MIMO_mode_t mimo_mode){
+void dlsch_channel_level_core(int **dl_ch_estimates_ext,
+                              int32_t *avg,
+                              int n_tx,
+                              int n_rx,
+                              int length,
+                              int start_point)
+{
 
 #if defined(__x86_64__)||defined(__i386__)
 
+  short ii;
+  int aatx,aarx;
+  int length_mod8;
+  int length2;
+  __m128i *dl_ch128, avg128D;
 
-  short rb;
-  unsigned char aarx,nre=12,symbol_mod;
-  __m128i *dl_ch0_128,*dl_ch1_128, dl_ch0_128_tmp, dl_ch1_128_tmp, avg_0_128D, avg_1_128D;
-
-  symbol_mod = (symbol>=(7-frame_parms->Ncp)) ? symbol-(7-frame_parms->Ncp) : symbol;
-
-  //clear average level
- // avg_0_128D = _mm_setzero_si128();
- // avg_1_128D = _mm_setzero_si128();
-  avg_0[0] = 0;
-  avg_0[1] = 0;
-  avg_1[0] = 0;
-  avg_1[1] = 0;
-  // 5 is always a symbol with no pilots for both normal and extended prefix
-
-  if (((symbol_mod == 0) || (symbol_mod == (frame_parms->Ncp-1)))&&(frame_parms->nb_antenna_ports_eNB!=1))
-    nre=8;
-  else if (((symbol_mod == 0) || (symbol_mod == (frame_parms->Ncp-1)))&&(frame_parms->nb_antenna_ports_eNB==1))
-    nre=10;
-  else
-    nre=12;
+  int16_t x = factor2(length);
+  int16_t y = (length)>>x;
 
-  for (aarx=0; aarx<frame_parms->nb_antennas_rx; aarx++) {
-    dl_ch0_128 = (__m128i *)&dl_ch_estimates_ext[aarx][symbol*frame_parms->N_RB_DL*12];
-    dl_ch1_128 = (__m128i *)&dl_ch_estimates_ext[2+aarx][symbol*frame_parms->N_RB_DL*12];
+  for (aatx=0; aatx<n_tx; aatx++)
+    for (aarx=0; aarx<n_rx; aarx++) {
 
-    avg_0_128D = _mm_setzero_si128();
-    avg_1_128D = _mm_setzero_si128();
-    for (rb=0; rb<nb_rb; rb++) {
-              // printf("rb %d : \n",rb);
-              // print_shorts("ch0\n",&dl_ch0_128[0]);
-               //print_shorts("ch1\n",&dl_ch1_128[0]);
-      dl_ch0_128_tmp = _mm_load_si128(&dl_ch0_128[0]);
-      dl_ch1_128_tmp = _mm_load_si128(&dl_ch1_128[0]);
+      avg128D = _mm_setzero_si128();
 
-      if (mimo_mode==LARGE_CDD)
-        prec2A_TM3_128(&dl_ch0_128_tmp,&dl_ch1_128_tmp);
-      else if (mimo_mode==DUALSTREAM_UNIFORM_PRECODING1)
-        prec2A_TM4_128(0,&dl_ch0_128_tmp,&dl_ch1_128_tmp);
-      else if (mimo_mode==DUALSTREAM_UNIFORM_PRECODINGj)
-        prec2A_TM4_128(1,&dl_ch0_128_tmp,&dl_ch1_128_tmp);
-      else if (mimo_mode==DUALSTREAM_PUSCH_PRECODING)
-        prec2A_TM4_128(pmi_ext[rb],&dl_ch0_128_tmp,&dl_ch1_128_tmp);
+      dl_ch128=(__m128i *)&dl_ch_estimates_ext[aatx*n_rx + aarx][start_point];
 
-      //      mmtmpD0 = _mm_madd_epi16(dl_ch0_128_tmp,dl_ch0_128_tmp);
-      avg_0_128D = _mm_add_epi32(avg_0_128D,_mm_madd_epi16(dl_ch0_128_tmp,dl_ch0_128_tmp));
+      length_mod8=length&7;
 
-      avg_1_128D = _mm_add_epi32(avg_1_128D,_mm_madd_epi16(dl_ch1_128_tmp,dl_ch1_128_tmp));
+      if (length_mod8 == 0){
 
-      dl_ch0_128_tmp = _mm_load_si128(&dl_ch0_128[1]);
-      dl_ch1_128_tmp = _mm_load_si128(&dl_ch1_128[1]);
+        length2 = length>>3;
 
-      if (mimo_mode==LARGE_CDD)
-        prec2A_TM3_128(&dl_ch0_128_tmp,&dl_ch1_128_tmp);
-      else if (mimo_mode==DUALSTREAM_UNIFORM_PRECODING1)
-        prec2A_TM4_128(0,&dl_ch0_128_tmp,&dl_ch1_128_tmp);
-      else if (mimo_mode==DUALSTREAM_UNIFORM_PRECODINGj)
-        prec2A_TM4_128(1,&dl_ch0_128_tmp,&dl_ch1_128_tmp);
-      else if (mimo_mode==DUALSTREAM_PUSCH_PRECODING)
-        prec2A_TM4_128(pmi_ext[rb],&dl_ch0_128_tmp,&dl_ch1_128_tmp);
+        for (ii=0;ii<length2;ii++) {
+          avg128D = _mm_add_epi32(avg128D,_mm_srai_epi16(_mm_madd_epi16(dl_ch128[0],dl_ch128[0]),x));
+          avg128D = _mm_add_epi32(avg128D,_mm_srai_epi16(_mm_madd_epi16(dl_ch128[1],dl_ch128[1]),x));
 
-      //      mmtmpD1 = _mm_madd_epi16(dl_ch0_128_tmp,dl_ch0_128_tmp);
-      avg_0_128D = _mm_add_epi32(avg_0_128D,_mm_madd_epi16(dl_ch0_128_tmp,dl_ch0_128_tmp));
+          dl_ch128+=2;
+        }
+      }else {
+        printf ("Channel level: Received number of subcarriers is not multiple of 4, \n"
+                 "need to adapt the code!\n");
+      }
 
-      avg_1_128D = _mm_add_epi32(avg_1_128D,_mm_madd_epi16(dl_ch1_128_tmp,dl_ch1_128_tmp));
 
-      if (((symbol_mod == 0) || (symbol_mod == (frame_parms->Ncp-1)))&&(frame_parms->nb_antenna_ports_eNB!=1)) {
-        dl_ch0_128+=2;
-        dl_ch1_128+=2;
+      avg[aatx*n_rx + aarx] =(((int32_t*)&avg128D)[0] +
+                              ((int32_t*)&avg128D)[1] +
+                              ((int32_t*)&avg128D)[2] +
+                              ((int32_t*)&avg128D)[3])/y;
+      //printf("Channel level [%d]: %d\n",aatx*n_rx + aarx, avg[aatx*n_rx + aarx]);
       }
-      else {
-        dl_ch0_128_tmp = _mm_load_si128(&dl_ch0_128[2]);
-        dl_ch1_128_tmp = _mm_load_si128(&dl_ch1_128[2]);
 
-        if (mimo_mode==LARGE_CDD)
-          prec2A_TM3_128(&dl_ch0_128_tmp,&dl_ch1_128_tmp);
-        else if (mimo_mode==DUALSTREAM_UNIFORM_PRECODING1)
-          prec2A_TM4_128(0,&dl_ch0_128_tmp,&dl_ch1_128_tmp);
-        else if (mimo_mode==DUALSTREAM_UNIFORM_PRECODINGj)
-          prec2A_TM4_128(1,&dl_ch0_128_tmp,&dl_ch1_128_tmp);
-        else if (mimo_mode==DUALSTREAM_PUSCH_PRECODING)
-          prec2A_TM4_128(pmi_ext[rb],&dl_ch0_128_tmp,&dl_ch1_128_tmp);
-        //      mmtmpD2 = _mm_madd_epi16(dl_ch0_128_tmp,dl_ch0_128_tmp);
+  _mm_empty();
+  _m_empty();
 
-        avg_1_128D = _mm_add_epi32(avg_1_128D,_mm_madd_epi16(dl_ch1_128_tmp,dl_ch1_128_tmp));
-        avg_0_128D = _mm_add_epi32(avg_0_128D,_mm_madd_epi16(dl_ch0_128_tmp,dl_ch0_128_tmp));
+ /* FIXME This part needs to be adapted like the one above */
+#elif defined(__arm__)
 
-        dl_ch0_128+=3;
-        dl_ch1_128+=3;
-      }
-    }
+  short rb;
+  unsigned char aatx,aarx,nre=12,symbol_mod;
+  int32x4_t avg128D;
+  int16x4_t *dl_ch128;
 
+  symbol_mod = (symbol>=(7-frame_parms->Ncp)) ? symbol-(7-frame_parms->Ncp) : symbol;
 
-    avg_0[aarx] = (((int*)&avg_0_128D)[0])/(nb_rb*nre) +
-      (((int*)&avg_0_128D)[1])/(nb_rb*nre) +
-      (((int*)&avg_0_128D)[2])/(nb_rb*nre) +
-      (((int*)&avg_0_128D)[3])/(nb_rb*nre);
-    //  printf("From Chan_level aver stream 0 %d =%d\n", aarx, avg_0[aarx]);
+  for (aatx=0; aatx<frame_parms->nb_antenna_ports_eNB; aatx++)
+    for (aarx=0; aarx<frame_parms->nb_antennas_rx; aarx++) {
+      //clear average level
+      avg128D = vdupq_n_s32(0);
+      // 5 is always a symbol with no pilots for both normal and extended prefix
 
-    avg_1[aarx] = (((int*)&avg_1_128D)[0])/(nb_rb*nre) +
-      (((int*)&avg_1_128D)[1])/(nb_rb*nre) +
-      (((int*)&avg_1_128D)[2])/(nb_rb*nre) +
-      (((int*)&avg_1_128D)[3])/(nb_rb*nre);
-  //    printf("From Chan_level aver stream 1 %d =%d\n", aarx, avg_1[aarx]);
+      dl_ch128=(int16x4_t *)&dl_ch_estimates_ext[aatx*frame_parms->nb_antennas_rx + aarx][symbol*frame_parms->N_RB_DL*12];
+
+      for (rb=0; rb<nb_rb; rb++) {
+        //  printf("rb %d : ",rb);
+        //  print_shorts("ch",&dl_ch128[0]);
+        avg128D = vqaddq_s32(avg128D,vmull_s16(dl_ch128[0],dl_ch128[0]));
+        avg128D = vqaddq_s32(avg128D,vmull_s16(dl_ch128[1],dl_ch128[1]));
+        avg128D = vqaddq_s32(avg128D,vmull_s16(dl_ch128[2],dl_ch128[2]));
+        avg128D = vqaddq_s32(avg128D,vmull_s16(dl_ch128[3],dl_ch128[3]));
+
+        if (((symbol_mod == 0) || (symbol_mod == (frame_parms->Ncp-1)))&&(frame_parms->nb_antenna_ports_eNB!=1)) {
+          dl_ch128+=4;
+        } else {
+          avg128D = vqaddq_s32(avg128D,vmull_s16(dl_ch128[4],dl_ch128[4]));
+          avg128D = vqaddq_s32(avg128D,vmull_s16(dl_ch128[5],dl_ch128[5]));
+          dl_ch128+=6;
+        }
+      }
+
+
+      if (((symbol_mod == 0) || (symbol_mod == (frame_parms->Ncp-1)))&&(frame_parms->nb_antenna_ports_eNB!=1))
+        nre=8;
+      else if (((symbol_mod == 0) || (symbol_mod == (frame_parms->Ncp-1)))&&(frame_parms->nb_antenna_ports_eNB==1))
+        nre=10;
+      else
+        nre=12;
+
+      avg[aatx*frame_parms->nb_antennas_rx + aarx] = (((int32_t*)&avg128D)[0] +
+                                                          ((int32_t*)&avg128D)[1] +
+                                                          ((int32_t*)&avg128D)[2] +
+                                                          ((int32_t*)&avg128D)[3])/(nb_rb*nre);
+
+      //printf("Channel level : %d\n",avg[aatx*(frame_parms->nb_antennas_rx-1) + aarx]);
+    }
+#endif
+
+}
+
+void mmse_processing_oai(LTE_UE_PDSCH *pdsch_vars,
+                     LTE_DL_FRAME_PARMS *frame_parms,
+                     PHY_MEASUREMENTS *measurements,
+                     unsigned char first_symbol_flag,
+                     MIMO_mode_t mimo_mode,
+                     unsigned short mmse_flag,
+                     int noise_power,
+                     unsigned char symbol,
+                     unsigned short nb_rb){
+
+  int **rxdataF_ext           = pdsch_vars->rxdataF_ext;
+  int **dl_ch_estimates_ext   = pdsch_vars->dl_ch_estimates_ext;
+  unsigned char *pmi_ext      = pdsch_vars->pmi_ext;
+  int avg_00[frame_parms->nb_antenna_ports_eNB*frame_parms->nb_antennas_rx];
+  int avg_01[frame_parms->nb_antenna_ports_eNB*frame_parms->nb_antennas_rx];
+  int symbol_mod, length, start_point, nre;
+
+  symbol_mod = (symbol>=(7-frame_parms->Ncp)) ? symbol-(7-frame_parms->Ncp) : symbol;
+
+  if (((symbol_mod == 0) || (symbol_mod == (frame_parms->Ncp-1)))&&(frame_parms->nb_antenna_ports_eNB!=1))
+    nre=8;
+  else if (((symbol_mod == 0) || (symbol_mod == (frame_parms->Ncp-1)))&&(frame_parms->nb_antenna_ports_eNB==1))
+    nre=10;
+  else
+    nre=12;
+
+  length  = nre*nb_rb;
+  start_point = symbol*nb_rb*12;
+
+
+  mmse_processing_core(rxdataF_ext,
+                       dl_ch_estimates_ext,
+                       noise_power,
+                       frame_parms->nb_antenna_ports_eNB,
+                       frame_parms->nb_antennas_rx,
+                       length,
+                       start_point);
+
+
+  /*dlsch_channel_aver_band(dl_ch_estimates_ext,
+                          frame_parms,
+                          chan_avg,
+                          symbol,
+                          nb_rb);
+
+
+   for (aatx=0; aatx<frame_parms->nb_antenna_ports_eNB; aatx++)
+     for (aarx=0; aarx<frame_parms->nb_antennas_rx; aarx++) {
+       H[aatx*frame_parms->nb_antennas_rx + aarx] = (float)(chan_avg[aatx*frame_parms->nb_antennas_rx + aarx].r/(32768.0)) + I*(float)(chan_avg[aatx*frame_parms->nb_antennas_rx + aarx].i/(32768.0));
+      // printf("H [%d] = (%f, %f) \n", aatx*frame_parms->nb_antennas_rx + aarx, creal(H[aatx*frame_parms->nb_antennas_rx + aarx]), cimag(H[aatx*frame_parms->nb_antennas_rx + aarx]));
+   }*/
+
+    if (first_symbol_flag == 1){
+      dlsch_channel_level_TM34(dl_ch_estimates_ext,
+                                 frame_parms,
+                                 pmi_ext,
+                                 avg_00,
+                                 avg_01,
+                                 symbol,
+                                 nb_rb,
+                                 mmse_flag,
+                                 mimo_mode);
+
+      avg_00[0] = (log2_approx(avg_00[0])/2) + dlsch_demod_shift+4;// + 2 ;//+ 4;
+      avg_01[0] = (log2_approx(avg_01[0])/2) + dlsch_demod_shift+4;// + 2 ;//+ 4;
+      pdsch_vars->log2_maxh0 = cmax(avg_00[0],0);
+      pdsch_vars->log2_maxh1 = cmax(avg_01[0],0);
   }
-//avg_0[0] = max(avg_0[0],avg_0[1]);
-//avg_1[0] = max(avg_1[0],avg_1[1]);
-//avg_0[0]= max(avg_0[0], avg_1[0]);
+}
 
-  avg_0[0] = avg_0[0] + avg_0[1];
- // printf("From Chan_level aver stream 0 final =%d\n", avg_0[0]);
-  avg_1[0] = avg_1[0] + avg_1[1];
- // printf("From Chan_level aver stream 1 final =%d\n", avg_1[0]);
- avg_0[0] = min (avg_0[0], avg_1[0]);
- avg_1[0] = avg_0[0];
+void mmse_processing_core(int32_t **rxdataF_ext,
+                          int32_t **dl_ch_estimates_ext,
+                          int noise_power,
+                          int n_tx,
+                          int n_rx,
+                          int length,
+                          int start_point){
 
-  _mm_empty();
-  _m_empty();
+  int aatx, aarx, re;
+  float imag;
+  float real;
+
+
+  float complex **W_MMSE= malloc(n_tx*n_rx*sizeof(float complex*));
+   for (int j=0; j<n_tx*n_rx; j++) {
+     W_MMSE[j] = malloc(sizeof(float complex)*length);
+  }
+
+  float complex *H=  malloc(n_tx*n_rx*sizeof(float complex));
+  float complex *W_MMSE_re=  malloc(n_tx*n_rx*sizeof(float complex));
+
+  float complex** dl_ch_estimates_ext_flcpx = malloc(n_tx*n_rx*sizeof(float complex*));
+  for (int j=0; j<n_tx*n_rx; j++) {
+    dl_ch_estimates_ext_flcpx[j] = malloc(sizeof(float complex)*length);
+  }
+
+  float complex** rxdataF_ext_flcpx = malloc(n_rx*sizeof(float complex*));
+  for (int j=0; j<n_rx; j++) {
+    rxdataF_ext_flcpx[j] = malloc(sizeof(float complex)*length);
+  }
+
+  chan_est_to_float(dl_ch_estimates_ext,
+                    dl_ch_estimates_ext_flcpx,
+                    n_tx,
+                    n_rx,
+                    length,
+                    start_point);
+
+  for (re=0; re<length; re++){
+    for (aatx=0; aatx<n_tx; aatx++){
+      for (aarx=0; aarx<n_rx; aarx++) {
+        imag = cimag(dl_ch_estimates_ext_flcpx[aatx*n_rx + aarx][re]);
+        real = creal(dl_ch_estimates_ext_flcpx[aatx*n_rx + aarx][re]);
+        H[aatx*n_rx + aarx] = real+ I*imag;
+      }
+    }
+    compute_MMSE(H, n_tx, noise_power, W_MMSE_re);
+    for (aatx=0; aatx<n_tx; aatx++){
+      for (aarx=0; aarx<n_rx; aarx++) {
+        W_MMSE[aatx*n_rx + aarx][re] = W_MMSE_re[aatx*n_rx + aarx];
+      }
+    }
+  }
+
+  rxdataF_to_float(rxdataF_ext,
+                   rxdataF_ext_flcpx,
+                   n_rx,
+                   length,
+                   start_point);
+
+  mult_mmse_rxdataF(W_MMSE,
+                    rxdataF_ext_flcpx,
+                    n_tx,
+                    n_rx,
+                    length,
+                    start_point);
+
+
+  mult_mmse_chan_est(W_MMSE,
+                     dl_ch_estimates_ext_flcpx,
+                     n_tx,
+                     n_rx,
+                     length,
+                     start_point);
+
+
+  float_to_rxdataF(rxdataF_ext,
+                   rxdataF_ext_flcpx,
+                   n_tx,
+                   n_rx,
+                   length,
+                   start_point);
+
+
+  float_to_chan_est(dl_ch_estimates_ext,
+                    dl_ch_estimates_ext_flcpx,
+                    n_tx,
+                    n_rx,
+                    length,
+                    start_point);
+
+free(W_MMSE);
+free(H);
+free(W_MMSE_re);
+free(dl_ch_estimates_ext_flcpx);
+free(rxdataF_ext_flcpx);
+
+}
+
+
+/*THIS FUNCTION TAKES FLOAT_POINT INPUT. SHOULD NOT BE USED WITH OAI*/
+void mmse_processing_core_flp(float complex** rxdataF_ext_flcpx,
+                              float complex **H,
+                              int32_t **rxdataF_ext,
+                              int32_t **dl_ch_estimates_ext,
+                              float noise_power,
+                              int n_tx,
+                              int n_rx,
+                              int length,
+                              int start_point){
+
+  int aatx, aarx, re;
+  float max = 0;
+  float one_over_max = 0;
+
+  float complex **W_MMSE= malloc(n_tx*n_rx*sizeof(float complex*));
+   for (int j=0; j<n_tx*n_rx; j++) {
+     W_MMSE[j] = malloc(sizeof(float complex)*length);
+  }
+
+  float complex *H_re=  malloc(n_tx*n_rx*sizeof(float complex));
+  float complex *W_MMSE_re=  malloc(n_tx*n_rx*sizeof(float complex));
+
+  for (re=0; re<length; re++){
+    for (aatx=0; aatx<n_tx; aatx++){
+      for (aarx=0; aarx<n_rx; aarx++) {
+        H_re[aatx*n_rx + aarx] = H[aatx*n_rx + aarx][re];
+#ifdef DEBUG_MMSE
+        if (re == 0)
+        printf(" H_re[%d]= (%f + i%f)\n", aatx*n_rx + aarx, creal(H_re[aatx*n_rx + aarx]), cimag(H_re[aatx*n_rx + aarx]));
+#endif
+      }
+    }
+    compute_MMSE(H_re, n_tx, noise_power, W_MMSE_re);
+    for (aatx=0; aatx<n_tx; aatx++){
+      for (aarx=0; aarx<n_rx; aarx++) {
+        W_MMSE[aatx*n_rx + aarx][re] = W_MMSE_re[aatx*n_rx + aarx];
+        if (fabs(creal(W_MMSE_re[aatx*n_rx + aarx])) > max)
+          max = fabs(creal(W_MMSE_re[aatx*n_rx + aarx]));
+        if (fabs(cimag(W_MMSE_re[aatx*n_rx + aarx])) > max)
+          max = fabs(cimag(W_MMSE_re[aatx*n_rx + aarx]));
+      }
+    }
+  }
+  one_over_max = 1.0/max;
+
+  for (re=0; re<length; re++)
+    for (aatx=0; aatx<n_tx; aatx++)
+      for (aarx=0; aarx<n_rx; aarx++){
+#ifdef DEBUG_MMSE
+        if (re == 0)
+          printf(" W_MMSE[%d] = (%f + i%f)\n", aatx*n_rx + aarx, creal(W_MMSE[aatx*n_rx + aarx][re]), cimag(W_MMSE[aatx*n_rx + aarx][re]));
+#endif
+        W_MMSE[aatx*n_rx + aarx][re] = one_over_max*W_MMSE[aatx*n_rx + aarx][re];
+#ifdef DEBUG_MMSE
+        if (re == 0)
+          printf(" AFTER NORM W_MMSE[%d] = (%f + i%f), max = %f \n", aatx*n_rx + aarx, creal(W_MMSE[aatx*n_rx + aarx][re]), cimag(W_MMSE[aatx*n_rx + aarx][re]), max);
+#endif
+      }
+
+
+  mult_mmse_rxdataF(W_MMSE,
+                    rxdataF_ext_flcpx,
+                    n_tx,
+                    n_rx,
+                    length,
+                    start_point);
+
+  mult_mmse_chan_est(W_MMSE,
+                     H,
+                     n_tx,
+                     n_rx,
+                     length,
+                     start_point);
+
+  float_to_rxdataF(rxdataF_ext,
+                   rxdataF_ext_flcpx,
+                   n_tx,
+                   n_rx,
+                   length,
+                   start_point);
+
+  float_to_chan_est(dl_ch_estimates_ext,
+                    H,
+                    n_tx,
+                    n_rx,
+                    length,
+                    start_point);
+  free(H_re);
+  free(W_MMSE);
+  free(W_MMSE_re);
+
+}
+
+
+void dlsch_channel_aver_band(int **dl_ch_estimates_ext,
+                             LTE_DL_FRAME_PARMS *frame_parms,
+                             struct complex32 *chan_avg,
+                             unsigned char symbol,
+                             unsigned short nb_rb)
+{
+
+#if defined(__x86_64__)||defined(__i386__)
+
+  short rb;
+  unsigned char aatx,aarx,nre=12,symbol_mod;
+  __m128i *dl_ch128, avg128D;
+  int32_t chan_est_avg[4];
+
+  symbol_mod = (symbol>=(7-frame_parms->Ncp)) ? symbol-(7-frame_parms->Ncp) : symbol;
+
+  if (((symbol_mod == 0) || (symbol_mod == (frame_parms->Ncp-1)))&&(frame_parms->nb_antenna_ports_eNB!=1))
+    nre=8;
+  else if (((symbol_mod == 0) || (symbol_mod == (frame_parms->Ncp-1)))&&(frame_parms->nb_antenna_ports_eNB==1))
+    nre=10;
+  else
+    nre=12;
+
+  for (aatx=0; aatx<frame_parms->nb_antennas_tx; aatx++){
+    for (aarx=0; aarx<frame_parms->nb_antennas_rx; aarx++) {
+      dl_ch128=(__m128i *)&dl_ch_estimates_ext[aatx*frame_parms->nb_antennas_rx + aarx][symbol*frame_parms->N_RB_DL*12];
+      avg128D = _mm_setzero_si128();
+     //  print_shorts("avg128D 1",&avg128D);
+
+      for (rb=0;rb<nb_rb;rb++) {
+        /*  printf("symbol %d, ant %d, nre*nrb %d, rb %d \n", symbol, aatx*frame_parms->nb_antennas_rx + aarx, nb_rb*nre, rb);
+          print_shorts("aver dl_ch128",&dl_ch128[0]);
+          print_shorts("aver dl_ch128",&dl_ch128[1]);
+          print_shorts("aver dl_ch128",&dl_ch128[2]);
+        avg128D = _mm_add_epi16(avg128D, dl_ch128[0]);*/
+        //print_shorts("avg128D 2",&avg128D);
+
+        avg128D = _mm_add_epi16(avg128D, dl_ch128[1]);
+       //  print_shorts("avg128D 3",&avg128D);
+
+        if (((symbol_mod == 0) || (symbol_mod == (frame_parms->Ncp-1)))&&(frame_parms->nb_antenna_ports_eNB!=1)) {
+          dl_ch128+=2;
+        }else {
+          avg128D = _mm_add_epi16(avg128D,dl_ch128[2]);
+         //  print_shorts("avg128D 4",&avg128D);
+          dl_ch128+=3;
+        }
+      }
+
+      chan_avg[aatx*frame_parms->nb_antennas_rx + aarx].r =(((int16_t*)&avg128D)[0] +
+                                                              ((int16_t*)&avg128D)[2] +
+                                                              ((int16_t*)&avg128D)[4] +
+                                                              ((int16_t*)&avg128D)[6])/(nb_rb*nre);
+    //  printf("symb %d chan_avg re [%d] = %d\n", symbol, aatx*frame_parms->nb_antennas_rx + aarx, chan_avg[aatx*frame_parms->nb_antennas_rx + aarx].r);
+
+
+
+      chan_avg[aatx*frame_parms->nb_antennas_rx + aarx].i =(((int16_t*)&avg128D)[1] +
+                                                            ((int16_t*)&avg128D)[3] +
+                                                            ((int16_t*)&avg128D)[5] +
+                                                            ((int16_t*)&avg128D)[7])/(nb_rb*nre);
+    //  printf("symb %d chan_avg im [%d] = %d\n", symbol, aatx*frame_parms->nb_antennas_rx + aarx, chan_avg[aatx*frame_parms->nb_antennas_rx + aarx].i);
+
+      //printf("symb %d chan_avg im [%d] = %d\n", symbol, aatx*frame_parms->nb_antennas_rx + aarx, chan_avg[aatx*frame_parms->nb_antennas_rx + aarx].i);
+
+
+      chan_est_avg[aatx*frame_parms->nb_antennas_rx + aarx] = (((int32_t)chan_avg[aatx*frame_parms->nb_antennas_rx + aarx].i)<<16)|(((int32_t)chan_avg[aatx*frame_parms->nb_antennas_rx + aarx].r) & 0xffff);
+
+      //printf("symb %d chan_est_avg [%d] = %d\n", symbol, aatx*frame_parms->nb_antennas_rx + aarx, chan_est_avg[aatx*frame_parms->nb_antennas_rx + aarx]);
+
+      dl_ch128=(__m128i *)&dl_ch_estimates_ext[aatx*frame_parms->nb_antennas_rx + aarx][symbol*frame_parms->N_RB_DL*12];
+
+      for (rb=0;rb<nb_rb;rb++) {
+        dl_ch128[0] = _mm_set1_epi32(chan_est_avg[aatx*frame_parms->nb_antennas_rx + aarx]);
+        dl_ch128[1] = _mm_set1_epi32(chan_est_avg[aatx*frame_parms->nb_antennas_rx + aarx]);
+        if (((symbol_mod == 0) || (symbol_mod == (frame_parms->Ncp-1)))&&(frame_parms->nb_antenna_ports_eNB!=1)) {
+          dl_ch128+=2;
+        }else {
+        dl_ch128[2] = _mm_set1_epi32(chan_est_avg[aatx*frame_parms->nb_antennas_rx + aarx]);
+          dl_ch128+=3;
+        }
+       }
+     }
+   }
+
+    _mm_empty();
+    _m_empty();
 
 #elif defined(__arm__)
+#endif
+  }
+
+void rxdataF_to_float(int32_t **rxdataF_ext,
+                      float complex **rxdataF_f,
+                      int n_rx,
+                      int length,
+                      int start_point)
+{
+  short re;
+  int aarx;
+  int16_t imag;
+  int16_t real;
+
+  for (aarx=0; aarx<n_rx; aarx++) {
+    for (re=0; re<length; re++){
+      imag = (int16_t) (rxdataF_ext[aarx][start_point + re] >> 16);
+      real = (int16_t) (rxdataF_ext[aarx][start_point + re] & 0xffff);
+      rxdataF_f[aarx][re] = (float)(real/(32768.0)) + I*(float)(imag/(32768.0));
+#ifdef DEBUG_MMSE
+        if (re==0){
+          printf("rxdataF_to_float: aarx = %d, real= %d, imag = %d\n", aarx, real, imag);
+          //printf("rxdataF_to_float: rxdataF_ext[%d][%d] = %d\n", aarx, start_point + re, rxdataF_ext[aarx][start_point + re]);
+          //printf("rxdataF_to_float: ant %d, re = %d, rxdataF_f real = %f, rxdataF_f imag = %f \n", aarx, re, creal(rxdataF_f[aarx][re]), cimag(rxdataF_f[aarx][re]));
+        }
+#endif
+    }
+  }
+}
+
+
+
+void chan_est_to_float(int32_t **dl_ch_estimates_ext,
+                       float complex **dl_ch_estimates_ext_f,
+                       int n_tx,
+                       int n_rx,
+                       int length,
+                       int start_point)
+{
+  short re;
+  int aatx,aarx;
+  int16_t imag;
+  int16_t real;
+
+  for (aatx=0; aatx<n_tx; aatx++){
+    for (aarx=0; aarx<n_rx; aarx++) {
+      for (re=0; re<length; re++){
+        imag = (int16_t) (dl_ch_estimates_ext[aatx*n_rx + aarx][start_point + re] >> 16);
+        real = (int16_t) (dl_ch_estimates_ext[aatx*n_rx + aarx][start_point+ re] & 0xffff);
+        dl_ch_estimates_ext_f[aatx*n_rx + aarx][re] = (float)(real/(32768.0)) + I*(float)(imag/(32768.0));
+#ifdef DEBUG_MMSE
+        if (re==0){
+          printf("ant %d, re = %d, real = %d, imag = %d \n", aatx*n_rx + aarx, re, real, imag);
+          printf("ant %d, re = %d, real = %f, imag = %f \n", aatx*n_rx + aarx, re, creal(dl_ch_estimates_ext_f[aatx*n_rx + aarx][re]), cimag(dl_ch_estimates_ext_f[aatx*n_rx + aarx][re]));
+        }
+#endif
+     }
+    }
+  }
+}
+
+void float_to_chan_est(int32_t **dl_ch_estimates_ext,
+                      float complex **dl_ch_estimates_ext_f,
+                      int n_tx,
+                      int n_rx,
+                      int length,
+                      int start_point)
+{
+
+  short re;
+  int aarx, aatx;
+  int16_t imag;
+  int16_t real;
+
+  for (aatx=0; aatx<n_tx; aatx++){
+    for (aarx=0; aarx<n_rx; aarx++) {
+      for (re=0; re<length; re++){
+        if (cimag(dl_ch_estimates_ext_f[aatx*n_rx + aarx][re])<-1)
+           imag = 0x8000;
+         else if (cimag(dl_ch_estimates_ext_f[aatx*n_rx + aarx][re])>=1)
+           imag = 0x7FFF;
+         else
+          imag = cimag(dl_ch_estimates_ext_f[aatx*n_rx + aarx][re])*32768;
+         if (creal(dl_ch_estimates_ext_f[aatx*n_rx + aarx][re])<-1)
+           real = 0x8000;
+         else if (creal(dl_ch_estimates_ext_f[aatx*n_rx + aarx][re])>=1)
+           real = 0x7FFF;
+         else
+           real = creal(dl_ch_estimates_ext_f[aatx*n_rx + aarx][re])*32768;
+
+         dl_ch_estimates_ext[aatx*n_rx + aarx][start_point + re] = (((int32_t)imag)<<16)|((int32_t)real & 0xffff);
+#ifdef DEBUG_MMSE
+        if (re==0){
+          printf(" float_to_chan_est: chan est real = %f, chan est imag = %f\n",creal(dl_ch_estimates_ext_f[aatx*n_rx + aarx][re]), cimag(dl_ch_estimates_ext_f[aatx*n_rx + aarx][re]));
+          printf("float_to_chan_est: real fixed = %d, imag fixed = %d\n", real, imag);
+          printf("float_to_chan_est: ant %d, re = %d, dl_ch_estimates_ext = %d \n", aatx*n_rx + aarx, re,  dl_ch_estimates_ext[aatx*n_rx + aarx][start_point + re]);
+        }
+#endif
+      }
+    }
+  }
+}
+
+
+void float_to_rxdataF(int32_t **rxdataF_ext,
+                      float complex **rxdataF_f,
+                      int n_tx,
+                      int n_rx,
+                      int length,
+                      int start_point)
+{
+
+  short re;
+  int aarx;
+  int16_t imag;
+  int16_t real;
+
+  for (aarx=0; aarx<n_rx; aarx++) {
+    for (re=0; re<length; re++){
+      if (cimag(rxdataF_f[aarx][re])<-1)
+        imag = 0x8000;
+      else if (cimag(rxdataF_f[aarx][re])>=1)
+        imag = 0x7FFF;
+      else
+        imag = cimag(rxdataF_f[aarx][re])*32768;
+      if (creal(rxdataF_f[aarx][re])<-1)
+        real = 0x8000;
+      else if (creal(rxdataF_f[aarx][re])>=1)
+        real = 0x7FFF;
+      else
+        real = creal(rxdataF_f[aarx][re])*32768;
+      rxdataF_ext[aarx][start_point + re] = (((int32_t)imag)<<16)|(((int32_t)real) & 0xffff);
+#ifdef DEBUG_MMSE
+        if (re==0){
+          printf(" float_to_rxdataF: real = %f, imag = %f\n",creal(rxdataF_f[aarx][re]), cimag(rxdataF_f[aarx][re]));
+          printf("float_to_rxdataF: real fixed = %d, imag fixed = %d\n", real, imag);
+          printf("float_to_rxdataF: ant %d, re = %d, rxdataF_ext = %d \n", aarx, re,  rxdataF_ext[aarx][start_point + re]);
+        }
+#endif
+      }
+    }
+}
+
+
+void mult_mmse_rxdataF(float complex** Wmmse,
+                       float complex** rxdataF_ext_f,
+                       int n_tx,
+                       int n_rx,
+                       int length,
+                       int start_point)
+{
+  short re;
+  int aarx, aatx;
+
+
+  float complex* rxdata_re =  malloc(n_rx*sizeof(float complex));
+  float complex* rxdata_mmse_re =  malloc(n_rx*sizeof(float complex));
+  float complex* Wmmse_re =  malloc(n_tx*n_rx*sizeof(float complex));
+
+  for (re=0;re<length; re++){
+    for (aarx=0; aarx<n_rx; aarx++){
+      rxdata_re[aarx] = rxdataF_ext_f[aarx][re];
+#ifdef DEBUG_MMSE
+      if (re==0)
+        printf("mult_mmse_rxdataF before: rxdata_re[%d] = (%f, %f)\n", aarx, creal(rxdata_re[aarx]), cimag(rxdata_re[aarx]));
+#endif
+     }
+    for (aatx=0; aatx<n_tx; aatx++){
+      for (aarx=0; aarx<n_rx; aarx++){
+        Wmmse_re[aatx*n_rx + aarx] = Wmmse[aatx*n_rx + aarx][re];
+      }
+    }
+    mutl_matrix_matrix_col_based(Wmmse_re, rxdata_re, n_rx, n_tx, n_rx, 1, rxdata_mmse_re);
+
+    for (aarx=0; aarx<n_rx; aarx++){
+      rxdataF_ext_f[aarx][re] = rxdata_mmse_re[aarx];
+#ifdef DEBUG_MMSE
+       if (re==0)
+        printf("mult_mmse_rxdataF after: rxdataF_ext_f[%d] = (%f, %f)\n", aarx, creal(rxdataF_ext_f[aarx][re]), cimag(rxdataF_ext_f[aarx][re]));
+#endif
+    }
+  }
 
+  free(rxdata_re);
+  free(rxdata_mmse_re);
+  free(Wmmse_re);
+}
+
+void mult_mmse_chan_est(float complex** Wmmse,
+                        float complex** dl_ch_estimates_ext_f,
+                        int n_tx,
+                        int n_rx,
+                        int length,
+                        int start_point)
+{
+  short re;
+  int aarx, aatx;
+
+  float complex* chan_est_re =  malloc(n_tx*n_rx*sizeof(float complex));
+  float complex* chan_est_mmse_re =  malloc(n_tx*n_rx*sizeof(float complex));
+  float complex* Wmmse_re =  malloc(n_tx*n_rx*sizeof(float complex));
+
+  for (re=0;re<length; re++){
+    for (aatx=0; aatx<n_tx; aatx++){
+      for (aarx=0; aarx<n_rx; aarx++){
+        chan_est_re[aatx*n_rx + aarx] = dl_ch_estimates_ext_f[aatx*n_rx + aarx][re];
+        Wmmse_re[aatx*n_rx + aarx] = Wmmse[aatx*n_rx + aarx][re];
+#ifdef DEBUG_MMSE
+        if (re==0)
+        printf("mult_mmse_chan_est: chan_est_re[%d] = (%f, %f)\n", aatx*n_rx + aarx, creal(chan_est_re[aatx*n_rx + aarx]), cimag(chan_est_re[aatx*n_rx + aarx]));
+#endif
+      }
+    }
+      mutl_matrix_matrix_col_based(Wmmse_re, chan_est_re, n_rx, n_tx, n_rx, n_tx, chan_est_mmse_re);
+      for (aatx=0; aatx<n_tx; aatx++){
+        for (aarx=0; aarx<n_rx; aarx++){
+          dl_ch_estimates_ext_f[aatx*n_rx + aarx][re] = chan_est_mmse_re[aatx*n_rx + aarx];
+#ifdef DEBUG_MMSE
+          if (re==0)
+          printf("mult_mmse_chan_est: dl_ch_estimates_ext_f[%d][%d] = (%f, %f)\n", aatx*n_rx + aarx, re, creal(dl_ch_estimates_ext_f[aatx*n_rx + aarx][re]), cimag(dl_ch_estimates_ext_f[aatx*n_rx + aarx][re]));
 #endif
+        }
+      }
+   }
+   free(Wmmse_re);
+   free(chan_est_re);
+   free(chan_est_mmse_re);
 }
 
 
 
-/*void dlsch_channel_level_TM34(int **dl_ch_estimates_ext,
+
+
+//compute average channel_level of effective (precoded) channel
+void dlsch_channel_level_TM34(int **dl_ch_estimates_ext,
                               LTE_DL_FRAME_PARMS *frame_parms,
-                              int *avg,
+                              unsigned char *pmi_ext,
+                              int *avg_0,
+                              int *avg_1,
                               uint8_t symbol,
                               unsigned short nb_rb,
+                              unsigned int mmse_flag,
                               MIMO_mode_t mimo_mode){
 
 #if defined(__x86_64__)||defined(__i386__)
 
-
   short rb;
   unsigned char aarx,nre=12,symbol_mod;
-  __m128i *dl_ch0_128,*dl_ch1_128, dl_ch0_128_tmp, dl_ch1_128_tmp,avg128D;
+  __m128i *dl_ch0_128,*dl_ch1_128, dl_ch0_128_tmp, dl_ch1_128_tmp, avg_0_128D, avg_1_128D;
 
   symbol_mod = (symbol>=(7-frame_parms->Ncp)) ? symbol-(7-frame_parms->Ncp) : symbol;
 
   //clear average level
-  avg128D = _mm_setzero_si128();
-  avg[0] = 0;
-  avg[1] = 0;
+ // avg_0_128D = _mm_setzero_si128();
+ // avg_1_128D = _mm_setzero_si128();
+  avg_0[0] = 0;
+  avg_0[1] = 0;
+  avg_1[0] = 0;
+  avg_1[1] = 0;
   // 5 is always a symbol with no pilots for both normal and extended prefix
 
   if (((symbol_mod == 0) || (symbol_mod == (frame_parms->Ncp-1)))&&(frame_parms->nb_antenna_ports_eNB!=1))
@@ -3807,33 +4564,49 @@ void dlsch_channel_level_TM34(int **dl_ch_estimates_ext,
     dl_ch0_128 = (__m128i *)&dl_ch_estimates_ext[aarx][symbol*frame_parms->N_RB_DL*12];
     dl_ch1_128 = (__m128i *)&dl_ch_estimates_ext[2+aarx][symbol*frame_parms->N_RB_DL*12];
 
+    avg_0_128D = _mm_setzero_si128();
+    avg_1_128D = _mm_setzero_si128();
     for (rb=0; rb<nb_rb; rb++) {
-
+              // printf("rb %d : \n",rb);
+    //print_shorts("ch0\n",&dl_ch0_128[0]);
+    //print_shorts("ch1\n",&dl_ch1_128[0]);
       dl_ch0_128_tmp = _mm_load_si128(&dl_ch0_128[0]);
       dl_ch1_128_tmp = _mm_load_si128(&dl_ch1_128[0]);
 
-      if (mimo_mode==LARGE_CDD)
-        prec2A_TM3_128(&dl_ch0_128_tmp,&dl_ch1_128_tmp);
-      else if (mimo_mode==DUALSTREAM_UNIFORM_PRECODING1)
-        prec2A_TM4_128(0,&dl_ch0_128_tmp,&dl_ch1_128_tmp);
-      else if (mimo_mode==DUALSTREAM_UNIFORM_PRECODINGj)
-        prec2A_TM4_128(1,&dl_ch0_128_tmp,&dl_ch1_128_tmp);
+      if (mmse_flag == 0){
+        if (mimo_mode==LARGE_CDD)
+          prec2A_TM3_128(&dl_ch0_128_tmp,&dl_ch1_128_tmp);
+        else if (mimo_mode==DUALSTREAM_UNIFORM_PRECODING1)
+          prec2A_TM4_128(0,&dl_ch0_128_tmp,&dl_ch1_128_tmp);
+        else if (mimo_mode==DUALSTREAM_UNIFORM_PRECODINGj)
+          prec2A_TM4_128(1,&dl_ch0_128_tmp,&dl_ch1_128_tmp);
+        else if (mimo_mode==DUALSTREAM_PUSCH_PRECODING)
+          prec2A_TM4_128(pmi_ext[rb],&dl_ch0_128_tmp,&dl_ch1_128_tmp);
+      }
 
       //      mmtmpD0 = _mm_madd_epi16(dl_ch0_128_tmp,dl_ch0_128_tmp);
-      avg128D = _mm_add_epi32(avg128D,_mm_madd_epi16(dl_ch0_128_tmp,dl_ch0_128_tmp));
+      avg_0_128D = _mm_add_epi32(avg_0_128D,_mm_madd_epi16(dl_ch0_128_tmp,dl_ch0_128_tmp));
+
+      avg_1_128D = _mm_add_epi32(avg_1_128D,_mm_madd_epi16(dl_ch1_128_tmp,dl_ch1_128_tmp));
 
       dl_ch0_128_tmp = _mm_load_si128(&dl_ch0_128[1]);
       dl_ch1_128_tmp = _mm_load_si128(&dl_ch1_128[1]);
 
-      if (mimo_mode==LARGE_CDD)
-        prec2A_TM3_128(&dl_ch0_128_tmp,&dl_ch1_128_tmp);
-      else if (mimo_mode==DUALSTREAM_UNIFORM_PRECODING1)
-        prec2A_TM4_128(0,&dl_ch0_128_tmp,&dl_ch1_128_tmp);
-      else if (mimo_mode==DUALSTREAM_UNIFORM_PRECODINGj)
-        prec2A_TM4_128(1,&dl_ch0_128_tmp,&dl_ch1_128_tmp);
+      if (mmse_flag == 0){
+        if (mimo_mode==LARGE_CDD)
+          prec2A_TM3_128(&dl_ch0_128_tmp,&dl_ch1_128_tmp);
+        else if (mimo_mode==DUALSTREAM_UNIFORM_PRECODING1)
+          prec2A_TM4_128(0,&dl_ch0_128_tmp,&dl_ch1_128_tmp);
+        else if (mimo_mode==DUALSTREAM_UNIFORM_PRECODINGj)
+          prec2A_TM4_128(1,&dl_ch0_128_tmp,&dl_ch1_128_tmp);
+        else if (mimo_mode==DUALSTREAM_PUSCH_PRECODING)
+          prec2A_TM4_128(pmi_ext[rb],&dl_ch0_128_tmp,&dl_ch1_128_tmp);
+      }
 
       //      mmtmpD1 = _mm_madd_epi16(dl_ch0_128_tmp,dl_ch0_128_tmp);
-      avg128D = _mm_add_epi32(avg128D,_mm_madd_epi16(dl_ch0_128_tmp,dl_ch0_128_tmp));
+      avg_0_128D = _mm_add_epi32(avg_0_128D,_mm_madd_epi16(dl_ch0_128_tmp,dl_ch0_128_tmp));
+
+      avg_1_128D = _mm_add_epi32(avg_1_128D,_mm_madd_epi16(dl_ch1_128_tmp,dl_ch1_128_tmp));
 
       if (((symbol_mod == 0) || (symbol_mod == (frame_parms->Ncp-1)))&&(frame_parms->nb_antenna_ports_eNB!=1)) {
         dl_ch0_128+=2;
@@ -3843,29 +4616,49 @@ void dlsch_channel_level_TM34(int **dl_ch_estimates_ext,
         dl_ch0_128_tmp = _mm_load_si128(&dl_ch0_128[2]);
         dl_ch1_128_tmp = _mm_load_si128(&dl_ch1_128[2]);
 
-        if (mimo_mode==LARGE_CDD)
-          prec2A_TM3_128(&dl_ch0_128_tmp,&dl_ch1_128_tmp);
-        else if (mimo_mode==DUALSTREAM_UNIFORM_PRECODING1)
-          prec2A_TM4_128(0,&dl_ch0_128_tmp,&dl_ch1_128_tmp);
-        else if (mimo_mode==DUALSTREAM_UNIFORM_PRECODINGj)
-          prec2A_TM4_128(1,&dl_ch0_128_tmp,&dl_ch1_128_tmp);
-
+        if (mmse_flag == 0){
+          if (mimo_mode==LARGE_CDD)
+            prec2A_TM3_128(&dl_ch0_128_tmp,&dl_ch1_128_tmp);
+          else if (mimo_mode==DUALSTREAM_UNIFORM_PRECODING1)
+            prec2A_TM4_128(0,&dl_ch0_128_tmp,&dl_ch1_128_tmp);
+          else if (mimo_mode==DUALSTREAM_UNIFORM_PRECODINGj)
+            prec2A_TM4_128(1,&dl_ch0_128_tmp,&dl_ch1_128_tmp);
+          else if (mimo_mode==DUALSTREAM_PUSCH_PRECODING)
+            prec2A_TM4_128(pmi_ext[rb],&dl_ch0_128_tmp,&dl_ch1_128_tmp);
+        }
         //      mmtmpD2 = _mm_madd_epi16(dl_ch0_128_tmp,dl_ch0_128_tmp);
-        avg128D = _mm_add_epi32(avg128D,_mm_madd_epi16(dl_ch0_128_tmp,dl_ch0_128_tmp));
+
+        avg_1_128D = _mm_add_epi32(avg_1_128D,_mm_madd_epi16(dl_ch1_128_tmp,dl_ch1_128_tmp));
+        avg_0_128D = _mm_add_epi32(avg_0_128D,_mm_madd_epi16(dl_ch0_128_tmp,dl_ch0_128_tmp));
 
         dl_ch0_128+=3;
         dl_ch1_128+=3;
       }
     }
 
-    avg[aarx] = (((int*)&avg128D)[0])/(nb_rb*nre) +
-      (((int*)&avg128D)[1])/(nb_rb*nre) +
-      (((int*)&avg128D)[2])/(nb_rb*nre) +
-      (((int*)&avg128D)[3])/(nb_rb*nre);
+
+    avg_0[aarx] = (((int*)&avg_0_128D)[0])/(nb_rb*nre) +
+      (((int*)&avg_0_128D)[1])/(nb_rb*nre) +
+      (((int*)&avg_0_128D)[2])/(nb_rb*nre) +
+      (((int*)&avg_0_128D)[3])/(nb_rb*nre);
+    //  printf("From Chan_level aver stream 0 %d =%d\n", aarx, avg_0[aarx]);
+
+    avg_1[aarx] = (((int*)&avg_1_128D)[0])/(nb_rb*nre) +
+      (((int*)&avg_1_128D)[1])/(nb_rb*nre) +
+      (((int*)&avg_1_128D)[2])/(nb_rb*nre) +
+      (((int*)&avg_1_128D)[3])/(nb_rb*nre);
+  //    printf("From Chan_level aver stream 1 %d =%d\n", aarx, avg_1[aarx]);
   }
+//avg_0[0] = max(avg_0[0],avg_0[1]);
+//avg_1[0] = max(avg_1[0],avg_1[1]);
+//avg_0[0]= max(avg_0[0], avg_1[0]);
 
-  // choose maximum of the 2 effective channels
-  avg[0] = cmax(avg[0],avg[1]);
+  avg_0[0] = avg_0[0] + avg_0[1];
+ // printf("From Chan_level aver stream 0 final =%d\n", avg_0[0]);
+  avg_1[0] = avg_1[0] + avg_1[1];
+ // printf("From Chan_level aver stream 1 final =%d\n", avg_1[0]);
+ avg_0[0] = min (avg_0[0], avg_1[0]);
+ avg_1[0] = avg_0[0];
 
   _mm_empty();
   _m_empty();
@@ -3873,7 +4666,7 @@ void dlsch_channel_level_TM34(int **dl_ch_estimates_ext,
 #elif defined(__arm__)
 
 #endif
-}*/
+}
 
 //compute average channel_level of effective (precoded) channel
 void dlsch_channel_level_TM56(int **dl_ch_estimates_ext,
diff --git a/openair1/PHY/LTE_UE_TRANSPORT/dlsch_llr_computation.c b/openair1/PHY/LTE_UE_TRANSPORT/dlsch_llr_computation.c
index a3ad9b05ca008d30df368022b90d00e75b299265..ea3f100504e8b263b16e8e230e3bc7ba310f3910 100644
--- a/openair1/PHY/LTE_UE_TRANSPORT/dlsch_llr_computation.c
+++ b/openair1/PHY/LTE_UE_TRANSPORT/dlsch_llr_computation.c
@@ -642,7 +642,7 @@ int dlsch_qpsk_llr(LTE_DL_FRAME_PARMS *frame_parms,
 
   uint32_t *rxF = (uint32_t*)&rxdataF_comp[0][((int32_t)symbol*frame_parms->N_RB_DL*12)];
   uint32_t *llr32;
-  int i,len;
+  int len;
   uint8_t symbol_mod = (symbol >= (7-frame_parms->Ncp))? (symbol-(7-frame_parms->Ncp)) : symbol;
 
   /*
@@ -681,19 +681,28 @@ int dlsch_qpsk_llr(LTE_DL_FRAME_PARMS *frame_parms,
              dlsch_llr,
              llr32);
   */
-  //printf("ll32p=%p , dlsch_llr=%p, symbol=%d, flag=%d \n", llr32, dlsch_llr, symbol, first_symbol_flag);
-  for (i=0; i<len; i++) {
-    *llr32 = *rxF;
-     //printf("llr %d : (%d,%d)\n",i,((int16_t*)llr32)[0],((int16_t*)llr32)[1]);
-    rxF++;
-    llr32++;
-  }
 
-  //*llr32p = (int16_t *)llr32;
+  qpsk_llr((short *)rxF,
+           (short *)llr32,
+           len);
 
   return(0);
 }
 
+void qpsk_llr(int16_t *stream0_in,
+              int16_t *stream0_out,
+              int length)
+{
+  int i;
+  for (i=0; i<2*length; i++) {
+    *stream0_out = *stream0_in;
+    //printf("llr %d : (%d,%d)\n",i,((int16_t*)stream0_out)[0],((int16_t*)stream0_out)[1]);
+    stream0_in++;
+    stream0_out++;
+  }
+
+}
+
 int32_t dlsch_qpsk_llr_SIC(LTE_DL_FRAME_PARMS *frame_parms,
                            int32_t **rxdataF_comp,
                            int32_t **sic_buffer,  //Q15
@@ -817,45 +826,21 @@ void dlsch_16qam_llr(LTE_DL_FRAME_PARMS *frame_parms,
                      int16_t **llr32p,
                      uint8_t beamforming_mode)
 {
+  int32_t *rxF = (int32_t*)&rxdataF_comp[0][(symbol*frame_parms->N_RB_DL*12)];
+  int32_t *ch_mag = (int32_t*)&dl_ch_mag[0][(symbol*frame_parms->N_RB_DL*12)];
+  int32_t *llr32;
 
-#if defined(__x86_64__) || defined(__i386__)
-  __m128i *rxF = (__m128i*)&rxdataF_comp[0][(symbol*frame_parms->N_RB_DL*12)];
-  __m128i *ch_mag;
-  __m128i llr128[2];
-  uint32_t *llr32;
-#elif defined(__arm__)
-  int16x8_t *rxF = (int16x8_t*)&rxdataF_comp[0][(symbol*frame_parms->N_RB_DL*12)];
-  int16x8_t *ch_mag;
-  int16x8_t xmm0;
-  int16_t *llr16;
-#endif
-
-
-  int i,len;
+  int len;
   unsigned char symbol_mod,len_mod4=0;
 
-
-#if defined(__x86_64__) || defined(__i386__)
   if (first_symbol_flag==1) {
-    llr32 = (uint32_t*)dlsch_llr;
-  } else {
-    llr32 = (uint32_t*)*llr32p;
-  }
-#elif defined(__arm__)
-  if (first_symbol_flag==1) {
-    llr16 = (int16_t*)dlsch_llr;
+    llr32 = (int32_t*)dlsch_llr;
   } else {
-    llr16 = (int16_t*)*llr32p;
+    llr32 = (int32_t*)*llr32p;
   }
-#endif
 
   symbol_mod = (symbol>=(7-frame_parms->Ncp)) ? symbol-(7-frame_parms->Ncp) : symbol;
 
-#if defined(__x86_64__) || defined(__i386__)
-  ch_mag = (__m128i*)&dl_ch_mag[0][(symbol*frame_parms->N_RB_DL*12)];
-#elif defined(__arm__)
-  ch_mag = (int16x8_t*)&dl_ch_mag[0][(symbol*frame_parms->N_RB_DL*12)];
-#endif
   if ((symbol_mod==0) || (symbol_mod==(4-frame_parms->Ncp))) {
     if (frame_parms->nb_antenna_ports_eNB!=1)
       len = (nb_rb*8) - (2*pbch_pss_sss_adjust/3);
@@ -881,18 +866,45 @@ void dlsch_16qam_llr(LTE_DL_FRAME_PARMS *frame_parms,
   len>>=2;  // length in quad words (4 REs)
  // printf("len>>=2=%d\n", len);
   len+=(len_mod4==0 ? 0 : 1);
- // printf("len+=%d\n", len);
-  for (i=0; i<len; i++) {
 
+  qam16_llr((short *)rxF,
+            (short *)ch_mag,
+            (short *)llr32,
+            len);
+ // printf ("This line in qam16_llr is %d.\n", __LINE__);
+
+}
+
+void qam16_llr(int16_t *stream0_in,
+               int16_t *chan_magn,
+               int16_t *llr,
+               int length)
+{
+  int i;
+  #if defined(__x86_64__) || defined(__i386__)
+  __m128i *rxF_128 = (__m128i*)stream0_in;
+  __m128i *ch_mag_128 = (__m128i*)chan_magn;
+  __m128i llr128[2];
+  int32_t *llr32 = (int32_t*) llr;
+#elif defined(__arm__)
+  int16x8_t *rxF_128 = (int16x8_t*)stream0_in;
+  int16x8_t *ch_mag_128 = (int16x8_t*)chan_magn;
+  int16x8_t xmm0;
+  int16_t *llr16 = (int16_t*)llr;
+#endif
+
+ // printf ("This line in qam16_llr is %d.\n", __LINE__);
+
+  for (i=0; i<length; i++) {
 #if defined(__x86_64__) || defined(__i386)
-    xmm0 = _mm_abs_epi16(rxF[i]);
-    xmm0 = _mm_subs_epi16(ch_mag[i],xmm0);
+   xmm0 = _mm_abs_epi16(rxF_128[i]);
+   xmm0 = _mm_subs_epi16(ch_mag_128[i],xmm0);
 
     // lambda_1=y_R, lambda_2=|y_R|-|h|^2, lamda_3=y_I, lambda_4=|y_I|-|h|^2
-    llr128[0] = _mm_unpacklo_epi32(rxF[i],xmm0);
-    llr128[1] = _mm_unpackhi_epi32(rxF[i],xmm0);
+    llr128[0] = _mm_unpacklo_epi32(rxF_128[i],xmm0);
+    llr128[1] = _mm_unpackhi_epi32(rxF_128[i],xmm0);
     llr32[0] = _mm_extract_epi32(llr128[0],0); //((uint32_t *)&llr128[0])[0];
-    llr32[1] = _mm_extract_epi32(llr128[0],1); //((uint32_t *)&llr128[0])[1];
+    llr32[1] = _mm_extract_epi32(llr128[0],1); //((uint32_t *)&llr128[0])[0];
     llr32[2] = _mm_extract_epi32(llr128[0],2); //((uint32_t *)&llr128[0])[2];
     llr32[3] = _mm_extract_epi32(llr128[0],3); //((uint32_t *)&llr128[0])[3];
     llr32[4] = _mm_extract_epi32(llr128[1],0); //((uint32_t *)&llr128[1])[0];
@@ -922,14 +934,17 @@ void dlsch_16qam_llr(LTE_DL_FRAME_PARMS *frame_parms,
     llr16[14] = vgetq_lane_s16(xmm0,7);
     llr16[15] = vgetq_lane_s16(xmm0,7);
     llr16+=16;
+
 #endif
 
   }
 
-#if defined(__x86_64__) || defined(__i386__)
+#if defined(__x86_64__) || defined(__i386)
   _mm_empty();
   _m_empty();
 #endif
+
+
 }
 
 void dlsch_16qam_llr_SIC (LTE_DL_FRAME_PARMS *frame_parms,
@@ -1036,6 +1051,7 @@ void dlsch_16qam_llr_SIC (LTE_DL_FRAME_PARMS *frame_parms,
 }
 }
 
+
 //----------------------------------------------------------------------------------------------
 // 64-QAM
 //----------------------------------------------------------------------------------------------
@@ -1053,14 +1069,10 @@ void dlsch_64qam_llr(LTE_DL_FRAME_PARMS *frame_parms,
                      uint32_t llr_offset,
                      uint8_t beamforming_mode)
 {
-#if defined(__x86_64__) || defined(__i386__)
-  __m128i *rxF = (__m128i*)&rxdataF_comp[0][(symbol*frame_parms->N_RB_DL*12)];
-  __m128i *ch_mag,*ch_magb;
-#elif defined(__arm__)
-  int16x8_t *rxF = (int16x8_t*)&rxdataF_comp[0][(symbol*frame_parms->N_RB_DL*12)];
-  int16x8_t *ch_mag,*ch_magb,xmm1,xmm2;
-#endif
-  int i,len,len2;
+  int32_t *rxF = (int32_t*)&rxdataF_comp[0][(symbol*frame_parms->N_RB_DL*12)];
+  int32_t *ch_mag = (int32_t*)&dl_ch_mag[0][(symbol*frame_parms->N_RB_DL*12)];
+  int32_t *ch_magb = (int32_t*)&dl_ch_magb[0][(symbol*frame_parms->N_RB_DL*12)];
+  int len,len2;
   unsigned char symbol_mod,len_mod4;
   short *llr;
   int16_t *llr2;
@@ -1079,13 +1091,6 @@ void dlsch_64qam_llr(LTE_DL_FRAME_PARMS *frame_parms,
 
   symbol_mod = (symbol>=(7-frame_parms->Ncp)) ? symbol-(7-frame_parms->Ncp) : symbol;
 
-#if defined(__x86_64__) || defined(__i386__)
-  ch_mag = (__m128i*)&dl_ch_mag[0][(symbol*frame_parms->N_RB_DL*12)];
-  ch_magb = (__m128i*)&dl_ch_magb[0][(symbol*frame_parms->N_RB_DL*12)];
-#elif defined(__arm__)
-  ch_mag = (int16x8_t*)&dl_ch_mag[0][(symbol*frame_parms->N_RB_DL*12)];
-  ch_magb = (int16x8_t*)&dl_ch_magb[0][(symbol*frame_parms->N_RB_DL*12)];
-#endif
   if ((symbol_mod==0) || (symbol_mod==(4-frame_parms->Ncp))) {
     if (frame_parms->nb_antenna_ports_eNB!=1)
       len = (nb_rb*8) - (2*pbch_pss_sss_adjust/3);
@@ -1115,18 +1120,49 @@ void dlsch_64qam_llr(LTE_DL_FRAME_PARMS *frame_parms,
   len2=len>>2;  // length in quad words (4 REs)
   len2+=((len_mod4==0)?0:1);
 
-  for (i=0; i<len2; i++) {
+  qam64_llr((short *)rxF,
+           (short *)ch_mag,
+           (short *)ch_magb,
+           llr2,
+           len2);
+}
+
+
+void qam64_llr(int16_t *stream0_in,
+               int16_t *chan_magn,
+               int16_t *chan_magn_b,
+               int16_t *llr,
+               int length)
+{
 
 #if defined(__x86_64__) || defined(__i386__)
-    xmm1 = _mm_abs_epi16(rxF[i]);
-    xmm1 = _mm_subs_epi16(ch_mag[i],xmm1);
+  __m128i *rxF_128 = (__m128i*)stream0_in;
+  __m128i *ch_mag_128 = (__m128i*)chan_magn;
+  __m128i *ch_magb_128 = (__m128i*)chan_magn_b;
+#elif defined(__arm__)
+  int16x8_t *rxF_128 = (int16x8_t*)stream0_in;
+  int16x8_t *ch_mag_128 = (int16x8_t*)chan_magn;
+  int16x8_t *ch_magb_128 = (int16x8_t*)chan_magn_b;
+  int16x8_t xmm1,xmm2;
+#endif
+
+
+  int i;
+  //int16_t *llr2;
+  //llr2 = llr;
+
+  for (i=0; i<length; i++) {
+
+#if defined(__x86_64__) || defined(__i386__)
+    xmm1 = _mm_abs_epi16(rxF_128[i]);
+    xmm1 = _mm_subs_epi16(ch_mag_128[i],xmm1);
     xmm2 = _mm_abs_epi16(xmm1);
-    xmm2 = _mm_subs_epi16(ch_magb[i],xmm2);
+    xmm2 = _mm_subs_epi16(ch_magb_128[i],xmm2);
 #elif defined(__arm__)
-    xmm1 = vabsq_s16(rxF[i]);
-    xmm1 = vsubq_s16(ch_mag[i],xmm1);
+    xmm1 = vabsq_s16(rxF_128[i]);
+    xmm1 = vsubq_s16(ch_mag_128[i],xmm1);
     xmm2 = vabsq_s16(xmm1);
-    xmm2 = vsubq_s16(ch_magb[i],xmm2);
+    xmm2 = vsubq_s16(ch_magb_128[i],xmm2);
 #endif
     // loop over all LLRs in quad word (24 coded bits)
     /*
@@ -1141,64 +1177,64 @@ void dlsch_64qam_llr(LTE_DL_FRAME_PARMS *frame_parms,
      llr2+=6;
       }
     */
-    llr2[0] = ((short *)&rxF[i])[0];
-    llr2[1] = ((short *)&rxF[i])[1];
+    llr[0] = ((short *)&rxF_128[i])[0];
+    llr[1] = ((short *)&rxF_128[i])[1];
 #if defined(__x86_64__) || defined(__i386__)
-    llr2[2] = _mm_extract_epi16(xmm1,0);
-    llr2[3] = _mm_extract_epi16(xmm1,1);//((short *)&xmm1)[j+1];
-    llr2[4] = _mm_extract_epi16(xmm2,0);//((short *)&xmm2)[j];
-    llr2[5] = _mm_extract_epi16(xmm2,1);//((short *)&xmm2)[j+1];
+    llr[2] = _mm_extract_epi16(xmm1,0);
+    llr[3] = _mm_extract_epi16(xmm1,1);//((short *)&xmm1)[j+1];
+    llr[4] = _mm_extract_epi16(xmm2,0);//((short *)&xmm2)[j];
+    llr[5] = _mm_extract_epi16(xmm2,1);//((short *)&xmm2)[j+1];
 #elif defined(__arm__)
-    llr2[2] = vgetq_lane_s16(xmm1,0);
-    llr2[3] = vgetq_lane_s16(xmm1,1);//((short *)&xmm1)[j+1];
-    llr2[4] = vgetq_lane_s16(xmm2,0);//((short *)&xmm2)[j];
-    llr2[5] = vgetq_lane_s16(xmm2,1);//((short *)&xmm2)[j+1];
+    llr[2] = vgetq_lane_s16(xmm1,0);
+    llr[3] = vgetq_lane_s16(xmm1,1);//((short *)&xmm1)[j+1];
+    llr[4] = vgetq_lane_s16(xmm2,0);//((short *)&xmm2)[j];
+    llr[5] = vgetq_lane_s16(xmm2,1);//((short *)&xmm2)[j+1];
 #endif
 
-    llr2+=6;
-    llr2[0] = ((short *)&rxF[i])[2];
-    llr2[1] = ((short *)&rxF[i])[3];
+    llr+=6;
+    llr[0] = ((short *)&rxF_128[i])[2];
+    llr[1] = ((short *)&rxF_128[i])[3];
 #if defined(__x86_64__) || defined(__i386__)
-    llr2[2] = _mm_extract_epi16(xmm1,2);
-    llr2[3] = _mm_extract_epi16(xmm1,3);//((short *)&xmm1)[j+1];
-    llr2[4] = _mm_extract_epi16(xmm2,2);//((short *)&xmm2)[j];
-    llr2[5] = _mm_extract_epi16(xmm2,3);//((short *)&xmm2)[j+1];
+    llr[2] = _mm_extract_epi16(xmm1,2);
+    llr[3] = _mm_extract_epi16(xmm1,3);//((short *)&xmm1)[j+1];
+    llr[4] = _mm_extract_epi16(xmm2,2);//((short *)&xmm2)[j];
+    llr[5] = _mm_extract_epi16(xmm2,3);//((short *)&xmm2)[j+1];
 #elif defined(__arm__)
-    llr2[2] = vgetq_lane_s16(xmm1,2);
-    llr2[3] = vgetq_lane_s16(xmm1,3);//((short *)&xmm1)[j+1];
-    llr2[4] = vgetq_lane_s16(xmm2,2);//((short *)&xmm2)[j];
-    llr2[5] = vgetq_lane_s16(xmm2,3);//((short *)&xmm2)[j+1];
+    llr[2] = vgetq_lane_s16(xmm1,2);
+    llr[3] = vgetq_lane_s16(xmm1,3);//((short *)&xmm1)[j+1];
+    llr[4] = vgetq_lane_s16(xmm2,2);//((short *)&xmm2)[j];
+    llr[5] = vgetq_lane_s16(xmm2,3);//((short *)&xmm2)[j+1];
 #endif
 
-    llr2+=6;
-    llr2[0] = ((short *)&rxF[i])[4];
-    llr2[1] = ((short *)&rxF[i])[5];
+    llr+=6;
+    llr[0] = ((short *)&rxF_128[i])[4];
+    llr[1] = ((short *)&rxF_128[i])[5];
 #if defined(__x86_64__) || defined(__i386__)
-    llr2[2] = _mm_extract_epi16(xmm1,4);
-    llr2[3] = _mm_extract_epi16(xmm1,5);//((short *)&xmm1)[j+1];
-    llr2[4] = _mm_extract_epi16(xmm2,4);//((short *)&xmm2)[j];
-    llr2[5] = _mm_extract_epi16(xmm2,5);//((short *)&xmm2)[j+1];
+    llr[2] = _mm_extract_epi16(xmm1,4);
+    llr[3] = _mm_extract_epi16(xmm1,5);//((short *)&xmm1)[j+1];
+    llr[4] = _mm_extract_epi16(xmm2,4);//((short *)&xmm2)[j];
+    llr[5] = _mm_extract_epi16(xmm2,5);//((short *)&xmm2)[j+1];
 #elif defined(__arm__)
-    llr2[2] = vgetq_lane_s16(xmm1,4);
-    llr2[3] = vgetq_lane_s16(xmm1,5);//((short *)&xmm1)[j+1];
-    llr2[4] = vgetq_lane_s16(xmm2,4);//((short *)&xmm2)[j];
-    llr2[5] = vgetq_lane_s16(xmm2,5);//((short *)&xmm2)[j+1];
+    llr[2] = vgetq_lane_s16(xmm1,4);
+    llr[3] = vgetq_lane_s16(xmm1,5);//((short *)&xmm1)[j+1];
+    llr[4] = vgetq_lane_s16(xmm2,4);//((short *)&xmm2)[j];
+    llr[5] = vgetq_lane_s16(xmm2,5);//((short *)&xmm2)[j+1];
 #endif
-    llr2+=6;
-    llr2[0] = ((short *)&rxF[i])[6];
-    llr2[1] = ((short *)&rxF[i])[7];
+    llr+=6;
+    llr[0] = ((short *)&rxF_128[i])[6];
+    llr[1] = ((short *)&rxF_128[i])[7];
 #if defined(__x86_64__) || defined(__i386__)
-    llr2[2] = _mm_extract_epi16(xmm1,6);
-    llr2[3] = _mm_extract_epi16(xmm1,7);//((short *)&xmm1)[j+1];
-    llr2[4] = _mm_extract_epi16(xmm2,6);//((short *)&xmm2)[j];
-    llr2[5] = _mm_extract_epi16(xmm2,7);//((short *)&xmm2)[j+1];
+    llr[2] = _mm_extract_epi16(xmm1,6);
+    llr[3] = _mm_extract_epi16(xmm1,7);//((short *)&xmm1)[j+1];
+    llr[4] = _mm_extract_epi16(xmm2,6);//((short *)&xmm2)[j];
+    llr[5] = _mm_extract_epi16(xmm2,7);//((short *)&xmm2)[j+1];
 #elif defined(__arm__)
-    llr2[2] = vgetq_lane_s16(xmm1,6);
-    llr2[3] = vgetq_lane_s16(xmm1,7);//((short *)&xmm1)[j+1];
-    llr2[4] = vgetq_lane_s16(xmm2,6);//((short *)&xmm2)[j];
-    llr2[5] = vgetq_lane_s16(xmm2,7);//((short *)&xmm2)[j+1];
+    llr[2] = vgetq_lane_s16(xmm1,6);
+    llr[3] = vgetq_lane_s16(xmm1,7);//((short *)&xmm1)[j+1];
+    llr[4] = vgetq_lane_s16(xmm2,6);//((short *)&xmm2)[j];
+    llr[5] = vgetq_lane_s16(xmm2,7);//((short *)&xmm2)[j+1];
 #endif
-    llr2+=6;
+    llr+=6;
 
   }
 
@@ -8865,7 +8901,7 @@ int dlsch_64qam_64qam_llr(LTE_DL_FRAME_PARMS *frame_parms,
                    (int16_t *)llr16,
                    (int32_t *) rho_256i,
                    len);
-  
+
   free16(rxF_256i, sizeof(rxF_256i));
   free16(rxF_i_256i, sizeof(rxF_i_256i));
   free16(ch_mag_256i, sizeof(ch_mag_256i));
diff --git a/openair1/PHY/LTE_UE_TRANSPORT/get_pmi.c b/openair1/PHY/LTE_UE_TRANSPORT/get_pmi.c
new file mode 100644
index 0000000000000000000000000000000000000000..7bbe8e894257d772ae1edc96795df9e84119a0d7
--- /dev/null
+++ b/openair1/PHY/LTE_UE_TRANSPORT/get_pmi.c
@@ -0,0 +1,65 @@
+/*
+ * 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
+ */
+
+#include "PHY/LTE_UE_TRANSPORT/transport_proto_ue.h"
+
+uint8_t get_pmi(uint8_t N_RB_DL, MIMO_mode_t mode, uint32_t pmi_alloc,uint16_t rb)
+{
+  /*
+  MIMO_mode_t mode   = dlsch_harq->mimo_mode;
+  uint32_t pmi_alloc = dlsch_harq->pmi_alloc;
+  */
+
+  switch (N_RB_DL) {
+    case 6:   // 1 PRB per subband
+      if (mode <= PUSCH_PRECODING1)
+        return((pmi_alloc>>(rb<<1))&3);
+      else
+        return((pmi_alloc>>rb)&1);
+
+      break;
+
+    default:
+    case 25:  // 4 PRBs per subband
+      if (mode <= PUSCH_PRECODING1)
+        return((pmi_alloc>>((rb>>2)<<1))&3);
+      else
+        return((pmi_alloc>>(rb>>2))&1);
+
+      break;
+
+    case 50: // 6 PRBs per subband
+      if (mode <= PUSCH_PRECODING1)
+        return((pmi_alloc>>((rb/6)<<1))&3);
+      else
+        return((pmi_alloc>>(rb/6))&1);
+
+      break;
+
+    case 100: // 8 PRBs per subband
+      if (mode <= PUSCH_PRECODING1)
+        return((pmi_alloc>>((rb>>3)<<1))&3);
+      else
+        return((pmi_alloc>>(rb>>3))&1);
+
+      break;
+  }
+}
diff --git a/openair1/PHY/LTE_UE_TRANSPORT/linear_preprocessing_rec.c b/openair1/PHY/LTE_UE_TRANSPORT/linear_preprocessing_rec.c
new file mode 100644
index 0000000000000000000000000000000000000000..d85d440193757044eedadaf820ef4d46b47eddb6
--- /dev/null
+++ b/openair1/PHY/LTE_UE_TRANSPORT/linear_preprocessing_rec.c
@@ -0,0 +1,369 @@
+/* These functions compute linear preprocessing for
+the UE using LAPACKE and CBLAS modules of
+LAPACK libraries.
+MMSE and MMSE whitening filters are available.
+Functions are using RowMajor storage of the
+matrices, like in conventional C. Traditional
+Fortran functions of LAPACK employ ColumnMajor
+data storage. */
+
+#include<stdio.h>
+#include<math.h>
+#include<complex.h>
+#include <stdlib.h>
+#include <cblas.h>
+#include <string.h>
+#include <lapacke_utils.h>
+#include <lapacke.h>
+
+//#define DEBUG_PREPROC
+
+
+void transpose (int N, float complex *A, float complex *Result)
+{
+  // COnputes C := alpha*op(A)*op(B) + beta*C,
+  enum CBLAS_TRANSPOSE transa = CblasTrans;
+  enum CBLAS_TRANSPOSE transb = CblasNoTrans;
+  int rows_opA = N; // number of rows in op(A) and in C
+  int col_opB = N; //number of columns of op(B) and in C
+  int col_opA = N; //number of columns in op(A) and rows in op(B)
+  int col_B; //number of columns in B
+  float complex alpha = 1.0+I*0;
+  int lda  = rows_opA;
+  float complex beta = 0.0+I*0;
+  int ldc = rows_opA;
+  int i;
+  float complex* B;
+
+  int ldb = col_opB;
+
+  if (transb == CblasNoTrans) {
+    B = (float complex*)calloc(ldb*col_opB,sizeof(float complex));
+    col_B= col_opB;
+  }
+  else {
+    B = (float complex*)calloc(ldb*col_opA, sizeof(float complex));
+    col_B = col_opA;
+  }
+  float complex* C = (float complex*)malloc(ldc*col_opB*sizeof(float complex));
+
+  for (i=0; i<lda*col_B; i+=N+1)
+    B[i]=1.0+I*0;
+
+  cblas_cgemm(CblasRowMajor, transa, transb, rows_opA, col_opB, col_opA, &alpha, A, lda, B, ldb, &beta, C, ldc);
+
+  memcpy(Result, C, N*N*sizeof(float complex));
+
+  free(B);
+  free(C);
+ }
+
+
+void conjugate_transpose (int N, float complex *A, float complex *Result)
+{
+  // Computes C := alpha*op(A)*op(B) + beta*C,
+  enum CBLAS_TRANSPOSE transa = CblasConjTrans;
+  enum CBLAS_TRANSPOSE transb = CblasNoTrans;
+  int rows_opA = N; // number of rows in op(A) and in C
+  int col_opB = N; //number of columns of op(B) and in C
+  int col_opA = N; //number of columns in op(A) and rows in op(B)
+  int col_B; //number of columns in B
+  float complex alpha = 1.0+I*0;
+  int lda  = rows_opA;
+  float complex beta = 0.0+I*0;
+  int ldc = rows_opA;
+  int i;
+  float complex* B;
+  int ldb = col_opB;
+
+  if (transb == CblasNoTrans) {
+    B = (float complex*)calloc(ldb*col_opB,sizeof(float complex));
+    col_B= col_opB;
+  }
+  else {
+    B = (float complex*)calloc(ldb*col_opA, sizeof(float complex));
+    col_B = col_opA;
+  }
+  float complex* C = (float complex*)malloc(ldc*col_opB*sizeof(float complex));
+
+  for (i=0; i<lda*col_B; i+=N+1)
+    B[i]=1.0+I*0;
+
+  cblas_cgemm(CblasRowMajor, transa, transb, rows_opA, col_opB, col_opA, &alpha, A, lda, B, ldb, &beta, C, ldc);
+
+  memcpy(Result, C, N*N*sizeof(float complex));
+
+  free(B);
+  free(C);
+ }
+
+void H_hermH_plus_sigma2I (int N, int M, float complex *A, float sigma2, float complex *Result)
+{
+  //C := alpha*op(A)*op(B) + beta*C,
+  enum CBLAS_TRANSPOSE transa = CblasConjTrans;
+  enum CBLAS_TRANSPOSE transb = CblasNoTrans;
+  int rows_opA = N; // number of rows in op(A) and in C
+  int col_opB = N; //number of columns of op(B) and in C
+  int col_opA = N; //number of columns in op(A) and rows in op(B)
+  int col_C = N; //number of columns in B
+  float complex alpha = 1.0+I*0;
+  int lda  = col_opA;
+  float complex beta = 1.0 + I*0;
+  int ldc = col_opA;
+  int i;
+
+  float complex* C = (float complex*)calloc(ldc*col_opB, sizeof(float complex));
+
+  for (i=0; i<lda*col_C; i+=N+1)
+    C[i]=sigma2*(1.0+I*0);
+
+  cblas_cgemm(CblasRowMajor, transa, transb, rows_opA, col_opB, col_opA, &alpha, A, lda, A, lda, &beta, C, ldc);
+
+  memcpy(Result, C, N*M*sizeof(float complex));
+  free(C);
+
+ }
+
+ void HH_herm_plus_sigma2I (int M, int N, float complex *A, float sigma2, float complex *Result)
+{
+  //C := alpha*op(A)*op(B) + beta*C,
+  enum CBLAS_TRANSPOSE transa = CblasNoTrans;
+  enum CBLAS_TRANSPOSE transb = CblasConjTrans;
+  int k = N; //number of columns in op(A) and rows in op(B),k
+  float complex alpha = 1.0+I*0;
+  int lda  = N;
+  int ldb  = N;
+  int ldc = M;
+  int i;
+
+  float complex* C = (float complex*)calloc(M*M, sizeof(float complex));
+
+  for (i=0; i<M*M; i+=M+1)
+    C[i]=1.0+I*0;
+
+  cblas_cgemm(CblasRowMajor, transa, transb, M, M, k, &alpha, A, lda, A, ldb, &sigma2, C, ldc);
+
+  memcpy(Result, C, M*M*sizeof(float complex));
+  free(C);
+
+}
+
+void eigen_vectors_values (int N, float complex *A, float complex *Vectors, float *Values_Matrix)
+{
+  // This function computes ORTHONORMAL eigenvectors and eigenvalues of matrix A,
+  // where Values_Matrix is a diagonal matrix of eigenvalues.
+  // A=Vectors*Values_Matrix*Vectors'
+  char jobz = 'V';
+  char uplo = 'U';
+  int order_A = N;
+  int lda = N;
+  int i;
+  float* Values = (float*)malloc(sizeof(float)*1*N);
+
+  LAPACKE_cheev(LAPACK_ROW_MAJOR, jobz, uplo, order_A, A, lda, Values);
+
+  memcpy(Vectors, A, N*N*sizeof(float complex));
+
+  for (i=0; i<lda; i+=1)
+    Values_Matrix[i*(lda+1)]=Values[i];
+
+  free(Values);
+}
+
+ void lin_eq_solver (int N, float complex* A, float complex* B, float complex* Result)
+{
+  int n = N;
+  int lda = N;
+  int ldb = N;
+  int nrhs = N;
+
+  char transa = 'N';
+  int* IPIV = malloc(N*N*sizeof(int));
+
+  // Compute LU-factorization
+  LAPACKE_cgetrf(LAPACK_ROW_MAJOR, n, nrhs, A, lda, IPIV);
+
+  // Solve AX=B
+  LAPACKE_cgetrs(LAPACK_ROW_MAJOR, transa, n, nrhs, A, lda, IPIV, B, ldb);
+
+  // cgetrs( "N", N, 4, A, lda, IPIV, B, ldb, INFO )
+
+  memcpy(Result, B, N*N*sizeof(float complex));
+
+  free(IPIV);
+
+}
+
+void mutl_matrix_matrix_row_based(float complex* M0, float complex* M1, int rows_M0, int col_M0, int rows_M1, int col_M1, float complex* Result ){
+  enum CBLAS_TRANSPOSE transa = CblasNoTrans;
+  enum CBLAS_TRANSPOSE transb = CblasNoTrans;
+  int rows_opA = rows_M0; // number of rows in op(A) and in C
+  int col_opB = col_M1; //number of columns of op(B) and in C
+  int col_opA = col_M0; //number of columns in op(A) and rows in op(B)
+  float complex alpha =1.0;
+  int lda  = col_M0;
+  float complex beta = 0.0;
+  int ldc = col_M1;
+  int ldb = col_M1;
+
+#ifdef DEBUG_PREPROC
+  int i=0;
+  printf("rows_M0 %d, col_M0 %d, rows_M1 %d, col_M1 %d\n", rows_M0, col_M0, rows_M1, col_M1);
+
+  for(i=0; i<rows_M0*col_M0; ++i)
+    printf(" rows_opA = %d, col_opB = %d, W_MMSE[%d] = (%f + i%f)\n", rows_opA, col_opB,  i , creal(M0[i]), cimag(M0[i]));
+
+  for(i=0; i<rows_M1*col_M1; ++i)
+    printf(" M1[%d] = (%f + i%f)\n", i , creal(M1[i]), cimag(M1[i]));
+#endif
+
+  cblas_cgemm(CblasRowMajor, transa, transb, rows_opA, col_opB, col_opA, &alpha, M0, lda, M1, ldb, &beta, Result, ldc);
+
+#ifdef DEBUG_PREPROC
+  for(i=0; i<rows_opA*col_opB; ++i)
+    printf(" result[%d] = (%f + i%f)\n", i , creal(Result[i]), cimag(Result[i]));
+#endif
+
+}
+void mutl_matrix_matrix_col_based(float complex* M0, float complex* M1, int rows_M0, int col_M0, int rows_M1, int col_M1, float complex* Result ){
+  enum CBLAS_TRANSPOSE transa = CblasNoTrans;
+  enum CBLAS_TRANSPOSE transb = CblasNoTrans;
+  int rows_opA = rows_M0; // number of rows in op(A) and in C
+  int col_opB = col_M1; //number of columns of op(B) and in C
+  int col_opA = col_M0; //number of columns in op(A) and rows in op(B)
+  float complex alpha =1.0;
+  int lda  = col_M0;
+  float complex beta = 0.0;
+  int ldc = rows_M1;
+  int ldb = rows_M1;
+
+#ifdef DEBUG_PREPROC
+  int i = 0;
+  printf("rows_M0 %d, col_M0 %d, rows_M1 %d, col_M1 %d\n", rows_M0, col_M0, rows_M1, col_M1);
+
+  for(i=0; i<rows_M0*col_M0; ++i)
+    printf(" rows_opA = %d, col_opB = %d, W_MMSE[%d] = (%f + i%f)\n", rows_opA, col_opB,  i , creal(M0[i]), cimag(M0[i]));
+
+
+  for(i=0; i<rows_M1*col_M1; ++i)
+    printf(" M1[%d] = (%f + i%f)\n", i , creal(M1[i]), cimag(M1[i]));
+#endif
+
+  cblas_cgemm(CblasColMajor, transa, transb, rows_opA, col_opB, col_opA, &alpha, M0, lda, M1, ldb, &beta, Result, ldc);
+
+#ifdef DEBUG_PREPROC
+  for(i=0; i<rows_opA*col_opB; ++i)
+    printf(" result[%d] = (%f + i%f)\n", i , creal(Result[i]), cimag(Result[i]));
+#endif
+}
+
+
+/*FILTERS */
+void compute_MMSE(float complex* H, int order_H, float sigma2, float complex* W_MMSE)
+{
+  int N = order_H;
+  float complex* H_hermH_sigmaI = malloc(N*N*sizeof(float complex));
+  float complex* H_herm =  malloc(N*N*sizeof(float complex));
+
+  H_hermH_plus_sigma2I(N, N, H, sigma2, H_hermH_sigmaI);
+
+#ifdef DEBUG_PREPROC
+  int i =0;
+  for(i=0;i<N*N;i++)
+    printf(" H_hermH_sigmaI[%d] = (%f + i%f)\n", i , creal(H_hermH_sigmaI[i]), cimag(H_hermH_sigmaI[i]));
+#endif
+
+  conjugate_transpose (N, H, H_herm); //equals H_herm
+
+#ifdef DEBUG_PREPROC
+  for(i=0;i<N*N;i++)
+    printf(" H_herm[%d] = (%f + i%f)\n", i , creal(H_herm[i]), cimag(H_herm[i]));
+#endif
+
+  lin_eq_solver(N, H_hermH_sigmaI, H_herm, W_MMSE);
+
+#ifdef DEBUG_PREPROC
+  for(i=0;i<N*N;i++)
+    printf(" W_MMSE[%d] = (%f + i%f)\n", i , creal(W_MMSE[i]), cimag(W_MMSE[i]));
+#endif
+
+  free(H_hermH_sigmaI);
+  free(H_herm);
+}
+
+#if 0
+void compute_white_filter(float complex* H_re,
+                          int order_H,
+                          float sigma2,
+                          float complex* W_Wh_0_re,
+                          float complex* W_Wh_1_re){
+
+  int aatx, aarx, re;
+  int i,j;
+  int M =n_rx;
+  int N = n_tx;
+  int sigma2=noise_power;
+
+  float complex *H0_re = malloc(n_rx*(n_tx>>2)*sizeof(float complex));
+  float complex *H1_re = malloc(n_rx*(n_tx>>2)*sizeof(float complex));
+  float complex *R_corr_col_n_0_re = malloc(n_rx*n_tx*sizeof(float complex));
+  float complex *R_corr_col_n_1_re = malloc(n_rx*n_tx*sizeof(float complex));
+  float complex *U_0_re = malloc(n_rx*n_tx*sizeof(float complex));
+  float complex *U_1_re = malloc(n_rx*n_tx*sizeof(float complex));
+  float complex *U_0_herm_re = malloc(n_rx*n_tx*sizeof(float complex));
+  float complex *U_1_herm_re = malloc(n_rx*n_tx*sizeof(float complex));
+  float complex *D_0_re = malloc(n_rx*n_tx*sizeof(float complex));
+  float complex *D_1_re = malloc(n_rx*n_tx*sizeof(float complex));
+  float complex *W_Wh_0_re = malloc(n_rx*n_tx*sizeof(float complex));
+  float complex *W_Wh_1_re = malloc(n_rx*n_tx*sizeof(float complex));
+
+  for (aatx=0; aatx<n_tx/2; aatx++){
+    for (aarx=0; aarx<n_rx; aarx++) {
+      H0_re[aatx*n_rx + aarx] = H_re[aatx*n_rx + aarx][re]; // H0 gets [0 1 2 3; 4,5,6,7].' coefficients of H
+      H1_re[aatx*n_rx + aarx] = H_re[aatx*n_rx + aarx + 8][re]; // H1 gets [8 9 10 11; 12, 13, 14, 15].' coefficients of H
+        if (re == 0)
+        printf("ant %d, H_re = (%f + i%f) \n", aatx*n_rx + aarx, creal(H[aatx*n_rx + aarx][re]), cimag(H[aatx*n_rx + aarx][re]));
+      }
+   }
+
+
+    //HH_herm_plus_sigma2I(n_rx, (n_tx>>2), H1_re, sigma2, R_corr_col_n_0_re);
+    HH_herm_plus_sigma2I(n_rx, (n_tx>>2), H0_re, sigma2, R_corr_col_n_1_re);
+
+    eigen_vectors_values(n_rx, R_corr_col_n_0_re, U_0_re, D_0_re);
+    eigen_vectors_values(n_rx, R_corr_col_n_1_re, U_1_re, D_1_re);
+
+    transpose (n_rx, U_0_re, U_0_herm_re);
+    transpose (n_rx, U_1_re, U_1_herm_re);
+
+    sigma = (float)(sqrt((double)(sigma2)));
+
+    /*The inverse of a diagonal matrix is obtained by replacing each element in the diagonal with its reciprocal.
+    A square root of a diagonal matrix is given by the diagonal matrix, whose diagonal entries are just the square
+     roots of the original matrix.*/
+
+
+    D_0_re_inv_sqrt[0] = sqrt_float(1/D_0_re_inv[0]);
+    D_0_re_inv_sqrt[5] = sqrt_float(1/D_0_re_inv[5]);
+    D_0_re_inv_sqrt[10] = sqrt_float(1/D_0_re_inv[10]);
+    D_0_re_inv_sqrt[15] = sqrt_float(1/D_0_re_inv[15]);
+
+    D_1_re_inv[0] = sqrt_float(1/D_1_re_inv[0]);
+    D_1_re_inv[5] = sqrt_float(1/D_1_re_inv[5]);
+    D_1_re_inv[10] = sqrt_float(1/D_1_re_inv[10]);
+    D_1_re_inv[15] = sqrt_float(1/D_1_re_inv[15]);
+
+    now only to multiply
+
+  free(H0);
+  free(H1);
+  free(R_corr_col_n_0);
+  free(R_corr_col_n_1);
+}
+#endif
+
+float sqrt_float(float x, float sqrt_x)
+{
+  sqrt_x = (float)(sqrt((double)(x)));
+  return sqrt_x;
+}
\ No newline at end of file
diff --git a/openair1/PHY/LTE_UE_TRANSPORT/linear_preprocessing_rec.h b/openair1/PHY/LTE_UE_TRANSPORT/linear_preprocessing_rec.h
new file mode 100755
index 0000000000000000000000000000000000000000..f38bc475567633a97fd55e3ad4cccc4c3c964ace
--- /dev/null
+++ b/openair1/PHY/LTE_UE_TRANSPORT/linear_preprocessing_rec.h
@@ -0,0 +1,121 @@
+
+#include<stdio.h>
+#include<math.h>
+#include<complex.h>
+#include <stdlib.h>
+#include "PHY/defs_UE.h"
+
+
+/* FUNCTIONS FOR LINEAR PREPROCESSING: MMSE, WHITENNING, etc*/
+void transpose(int N, float complex *A, float complex *Result);
+
+void conjugate_transpose(int N, float complex *A, float complex *Result);
+
+void H_hermH_plus_sigma2I(int N, int M, float complex *A, float sigma2, float complex *Result);
+
+void HH_herm_plus_sigma2I(int M, int N, float complex *A, float sigma2, float complex *Result);
+
+void eigen_vectors_values(int N, float complex *A, float complex *Vectors, float *Values_Matrix);
+
+void lin_eq_solver(int N, float complex *A, float complex* B);
+//float complex* lin_eq_solver (int N, float complex* A, float complex* B);
+
+/* mutl_matrix_matrix_row_based performs multiplications when matrix is row-oriented H[0], H[1]; H[2], H[3]*/
+void mutl_matrix_matrix_row_based(float complex* M0, float complex* M1, int rows_M0, int col_M0, int rows_M1, int col_M1, float complex* Result );
+
+/* mutl_matrix_matrix_col_based performs multiplications matrix is column-oriented H[0], H[2]; H[1], H[3]*/
+void mutl_matrix_matrix_col_based(float complex* M0, float complex* M1, int rows_M0, int col_M0, int rows_M1, int col_M1, float complex* Result );
+
+void compute_MMSE(float complex* H, int order_H, float sigma2, float complex* W_MMSE);
+
+void compute_white_filter(float complex* H, int order_H, float sigma2, float complex* U_1, float complex* D_1);
+
+void mmse_processing_oai(LTE_UE_PDSCH *pdsch_vars,
+                         LTE_DL_FRAME_PARMS *frame_parms,
+                         PHY_MEASUREMENTS *measurements,
+                         unsigned char first_symbol_flag,
+                         MIMO_mode_t mimo_mode,
+                         unsigned short mmse_flag,
+                         int noise_power,
+                         unsigned char symbol,
+                         unsigned short nb_rb);
+
+
+void precode_channel_est(int32_t **dl_ch_estimates_ext,
+                        LTE_DL_FRAME_PARMS *frame_parms,
+                        LTE_UE_PDSCH *pdsch_vars,
+                        unsigned char symbol,
+                        unsigned short nb_rb,
+                        MIMO_mode_t mimo_mode);
+
+
+void rxdataF_to_float(int32_t **rxdataF_ext,
+                      float complex **rxdataF_f,
+                      int n_rx,
+                      int length,
+                      int start_point);
+
+void chan_est_to_float(int32_t **dl_ch_estimates_ext,
+                       float complex **dl_ch_estimates_ext_f,
+                       int n_tx,
+                       int n_rx,
+                       int length,
+                       int start_point);
+
+void float_to_chan_est(int32_t **dl_ch_estimates_ext,
+                      float complex **dl_ch_estimates_ext_f,
+                      int n_tx,
+                      int n_rx,
+                      int length,
+                      int start_point);
+
+void float_to_rxdataF(int32_t **rxdataF_ext,
+                      float complex **rxdataF_f,
+                      int n_tx,
+                      int n_rx,
+                      int length,
+                      int start_point);
+
+void mult_mmse_rxdataF(float complex** Wmmse,
+                       float complex** rxdataF_ext_f,
+                       int n_tx,
+                       int n_rx,
+                       int length,
+                       int start_point);
+
+void mult_mmse_chan_est(float complex** Wmmse,
+                        float complex** dl_ch_estimates_ext_f,
+                        int n_tx,
+                        int n_rx,
+                        int length,
+                        int start_point);
+
+void  mmse_processing_core(int32_t **rxdataF_ext,
+                           int32_t **dl_ch_estimates_ext,
+                           int sigma2,
+                           int n_tx,
+                           int n_rx,
+                           int length,
+                           int start_point);
+
+void mmse_processing_core_flp(float complex** rxdataF_ext_flcpx,
+                              float complex **H,
+                              int32_t **rxdataF_ext,
+                              int32_t **dl_ch_estimates_ext,
+                              float sigma2,
+                              int n_tx,
+                              int n_rx,
+                              int length,
+                              int start_point);
+
+void whitening_processing_core_flp(float complex** rxdataF_ext_flcpx,
+                                   float complex **H,
+                                   int32_t **rxdataF_ext,
+                                   int32_t **dl_ch_estimates_ext,
+                                   float sigma2,
+                                   int n_tx,
+                                   int n_rx,
+                                   int length,
+                                   int start_point);
+
+float sqrt_float(float x, float sqrt_x);
diff --git a/openair1/PHY/LTE_UE_TRANSPORT/transport_proto_ue.h b/openair1/PHY/LTE_UE_TRANSPORT/transport_proto_ue.h
index ade621faa2a3fb3b386e4df3e8a1782549f56219..814816a8852797713b44f89a6193f32fbf863d7a 100644
--- a/openair1/PHY/LTE_UE_TRANSPORT/transport_proto_ue.h
+++ b/openair1/PHY/LTE_UE_TRANSPORT/transport_proto_ue.h
@@ -106,6 +106,22 @@ void qpsk_qpsk(int16_t *stream0_in,
     @param nb_rb number of RBs for this allocation
     @param pbch_pss_sss_adj Number of channel bits taken by PBCH/PSS/SSS
     @param llr128p pointer to pointer to symbol in dlsch_llr*/
+
+void qpsk_llr(int16_t *stream0_in,
+              int16_t *stream0_out,
+              int length);
+
+void qam16_llr(int16_t *stream0_in,
+               int16_t *chan_magn,
+               int16_t *llr,
+               int length);
+
+void qam64_llr(int16_t *stream0_in,
+               int16_t *chan_magn,
+               int16_t *chan_magn_b,
+               int16_t *llr,
+               int length);
+
 int32_t dlsch_qpsk_qpsk_llr(LTE_DL_FRAME_PARMS *frame_parms,
                             int32_t **rxdataF_comp,
                             int32_t **rxdataF_comp_i,
@@ -816,6 +832,19 @@ void dlsch_channel_compensation(int32_t **rxdataF_ext,
                                 uint8_t output_shift,
                                 PHY_MEASUREMENTS *phy_measurements);
 
+void dlsch_channel_compensation_core(int **rxdataF_ext,
+                                     int **dl_ch_estimates_ext,
+                                     int **dl_ch_mag,
+                                     int **dl_ch_magb,
+                                     int **rxdataF_comp,
+                                     int **rho,
+                                     unsigned char n_tx,
+                                     unsigned char n_rx,
+                                     unsigned char mod_order,
+                                     unsigned char output_shift,
+                                     int length,
+                                     int start_point);
+
 void dlsch_dual_stream_correlation(LTE_DL_FRAME_PARMS *frame_parms,
                                    unsigned char symbol,
                                    unsigned short nb_rb,
@@ -912,6 +941,7 @@ void dlsch_channel_compensation_TM34(LTE_DL_FRAME_PARMS *frame_parms,
                                     int round,
                                     MIMO_mode_t mimo_mode,
                                     unsigned short nb_rb,
+                                    unsigned short mmse_flag,
                                     unsigned char output_shift0,
                                     unsigned char output_shift1);
 
@@ -929,6 +959,13 @@ void dlsch_channel_level(int32_t **dl_ch_estimates_ext,
                          uint8_t pilots_flag,
                          uint16_t nb_rb);
 
+void dlsch_channel_level_core(int32_t **dl_ch_estimates_ext,
+                              int32_t *avg,
+                              int n_tx,
+                              int n_rx,
+                              int length,
+                              int start_point);
+
 
 void dlsch_channel_level_TM34(int **dl_ch_estimates_ext,
                               LTE_DL_FRAME_PARMS *frame_parms,
@@ -937,6 +974,7 @@ void dlsch_channel_level_TM34(int **dl_ch_estimates_ext,
                               int *avg_1,
                               uint8_t symbol,
                               unsigned short nb_rb,
+                              unsigned int mmse_flag,
                               MIMO_mode_t mimo_mode);
 
 
@@ -1672,8 +1710,8 @@ double computeRhoB_UE(PDSCH_CONFIG_DEDICATED  *pdsch_config_dedicated,
   LTE_UE_DLSCH_t *dlsch_ue);
 */
 
-uint8_t get_prach_prb_offset(LTE_DL_FRAME_PARMS *frame_parms, 
-			     uint8_t prach_ConfigIndex, 
+uint8_t get_prach_prb_offset(LTE_DL_FRAME_PARMS *frame_parms,
+			     uint8_t prach_ConfigIndex,
 			     uint8_t n_ra_prboffset,
 			     uint8_t tdd_mapindex, uint16_t Nf);
 
diff --git a/openair1/PHY/defs_UE.h b/openair1/PHY/defs_UE.h
index de17bbee0b9856833664acf3375a07a1f612cc4f..f079794a34afa069d83032b6f0e20a00353d50e4 100644
--- a/openair1/PHY/defs_UE.h
+++ b/openair1/PHY/defs_UE.h
@@ -69,6 +69,38 @@
 #include <pthread.h>
 #include "assertions.h"
 
+#ifdef MEX
+#include "mex.h"
+# define msg mexPrintf
+# undef LOG_D
+# undef LOG_E
+# undef LOG_I
+# undef LOG_N
+# undef LOG_T
+# undef LOG_W
+# undef LOG_M
+# define LOG_D(x, ...) mexPrintf(__VA_ARGS__)
+# define LOG_E(x, ...) mexPrintf(__VA_ARGS__)
+# define LOG_I(x, ...) mexPrintf(__VA_ARGS__)
+# define LOG_N(x, ...) mexPrintf(__VA_ARGS__)
+# define LOG_T(x, ...) mexPrintf(__VA_ARGS__)
+# define LOG_W(x, ...) mexPrintf(__VA_ARGS__)
+# define LOG_M(x, ...) mexPrintf(__VA_ARGS__)
+#else
+# ifdef OPENAIR2
+#   if ENABLE_RAL
+#     include "collection/hashtable/hashtable.h"
+#     include "COMMON/ral_messages_types.h"
+#     include "UTIL/queue.h"
+#   endif
+#   include "log.h"
+#   define msg(aRGS...) LOG_D(PHY, ##aRGS)
+# else
+#   define msg printf
+# endif
+#endif
+
+
 
 /// Context data structure for RX/TX portion of subframe processing
 typedef struct {
@@ -273,13 +305,13 @@ typedef struct {
   /// - first index: rx antenna [0..nb_antennas_rx[
   /// - second index: symbol [0..28*ofdm_symbol_size[
   int32_t **rxdataF;
-  
+
   /// \brief Hold the channel estimates in frequency domain.
   /// - first index: eNB id [0..6] (hard coded)
   /// - second index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx
   /// - third index: samples? [0..symbols_per_tti*(ofdm_symbol_size+LTE_CE_FILTER_LENGTH)[
   int32_t **dl_ch_estimates[7];
-  
+
   /// \brief Hold the channel estimates in time domain (used for tracking).
   /// - first index: eNB id [0..6] (hard coded)
   /// - second index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx
@@ -848,7 +880,7 @@ typedef struct {
 
   /// RF and Interface devices per CC
 
-  openair0_device rfdevice; 
+  openair0_device rfdevice;
 } PHY_VARS_UE;
 
 /* this structure is used to pass both UE phy vars and
diff --git a/targets/build_helper.bash b/targets/build_helper.bash
index a3c57b8dce53bbce85d15422aae272874ec22f4d..9c98ef85b0173ce4f9bac95a529d0363f727f8c1 100755
--- a/targets/build_helper.bash
+++ b/targets/build_helper.bash
@@ -23,7 +23,7 @@
 # brief
 # author Lionel Gauthier and Navid Nikaein
 # company Eurecom
-# email: lionel.gauthier@eurecom.fr and navid.nikaein@eurecom.fr 
+# email: lionel.gauthier@eurecom.fr and navid.nikaein@eurecom.fr
 #
 #######################################
 #            Helper Func
@@ -42,30 +42,30 @@ declare UBUNTU_REL=`lsb_release -r | cut  -f2`
 declare UBUNTU_REL_NAME=`lsb_release -cs`
 
 set_build_from_makefile(){
-    BUILD_FROM_MAKEFILE=$1   
+    BUILD_FROM_MAKEFILE=$1
 }
 
 check_for_root_rights() {
-    
+
   #  if [[ $EUID -ne $ROOT_EUID ]]; then
     if [ $USER != "root" ]; then
         SUDO="sudo -E "
-        echo "Run as a sudoers" 
+        echo "Run as a sudoers"
         return 1
-    else 
-        echo  "Run as a root" 
+    else
+        echo  "Run as a root"
         return 0
     fi
 }
 
 test_install_package() {
   # usage: test_install_package package_name
- 
+
  if [ $# -eq 1 ]; then
       dpkg -s "$1" > /dev/null 2>&1 && {
-          echo "$1 is installed." 
+          echo "$1 is installed."
       } || {
-          echo "$1 is not installed." 
+          echo "$1 is not installed."
           OAI_INSTALLED=0
           $SUDO apt-get install -y $@
       }
@@ -73,13 +73,13 @@ test_install_package() {
 }
 
 test_uninstall_package() {
-  
+
  if [ $# -eq 1 ]; then
       dpkg -s "$1" > /dev/null 2>&1 && {
-          $SUDO apt-get remove --assume-yes $1  
-          echo "$1 is uninstalled." 
+          $SUDO apt-get remove --assume-yes $1
+          echo "$1 is uninstalled."
       } || {
-          echo "$1 is not installed." 
+          echo "$1 is not installed."
       }
   fi
 }
@@ -97,8 +97,8 @@ check_for_machine_type(){
     else
         if [ ${MACHINE_TYPE} = "i686" ]; then
             return 32 # 32-bit stuff here
-        else 
-            return -1 
+        else
+            return -1
         fi
     fi
 }
@@ -108,7 +108,7 @@ check_for_machine_type(){
 #####################################################
 
 ####################################################
-# 1. install the required packages 
+# 1. install the required packages
 ####################################################
 
 make_certs(){
@@ -118,32 +118,32 @@ make_certs(){
     mkdir -m 777 -p demoCA
     echo 01 > demoCA/serial
     touch demoCA/index.txt
-    
+
     echo "creating the certificate"
-    
+
     user=$(whoami)
     HOSTNAME=$(hostname -f)
 
     echo "Creating certificate for user '$HOSTNAME'"
-    
+
 # CA self certificate
     openssl req  -new -batch -x509 -days 3650 -nodes -newkey rsa:1024 -out cacert.pem -keyout cakey.pem -subj /CN=eur/C=FR/ST=PACA/L=Aix/O=Eurecom/OU=CM
-    
+
    # openssl genrsa -out user.key.pem 1024
     openssl genrsa -out hss.key.pem 1024
     #openssl req -new -batch -out user.csr.pem -key user.key.pem -subj /CN=$HOSTNAME.eur/C=FR/ST=PACA/L=Aix/O=Eurecom/OU=CM
     openssl req -new -batch -out hss.csr.pem -key hss.key.pem -subj /CN=hss.eur/C=FR/ST=PACA/L=Aix/O=Eurecom/OU=CM
     openssl ca -cert cacert.pem -keyfile cakey.pem -in hss.csr.pem -out hss.cert.pem -outdir . -batch
-    
+
     if [ ! -d /usr/local/etc/freeDiameter ];  then
         echo "Creating non existing directory: /usr/local/etc/freeDiameter/"
         $SUDO mkdir /usr/local/etc/freeDiameter/
     fi
-    
+
     echo "Copying *.pem to /usr/local/etc/freeDiameter/"
     $SUDO cp *.pem /usr/local/etc/freeDiameter/
     mv *.pem bin/
-    
+
 # openssl genrsa -out ubuntu.key.pem 1024
 # openssl req -new -batch -x509 -out ubuntu.csr.pem -key ubuntu.key.pem -subj /CN=ubuntu.localdomain/C=FR/ST=BdR/L=Aix/O=fD/OU=Tests
 # openssl ca -cert cacert.pem -keyfile cakey.pem -in ubuntu.csr.pem -out ubuntu.cert.pem -outdir . -batch
@@ -151,25 +151,25 @@ make_certs(){
 }
 
 check_install_nettle(){
-    if [ ! -f ./.lock_oaibuild ]; then 
-	if [ $UBUNTU_REL = "12.04" ]; then 
+    if [ ! -f ./.lock_oaibuild ]; then
+	if [ $UBUNTU_REL = "12.04" ]; then
 	    test_uninstall_package nettle-dev
 	    test_uninstall_package nettle-bin
-	
+
 	    if [ ! -d /usr/local/src/ ]; then
 		echo "/usr/local/src/ doesn't exist please create one"
 		exit -1
 	    fi
-	    
+
 	    if [ ! -w /usr/local/src/ ];  then
 		echo "You don't have permissions to write to /usr/local/src/, installing as a sudoer"
 		#	exit -1
 	    fi
-	    
+
 	    cd /usr/local/src/
-	    
+
 	    echo "Downloading nettle archive"
-	    
+
 	    if [ -f nettle-2.5.tar.gz ]; then
 		$SUDO rm -f nettle-2.5.tar.gz
 	    fi
@@ -179,44 +179,44 @@ check_install_nettle(){
 	    if [ -d nettle-2.5 ];  then
 		$SUDO rm -rf nettle-2.5/
 	    fi
-	    
-	    
-	    $SUDO wget ftp://ftp.lysator.liu.se/pub/security/lsh/nettle-2.5.tar.gz 
-	    $SUDO gunzip nettle-2.5.tar.gz 
+
+
+	    $SUDO wget ftp://ftp.lysator.liu.se/pub/security/lsh/nettle-2.5.tar.gz
+	    $SUDO gunzip nettle-2.5.tar.gz
 	    $SUDO echo "Uncompressing nettle archive"
 	    $SUDO tar -xf nettle-2.5.tar
 	    cd nettle-2.5/
-	    $SUDO ./configure --disable-openssl --enable-shared --prefix=/usr 
+	    $SUDO ./configure --disable-openssl --enable-shared --prefix=/usr
 	    if [ $? -ne 0 ]; then
 		exit -1
 	    fi
 	    echo "Compiling nettle"
-	    $SUDO make -j $NUM_CPU  
-	    $SUDO make check 
-	    $SUDO make install 
+	    $SUDO make -j $NUM_CPU
+	    $SUDO make check
+	    $SUDO make install
 	    cd ../
 	fi
     fi
 }
 
 check_install_freediamter(){
-    
-    if [ $UBUNTU_REL = "12.04" ]; then 
+
+    if [ $UBUNTU_REL = "12.04" ]; then
 
 	if [ ! -d /usr/local/src/ ]; then
 	    echo "/usr/local/src/ doesn't exist please create one"
 	    exit -1
 	fi
-	
+
 	if [ ! -w /usr/local/src/ ];  then
 	    echo "You don't have permissions to write to /usr/local/src/, installing as a sudoer"
 #	exit -1
 	fi
-	
+
 	cd /usr/local/src/
-	
+
 	echo "Downloading nettle archive"
-	
+
 	if [ -f nettle-2.5.tar.gz ]; then
 	    $SUDO rm -f nettle-2.5.tar.gz
 	fi
@@ -226,36 +226,36 @@ check_install_freediamter(){
 	if [ -d nettle-2.5 ];  then
 	    $SUDO rm -rf nettle-2.5/
 	fi
-	
-	
-	$SUDO wget ftp://ftp.lysator.liu.se/pub/security/lsh/nettle-2.5.tar.gz 
-	$SUDO gunzip nettle-2.5.tar.gz 
+
+
+	$SUDO wget ftp://ftp.lysator.liu.se/pub/security/lsh/nettle-2.5.tar.gz
+	$SUDO gunzip nettle-2.5.tar.gz
 	$SUDO echo "Uncompressing nettle archive"
 	$SUDO tar -xf nettle-2.5.tar
 	cd nettle-2.5/
-	$SUDO ./configure --disable-openssl --enable-shared --prefix=/usr 
+	$SUDO ./configure --disable-openssl --enable-shared --prefix=/usr
 	if [ $? -ne 0 ]; then
 	    exit -1
 	fi
 	echo "Compiling nettle"
-	$SUDO make -j $NUM_CPU  
-	$SUDO make check 
-	$SUDO make install 
+	$SUDO make -j $NUM_CPU
+	$SUDO make check
+	$SUDO make install
 	cd ../
     fi
-    
+
     echo "Downloading gnutls archive"
-    
+
     if [ -f gnutls-3.1.23.tar.xz ];  then
 	$SUDO rm -f gnutls-3.1.23.tar.xz
     fi
     if [ -d gnutls-3.1.23/ ];  then
 	$SUDO rm -rf gnutls-3.1.23/
     fi
-    
+
     test_uninstall_package libgnutls-dev
-    
-    $SUDO wget ftp://ftp.gnutls.org/gcrypt/gnutls/v3.1/gnutls-3.1.23.tar.xz 
+
+    $SUDO wget ftp://ftp.gnutls.org/gcrypt/gnutls/v3.1/gnutls-3.1.23.tar.xz
     $SUDO tar -xf gnutls-3.1.23.tar.xz
     echo "Uncompressing gnutls archive ($PWD)"
     cd gnutls-3.1.23/
@@ -264,38 +264,38 @@ check_install_freediamter(){
 	exit -1
     fi
     echo "Compiling gnutls"
-    $SUDO make -j $NUM_CPU 
-    $SUDO make install 
+    $SUDO make -j $NUM_CPU
+    $SUDO make install
     cd ../
-    
+
     echo "Downloading freeDiameter archive"
-    
+
     if [ -f 1.1.5.tar.gz ];  then
 	$SUDO rm -f 1.1.5.tar.gz
     fi
     if [ -d freeDiameter-1.1.5/ ];   then
 	$SUDO rm -rf freeDiameter-1.1.5/
     fi
-    
-    $SUDO wget http://www.freediameter.net/hg/freeDiameter/archive/1.1.5.tar.gz 
-    $SUDO tar -xzf 1.1.5.tar.gz 
+
+    $SUDO wget http://www.freediameter.net/hg/freeDiameter/archive/1.1.5.tar.gz
+    $SUDO tar -xzf 1.1.5.tar.gz
     echo "Uncompressing freeDiameter archive"
     cd freeDiameter-1.1.5
-    $SUDO patch -p1 < $OPENAIR3_DIR/S6A/freediameter/freediameter-1.1.5.patch 
+    $SUDO patch -p1 < $OPENAIR3_DIR/S6A/freediameter/freediameter-1.1.5.patch
     $SUDO mkdir build
     cd build
-    $SUDO cmake -DCMAKE_INSTALL_PREFIX:PATH=/usr ../ 
+    $SUDO cmake -DCMAKE_INSTALL_PREFIX:PATH=/usr ../
     if [ $? -ne 0 ];  then
 	exit -1
     fi
     echo "Compiling freeDiameter"
-    $SUDO make -j $NUM_CPU 
+    $SUDO make -j $NUM_CPU
 #make help
-    $SUDO make test 
-    $SUDO sudo make install 
-  
+    $SUDO make test
+    $SUDO sudo make install
+
 #    make_certs
-   
+
 }
 
 
@@ -339,7 +339,7 @@ check_hss_s6a_certificate() {
             then
                 echo_success "HSS S6A: Found valid certificate in /usr/local/etc/freeDiameter"
                 return 0
-            else 
+            else
                 echo_error "Bad hss hostname found in cert file: "$full_hostname " hostname is "`hostname`
             fi
         fi
@@ -357,43 +357,43 @@ check_hss_s6a_certificate() {
 }
 
 check_install_usrp_uhd_driver(){
-    if [ ! -f /etc/apt/sources.list.d/ettus.list ] ; then 
+    if [ ! -f /etc/apt/sources.list.d/ettus.list ] ; then
         $SUDO bash -c 'echo "deb http://files.ettus.com/binaries/uhd/repo/uhd/ubuntu/`lsb_release -cs` `lsb_release -cs` main" >> /etc/apt/sources.list.d/ettus.list'
         $SUDO apt-get update
-    fi 
+    fi
     $SUDO apt-get install -t $UBUNTU_REL_NAME uhd
-    test_install_package python 
-    test_install_package libboost-all-dev 
+    test_install_package python
+    test_install_package libboost-all-dev
     test_install_package libusb-1.0-0-dev
     #test_install_package uhd
 }
 
 check_install_oai_software() {
-    
-    if [ ! -f ./.lock_oaibuild ]; then 
+
+    if [ ! -f ./.lock_oaibuild ]; then
         $SUDO apt-get update
-        if [ $UBUNTU_REL = "12.04" ]; then 
+        if [ $UBUNTU_REL = "12.04" ]; then
             test_uninstall_package nettle-dev
             test_uninstall_package nettle-bin
-        else 
+        else
             test_install_package nettle-dev
             test_install_package nettle-bin
-        fi 
-        test_install_package autoconf 
-        test_install_package automake 
-        test_install_package bison 
+        fi
+        test_install_package autoconf
+        test_install_package automake
+        test_install_package bison
         test_install_package build-essential
         test_install_package dialog
-        test_install_package flex 
+        test_install_package flex
         test_install_package gawk
         test_install_package gcc
-        test_install_package gdb 
+        test_install_package gdb
         test_install_package make
         test_install_package cmake
         test_install_package openssh-client
         test_install_package openssh-server
         sudo service ssh start
-        test_install_package unzip 
+        test_install_package unzip
         test_install_package autoconf
         test_install_package automake
         test_install_package bison
@@ -405,7 +405,7 @@ check_install_oai_software() {
         test_install_package gawk
         test_install_package gcc
         test_install_package gccxml
-        test_install_package gdb 
+        test_install_package gdb
         test_install_package guile-2.0-dev
         test_install_package iperf
         test_install_package iproute
@@ -414,6 +414,8 @@ check_install_oai_software() {
         test_install_package libatlas-dev
         test_install_package libblas3gf
         test_install_package libblas-dev
+        test_install_package liblapack-dev
+        test_install_package liblapack-dev
 #	if [ $MACHINE_ARCH = 64 ]; then
             test_install_package libconfig8-dev
 #	else
@@ -436,7 +438,7 @@ check_install_oai_software() {
         test_install_package libxml2-dev
 #       test_install_package linux-headers-`uname -r`
         test_install_package openssl
-        test_install_package libssl-dev 
+        test_install_package libssl-dev
         test_install_package pkg-config
         test_install_package python-dev
         test_install_package python-pexpect
@@ -445,90 +447,90 @@ check_install_oai_software() {
         test_install_package valgrind
         test_install_package doxygen
         test_install_package graphviz
-	
+
 #        test_install_package libboost-all-dev
-	
-        if [ $OAI_INSTALLED = 1 ]; then 
+
+        if [ $OAI_INSTALLED = 1 ]; then
             touch ./.lock_oaibuild
-        fi 
-    
+        fi
+
      else
         echo_info "All the required packages installed: skip"
-    fi 
-    
+    fi
+
 }
 
 check_install_hss_software() {
-    if [ ! -f ./.lock_oaibuild ]; then 
+    if [ ! -f ./.lock_oaibuild ]; then
         $SUDO apt-get update
-        if [ $UBUNTU_REL = "12.04" ]; then 
+        if [ $UBUNTU_REL = "12.04" ]; then
             test_uninstall_package nettle-dev
             test_uninstall_package nettle-bin
-        else 
+        else
             test_install_package nettle-dev
             test_install_package nettle-bin
-        fi 
-	test_install_package autoconf 
-	test_install_package automake 
-	test_install_package bison 
+        fi
+	test_install_package autoconf
+	test_install_package automake
+	test_install_package bison
 	test_install_package build-essential
 	test_install_package cmake
-	test_install_package cmake-curses-gui 
+	test_install_package cmake-curses-gui
     test_install_package dialog
     test_install_package dkms
-	test_install_package flex 
+	test_install_package flex
 	test_install_package gawk
 	test_install_package gcc
-	test_install_package gdb 
-	test_install_package guile-2.0-dev 
+	test_install_package gdb
+	test_install_package guile-2.0-dev
 	test_install_package g++
-	test_install_package libgmp-dev 
-	test_install_package libgcrypt11-dev 
-	test_install_package libidn11-dev 
-	test_install_package libidn2-0-dev 
-	test_install_package libmysqlclient-dev 
-	test_install_package libtasn1-3-dev 
-	test_install_package libsctp1 
-	test_install_package libsctp-dev 
-	test_install_package libxml2-dev 
-#	test_install_package linux-headers-`uname -r` 
+	test_install_package libgmp-dev
+	test_install_package libgcrypt11-dev
+	test_install_package libidn11-dev
+	test_install_package libidn2-0-dev
+	test_install_package libmysqlclient-dev
+	test_install_package libtasn1-3-dev
+	test_install_package libsctp1
+	test_install_package libsctp-dev
+	test_install_package libxml2-dev
+#	test_install_package linux-headers-`uname -r`
 	test_install_package make
-	test_install_package mysql-client 
-	test_install_package mysql-server-core-5.5 
+	test_install_package mysql-client
+	test_install_package mysql-server-core-5.5
 	test_install_package mysql-server
 	test_install_package openssh-client
 	test_install_package openssh-server
         sudo service ssh start
 	test_install_package phpmyadmin
-	test_install_package python-dev 
+	test_install_package python-dev
 	test_install_package sshfs
-	test_install_package swig 
-	test_install_package unzip 
+	test_install_package swig
+	test_install_package unzip
 #	test_install_package nettle-bin
 #	test_install_package nettle-dev
-	test_install_package valgrind 
+	test_install_package valgrind
 
-	if [ $OAI_INSTALLED = 1 ]; then 
+	if [ $OAI_INSTALLED = 1 ]; then
 	    touch ./.lock_oaibuild
-	fi 
-	
+	fi
+
     else
 	echo_info "All the required packages installed: skip"
-    fi 
+    fi
 
 }
 
 check_install_epc_software() {
 
-    if [ ! -f ./.lock_oaibuild ]; then 
+    if [ ! -f ./.lock_oaibuild ]; then
         $SUDO apt-get update
-        if [ $UBUNTU_REL = "12.04" ]; then 
+        if [ $UBUNTU_REL = "12.04" ]; then
             test_uninstall_package nettle-dev
             test_uninstall_package nettle-bin
-        else 
+        else
             test_install_package nettle-dev
             test_install_package nettle-bin
-        fi 
+        fi
         test_install_package autoconf
         test_install_package automake
         test_install_package bison
@@ -543,7 +545,7 @@ check_install_epc_software() {
         test_install_package gawk
         test_install_package gcc
         test_install_package gccxml
-        test_install_package gdb 
+        test_install_package gdb
         test_install_package guile-2.0-dev
         test_install_package gtkwave
         test_install_package iperf
@@ -573,7 +575,7 @@ check_install_epc_software() {
         test_install_package libsctp-dev
         test_install_package libssl-dev
         test_install_package libtasn1-3-dev
-        test_install_package libtool 
+        test_install_package libtool
         test_install_package libxml2
         test_install_package libxml2-dev
 #        test_install_package linux-headers-`uname -r`
@@ -593,21 +595,21 @@ check_install_epc_software() {
         test_install_package unzip
         test_install_package valgrind
         test_install_package vlan
-	
-        if [ $OAI_INSTALLED = 1 ]; then 
+
+        if [ $OAI_INSTALLED = 1 ]; then
             touch ./.lock_oaibuild
-        fi 
-    
+        fi
+
     else
         echo_info "All the required packages installed: skip"
-    fi 
+    fi
 
 }
 
 check_install_asn1c(){
-    
+
     test_command_install_script   "asn1c" "$OPENAIR_TARGETS/SCRIPTS/install_asn1c_0.9.24.modified.bash $SUDO"
-    
+
     # One mor check about version of asn1c
     ASN1C_COMPILER_REQUIRED_VERSION_MESSAGE="ASN.1 Compiler, v0.9.24"
     ASN1C_COMPILER_VERSION_MESSAGE=`asn1c -h 2>&1 | grep -i ASN\.1\ Compiler`
@@ -624,15 +626,15 @@ check_install_asn1c(){
             fi
         done
     fi
-    
+
 }
 
 #################################################
-# 2. compile 
+# 2. compile
 ################################################
 compile_hss() {
     cd $OPENAIR3_DIR/OPENAIRHSS
-    
+
     if [ "$1" -eq 1 ]; then
         echo_info "build a clean HSS"
         rm -rfv obj*
@@ -642,14 +644,14 @@ compile_hss() {
     fi
 
     OBJ_DIR=`find . -maxdepth 1 -type d -iname obj*`
-    
+
     if [ ! -n "$OBJ_DIR" ]; then
         OBJ_DIR="objs"
         mkdir --verbose -m 777 ./$OBJ_DIR
     else
         OBJ_DIR=`basename $OBJ_DIR`
     fi
-    
+
     if [ ! -f "$OBJ_DIR"/Makefile ]; then
         if [ ! -d m4 ]; then
             mkdir --verbose -m 777 m4
@@ -661,7 +663,7 @@ compile_hss() {
         fi
         cd $OBJ_DIR
         echo_success "Invoking configure"
-        ../configure 
+        ../configure
         if [ $? -ne 0 ]; then
             return 1
         fi
@@ -675,7 +677,7 @@ compile_hss() {
         if [ $? -ne 0 ]; then
             echo_error "Build failed, exiting"
             return 1
-        else 
+        else
             return 0
         fi
     else
@@ -705,11 +707,11 @@ compile_epc() {
         fi
         bash_exec "autoreconf -i -f"
         echo_success "Invoking autogen"
-        bash_exec "libtoolize"        
+        bash_exec "libtoolize"
         bash_exec "./autogen.sh"
         cd ./$OBJ_DIR
         echo_success "Invoking configure"
-        if [ $DEBUG -ne 0 ]; then 
+        if [ $DEBUG -ne 0 ]; then
             ../configure --enable-debug --enable-standalone-epc --enable-gtp1u-in-kernel LDFLAGS=-L/usr/local/lib
         else
             ../configure                --enable-standalone-epc --enable-gtp1u-in-kernel LDFLAGS=-L/usr/local/lib
@@ -727,30 +729,30 @@ compile_epc() {
         if [ $? -ne 0 ]; then
             echo_error "Build failed, exiting"
             return 1
-        else 
+        else
             cp -pf ./OAI_EPC/oai_epc  $OPENAIR_TARGETS/bin
         fi
     else
         echo_error "Configure failed, exiting"
         return 1
     fi
-    
+
     cd $OPENAIR3_DIR/GTPV1-U/GTPUAH;
     make
     if [ $? -ne 0 ]; then
         echo_error "Build GTPUAH module failed, exiting"
         return 1
-    else 
+    else
        	$SUDO cp -pfv ./Bin/libxt_*.so /lib/xtables
         $SUDO cp -pfv ./Bin/*.ko $OPENAIR_TARGETS/bin
     fi
-    
+
     cd $OPENAIR3_DIR/GTPV1-U/GTPURH;
     make
     if [ $? -ne 0 ]; then
         echo_error "Build GTPURH module failed, exiting"
         return 1
-    else 
+    else
        $SUDO cp -pfv ./Bin/libxt_*.so /lib/xtables
        $SUDO cp -pfv ./Bin/*.ko $OPENAIR_TARGETS/bin
     fi
@@ -777,15 +779,15 @@ compile_ltesoftmodem() {
         if [ $? -ne 0 ]; then
             # to locate easily compilation error in log file
             make  $SOFTMODEM_DIRECTIVES
-        fi 
+        fi
         if [ $? -ne 0 ]; then
-            if [ ! -f ./lte-softmodem ]; then 
+            if [ ! -f ./lte-softmodem ]; then
                 echo_error "Build lte-softmodem failed, returning"
                 return 1
-            else 
+            else
                 cp -pf ./lte-softmodem  $OPENAIR_TARGETS/bin
                 return 0
-            fi 
+            fi
         else
             cp -pf ./lte-softmodem  $OPENAIR_TARGETS/bin
             return 0
@@ -801,11 +803,11 @@ compile_oaisim() {
     if [ -f Makefile ]; then
         echo "Compiling for oaisim  target ($OAISIM_DIRECTIVES)"
         make cleanall > /dev/null
-        make -j $NUM_CPU $OAISIM_DIRECTIVES 
+        make -j $NUM_CPU $OAISIM_DIRECTIVES
         if [ $? -ne 0 ]; then
             echo_error "Build oaisim failed, returning"
             return 1
-        else 
+        else
             cp -pf ./oaisim $OPENAIR_TARGETS/bin
             return 0
         fi
@@ -820,11 +822,11 @@ compile_unisim() {
     if [ -f Makefile ]; then
         echo "Compiling for UNISIM target ..."
         make cleanall
-        make  -j $NUM_CPU all 
+        make  -j $NUM_CPU all
         if [ $? -ne 0 ]; then
             echo_error "Build unisim failed, returning"
             return 1
-        else 
+        else
             cp -pf ./dlsim     $OPENAIR_TARGETS/bin
             cp -pf ./ulsim     $OPENAIR_TARGETS/bin
             cp -pf ./pucchsim  $OPENAIR_TARGETS/bin
@@ -843,9 +845,9 @@ compile_unisim() {
 compile_nas_tools() {
 
     export NVRAM_DIR=$OPENAIR_TARGETS/bin
-    
+
     cd $NVRAM_DIR
-    
+
         if [ ! -f /tmp/nas_cleaned ]; then
             echo_success "make --directory=$OPENAIR3_DIR/NAS/EURECOM-NAS/tools veryveryclean"
             make --directory=$OPENAIR3_DIR/NAS/EURECOM-NAS/tools veryveryclean
@@ -963,11 +965,11 @@ check_for_nas_ue_executable() {
 ###############################################
 
 # arg1 is RT
-# arg2 is HW 
+# arg2 is HW
 # arg3 is ENB_S1
 install_ltesoftmodem() {
     # RT
-    if [ $1 = "RTAI" ]; then 
+    if [ $1 = "RTAI" ]; then
         if [ ! -f /tmp/init_rt_done.tmp ]; then
             echo_info "  8.1 Insert RTAI modules"
             $SUDO insmod /usr/realtime/modules/rtai_hal.ko     > /dev/null 2>&1
@@ -982,46 +984,46 @@ install_ltesoftmodem() {
         fi
     fi
     #HW
-    if [ $2 = "EXMIMO" ]; then 
+    if [ $2 = "EXMIMO" ]; then
 	echo_info "  8.2 [EXMIMO] creating RTAI fifos"
-	for i in `seq 0 64`; do 
+	for i in `seq 0 64`; do
 	    have_rtfX=`ls /dev/ |grep -c rtf$i`;
-	    if [ "$have_rtfX" -eq 0 ] ; then 
-		$SUDO mknod -m 666 /dev/rtf$i c 150 $i; 
+	    if [ "$have_rtfX" -eq 0 ] ; then
+		$SUDO mknod -m 666 /dev/rtf$i c 150 $i;
 	    fi;
 	done
 	echo_info "  8.3 [EXMIMO] Build lte-softmodemdrivers"
 	cd $OPENAIR_TARGETS/ARCH/EXMIMO/DRIVER/eurecom && make clean && make  # || exit 1
 	cd $OPENAIR_TARGETS/ARCH/EXMIMO/USERSPACE/OAI_FW_INIT && make clean && make  # || exit 1
-	
+
 	echo_info "  8.4 [EXMIMO] Setup RF card"
 	cd $OPENAIR_TARGETS/RT/USER
 	. ./init_exmimo2.sh
-    else 
+    else
 	if [ $2 = "USRP" ]; then
 	    echo_info "  8.2 [USRP] "
 	fi
 
     fi
-    
+
     # ENB_S1
-    if [ $3 = 0 ]; then 
+    if [ $3 = 0 ]; then
         cd $OPENAIR2_DIR && make clean && make nasmesh_netlink.ko  #|| exit 1
         cd $OPENAIR2_DIR/NAS/DRIVER/MESH/RB_TOOL && make clean && make  # || exit 1
     fi
-    
+
 }
 
 # arg1 is ENB_S1 'boolean'
 install_oaisim() {
-   if [ $1 = 0 ]; then 
+   if [ $1 = 0 ]; then
        cd $OPENAIR2_DIR && make clean && make nasmesh_netlink.ko  #|| exit 1
        cd $OPENAIR2_DIR/NAS/DRIVER/MESH/RB_TOOL && make clean && make  # || exit 1
    else
        compile_ue_ip_nw_driver
        install_nas_tools
-   fi 
-   
+   fi
+
 }
 
 
@@ -1041,7 +1043,7 @@ install_nas_tools() {
 }
 
 install_nasmesh(){
-    echo_success "LOAD NASMESH IP DRIVER FOR UE AND eNB" 
+    echo_success "LOAD NASMESH IP DRIVER FOR UE AND eNB"
     (cd $OPENAIR2_DIR/NAS/DRIVER/MESH/RB_TOOL && make clean && make)
     (cd $OPENAIR2_DIR && make clean && make nasmesh_netlink_address_fix.ko)
     $SUDO rmmod nasmesh
@@ -1069,7 +1071,7 @@ create_hss_database(){
     fi
 
     set_openair_env
-    
+
     # removed %
     #Q1="GRANT ALL PRIVILEGES ON *.* TO '$3'@'%' IDENTIFIED BY '$4' WITH GRANT OPTION;"
     Q1="GRANT ALL PRIVILEGES ON *.* TO '$3'@'localhost' IDENTIFIED BY '$4' WITH GRANT OPTION;"
@@ -1082,8 +1084,8 @@ create_hss_database(){
     else
        echo_success "$3 permissions succeeded"
     fi
-    
-    
+
+
     Q1="CREATE DATABASE IF NOT EXISTS ${BTICK}$5${BTICK};"
     SQL="${Q1}"
     $MYSQL -u $3 --password=$4 -e "$SQL"
@@ -1093,12 +1095,12 @@ create_hss_database(){
     else
        echo_success "$5 creation succeeded"
     fi
-    
-    
+
+
     # test if tables have been created
     mysql -u $3 --password=$4  -e "desc $5.users" > /dev/null 2>&1
-    
-    if [ $? -eq 1 ]; then 
+
+    if [ $? -eq 1 ]; then
         $MYSQL -u $3 --password=$4 $5 < $OPENAIR3_DIR/OPENAIRHSS/db/oai_db.sql
         if [ $? -ne 0 ]; then
             echo_error "$5 tables creation failed"
@@ -1107,7 +1109,7 @@ create_hss_database(){
             echo_success "$5 tables creation succeeded"
         fi
     fi
-    
+
     return 0
 }
 
@@ -1176,7 +1178,7 @@ print_help_perf(){
 
 }
 ###############################
-## echo and  family 
+## echo and  family
 ###############################
 black='\E[30m'
 red='\E[31m'
@@ -1196,10 +1198,10 @@ cecho()   # Color-echo
     local default_msg="No Message."
     message=${1:-$default_msg}
     color=${2:-$green}
-    if [ $BUILD_FROM_MAKEFILE = 0 ]; then 
+    if [ $BUILD_FROM_MAKEFILE = 0 ]; then
 	echo -e -n "$color$message$reset_color"
 	echo
-    else 
+    else
 	echo "$message"
     fi
     return
@@ -1304,7 +1306,7 @@ assert() {
     if [ -z "$2" ] ; then # Not enought parameters passed.
         return $E_PARAM_ERR
     fi
-    
+
     lineno=$2
     if [ ! $1 ]; then
         echo_error "Assertion failed:  \"$1\""