diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt
index 02a6ac51519d0f38f34bb20649aef48e7e131b8a..1027718d48d1e3cd8cd0aeb461f4c929ad22314c 100644
--- a/cmake_targets/CMakeLists.txt
+++ b/cmake_targets/CMakeLists.txt
@@ -976,6 +976,7 @@ set(PHY_SRC
   ${OPENAIR1_DIR}/PHY/MODULATION/slot_fep_ul.c
   ${OPENAIR1_DIR}/PHY/MODULATION/ul_7_5_kHz.c
   ${OPENAIR1_DIR}/PHY/MODULATION/beamforming.c
+  ${OPENAIR1_DIR}/PHY/MODULATION/compute_bf_weights.c
   ${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/freq_equalization.c
   ${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/lte_sync_time.c
   ${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/lte_sync_timefreq.c
diff --git a/openair1/PHY/LTE_TRANSPORT/defs.h b/openair1/PHY/LTE_TRANSPORT/defs.h
index 8bcf312c3e39a81ee0301009db78206c90f33a27..e0029be3182575f85e932fd1662429f4b9a5bbd3 100644
--- a/openair1/PHY/LTE_TRANSPORT/defs.h
+++ b/openair1/PHY/LTE_TRANSPORT/defs.h
@@ -242,6 +242,8 @@ typedef struct {
   int32_t *txdataF[8];
   /// beamforming weights for UE-spec transmission (antenna ports 5 or 7..14), for each codeword, maximum 4 layers?
   int32_t **ue_spec_bf_weights[4]; 
+  /// dl channel estimates (estimated from ul channel estimates)
+  int32_t **calib_dl_ch_estimates;
   /// Allocated RNTI (0 means DLSCH_t is not currently used)
   uint16_t rnti;
   /// Active flag for baseband transmitter processing
diff --git a/openair1/PHY/MODULATION/beamforming.c b/openair1/PHY/MODULATION/beamforming.c
index 2e38b7cb93bc0e722e238d9b3a238e3954516593..00bb9e5dcaef09ba92aae988e16193ac2fb800b7 100644
--- a/openair1/PHY/MODULATION/beamforming.c
+++ b/openair1/PHY/MODULATION/beamforming.c
@@ -120,4 +120,3 @@ int beam_precoding(int32_t **txdataF,
     }  
   }
 }
-
diff --git a/openair1/PHY/MODULATION/compute_bf_weights.c b/openair1/PHY/MODULATION/compute_bf_weights.c
new file mode 100644
index 0000000000000000000000000000000000000000..32a91c11f50706718e3c75823ec48a67c6d9806c
--- /dev/null
+++ b/openair1/PHY/MODULATION/compute_bf_weights.c
@@ -0,0 +1,56 @@
+#include <stdio.h>
+#include <stdint.h>
+#include "PHY/impl_defs_lte.h"
+
+int f_read(char *calibF_fname, int nb_ant, int nb_freq, int32_t **tdd_calib_coeffs){
+
+  FILE *calibF_fd;
+  int i,j,l,calibF_e;
+  
+  calibF_fd = fopen(calibF_fname,"r");
+ 
+  if (calibF_fd) {
+    printf("Loading Calibration matrix from %s\n", calibF_fname);
+  
+    for(i=0;i<nb_ant;i++){
+      for(j=0;j<nb_freq*2;j++){
+  fscanf(calibF_fd, "%d", &calibF_e);
+        tdd_calib_coeffs[i][j] = (int16_t)calibF_e;
+      }
+    }
+    printf("%d\n",(int)tdd_calib_coeffs[0][0]);
+    printf("%d\n",(int)tdd_calib_coeffs[1][599]);
+  } else
+   printf("%s not found, running with defaults\n",calibF_fname);
+}
+
+
+int estimate_DLCSI_from_ULCSI(int32_t **calib_dl_ch_estimates, int32_t **ul_ch_estimates, int32_t **tdd_calib_coeffs, int nb_ant, int nb_freq) {
+
+
+}
+
+int compute_BF_weights(int32_t **beam_weights, int32_t **calib_dl_ch_estimates, PRECODE_TYPE_t precode_type, int nb_ant, int nb_freq) {
+  switch (precode_type) {
+  //case MRT
+  case 0 :
+  //case ZF
+  break;
+  case 1 :
+  //case MMSE
+  break;
+  case 2 :
+  break;
+  default :
+  break;  
+}
+} 
+
+// temporal test function
+/*
+void main(){
+  // initialization
+  // compare
+  printf("Hello world!\n");
+}
+*/
diff --git a/openair1/PHY/MODULATION/defs.h b/openair1/PHY/MODULATION/defs.h
index 1c1cd196ff9839b2d907de151bed931bb70b8598..597d433df84a12d8361846b0ce572ef2cf7eea93 100644
--- a/openair1/PHY/MODULATION/defs.h
+++ b/openair1/PHY/MODULATION/defs.h
@@ -118,6 +118,13 @@ int beam_precoding(int32_t **txdataF,
                    int slot,
                    int symbol);
 
+int f_read(char *calibF_fname, int nb_ant, int nb_freq, int32_t **tdd_calib_coeffs);
+
+int estimate_DLCSI_from_ULCSI(int32_t **calib_dl_ch_estimates, int32_t **ul_ch_estimates, int32_t **tdd_calib_coeffs, int nb_ant, int nb_freq);
+
+int compute_BF_weights(int32_t **beam_weights, int32_t **calib_dl_ch_estimates, PRECODE_TYPE_t precode_type, int nb_ant, int nb_freq);
+
+
 #endif
 /** @}*/
 #endif
diff --git a/openair1/PHY/impl_defs_lte.h b/openair1/PHY/impl_defs_lte.h
index f61aa2dcc9f5f46bbe832b8848d853bac0a8f595..9d075dd9bb4c2cffe1fc47b763dd49f28609a6ea 100644
--- a/openair1/PHY/impl_defs_lte.h
+++ b/openair1/PHY/impl_defs_lte.h
@@ -593,6 +593,15 @@ typedef enum {
   TM9_10=14
 } MIMO_mode_t;
 
+typedef enum {
+  /// MRT
+  MRT=0,
+  /// ZF
+  ZF=1,
+  /// MMSE
+  MMSE=2
+} PRECODE_TYPE_t;
+
 typedef struct {
   /// \brief Holds the transmit data in time domain.
   /// For IFFT_FPGA this points to the same memory as PHY_vars->rx_vars[a].RX_DMA_BUFFER.
@@ -632,18 +641,16 @@ typedef struct {
   /// - first index: eNB id [0..2] (hard coded)
   /// - second index: sample [0..samples_per_tti*10[
   uint32_t *sync_corr[3];
-  // int32_t **beam_weights[3][15];
   /// \brief Holds the beamforming weights
   /// - first index: eNB id [0..2] (hard coded)
-  /// - second index: eNB antenna port index
+  /// - second index: eNB antenna port index (hard coded)
   /// - third index: tx antenna [0..nb_antennas_tx[
   /// - fourth index: sample [0..]
   int32_t **beam_weights[3][15];
   /// \brief Holds the tdd reciprocity calibration coefficients 
   /// - first index: eNB id [0..2] (hard coded) 
-  /// - second index: ue specific eNB antenna port index, port5->index0, port7-15->index0-7
-  /// - third index: tx antenna [0..nb_antennas_tx[
-  /// - forth index: frenquency [0..]
+  /// - second index: tx antenna [0..nb_antennas_tx[
+  /// - third index: frequency [0..]
   int32_t **tdd_calib_coeffs[3];
 } LTE_eNB_COMMON;
 
diff --git a/openair1/SIMULATION/LTE_PHY/dlsim.c b/openair1/SIMULATION/LTE_PHY/dlsim.c
index dd535064d1743ad5e860110607d7f3603166439e..1a34e59f5a30f6dc3ac421ae9e65724c914de452 100644
--- a/openair1/SIMULATION/LTE_PHY/dlsim.c
+++ b/openair1/SIMULATION/LTE_PHY/dlsim.c
@@ -991,6 +991,9 @@ int main(int argc, char **argv)
       PHY_vars_eNB->eNB_UE_stats[1].DL_pmi_single = 0;
   }
 
+  //TODO: allocate memory for calibration matrix and calib_dl_ch_estimates in init_lte.c
+  //for first tests initialze calibration matrix with idendity
+  //read_calibration_matrix(calib_fname, nb_ant, nb_freq, PHY_vars_eNB->lte_eNB_common_vars.tdd_calib_coeffs[0]);
 
   if (input_fd==NULL) {
 
@@ -2142,6 +2145,32 @@ int main(int argc, char **argv)
 
 PMI_FEEDBACK:
 
+	  //make sure dlsim is called with perfect channel estimation option (for freq_channel)
+	  //fill drs_ch_estimates with data from eNB2UE->chF
+	  for(aa=0; aa<frame_parms->nb_antenna_ports_eNB; aa++) {
+	    for (aarx=0; aarx<frame_parms->nb_antennas_rx; aarx++) {
+	      for (i=0; i<frame_parms->N_RB_DL*12; i++) {
+		for (l=0; l<frame_parms->symbols_per_tti; l++) {
+		  ((int16_t *) PHY_vars_eNB->lte_eNB_pusch_vars[0]->drs_ch_estimates[0][(aa<<1)+aarx])[2*i+(l*frame_parms->ofdm_symbol_size)*2]=(int16_t)(eNB2UE[round]->chF[aarx+(aa*frame_parms->nb_antennas_rx)][i].x*AMP);
+                          //printf("x=%d,AMP=%d\n",eNB2UE[round]->chF[aarx+(aa*frame_parms->nb_antennas_rx)][i].x,AMP);
+		  ((int16_t *) PHY_vars_eNB->lte_eNB_pusch_vars[0]->drs_ch_estimates[0][(aa<<1)+aarx])[2*i+1+(l*frame_parms->ofdm_symbol_size)*2]=(int16_t)(eNB2UE[round]->chF[aarx+(aa*frame_parms->nb_antennas_rx)][i].y*AMP);
+		}
+	      }
+	    }
+	  }
+
+	  estimate_DLCSI_from_ULCSI(PHY_vars_eNB->dlsch_eNB[0][0]->calib_dl_ch_estimates,
+					 &PHY_vars_eNB->lte_eNB_pusch_vars[0]->drs_ch_estimates[0][0/*position of second DMRS*/],
+					 PHY_vars_eNB->lte_eNB_common_vars.tdd_calib_coeffs[0],
+					 frame_parms->nb_antennas_tx,
+					 frame_parms->N_RB_DL*12);
+	  
+	  compute_BF_weights(PHY_vars_eNB->dlsch_eNB[0][0]->ue_spec_bf_weights[0],
+			     PHY_vars_eNB->dlsch_eNB[0][0]->calib_dl_ch_estimates,
+			     MRT,
+			     frame_parms->nb_antennas_tx,
+			     frame_parms->N_RB_DL*12);
+
           //printf("Trial %d : Round %d, pmi_feedback %d \n",trials,round,pmi_feedback);
           for (aa=0; aa<NB_ANTENNA_PORTS_ENB; aa++) {
             memset(&PHY_vars_eNB->lte_eNB_common_vars.txdataF[eNB_id][aa][0],0,FRAME_LENGTH_COMPLEX_SAMPLES_NO_PREFIX*sizeof(int32_t));
@@ -3088,6 +3117,7 @@ PMI_FEEDBACK:
                                 eNB2UE[round]->chF[aarx+(aa*frame_parms->nb_antennas_rx)][i].y*AMP);
 
                           if (transmission_mode == 7){
+			    //this should include the BF weights! Will not work for a random channel
                             if (PHY_vars_UE->high_speed_flag==0) {
                               ((int16_t *)PHY_vars_UE->lte_ue_pdsch_vars[0]->dl_bf_ch_estimates[(aa<<1)+aarx])[2*i]=(int16_t)(
                                   eNB2UE[round]->chF[aarx+(aa*frame_parms->nb_antennas_rx)][i].x*AMP);