diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt
index c4d3d7e62e2c75425cd21c7864b613ae41dcbd18..e62d8fe33c95df999868bd43e3dc73f0bd2c46a9 100644
--- a/cmake_targets/CMakeLists.txt
+++ b/cmake_targets/CMakeLists.txt
@@ -1298,14 +1298,35 @@ set(PHY_SMALLBLOCKSRC
 set(PHY_TURBOIF
   ${OPENAIR1_DIR}/PHY/CODING/coding_load.c
 )
-set(PHY_LDPCSRC
+
+set(PHY_LDPC_ORIG_SRC
   ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.c
   ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_encoder/ldpc_encoder.c
-  ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_encoder/ldpc_encoder2.c
-  ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_encoder/ldpc_generate_coefficient.c
 )
 
+set(PHY_LDPC_OPTIM_SRC
+  ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.c
+  ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_encoder/ldpc_encoder_optim.c
+)
+set(PHY_LDPC_OPTIM8SEG_SRC
+  ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.c
+  ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_encoder/ldpc_encoder_optim8seg.c
+)
+set(PHY_LDPC_OPTIM8SEGMULTI_SRC
+  ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.c
+  ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_encoder/ldpc_encoder_optim8segmulti.c
+)
+set(PHY_NR_CODINGIF
+  ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_load.c;
+)
+
+add_library(ldpc_orig MODULE ${PHY_LDPC_ORIG_SRC} )
+add_library(ldpc_optim MODULE ${PHY_LDPC_OPTIM_SRC} )
+add_library(ldpc_optim8seg MODULE ${PHY_LDPC_OPTIM8SEG_SRC} )
+add_library(ldpc MODULE ${PHY_LDPC_OPTIM8SEGMULTI_SRC} )
+
 add_library(coding MODULE ${PHY_TURBOSRC} )
+
 set(PHY_SRC_COMMON
   ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/dci_tools_common.c
   ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/lte_mcs.c
@@ -1467,6 +1488,7 @@ set(PHY_SRC_UE
   ${OPENAIR1_DIR}/PHY/NR_REFSIG/nr_dmrs_rx.c
   ${OPENAIR1_DIR}/PHY/NR_REFSIG/nr_gold.c
   ${OPENAIR1_DIR}/PHY/NR_REFSIG/dmrs_nr.c
+  ${OPENAIR1_DIR}/PHY/NR_REFSIG/ptrs_nr.c
   ${OPENAIR1_DIR}/PHY/NR_UE_ESTIMATION/filt16a_32.c
   ${OPENAIR1_DIR}/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c
   ${OPENAIR1_DIR}/PHY/NR_ESTIMATION/nr_adjust_sync_gNB.c
@@ -1484,10 +1506,9 @@ set(PHY_SRC_UE
   ${OPENAIR1_DIR}/PHY/TOOLS/lut.c
   ${PHY_POLARSRC}
   ${PHY_SMALLBLOCKSRC}
-  ${PHY_LDPCSRC}
+  ${PHY_NR_CODINGIF}
   ${OPENAIR1_DIR}/PHY/NR_TRANSPORT/pucch_rx.c 
   )
-
   set(PHY_NR_UE_SRC
   ${OPENAIR1_DIR}/PHY/INIT/nr_parms.c
   ${OPENAIR1_DIR}/PHY/MODULATION/nr_modulation.c
@@ -1513,6 +1534,7 @@ set(PHY_SRC_UE
   ${OPENAIR1_DIR}/PHY/NR_REFSIG/ul_ref_seq_nr.c
   ${OPENAIR1_DIR}/PHY/NR_REFSIG/nr_dmrs_rx.c
   ${OPENAIR1_DIR}/PHY/NR_REFSIG/dmrs_nr.c
+  ${OPENAIR1_DIR}/PHY/NR_REFSIG/ptrs_nr.c
   ${OPENAIR1_DIR}/PHY/NR_REFSIG/nr_gold_ue.c
   ${OPENAIR1_DIR}/PHY/NR_UE_ESTIMATION/filt16a_32.c
   ${OPENAIR1_DIR}/PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c
@@ -1535,7 +1557,7 @@ set(PHY_SRC_UE
   #  ${OPENAIR1_DIR}/SIMULATION/NR_UE_PHY/unit_tests/src/pucch_uci_test.c
   ${PHY_POLARSRC}
   ${PHY_SMALLBLOCKSRC}
-  ${PHY_LDPCSRC}
+  ${PHY_NR_CODINGIF}
   )
 
 
@@ -2588,7 +2610,7 @@ target_link_libraries (nr-softmodem pthread m ${CONFIG_LIB} rt crypt ${CRYPTO_LI
 target_link_libraries (nr-softmodem ${LIB_LMS_LIBRARIES})
 target_link_libraries (nr-softmodem ${T_LIB})
 
-
+add_dependencies( nr-softmodem ldpc_orig ldpc_optim ldpc_optim8seg ldpc )
 # nr-uesoftmodem is  UE implementation
 #######################################
 
@@ -2629,7 +2651,7 @@ target_link_libraries (nr-uesoftmodem pthread m ${CONFIG_LIB} rt crypt ${CRYPTO_
 target_link_libraries (nr-uesoftmodem ${LIB_LMS_LIBRARIES})
 target_link_libraries (nr-uesoftmodem ${T_LIB})
 
-
+add_dependencies( nr-uesoftmodem ldpc_orig ldpc_optim ldpc_optim8seg ldpc )
 
 # USIM process
 #################
@@ -2696,10 +2718,13 @@ target_link_libraries(smallblocktest
   )
 
 add_executable(ldpctest  
+  ${PHY_NR_CODINGIF}
   ${OPENAIR1_DIR}/PHY/CODING/TESTBENCH/ldpctest.c
   ${T_SOURCE}
   ${SHLIB_LOADER_SOURCES}
   )
+add_dependencies( ldpctest ldpc_orig ldpc_optim ldpc_optim8seg ldpc ) 
+
 target_link_libraries(ldpctest
   -Wl,--start-group UTIL SIMU PHY_NR CONFIG_LIB -Wl,--end-group
   m pthread ${ATLAS_LIBRARIES} dl
diff --git a/common/config/config_userapi.c b/common/config/config_userapi.c
index 67fdc2c920c17df6a29d32881875677036a21a7f..c951905101b314eccaf8f5354b1eabb83751a57f 100644
--- a/common/config/config_userapi.c
+++ b/common/config/config_userapi.c
@@ -45,7 +45,8 @@
 
 configmodule_interface_t *config_get_if(void) {
   if (cfgptr == NULL) {
-    CONFIG_PRINTF_ERROR("[CONFIG] %s %d config module not initialized\n",__FILE__,__LINE__);
+  	if (isLogInitDone())
+       LOG_W(ENB_APP,"[CONFIG] %s %d config module not initialized\n",__FILE__,__LINE__);
   }
 
   return cfgptr;
diff --git a/common/utils/telnetsrv/telnetsrv.c b/common/utils/telnetsrv/telnetsrv.c
index 10163b22b5c0a8bb380b762b9608d596fbffbbe2..06a5d350c75a452ef18e325813de53453912d66d 100644
--- a/common/utils/telnetsrv/telnetsrv.c
+++ b/common/utils/telnetsrv/telnetsrv.c
@@ -377,6 +377,14 @@ int setgetvar(int moduleindex,char getorset,char *params) {
             client_printf("%hi\n",*(short *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr));
             break;
 
+          case TELNET_VARTYPE_INT8:
+            client_printf("%i\n",(int)(*(int8_t *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr)));
+            break;
+            
+          case TELNET_VARTYPE_UINT:
+            client_printf("%u\n",*(unsigned int *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr));
+            break;
+            
           case TELNET_VARTYPE_DOUBLE:
             client_printf("%g\n",*(double *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr));
             break;
@@ -405,7 +413,17 @@ int setgetvar(int moduleindex,char getorset,char *params) {
             *(short *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr) = (short)strtol(varval,NULL,0);
             client_printf("%hi\n",*(short *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr));
             break;
-
+            
+          case TELNET_VARTYPE_INT8:
+            *(char *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr) = (char)strtol(varval,NULL,0);
+            client_printf("%i\n",*(int *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr));
+            break;
+            
+          case TELNET_VARTYPE_UINT:
+            *(unsigned int *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr) = (unsigned int)strtol(varval,NULL,0);
+            client_printf("%u\n",*(unsigned int *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr));
+            break;
+ 
           case TELNET_VARTYPE_DOUBLE:
             *(double *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr) = strtod(varval,NULL);
             client_printf("%g\n",*(double *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr));
diff --git a/openair1/PHY/CODING/DOC/LDPCImplementation.md b/openair1/PHY/CODING/DOC/LDPCImplementation.md
new file mode 100644
index 0000000000000000000000000000000000000000..89ae6b4dbb64a28935436e59b40b39724f0c7d2e
--- /dev/null
+++ b/openair1/PHY/CODING/DOC/LDPCImplementation.md
@@ -0,0 +1,26 @@
+#LDPC coder/decoder implementation
+The LDPC coder and decoder are implemented in a shared library, dynamically loaded at run-time using the [oai shared library loader](file://../../../../common/utils/DOC/loader.md). The code loading the LDPC library is in [nrLDPC_load.c](file://../nrLDPC_load.c), in function `load_nrLDPClib`, which must be called at init time.
+
+## Selecting the LDPC library at run time
+
+By default the function `int load_nrLDPClib(void)` looks for `libldpc.so`, this default behavior can be changed using the oai loader configuration options in the configuration file or from the command line as shown below:
+
+>loading `libldpc_optim8seg.so` instead of `libldpc.so`
+
+```
+./nr-softmodem -O libconfig:gnb.band78.tm1.106PRB.usrpx300.conf:dbgl5  --loader.ldpc.shlibversion _optim8seg
+.......................
+[CONFIG] loader.ldpc.shlibversion set to default value ""
+[LIBCONFIG] loader.ldpc: 2/2 parameters successfully set, (1 to default value)
+[CONFIG] shlibversion set to  _optim8seg from command line
+[CONFIG] loader.ldpc 1 options set from command line
+[LOADER] library libldpc_optim8seg.so successfully loaded
+........................
+```
+
+Today, this mechanism is not available in the `ldpctest` phy simulator which doesn't initialize the [configuration module](file://../../../../common/config/DOC/config.md). loads `libldpc.so` and `libldpc_orig.so` to compare the performance of the two implementations.
+
+###LDPC libraries
+Libraries implementing the LDPC algorithms must be named `libldpc<_version>.so`, they must implement two functions: `nrLDPC_decod` and `nrLDPC_encod`. The prototypes for these functions is defined in [nrLDPC_defs.h](file://nrLDPC_defs.h).
+
+[oai Wikis home](https://gitlab.eurecom.fr/oai/openairinterface5g/wikis/home)
diff --git a/openair1/PHY/CODING/TESTBENCH/ldpctest.c b/openair1/PHY/CODING/TESTBENCH/ldpctest.c
index 95ee3fed170f5895f2f6048cb4bfb8f9bfc98686..552af99c41e78e3de1ddf114c3a90fcc13d33e57 100644
--- a/openair1/PHY/CODING/TESTBENCH/ldpctest.c
+++ b/openair1/PHY/CODING/TESTBENCH/ldpctest.c
@@ -25,8 +25,7 @@
 #include <string.h>
 #include "assertions.h"
 #include "SIMULATION/TOOLS/sim.h"
-#include "PHY/CODING/nrLDPC_encoder/defs.h"
-#include "PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.h"
+#include "PHY/CODING/nrLDPC_extern.h"
 #include "openair1/SIMULATION/NR_PHY/nr_unitary_defs.h"
 
 #define MAX_NUM_DLSCH_SEGMENTS 16
@@ -85,6 +84,7 @@ typedef struct {
 RAN_CONTEXT_t RC;
 PHY_VARS_UE ***PHY_vars_UE_g;
 uint16_t NB_UE_INST = 1;
+nrLDPC_encoderfunc_t encoder_orig;
 
 short lift_size[51]= {2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,18,20,22,24,26,28,30,32,36,40,44,48,52,56,60,64,72,80,88,96,104,112,120,128,144,160,176,192,208,224,240,256,288,320,352,384};
 
@@ -286,16 +286,19 @@ int test_ldpc(short No_iteration,
   no_punctured_columns=(int)((nrows-2)*Zc+block_length-block_length*(1/((float)nom_rate/(float)denom_rate)))/Zc;
   //  printf("puncture:%d\n",no_punctured_columns);
   removed_bit=(nrows-no_punctured_columns-2) * Zc+block_length-(int)(block_length/((float)nom_rate/(float)denom_rate));
+  encoder_implemparams_t impp=INIT0_LDPCIMPLEMPARAMS;
+ 
+  impp.gen_code=1;
   if (ntrials==0)
-    ldpc_encoder_orig(test_input[0],channel_input[0], Zc, BG, block_length, BG, 1);
-
+    encoder_orig(test_input,channel_input, Zc, BG, block_length, BG, &impp);
+  impp.gen_code=0;
   for (trial=0; trial < ntrials; trial++)
   {
 	segment_bler = 0;
     //// encoder
     start_meas(&time);
     for(j=0;j<n_segments;j++) {
-      ldpc_encoder_orig(test_input[j], channel_input[j],Zc,Kb,block_length,BG,0);
+      encoder_orig(&(test_input[j]), &(channel_input[j]),Zc,Kb,block_length,BG,&impp);
     }
     stop_meas(&time);
 
@@ -305,10 +308,11 @@ int test_ldpc(short No_iteration,
       ldpc_encoder_optim(test_input[j],channel_input_optim[j],Zc,Kb,block_length,BG,&tinput,&tprep,&tparity,&toutput);
       }
     stop_meas(time_optim);*/
-
+    impp.n_segments=n_segments;
     for(j=0;j<(n_segments/8+1);j++) {
     	start_meas(time_optim);
-    	ldpc_encoder_optim_8seg_multi(test_input,channel_input_optim,Zc,Kb,block_length, BG, n_segments,j,&tinput,&tprep,&tparity,&toutput);
+    	impp.macro_num=j;
+    	nrLDPC_encoder(test_input,channel_input_optim,Zc,Kb,block_length, BG, &impp);
     	stop_meas(time_optim);
     }
     
@@ -598,8 +602,8 @@ int main(int argc, char *argv[])
   printf("SNR0 %f: \n", SNR0);
 
 
-
-
+  load_nrLDPClib();
+  load_nrLDPClib_ref("_orig", &encoder_orig);
   //for (block_length=8;block_length<=MAX_BLOCK_LENGTH;block_length+=8)
 
 
diff --git a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.c b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.c
index d3e851f07bf2fec6e695a7dd9f3c3e924321a4b3..3226c97f8759ed856232277efd052527f68678eb 100644
--- a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.c
+++ b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.c
@@ -31,7 +31,7 @@
 
 #include <stdint.h>
 #include <immintrin.h>
-#include "nrLDPC_defs.h"
+#include "nrLDPCdecoder_defs.h"
 #include "nrLDPC_types.h"
 #include "nrLDPC_init.h"
 #include "nrLDPC_mPass.h"
@@ -47,7 +47,7 @@
 
 static inline uint32_t nrLDPC_decoder_core(int8_t* p_llr, int8_t* p_out, t_nrLDPC_procBuf* p_procBuf, uint32_t numLLR, t_nrLDPC_lut* p_lut, t_nrLDPC_dec_params* p_decParams, t_nrLDPC_time_stats* p_profiler);
 
-int32_t nrLDPC_decoder(t_nrLDPC_dec_params* p_decParams, int8_t* p_llr, int8_t* p_out, t_nrLDPC_procBuf* p_procBuf, t_nrLDPC_time_stats* p_profiler)
+int32_t nrLDPC_decod(t_nrLDPC_dec_params* p_decParams, int8_t* p_llr, int8_t* p_out, t_nrLDPC_procBuf* p_procBuf, t_nrLDPC_time_stats* p_profiler)
 {
     uint32_t numLLR;
     uint32_t numIter = 0;
diff --git a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_init.h b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_init.h
index 82462c6d95a7c0f082a5fa92dbb9b2402736bf26..ea031dc2daee68539a0e4d0450dcdec6be9b525f 100644
--- a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_init.h
+++ b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_init.h
@@ -32,7 +32,7 @@
 #define __NR_LDPC_INIT__H__
 
 #include "nrLDPC_lut.h"
-#include "nrLDPC_defs.h"
+#include "nrLDPCdecoder_defs.h"
 
 /**
    \brief Initializes the decoder and sets correct LUTs
diff --git a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_init_mem.h b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_init_mem.h
index bdaa118e1f338f9fa8717e9f22b9511ec34304be..3292c0debefc82ffb5ef9dbc71d6c2d39791747d 100644
--- a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_init_mem.h
+++ b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_init_mem.h
@@ -32,7 +32,6 @@
 #define __NR_LDPC_INIT_MEM__H__
 
 #include <stdlib.h>
-#include "nrLDPC_defs.h"
 #include "nrLDPC_types.h"
 
 #ifndef malloc32_clear
diff --git a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_mPass.h b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_mPass.h
index 66715618d05b717fe3cf684d137ba9a2a1fe9c64..7d0f5f077a90bd7b00ceebbe4eb07b96149c2d70 100644
--- a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_mPass.h
+++ b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_mPass.h
@@ -32,7 +32,7 @@
 #define __NR_LDPC_MPASS__H__
 
 #include <string.h>
-#include "nrLDPC_defs.h"
+#include "nrLDPCdecoder_defs.h"
 
 /**
    \brief Circular memcpy
diff --git a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_types.h b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_types.h
index 34322a7780568f86dd4a8bb793b18fc8fffa57d6..e5b99246d533fa14675565e57115343b327d586e 100644
--- a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_types.h
+++ b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_types.h
@@ -32,8 +32,7 @@
 #define __NR_LDPC_TYPES__H__
 
 #include "PHY/TOOLS/time_meas.h"
-#include "nrLDPC_defs.h"
-
+#include "nrLDPCdecoder_defs.h"
 // ==============================================================================
 // TYPES
 
@@ -103,4 +102,6 @@ typedef struct nrLDPC_procBuf {
     int8_t* llrProcBuf; /**< LLR processing buffer */
 } t_nrLDPC_procBuf;
 
+
+
 #endif
diff --git a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_defs.h b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPCdecoder_defs.h
similarity index 99%
rename from openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_defs.h
rename to openair1/PHY/CODING/nrLDPC_decoder/nrLDPCdecoder_defs.h
index 940d842550ea116aa496d3d81a1449e43dd7bb6b..69fc88752fb44b5737ad11a0bd8285f7cba05e86 100644
--- a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_defs.h
+++ b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPCdecoder_defs.h
@@ -19,7 +19,7 @@
  *      contact@openairinterface.org
  */
 
-/*!\file nrLDPC_defs.h
+/*!\file nrLDPCdecoder_defs.h
  * \brief Defines all constants and buffers for the LDPC decoder
  * \author Sebastian Wagner (TCL Communications) Email: <mailto:sebastian.wagner@tcl.com>
  * \date 27-03-2018
diff --git a/openair1/PHY/CODING/nrLDPC_defs.h b/openair1/PHY/CODING/nrLDPC_defs.h
new file mode 100644
index 0000000000000000000000000000000000000000..b96067f4b6eddfe4ca9e1652689aa69d44074833
--- /dev/null
+++ b/openair1/PHY/CODING/nrLDPC_defs.h
@@ -0,0 +1,59 @@
+/*
+ * 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
+ */
+//============================================================================================================================
+// encoder interface
+#ifndef __NRLDPC_DEFS__H__
+#define __NRLDPC_DEFS__H__
+#include "openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_types.h"
+/**
+   \brief LDPC encoder
+   \param 1 input
+   \param 2 channel_input
+   \param 3 int Zc
+   \param 4 int Kb
+   \param 5 short block_length
+   \param 6 short BG
+   \param 7 int n_segment
+   \param 8 unsigned int macro_num
+   \param 9-12 time_stats_t *tinput,*tprep, *tparity,*toutput
+*/
+typedef struct {
+	int n_segments;          // optim8seg
+	unsigned int macro_num; // optim8segmulti
+	unsigned char gen_code; //orig
+	time_stats_t *tinput;
+	time_stats_t *tprep;
+	time_stats_t *tparity;
+	time_stats_t *toutput;
+}encoder_implemparams_t;
+#define INIT0_LDPCIMPLEMPARAMS {0,0,0,NULL,NULL,NULL,NULL}
+typedef int(*nrLDPC_encoderfunc_t)(unsigned char **,unsigned char **,int,int,short, short, encoder_implemparams_t*);
+//============================================================================================================================
+// decoder interface
+/**
+   \brief LDPC decoder API type definition
+   \param p_decParams LDPC decoder parameters
+   \param p_llr Input LLRs
+   \param p_llrOut Output vector
+   \param p_profiler LDPC profiler statistics
+*/
+typedef int32_t(*nrLDPC_decoderfunc_t)(t_nrLDPC_dec_params* , int8_t*, int8_t* , t_nrLDPC_procBuf* , t_nrLDPC_time_stats* );
+#endif
\ No newline at end of file
diff --git a/openair1/PHY/CODING/nrLDPC_encoder/defs.h b/openair1/PHY/CODING/nrLDPC_encoder/defs.h
deleted file mode 100644
index 85cb852fe50042ace84d000da4b445e4df851d51..0000000000000000000000000000000000000000
--- a/openair1/PHY/CODING/nrLDPC_encoder/defs.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * 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
- */
-
-/*!\file defs.h
- * \brief LDPC encoder forward declarations
- * \author Florian Kaltenberger, Raymond Knopp, Kien le Trung (Eurecom)
- * \email openair_tech@eurecom.fr
- * \date 27-03-2018
- * \version 1.0
- * \note
- * \warning
- */
-
-#include "PHY/TOOLS/time_meas.h"
-
-/*ldpc_encoder.c*/
-int encode_parity_check_part_orig(unsigned char *c,unsigned char *d, short BG,short Zc,short Kb,short block_length);
-
-/*ldpc_encoder2.c*/
-void encode_parity_check_part_optim(uint8_t *c,uint8_t *d, short BG,short Zc,short Kb);
-int ldpc_encoder_optim(unsigned char *test_input,unsigned char *channel_input,int Zc,int Kb,short block_length,short BG,time_stats_t *tinput,time_stats_t *tprep,time_stats_t *tparity,time_stats_t *toutput);
-int ldpc_encoder_optim_8seg(unsigned char **test_input,unsigned char **channel_input,int Zc,int Kb,short block_length,short BG,int n_segments,time_stats_t *tinput,time_stats_t *tprep,time_stats_t *tparity,time_stats_t *toutput);
-int ldpc_encoder_optim_8seg_multi(unsigned char **test_input,unsigned char **channel_input,int Zc,int Kb,short block_length, short BG, int n_segments,unsigned int macro_num, time_stats_t *tinput,time_stats_t *tprep,time_stats_t *tparity,time_stats_t *toutput);
-
-/*ldpc_generate_coefficient.c*/
-int ldpc_encoder_orig(unsigned char *test_input,unsigned char *channel_input,int Zc,int Kb,short block_length,short BG,unsigned char gen_code);
-
-/*
-int encode_parity_check_part(unsigned char *c,unsigned char *d, short BG,short Zc,short Kb);
-int encode_parity_check_part_orig(unsigned char *c,unsigned char *d, short BG,short Zc,short Kb,short block_length);
-int ldpc_encoder(unsigned char *test_input,unsigned char *channel_input,short block_length, double rate);
-int ldpc_encoder_orig(unsigned char *test_input,unsigned char *channel_input,short block_length,int nom_rate,int denom_rate,unsigned char gen_code);
-int ldpc_encoder_multi_segment(unsigned char **test_input,unsigned char **channel_input,short block_length,double rate,uint8_t n_segments);
-int ldpc_encoder_optim(unsigned char *test_input,unsigned char *channel_input,short block_length,int nom_rate,int denom_rate,time_stats_t *tinput,time_stats_t *tprep,time_stats_t *tparity,time_stats_t *toutput);
-int ldpc_encoder_optim_8seg(unsigned char **test_input,unsigned char **channel_input,short block_length,int nom_rate,int denom_rate,int n_segments,time_stats_t *tinput,time_stats_t *tprep,time_stats_t *tparity,time_stats_t *toutput);
-*/
diff --git a/openair1/PHY/CODING/nrLDPC_encoder/ldpc_encode_parity_check.c b/openair1/PHY/CODING/nrLDPC_encoder/ldpc_encode_parity_check.c
new file mode 100644
index 0000000000000000000000000000000000000000..738fd49b7d36b1892aa3868a5f6d0c65baf6bbb3
--- /dev/null
+++ b/openair1/PHY/CODING/nrLDPC_encoder/ldpc_encode_parity_check.c
@@ -0,0 +1,201 @@
+/*
+ * 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
+ */
+
+/*!\file ldpc_encode_parity_check.c
+ * \brief Parity check function used by ldpc encoders
+ * \author Florian Kaltenberger, Raymond Knopp, Kien le Trung (Eurecom)
+ * \email openair_tech@eurecom.fr
+ * \date 27-03-2018
+ * \version 1.0
+ * \note
+ * \warning
+ */
+
+#include <stdlib.h>
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+#include <types.h>
+#include "assertions.h"
+#include "common/utils/LOG/log.h"
+
+
+//#define DEBUG_LDPC
+
+#include "ldpc384_byte.c"
+#include "ldpc352_byte.c"
+#include "ldpc320_byte.c"
+#include "ldpc288_byte.c"
+#include "ldpc256_byte.c"
+#include "ldpc240_byte.c"
+#include "ldpc224_byte.c"
+#include "ldpc208_byte.c"
+#include "ldpc192_byte.c"
+#include "ldpc176_byte.c"
+#include "ldpc_BG2_Zc384_byte.c"
+#include "ldpc_BG2_Zc352_byte.c"
+#include "ldpc_BG2_Zc320_byte.c"
+#include "ldpc_BG2_Zc288_byte.c"
+#include "ldpc_BG2_Zc256_byte.c"
+#include "ldpc_BG2_Zc240_byte.c"
+#include "ldpc_BG2_Zc224_byte.c"
+#include "ldpc_BG2_Zc208_byte.c"
+#include "ldpc_BG2_Zc192_byte.c"
+#include "ldpc_BG2_Zc176_byte.c"
+#include "ldpc_BG2_Zc160_byte.c"
+#include "ldpc_BG2_Zc144_byte.c"
+#include "ldpc_BG2_Zc128_byte.c"
+#include "ldpc_BG2_Zc120_byte.c"
+#include "ldpc_BG2_Zc112_byte.c"
+#include "ldpc_BG2_Zc104_byte.c"
+#include "ldpc_BG2_Zc96_byte.c"
+#include "ldpc_BG2_Zc88_byte.c"
+#include "ldpc_BG2_Zc80_byte.c"
+#include "ldpc_BG2_Zc72_byte.c"
+
+
+
+static inline void encode_parity_check_part_optim(uint8_t *c,uint8_t *d, short BG,short Zc,short Kb)
+{
+
+  if (BG==1)
+  {
+    switch (Zc)
+    {
+    case 2: break;
+    case 3: break;
+    case 4: break;
+    case 5: break;
+    case 6: break;
+    case 7: break;
+    case 8: break;
+    case 9: break;
+    case 10: break;
+    case 11: break;
+    case 12: break;
+    case 13: break;
+    case 14: break;
+    case 15: break;
+    case 16: break;
+    case 18: break;
+    case 20: break;
+    case 22: break;
+    case 24: break;      
+    case 26: break;
+    case 28: break;
+    case 30: break;
+    case 32: break;
+    case 36: break;
+    case 40: break;
+    case 44: break;
+    case 48: break;
+    case 52: break;
+    case 56: break;
+    case 60: break;
+    case 64: break;
+    case 72: break;
+    case 80: break;   
+    case 88: break;   
+    case 96: break;
+    case 104: break;
+    case 112: break;
+    case 120: break;
+    case 128: break;
+    case 144: break;
+    case 160: break;
+    case 176: ldpc176_byte(c,d); break;
+    case 192: ldpc192_byte(c,d); break;
+    case 208: ldpc208_byte(c,d); break;
+    case 224: ldpc224_byte(c,d); break;
+    case 240: ldpc240_byte(c,d); break;
+    case 256: ldpc256_byte(c,d); break;
+    case 288: ldpc288_byte(c,d); break;
+    case 320: ldpc320_byte(c,d); break;
+    case 352: ldpc352_byte(c,d); break;
+    case 384: ldpc384_byte(c,d); break;
+    default: AssertFatal(0,"BG %d Zc %d is not supported yet\n",BG,Zc); break;
+    }
+  }
+  else if (BG==2) {
+    switch (Zc)
+    {
+    case 2: break;
+    case 3: break;
+    case 4: break;
+    case 5: break;
+    case 6: break;
+    case 7: break;
+    case 8: break;
+    case 9: break;
+    case 10: break;
+    case 11: break;
+    case 12: break;
+    case 13: break;
+    case 14: break;
+    case 15: break;
+    case 16: break;
+    case 18: break;
+    case 20: break;
+    case 22: break;
+    case 24: break;      
+    case 26: break;
+    case 28: break;
+    case 30: break;
+    case 32: break;
+    case 36: break;
+    case 40: break;
+    case 44: break;
+    case 48: break;
+    case 52: break;
+    case 56: break;
+    case 60: break;
+    case 64: break;
+    case 72: ldpc_BG2_Zc72_byte(c,d); break;
+    case 80: ldpc_BG2_Zc80_byte(c,d); break;   
+    case 88: ldpc_BG2_Zc88_byte(c,d); break;   
+    case 96: ldpc_BG2_Zc96_byte(c,d); break;
+    case 104: ldpc_BG2_Zc104_byte(c,d); break;
+    case 112: ldpc_BG2_Zc112_byte(c,d); break;
+    case 120: ldpc_BG2_Zc120_byte(c,d); break;
+    case 128: ldpc_BG2_Zc128_byte(c,d); break;
+    case 144: ldpc_BG2_Zc144_byte(c,d); break;
+    case 160: ldpc_BG2_Zc160_byte(c,d); break;
+    case 176: ldpc_BG2_Zc176_byte(c,d); break;
+    case 192: ldpc_BG2_Zc192_byte(c,d); break;
+    case 208: ldpc_BG2_Zc208_byte(c,d); break;
+    case 224: ldpc_BG2_Zc224_byte(c,d); break;
+    case 240: ldpc_BG2_Zc240_byte(c,d); break;
+    case 256: ldpc_BG2_Zc256_byte(c,d); break;
+    case 288: ldpc_BG2_Zc288_byte(c,d); break;
+    case 320: ldpc_BG2_Zc320_byte(c,d); break;
+    case 352: ldpc_BG2_Zc352_byte(c,d); break;
+    case 384: ldpc_BG2_Zc384_byte(c,d); break;
+    default: AssertFatal(0,"BG %d Zc %d is not supported yet\n",BG,Zc); break;
+    }
+  }
+  else {
+    AssertFatal(0,"BG %d is not supported yet\n",BG);
+  } 
+
+}
+
+
+
diff --git a/openair1/PHY/CODING/nrLDPC_encoder/ldpc_encoder.c b/openair1/PHY/CODING/nrLDPC_encoder/ldpc_encoder.c
index 6ded22d8cab5222811a474dcb4b34c71c4bed435..76f92574bad3498c416a6318c1f84cbdc8ea5378 100644
--- a/openair1/PHY/CODING/nrLDPC_encoder/ldpc_encoder.c
+++ b/openair1/PHY/CODING/nrLDPC_encoder/ldpc_encoder.c
@@ -37,77 +37,247 @@
 #include <string.h>
 #include <types.h>
 #include "defs.h"
+#include "assertions.h"
+#include "openair1/PHY/CODING/nrLDPC_defs.h"
+#include "ldpc_generate_coefficient.c"
 
-short *choose_generator_matrix(short BG,short Zc);
-extern short no_shift_values_BG1[1012],pointer_shift_values_BG1[1012],no_shift_values_BG2[2109],pointer_shift_values_BG2[2019];
 
-int encode_parity_check_part_orig(unsigned char *c,unsigned char *d, short BG,short Zc,short Kb,short block_length)
+int ldpc_encoder_orig(unsigned char *test_input,unsigned char *channel_input,int Zc,int Kb,short block_length, short BG,unsigned char gen_code)
 {
-  short *Gen_shift_values=choose_generator_matrix(BG,Zc);
-  short *no_shift_values, *pointer_shift_values;
-  int no_punctured_columns;
-  short nrows,ncols,rate=3;
-  int i1,i2,i3,i4,i5,temp_prime;
+  unsigned char c[22*384]; //padded input, unpacked, max size
+  unsigned char d[68*384]; //coded output, unpacked, max size
   unsigned char channel_temp,temp;
+  short *Gen_shift_values, *no_shift_values, *pointer_shift_values;
 
+  short nrows = 46;//parity check bits
+  short ncols = 22;//info bits
+
+
+  int i,i1,i2,i3,i4,i5,temp_prime,var;
+  int no_punctured_columns,removed_bit,rate=3;
+  int nind=0;
+  int indlist[1000];
+  int indlist2[1000];
+
+  //determine number of bits in codeword
+  //if (block_length>3840)
+     if (BG==1)
+       {
+         nrows=46; //parity check bits
+         ncols=22; //info bits
+         rate=3;
+       }
+       //else if (block_length<=3840)
+      else if	(BG==2)
+       {
+         //BG=2;
+         nrows=42; //parity check bits
+         ncols=10; // info bits
+         rate=5;
+         }
+
+  Gen_shift_values=choose_generator_matrix(BG,Zc);
+  if (Gen_shift_values==NULL) {
+    printf("ldpc_encoder_orig: could not find generator matrix\n");
+    return(-1);
+  }
+
+  //printf("ldpc_encoder_orig: BG %d, Zc %d, Kb %d\n",BG, Zc, Kb);
+
+  // load base graph of generator matrix
   if (BG==1)
   {
     no_shift_values=(short *) no_shift_values_BG1;
     pointer_shift_values=(short *) pointer_shift_values_BG1;
-      nrows=46; //parity check bits
-      ncols=22; //info bits
-      rate=3;
   }
   else if (BG==2)
   {
     no_shift_values=(short *) no_shift_values_BG2;
     pointer_shift_values=(short *) pointer_shift_values_BG2;
-      nrows=42; //parity check bits
-      ncols=10; //info bits
-      rate=5;
   }
   else {
-    printf("problem with BG\n");
-    return(-1);
+    AssertFatal(0,"BG %d is not supported yet\n",BG);
   }
-
-
+  
   no_punctured_columns=(int)((nrows-2)*Zc+block_length-block_length*rate)/Zc;
+  removed_bit=(nrows-no_punctured_columns-2) * Zc+block_length-(block_length*rate);
+  //printf("%d\n",no_punctured_columns);
+  //printf("%d\n",removed_bit);
+  // unpack input
+  memset(c,0,sizeof(unsigned char) * ncols * Zc);
+  memset(d,0,sizeof(unsigned char) * nrows * Zc);
+
+  for (i=0; i<block_length; i++)
+  {
+    //c[i] = test_input[i/8]<<(i%8);
+    //c[i]=c[i]>>7&1;
+    c[i]=(test_input[i/8]&(128>>(i&7)))>>(7-(i&7));
+  }
 
-  //printf("no_punctured_columns = %d\n",no_punctured_columns);
+  // parity check part
 
-  for (i2=0; i2 < Zc; i2++)
+  if (gen_code==1)
   {
-    //t=Kb*Zc+i2;
+    char fname[100];
+    sprintf(fname,"ldpc_BG%d_Zc%d_byte.c",BG,Zc);
+    FILE *fd=fopen(fname,"w");
+    AssertFatal(fd!=NULL,"cannot open %s\n",fname);
+    sprintf(fname,"ldpc_BG%d_Zc%d_16bit.c",BG,Zc);
+    FILE *fd2=fopen(fname,"w");
+    AssertFatal(fd2!=NULL,"cannot open %s\n",fname);
 
-    //rotate matrix here
-    for (i5=0; i5 < Kb; i5++)
-    {
-      temp = c[i5*Zc];
-      memmove(&c[i5*Zc], &c[i5*Zc+1], (Zc-1)*sizeof(unsigned char));
-      c[i5*Zc+Zc-1] = temp;
+    int shift;
+    char data_type[100];
+    char xor_command[100];
+    int mask;
+
+
+
+
+    fprintf(fd,"#include \"PHY/sse_intrin.h\"\n");
+    fprintf(fd2,"#include \"PHY/sse_intrin.h\"\n");
+
+    if ((Zc&31)==0) {
+      shift=5; // AVX2 - 256-bit SIMD
+      mask=31;
+      strcpy(data_type,"__m256i");
+      strcpy(xor_command,"_mm256_xor_si256");
     }
+    else if ((Zc&15)==0) {
+      shift=4; // SSE4 - 128-bit SIMD
+      mask=15;
+      strcpy(data_type,"__m128i");
+      strcpy(xor_command,"_mm_xor_si128");
 
-    // calculate each row in base graph
-    for (i1=0; i1 < nrows-no_punctured_columns; i1++)
+    }
+    else if ((Zc&7)==0) {
+      shift=3; // MMX  - 64-bit SIMD
+      mask=7;
+      strcpy(data_type,"__m64");
+      strcpy(xor_command,"_mm_xor_si64"); 
+    }
+    else {
+      shift=0;                 // no SIMD
+      mask=0;
+      strcpy(data_type,"uint8_t");
+      strcpy(xor_command,"scalar_xor");
+      fprintf(fd,"#define scalar_xor(a,b) ((a)^(b))\n");
+      fprintf(fd2,"#define scalar_xor(a,b) ((a)^(b))\n");
+    }
+    fprintf(fd,"// generated code for Zc=%d, byte encoding\n",Zc);
+    fprintf(fd2,"// generated code for Zc=%d, 16bit encoding\n",Zc);
+    fprintf(fd,"static inline void ldpc_BG%d_Zc%d_byte(uint8_t *c,uint8_t *d) {\n",BG,Zc);
+    fprintf(fd2,"static inline void ldpc_BG%d_Zc%d_16bit(uint16_t *c,uint16_t *d) {\n",BG,Zc);
+    fprintf(fd,"  %s *csimd=(%s *)c,*dsimd=(%s *)d;\n\n",data_type,data_type,data_type);
+    fprintf(fd2,"  %s *csimd=(%s *)c,*dsimd=(%s *)d;\n\n",data_type,data_type,data_type);
+    fprintf(fd,"  %s *c2,*d2;\n\n",data_type);
+    fprintf(fd2,"  %s *c2,*d2;\n\n",data_type);
+    fprintf(fd,"  int i2;\n");
+    fprintf(fd2,"  int i2;\n");
+    fprintf(fd,"  for (i2=0; i2<%d; i2++) {\n",Zc>>shift);
+    if (shift > 0)
+      fprintf(fd2,"  for (i2=0; i2<%d; i2++) {\n",Zc>>(shift-1));
+    for (i2=0; i2 < 1; i2++)
     {
-      channel_temp=0;
-      for (i3=0; i3 < Kb; i3++)
+      //t=Kb*Zc+i2;
+    
+      // calculate each row in base graph
+     
+
+      fprintf(fd,"     c2=&csimd[i2];\n");
+      fprintf(fd,"     d2=&dsimd[i2];\n");
+      fprintf(fd2,"     c2=&csimd[i2];\n");
+      fprintf(fd2,"     d2=&dsimd[i2];\n");
+
+      for (i1=0; i1 < nrows; i1++)
+
       {
-        temp_prime=i1 * ncols + i3;
+        channel_temp=0;
+        fprintf(fd,"\n//row: %d\n",i1);
+        fprintf(fd2,"\n//row: %d\n",i1);
+	fprintf(fd,"     d2[%d]=",(Zc*i1)>>shift);
+	fprintf(fd2,"     d2[%d]=",(Zc*i1)>>(shift-1));
+
+        nind=0;
 
-        for (i4=0; i4 < no_shift_values[temp_prime]; i4++)
+        for (i3=0; i3 < ncols; i3++)
         {
-          channel_temp = channel_temp ^ c[ i3*Zc + Gen_shift_values[ pointer_shift_values[temp_prime]+i4 ] ];
+          temp_prime=i1 * ncols + i3;
+
+
+	  for (i4=0; i4 < no_shift_values[temp_prime]; i4++)
+	    {
+	          
+	      var=(int)((i3*Zc + (Gen_shift_values[ pointer_shift_values[temp_prime]+i4 ]+1)%Zc)/Zc);
+	      int index =var*2*Zc + (i3*Zc + (Gen_shift_values[ pointer_shift_values[temp_prime]+i4 ]+1)%Zc) % Zc;
+	      
+	      indlist[nind] = ((index&mask)*((2*Zc)>>shift)*Kb)+(index>>shift);
+	      indlist2[nind++] = ((index&(mask>>1))*((2*Zc)>>(shift-1))*Kb)+(index>>(shift-1));
+	      
+	    }
+	  
+
         }
+	for (i4=0;i4<nind-1;i4++) {
+	  fprintf(fd,"%s(c2[%d],",xor_command,indlist[i4]);
+	  fprintf(fd2,"%s(c2[%d],",xor_command,indlist2[i4]);
+	}
+	fprintf(fd,"c2[%d]",indlist[i4]);
+	fprintf(fd2,"c2[%d]",indlist2[i4]);
+	for (i4=0;i4<nind-1;i4++) { fprintf(fd,")"); fprintf(fd2,")"); }
+	fprintf(fd,";\n");
+	fprintf(fd2,";\n");
+
       }
-      d[i2+i1*Zc]=channel_temp;
-      //channel_input[t+i1*Zc]=channel_temp;
+      fprintf(fd,"  }\n}\n");
+      fprintf(fd2,"  }\n}\n");
     }
+    fclose(fd);
+    fclose(fd2);
   }
-  return(0);
-}
+  else if(gen_code==0)
+  {
+    for (i2=0; i2 < Zc; i2++)
+    {
+      //t=Kb*Zc+i2;
 
+      //rotate matrix here
+      for (i5=0; i5 < Kb; i5++)
+      {
+        temp = c[i5*Zc];
+        memmove(&c[i5*Zc], &c[i5*Zc+1], (Zc-1)*sizeof(unsigned char));
+        c[i5*Zc+Zc-1] = temp;
+      }
 
+      // calculate each row in base graph
+      for (i1=0; i1 < nrows-no_punctured_columns; i1++)
+      {
+        channel_temp=0;
+
+        for (i3=0; i3 < Kb; i3++)
+        {
+          temp_prime=i1 * ncols + i3;
+
+          for (i4=0; i4 < no_shift_values[temp_prime]; i4++)
+          {
+            channel_temp = channel_temp ^ c[ i3*Zc + Gen_shift_values[ pointer_shift_values[temp_prime]+i4 ] ];
+          }
+        }
+
+        d[i2+i1*Zc]=channel_temp;
+        //channel_input[t+i1*Zc]=channel_temp;
+      }
+    }
+  }
+
+  // information part and puncture columns
+  memcpy(&channel_input[0], &c[2*Zc], (block_length-2*Zc)*sizeof(unsigned char));
+  memcpy(&channel_input[block_length-2*Zc], &d[0], ((nrows-no_punctured_columns) * Zc-removed_bit)*sizeof(unsigned char));
+  //memcpy(channel_input,c,Kb*Zc*sizeof(unsigned char));
+  return 0;
+}
 
 
+int nrLDPC_encod(unsigned char **test_input,unsigned char **channel_input,int Zc,int Kb,short block_length, short BG, encoder_implemparams_t *impp) {
+  return ldpc_encoder_orig(test_input[0],channel_input[0],Zc,Kb,block_length,BG,impp->gen_code);
+}
\ No newline at end of file
diff --git a/openair1/PHY/CODING/nrLDPC_encoder/ldpc_encoder2.c b/openair1/PHY/CODING/nrLDPC_encoder/ldpc_encoder2.c
deleted file mode 100644
index ef207b6cdcd683dbc18c6a0f6541033635312315..0000000000000000000000000000000000000000
--- a/openair1/PHY/CODING/nrLDPC_encoder/ldpc_encoder2.c
+++ /dev/null
@@ -1,667 +0,0 @@
-/*
- * 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
- */
-
-/*!\file ldpc_encoder2.c
- * \brief Defines the optimized LDPC encoder
- * \author Florian Kaltenberger, Raymond Knopp, Kien le Trung (Eurecom)
- * \email openair_tech@eurecom.fr
- * \date 27-03-2018
- * \version 1.0
- * \note
- * \warning
- */
-
-#include <stdlib.h>
-#include <math.h>
-#include <stdio.h>
-#include <string.h>
-#include <types.h>
-#include "assertions.h"
-#include "common/utils/LOG/log.h"
-#include "PHY/TOOLS/time_meas.h"
-#include "defs.h"
-
-//#define DEBUG_LDPC
-
-#include "ldpc384_byte.c"
-#include "ldpc352_byte.c"
-#include "ldpc320_byte.c"
-#include "ldpc288_byte.c"
-#include "ldpc256_byte.c"
-#include "ldpc240_byte.c"
-#include "ldpc224_byte.c"
-#include "ldpc208_byte.c"
-#include "ldpc192_byte.c"
-#include "ldpc176_byte.c"
-#include "ldpc_BG2_Zc384_byte.c"
-#include "ldpc_BG2_Zc352_byte.c"
-#include "ldpc_BG2_Zc320_byte.c"
-#include "ldpc_BG2_Zc288_byte.c"
-#include "ldpc_BG2_Zc256_byte.c"
-#include "ldpc_BG2_Zc240_byte.c"
-#include "ldpc_BG2_Zc224_byte.c"
-#include "ldpc_BG2_Zc208_byte.c"
-#include "ldpc_BG2_Zc192_byte.c"
-#include "ldpc_BG2_Zc176_byte.c"
-#include "ldpc_BG2_Zc160_byte.c"
-#include "ldpc_BG2_Zc144_byte.c"
-#include "ldpc_BG2_Zc128_byte.c"
-#include "ldpc_BG2_Zc120_byte.c"
-#include "ldpc_BG2_Zc112_byte.c"
-#include "ldpc_BG2_Zc104_byte.c"
-#include "ldpc_BG2_Zc96_byte.c"
-#include "ldpc_BG2_Zc88_byte.c"
-#include "ldpc_BG2_Zc80_byte.c"
-#include "ldpc_BG2_Zc72_byte.c"
-
-
-
-void encode_parity_check_part_optim(uint8_t *c,uint8_t *d, short BG,short Zc,short Kb)
-{
-
-  if (BG==1)
-  {
-    switch (Zc)
-    {
-    case 2: break;
-    case 3: break;
-    case 4: break;
-    case 5: break;
-    case 6: break;
-    case 7: break;
-    case 8: break;
-    case 9: break;
-    case 10: break;
-    case 11: break;
-    case 12: break;
-    case 13: break;
-    case 14: break;
-    case 15: break;
-    case 16: break;
-    case 18: break;
-    case 20: break;
-    case 22: break;
-    case 24: break;      
-    case 26: break;
-    case 28: break;
-    case 30: break;
-    case 32: break;
-    case 36: break;
-    case 40: break;
-    case 44: break;
-    case 48: break;
-    case 52: break;
-    case 56: break;
-    case 60: break;
-    case 64: break;
-    case 72: break;
-    case 80: break;   
-    case 88: break;   
-    case 96: break;
-    case 104: break;
-    case 112: break;
-    case 120: break;
-    case 128: break;
-    case 144: break;
-    case 160: break;
-    case 176: ldpc176_byte(c,d); break;
-    case 192: ldpc192_byte(c,d); break;
-    case 208: ldpc208_byte(c,d); break;
-    case 224: ldpc224_byte(c,d); break;
-    case 240: ldpc240_byte(c,d); break;
-    case 256: ldpc256_byte(c,d); break;
-    case 288: ldpc288_byte(c,d); break;
-    case 320: ldpc320_byte(c,d); break;
-    case 352: ldpc352_byte(c,d); break;
-    case 384: ldpc384_byte(c,d); break;
-    default: AssertFatal(0,"BG %d Zc %d is not supported yet\n",BG,Zc); break;
-    }
-  }
-  else if (BG==2) {
-    switch (Zc)
-    {
-    case 2: break;
-    case 3: break;
-    case 4: break;
-    case 5: break;
-    case 6: break;
-    case 7: break;
-    case 8: break;
-    case 9: break;
-    case 10: break;
-    case 11: break;
-    case 12: break;
-    case 13: break;
-    case 14: break;
-    case 15: break;
-    case 16: break;
-    case 18: break;
-    case 20: break;
-    case 22: break;
-    case 24: break;      
-    case 26: break;
-    case 28: break;
-    case 30: break;
-    case 32: break;
-    case 36: break;
-    case 40: break;
-    case 44: break;
-    case 48: break;
-    case 52: break;
-    case 56: break;
-    case 60: break;
-    case 64: break;
-    case 72: ldpc_BG2_Zc72_byte(c,d); break;
-    case 80: ldpc_BG2_Zc80_byte(c,d); break;   
-    case 88: ldpc_BG2_Zc88_byte(c,d); break;   
-    case 96: ldpc_BG2_Zc96_byte(c,d); break;
-    case 104: ldpc_BG2_Zc104_byte(c,d); break;
-    case 112: ldpc_BG2_Zc112_byte(c,d); break;
-    case 120: ldpc_BG2_Zc120_byte(c,d); break;
-    case 128: ldpc_BG2_Zc128_byte(c,d); break;
-    case 144: ldpc_BG2_Zc144_byte(c,d); break;
-    case 160: ldpc_BG2_Zc160_byte(c,d); break;
-    case 176: ldpc_BG2_Zc176_byte(c,d); break;
-    case 192: ldpc_BG2_Zc192_byte(c,d); break;
-    case 208: ldpc_BG2_Zc208_byte(c,d); break;
-    case 224: ldpc_BG2_Zc224_byte(c,d); break;
-    case 240: ldpc_BG2_Zc240_byte(c,d); break;
-    case 256: ldpc_BG2_Zc256_byte(c,d); break;
-    case 288: ldpc_BG2_Zc288_byte(c,d); break;
-    case 320: ldpc_BG2_Zc320_byte(c,d); break;
-    case 352: ldpc_BG2_Zc352_byte(c,d); break;
-    case 384: ldpc_BG2_Zc384_byte(c,d); break;
-    default: AssertFatal(0,"BG %d Zc %d is not supported yet\n",BG,Zc); break;
-    }
-  }
-  else {
-    AssertFatal(0,"BG %d is not supported yet\n",BG);
-  } 
-
-}
-
-
-int ldpc_encoder_optim(unsigned char *test_input,unsigned char *channel_input,int Zc,int Kb,short block_length,short BG,time_stats_t *tinput,time_stats_t *tprep,time_stats_t *tparity,time_stats_t *toutput)
-{
-
-  short nrows=0,ncols=0;
-  int i,i1,rate=3;
-  int no_punctured_columns,removed_bit;
-
-  int simd_size;
-
-  //determine number of bits in codeword
-   //if (block_length>3840)
-   if (BG==1)
-     {
-       //BG=1;
-       nrows=46; //parity check bits
-       ncols=22; //info bits
-       rate=3;
-     }
-     //else if (block_length<=3840)
-    else if	(BG==2)
-     {
-       //BG=2;
-       nrows=42; //parity check bits
-       ncols=10; // info bits
-       rate=5;
-
-       }
-
-
-#ifdef DEBUG_LDPC
-  LOG_D(PHY,"ldpc_encoder_optim_8seg: BG %d, Zc %d, Kb %d, block_length %d\n",BG,Zc,Kb,block_length);
-  LOG_D(PHY,"ldpc_encoder_optim_8seg: PDU %x %x %x %x\n",test_input[0],test_input[1],test_input[2],test_input[3]);
-#endif
-
-  if ((Zc&31) > 0) simd_size = 16;
-  else simd_size = 32;
-
-  unsigned char c[22*Zc] __attribute__((aligned(32))); //padded input, unpacked, max size
-  unsigned char d[46*Zc] __attribute__((aligned(32))); //coded parity part output, unpacked, max size
-
-  unsigned char c_extension[2*22*Zc*simd_size] __attribute__((aligned(32)));      //double size matrix of c
-
-  // calculate number of punctured bits
-  no_punctured_columns=(int)((nrows-2)*Zc+block_length-block_length*rate)/Zc;
-  removed_bit=(nrows-no_punctured_columns-2) * Zc+block_length-(int)(block_length*rate);
-  // printf("%d\n",no_punctured_columns);
-  // printf("%d\n",removed_bit);
-  // unpack input
-  memset(c,0,sizeof(unsigned char) * ncols * Zc);
-  memset(d,0,sizeof(unsigned char) * nrows * Zc);
-
-  if(tinput != NULL) start_meas(tinput);
-  for (i=0; i<block_length; i++) {
-    c[i] = (test_input[i/8]&(128>>(i&7)))>>(7-(i&7));
-      //printf("c(%d,%d)=%d\n",j,i,temp);
-    }
-
-  if(tinput != NULL) stop_meas(tinput);
-
-  if ((BG==1 && Zc>176) || (BG==2 && Zc>64)) { 
-    // extend matrix
-    if(tprep != NULL) start_meas(tprep);
-    for (i1=0; i1 < ncols; i1++)
-      {
-	memcpy(&c_extension[2*i1*Zc], &c[i1*Zc], Zc*sizeof(unsigned char));
-	memcpy(&c_extension[(2*i1+1)*Zc], &c[i1*Zc], Zc*sizeof(unsigned char));
-      }
-    for (i1=1;i1<simd_size;i1++) {
-      memcpy(&c_extension[(2*ncols*Zc*i1)], &c_extension[i1], (2*ncols*Zc*sizeof(unsigned char))-i1);
-      //    memset(&c_extension[(2*ncols*Zc*i1)],0,i1);
-      /*
-	printf("shift %d: ",i1);
-	for (int j=0;j<64;j++) printf("%d ",c_extension[(2*ncols*Zc*i1)+j]);
-	printf("\n");
-      */
-    }
-    if(tprep != NULL) stop_meas(tprep);
-    //parity check part
-    if(tparity != NULL) start_meas(tparity);
-    encode_parity_check_part_optim(c_extension, d, BG, Zc, Kb);
-    if(tparity != NULL) stop_meas(tparity);
-  }
-  else {
-    if (encode_parity_check_part_orig(c, d, BG, Zc, Kb, block_length)!=0) {
-      printf("Problem with encoder\n");
-      return(-1);
-    }
-  }
-  if(toutput != NULL) start_meas(toutput);
-  // information part and puncture columns
-  memcpy(&channel_input[0], &c[2*Zc], (block_length-2*Zc)*sizeof(unsigned char));
-  memcpy(&channel_input[block_length-2*Zc], &d[0], ((nrows-no_punctured_columns) * Zc-removed_bit)*sizeof(unsigned char));
-
-  if(toutput != NULL) stop_meas(toutput);
-  return 0;
-}
-
-int ldpc_encoder_optim_8seg(unsigned char **test_input,unsigned char **channel_input,int Zc,int Kb,short block_length,short BG,int n_segments,time_stats_t *tinput,time_stats_t *tprep,time_stats_t *tparity,time_stats_t *toutput)
-{
-
-  short nrows=0,ncols=0;
-  int i,i1,j,rate=3;
-  int no_punctured_columns,removed_bit;
-  char temp;
-  int simd_size;
-
-#ifdef __AVX2__
-  __m256i shufmask = _mm256_set_epi64x(0x0303030303030303, 0x0202020202020202,0x0101010101010101, 0x0000000000000000);
-  __m256i andmask  = _mm256_set1_epi64x(0x0102040810204080);  // every 8 bits -> 8 bytes, pattern repeats.
-  __m256i zero256   = _mm256_setzero_si256();
-  __m256i masks[8];
-  register __m256i c256;
-  masks[0] = _mm256_set1_epi8(0x1);
-  masks[1] = _mm256_set1_epi8(0x2);
-  masks[2] = _mm256_set1_epi8(0x4);
-  masks[3] = _mm256_set1_epi8(0x8);
-  masks[4] = _mm256_set1_epi8(0x10);
-  masks[5] = _mm256_set1_epi8(0x20);
-  masks[6] = _mm256_set1_epi8(0x40);
-  masks[7] = _mm256_set1_epi8(0x80);
-#endif
-
-  AssertFatal(n_segments>0&&n_segments<=8,"0 < n_segments %d <= 8\n",n_segments);
-
-  //determine number of bits in codeword
-  //if (block_length>3840)
-  if (BG==1)
-    {
-      nrows=46; //parity check bits
-      ncols=22; //info bits
-      rate=3;
-    }
-    //else if (block_length<=3840)
-   else if	(BG==2)
-    {
-      //BG=2;
-      nrows=42; //parity check bits
-      ncols=10; // info bits
-      rate=5;
-
-      }
-
-#ifdef DEBUG_LDPC
-  LOG_D(PHY,"ldpc_encoder_optim_8seg: BG %d, Zc %d, Kb %d, block_length %d, segments %d\n",BG,Zc,Kb,block_length,n_segments);
-  LOG_D(PHY,"ldpc_encoder_optim_8seg: PDU (seg 0) %x %x %x %x\n",test_input[0][0],test_input[0][1],test_input[0][2],test_input[0][3]);
-#endif
-
-  AssertFatal(Zc>0,"no valid Zc found for block length %d\n",block_length);
-
-  if ((Zc&31) > 0) simd_size = 16;
-  else          simd_size = 32;
-
-  unsigned char c[22*Zc] __attribute__((aligned(32))); //padded input, unpacked, max size
-  unsigned char d[46*Zc] __attribute__((aligned(32))); //coded parity part output, unpacked, max size
-
-  unsigned char c_extension[2*22*Zc*simd_size] __attribute__((aligned(32)));      //double size matrix of c
-
-  // calculate number of punctured bits
-  no_punctured_columns=(int)((nrows-2)*Zc+block_length-block_length*rate)/Zc;
-  removed_bit=(nrows-no_punctured_columns-2) * Zc+block_length-(int)(block_length*rate);
-  // printf("%d\n",no_punctured_columns);
-  // printf("%d\n",removed_bit);
-  // unpack input
-  memset(c,0,sizeof(unsigned char) * ncols * Zc);
-  memset(d,0,sizeof(unsigned char) * nrows * Zc);
-
-  if(tinput != NULL) start_meas(tinput);
-#if 0
-  for (i=0; i<block_length; i++) {
-    for (j=0; j<n_segments; j++) {
-
-      temp = (test_input[j][i/8]&(128>>(i&7)))>>(7-(i&7));
-      //printf("c(%d,%d)=%d\n",j,i,temp);
-      c[i] |= (temp << j);
-    }
-  }
-#else
-#ifdef __AVX2__
-  for (i=0; i<block_length>>5; i++) {
-    c256 = _mm256_and_si256(_mm256_cmpeq_epi8(_mm256_andnot_si256(_mm256_shuffle_epi8(_mm256_set1_epi32(((uint32_t*)test_input[0])[i]), shufmask),andmask),zero256),masks[0]);
-    for (j=1; j<n_segments; j++) {
-      c256 = _mm256_or_si256(_mm256_and_si256(_mm256_cmpeq_epi8(_mm256_andnot_si256(_mm256_shuffle_epi8(_mm256_set1_epi32(((uint32_t*)test_input[j])[i]), shufmask),andmask),zero256),masks[j]),c256);
-    }
-    ((__m256i *)c)[i] = c256;
-  }
-
-  for (i=(block_length>>5)<<5;i<block_length;i++) {
-    for (j=0; j<n_segments; j++) {
-
-      temp = (test_input[j][i/8]&(128>>(i&7)))>>(7-(i&7));
-      //printf("c(%d,%d)=%d\n",j,i,temp);
-      c[i] |= (temp << j);
-    }
-  }
-#else
-  AssertFatal(1==0,"Need AVX2 for this\n");
-#endif
-#endif
-
-  if(tinput != NULL) stop_meas(tinput);
-
-  if ((BG==1 && Zc>176) || (BG==2 && Zc>64)) { 
-    // extend matrix
-    if(tprep != NULL) start_meas(tprep);
-    for (i1=0; i1 < ncols; i1++)
-      {
-	memcpy(&c_extension[2*i1*Zc], &c[i1*Zc], Zc*sizeof(unsigned char));
-	memcpy(&c_extension[(2*i1+1)*Zc], &c[i1*Zc], Zc*sizeof(unsigned char));
-      }
-    for (i1=1;i1<simd_size;i1++) {
-      memcpy(&c_extension[(2*ncols*Zc*i1)], &c_extension[i1], (2*ncols*Zc*sizeof(unsigned char))-i1);
-      //    memset(&c_extension[(2*ncols*Zc*i1)],0,i1);
-      /*
-	printf("shift %d: ",i1);
-	for (int j=0;j<64;j++) printf("%d ",c_extension[(2*ncols*Zc*i1)+j]);
-	printf("\n");
-      */
-    }
-    if(tprep != NULL) stop_meas(tprep);
-    //parity check part
-    if(tparity != NULL) start_meas(tparity);
-    encode_parity_check_part_optim(c_extension, d, BG, Zc, Kb);
-    if(tparity != NULL) stop_meas(tparity);
-  }
-  else {
-    if (encode_parity_check_part_orig(c, d, BG, Zc, Kb, block_length)!=0) {
-      printf("Problem with encoder\n");
-      return(-1);
-    }
-  }
-  if(toutput != NULL) start_meas(toutput);
-  // information part and puncture columns
-  /*
-  memcpy(&channel_input[0], &c[2*Zc], (block_length-2*Zc)*sizeof(unsigned char));
-  memcpy(&channel_input[block_length-2*Zc], &d[0], ((nrows-no_punctured_columns) * Zc-removed_bit)*sizeof(unsigned char));
-  */
-#ifdef __AVX2__
-  if ((((2*Zc)&31) == 0) && (((block_length-(2*Zc))&31) == 0)) {
-    //AssertFatal(((2*Zc)&31) == 0,"2*Zc needs to be a multiple of 32 for now\n");
-    //AssertFatal(((block_length-(2*Zc))&31) == 0,"block_length-(2*Zc) needs to be a multiple of 32 for now\n");
-    uint32_t l1 = (block_length-(2*Zc))>>5;
-    uint32_t l2 = ((nrows-no_punctured_columns) * Zc-removed_bit)>>5;
-    __m256i *c256p = (__m256i *)&c[2*Zc];
-    __m256i *d256p = (__m256i *)&d[0];
-    //  if (((block_length-(2*Zc))&31)>0) l1++;
-    
-    for (i=0;i<l1;i++)
-      for (j=0;j<n_segments;j++) ((__m256i *)channel_input[j])[i] = _mm256_and_si256(_mm256_srai_epi16(c256p[i],j),masks[0]);
-    
-    //  if ((((nrows-no_punctured_columns) * Zc-removed_bit)&31)>0) l2++;
-    
-    for (i1=0;i1<l2;i1++,i++)
-      for (j=0;j<n_segments;j++) ((__m256i *)channel_input[j])[i] = _mm256_and_si256(_mm256_srai_epi16(d256p[i1],j),masks[0]);
-  }
-  else {
-#ifdef DEBUG_LDPC
-  LOG_W(PHY,"using non-optimized version\n");
-#endif
-    // do non-SIMD version
-    for (i=0;i<(block_length-2*Zc);i++) 
-      for (j=0; j<n_segments; j++)
-	channel_input[j][i] = (c[2*Zc+i]>>j)&1;
-    for (i=0;i<((nrows-no_punctured_columns) * Zc-removed_bit);i++)
-      for (j=0; j<n_segments; j++)
-	channel_input[j][block_length-2*Zc+i] = (d[i]>>j)&1;
-    }
-
-#else
-    AssertFatal(1==0,"Need AVX2 for now\n");
-#endif
-
-  if(toutput != NULL) stop_meas(toutput);
-  return 0;
-}
-
-int ldpc_encoder_optim_8seg_multi(unsigned char **test_input,unsigned char **channel_input,int Zc,int Kb,short block_length, short BG, int n_segments,unsigned int macro_num, time_stats_t *tinput,time_stats_t *tprep,time_stats_t *tparity,time_stats_t *toutput)
-{
-
-  short nrows=0,ncols=0;
-  int i,i1,j,rate=3;
-  int no_punctured_columns,removed_bit;
-  //Table of possible lifting sizes
-  char temp;
-  int simd_size;
-  unsigned int macro_segment, macro_segment_end;
-
-  
-  macro_segment = 8*macro_num;
-  // macro_segment_end = (n_segments > 8*(macro_num+1)) ? 8*(macro_num+1) : n_segments;
-  macro_segment_end = macro_segment + (n_segments > 8 ? 8 : n_segments);
-  ///printf("macro_segment: %d\n", macro_segment);
-  ///printf("macro_segment_end: %d\n", macro_segment_end );
-
-#ifdef __AVX2__
-  __m256i shufmask = _mm256_set_epi64x(0x0303030303030303, 0x0202020202020202,0x0101010101010101, 0x0000000000000000);
-  __m256i andmask  = _mm256_set1_epi64x(0x0102040810204080);  // every 8 bits -> 8 bytes, pattern repeats.
-  __m256i zero256   = _mm256_setzero_si256();
-  __m256i masks[8];
-  register __m256i c256;
-  masks[0] = _mm256_set1_epi8(0x1);
-  masks[1] = _mm256_set1_epi8(0x2);
-  masks[2] = _mm256_set1_epi8(0x4);
-  masks[3] = _mm256_set1_epi8(0x8);
-  masks[4] = _mm256_set1_epi8(0x10);
-  masks[5] = _mm256_set1_epi8(0x20);
-  masks[6] = _mm256_set1_epi8(0x40);
-  masks[7] = _mm256_set1_epi8(0x80);
-#endif
-
-
-
-  //determine number of bits in codeword
-  if (BG==1)
-    {
-      nrows=46; //parity check bits
-      ncols=22; //info bits
-      rate=3;
-    }
-    else if (BG==2)
-    {
-      nrows=42; //parity check bits
-      ncols=10; // info bits
-      rate=5;
-    }
-
-#ifdef DEBUG_LDPC
-  LOG_D(PHY,"ldpc_encoder_optim_8seg: BG %d, Zc %d, Kb %d, block_length %d, segments %d\n",BG,Zc,Kb,block_length,n_segments);
-  LOG_D(PHY,"ldpc_encoder_optim_8seg: PDU (seg 0) %x %x %x %x\n",test_input[0][0],test_input[0][1],test_input[0][2],test_input[0][3]);
-#endif
-
-  AssertFatal(Zc>0,"no valid Zc found for block length %d\n",block_length);
-
-  if ((Zc&31) > 0) simd_size = 16;
-  else          simd_size = 32;
-
-  unsigned char c[22*Zc] __attribute__((aligned(32))); //padded input, unpacked, max size
-  unsigned char d[46*Zc] __attribute__((aligned(32))); //coded parity part output, unpacked, max size
-
-  unsigned char c_extension[2*22*Zc*simd_size] __attribute__((aligned(32)));      //double size matrix of c
-
-  // calculate number of punctured bits
-  no_punctured_columns=(int)((nrows-2)*Zc+block_length-block_length*rate)/Zc;
-  removed_bit=(nrows-no_punctured_columns-2) * Zc+block_length-(int)(block_length*rate);
-  //printf("%d\n",no_punctured_columns);
-  //printf("%d\n",removed_bit);
-  // unpack input
-  memset(c,0,sizeof(unsigned char) * ncols * Zc);
-  memset(d,0,sizeof(unsigned char) * nrows * Zc);
-
-  if(tinput != NULL) start_meas(tinput);
-#if 0
-  for (i=0; i<block_length; i++) {
-	//for (j=0; j<n_segments; j++) {
-    for (j=macro_segment; j < macro_segment_end; j++) {
-
-      temp = (test_input[j][i/8]&(1<<(i&7)))>>(i&7);
-      //printf("c(%d,%d)=%d\n",j,i,temp);
-      c[i] |= (temp << (j-macro_segment));
-    }
-  }
-#else
-#ifdef __AVX2__
-  for (i=0; i<block_length>>5; i++) {
-    c256 = _mm256_and_si256(_mm256_cmpeq_epi8(_mm256_andnot_si256(_mm256_shuffle_epi8(_mm256_set1_epi32(((uint32_t*)test_input[macro_segment])[i]), shufmask),andmask),zero256),masks[0]);
-    //for (j=1; j<n_segments; j++) {
-    for (j=macro_segment+1; j < macro_segment_end; j++) {    
-      c256 = _mm256_or_si256(_mm256_and_si256(_mm256_cmpeq_epi8(_mm256_andnot_si256(_mm256_shuffle_epi8(_mm256_set1_epi32(((uint32_t*)test_input[j])[i]), shufmask),andmask),zero256),masks[j-macro_segment]),c256);
-    }
-    ((__m256i *)c)[i] = c256;
-  }
-
-  for (i=(block_length>>5)<<5;i<block_length;i++) {
-    //for (j=0; j<n_segments; j++) {
-	  for (j=macro_segment; j < macro_segment_end; j++) {
-
-	    temp = (test_input[j][i/8]&(128>>(i&7)))>>(7-(i&7));
-      //printf("c(%d,%d)=%d\n",j,i,temp);
-      c[i] |= (temp << (j-macro_segment));
-    }
-  }
-#else
-  AssertFatal(1==0,"Need AVX2 for this\n");
-#endif
-#endif
-
-  if(tinput != NULL) stop_meas(tinput);
-
-  if ((BG==1 && Zc>176) || (BG==2 && Zc>64)) {
-    // extend matrix
-    if(tprep != NULL) start_meas(tprep);
-    for (i1=0; i1 < ncols; i1++)
-      {
-	memcpy(&c_extension[2*i1*Zc], &c[i1*Zc], Zc*sizeof(unsigned char));
-	memcpy(&c_extension[(2*i1+1)*Zc], &c[i1*Zc], Zc*sizeof(unsigned char));
-      }
-    for (i1=1;i1<simd_size;i1++) {
-      memcpy(&c_extension[(2*ncols*Zc*i1)], &c_extension[i1], (2*ncols*Zc*sizeof(unsigned char))-i1);
-      //    memset(&c_extension[(2*ncols*Zc*i1)],0,i1);
-      /*
-	printf("shift %d: ",i1);
-	for (int j=0;j<64;j++) printf("%d ",c_extension[(2*ncols*Zc*i1)+j]);
-	printf("\n");
-      */
-    }
-    if(tprep != NULL) stop_meas(tprep);
-    //parity check part
-    if(tparity != NULL) start_meas(tparity);
-    encode_parity_check_part_optim(c_extension, d, BG, Zc, Kb);
-    if(tparity != NULL) stop_meas(tparity);
-  }
-  else {
-    if (encode_parity_check_part_orig(c, d, BG, Zc, Kb, block_length)!=0) {
-      printf("Problem with encoder\n");
-      return(-1);
-    }
-  }
-  if(toutput != NULL) start_meas(toutput);
-  // information part and puncture columns
-  /*
-  memcpy(&channel_input[0], &c[2*Zc], (block_length-2*Zc)*sizeof(unsigned char));
-  memcpy(&channel_input[block_length-2*Zc], &d[0], ((nrows-no_punctured_columns) * Zc-removed_bit)*sizeof(unsigned char));
-  */
-#ifdef __AVX2__
-  if ((((2*Zc)&31) == 0) && (((block_length-(2*Zc))&31) == 0)) {
-    //AssertFatal(((2*Zc)&31) == 0,"2*Zc needs to be a multiple of 32 for now\n");
-    //AssertFatal(((block_length-(2*Zc))&31) == 0,"block_length-(2*Zc) needs to be a multiple of 32 for now\n");
-    uint32_t l1 = (block_length-(2*Zc))>>5;
-    uint32_t l2 = ((nrows-no_punctured_columns) * Zc-removed_bit)>>5;
-    __m256i *c256p = (__m256i *)&c[2*Zc];
-    __m256i *d256p = (__m256i *)&d[0];
-    //  if (((block_length-(2*Zc))&31)>0) l1++;
-
-    for (i=0;i<l1;i++)
-      //for (j=0;j<n_segments;j++) ((__m256i *)channel_input[j])[i] = _mm256_and_si256(_mm256_srai_epi16(c256p[i],j),masks[0]);
-    	for (j=macro_segment; j < macro_segment_end; j++) ((__m256i *)channel_input[j])[i] = _mm256_and_si256(_mm256_srai_epi16(c256p[i],j-macro_segment),masks[0]);
-
-
-    //  if ((((nrows-no_punctured_columns) * Zc-removed_bit)&31)>0) l2++;
-
-    for (i1=0;i1<l2;i1++,i++)
-      //for (j=0;j<n_segments;j++) ((__m256i *)channel_input[j])[i] = _mm256_and_si256(_mm256_srai_epi16(d256p[i1],j),masks[0]);
-    	for (j=macro_segment; j < macro_segment_end; j++)  ((__m256i *)channel_input[j])[i] = _mm256_and_si256(_mm256_srai_epi16(d256p[i1],j-macro_segment),masks[0]);
-  }
-  else {
-#ifdef DEBUG_LDPC
-  LOG_W(PHY,"using non-optimized version\n");
-#endif
-    // do non-SIMD version
-    for (i=0;i<(block_length-2*Zc);i++)
-      //for (j=0; j<n_segments; j++)
-      for (j=macro_segment; j < macro_segment_end; j++)
-	channel_input[j][i] = (c[2*Zc+i]>>(j-macro_segment))&1;
-    for (i=0;i<((nrows-no_punctured_columns) * Zc-removed_bit);i++)
-      //for (j=0; j<n_segments; j++)
-    	  for (j=macro_segment; j < macro_segment_end; j++)
-	channel_input[j][block_length-2*Zc+i] = (d[i]>>(j-macro_segment))&1;
-    }
-
-#else
-    AssertFatal(1==0,"Need AVX2 for now\n");
-#endif
-
-  if(toutput != NULL) stop_meas(toutput);
-  return 0;
-}
-
diff --git a/openair1/PHY/CODING/nrLDPC_encoder/ldpc_encoder_optim.c b/openair1/PHY/CODING/nrLDPC_encoder/ldpc_encoder_optim.c
new file mode 100644
index 0000000000000000000000000000000000000000..7da265494a020138a2c123ed1dcbe4c0e8d394ea
--- /dev/null
+++ b/openair1/PHY/CODING/nrLDPC_encoder/ldpc_encoder_optim.c
@@ -0,0 +1,146 @@
+/*
+ * 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
+ */
+
+/*!\file ldpc_encoder2.c
+ * \brief Defines the optimized LDPC encoder
+ * \author Florian Kaltenberger, Raymond Knopp, Kien le Trung (Eurecom)
+ * \email openair_tech@eurecom.fr
+ * \date 27-03-2018
+ * \version 1.0
+ * \note
+ * \warning
+ */
+
+#include <stdlib.h>
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+#include <types.h>
+#include "assertions.h"
+#include "common/utils/LOG/log.h"
+#include "PHY/TOOLS/time_meas.h"
+#include "openair1/PHY/CODING/nrLDPC_defs.h"
+#include "ldpc_encode_parity_check.c"
+#include "ldpc_generate_coefficient.c"
+//#define DEBUG_LDPC
+
+
+
+
+
+int nrLDPC_encod(unsigned char **test_input,unsigned char **channel_input,int Zc,int Kb,short block_length, short BG, encoder_implemparams_t *impp)
+{
+
+  short nrows=0,ncols=0;
+  int i,i1,rate=3;
+  int no_punctured_columns,removed_bit;
+
+  int simd_size;
+
+  //determine number of bits in codeword
+   //if (block_length>3840)
+   if (BG==1)
+     {
+       //BG=1;
+       nrows=46; //parity check bits
+       ncols=22; //info bits
+       rate=3;
+     }
+     //else if (block_length<=3840)
+    else if	(BG==2)
+     {
+       //BG=2;
+       nrows=42; //parity check bits
+       ncols=10; // info bits
+       rate=5;
+
+       }
+
+
+#ifdef DEBUG_LDPC
+  LOG_D(PHY,"ldpc_encoder_optim_8seg: BG %d, Zc %d, Kb %d, block_length %d\n",BG,Zc,Kb,block_length);
+  LOG_D(PHY,"ldpc_encoder_optim_8seg: PDU %x %x %x %x\n",test_input[0][0],test_input[0][1],test_input[0][2],test_input[0][3]);
+#endif
+
+  if ((Zc&31) > 0) simd_size = 16;
+  else simd_size = 32;
+
+  unsigned char c[22*Zc] __attribute__((aligned(32))); //padded input, unpacked, max size
+  unsigned char d[46*Zc] __attribute__((aligned(32))); //coded parity part output, unpacked, max size
+
+  unsigned char c_extension[2*22*Zc*simd_size] __attribute__((aligned(32)));      //double size matrix of c
+
+  // calculate number of punctured bits
+  no_punctured_columns=(int)((nrows-2)*Zc+block_length-block_length*rate)/Zc;
+  removed_bit=(nrows-no_punctured_columns-2) * Zc+block_length-(int)(block_length*rate);
+  // printf("%d\n",no_punctured_columns);
+  // printf("%d\n",removed_bit);
+  // unpack input
+  memset(c,0,sizeof(unsigned char) * ncols * Zc);
+  memset(d,0,sizeof(unsigned char) * nrows * Zc);
+
+  if(impp->tinput != NULL) start_meas(impp->tinput);
+  for (i=0; i<block_length; i++) {
+    c[i] = (test_input[0][i/8]&(128>>(i&7)))>>(7-(i&7));
+      //printf("c(%d,%d)=%d\n",j,i,temp);
+    }
+
+  if(impp->tinput != NULL) stop_meas(impp->tinput);
+
+  if ((BG==1 && Zc>176) || (BG==2 && Zc>64)) { 
+    // extend matrix
+    if(impp->tprep != NULL) start_meas(impp->tprep);
+    for (i1=0; i1 < ncols; i1++)
+      {
+	memcpy(&c_extension[2*i1*Zc], &c[i1*Zc], Zc*sizeof(unsigned char));
+	memcpy(&c_extension[(2*i1+1)*Zc], &c[i1*Zc], Zc*sizeof(unsigned char));
+      }
+    for (i1=1;i1<simd_size;i1++) {
+      memcpy(&c_extension[(2*ncols*Zc*i1)], &c_extension[i1], (2*ncols*Zc*sizeof(unsigned char))-i1);
+      //    memset(&c_extension[(2*ncols*Zc*i1)],0,i1);
+      /*
+	printf("shift %d: ",i1);
+	for (int j=0;j<64;j++) printf("%d ",c_extension[(2*ncols*Zc*i1)+j]);
+	printf("\n");
+      */
+    }
+    if(impp->tprep != NULL) stop_meas(impp->tprep);
+    //parity check part
+    if(impp->tparity != NULL) start_meas(impp->tparity);
+    encode_parity_check_part_optim(c_extension, d, BG, Zc, Kb);
+    if(impp->tparity != NULL) stop_meas(impp->tparity);
+  }
+  else {
+    if (encode_parity_check_part_orig(c, d, BG, Zc, Kb, block_length)!=0) {
+      printf("Problem with encoder\n");
+      return(-1);
+    }
+  }
+  if(impp->toutput != NULL) start_meas(impp->toutput);
+  // information part and puncture columns
+  memcpy(&channel_input[0][0], &c[2*Zc], (block_length-2*Zc)*sizeof(unsigned char));
+  memcpy(&channel_input[0][block_length-2*Zc], &d[0], ((nrows-no_punctured_columns) * Zc-removed_bit)*sizeof(unsigned char));
+
+  if(impp->toutput != NULL) stop_meas(impp->toutput);
+  return 0;
+}
+
+
diff --git a/openair1/PHY/CODING/nrLDPC_encoder/ldpc_encoder_optim8seg.c b/openair1/PHY/CODING/nrLDPC_encoder/ldpc_encoder_optim8seg.c
new file mode 100644
index 0000000000000000000000000000000000000000..a974e86e27c428c47574c0d7635f8cfd35ffbbff
--- /dev/null
+++ b/openair1/PHY/CODING/nrLDPC_encoder/ldpc_encoder_optim8seg.c
@@ -0,0 +1,225 @@
+/*
+ * 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
+ */
+
+/*!\file ldpc_encoder2.c
+ * \brief Defines the optimized LDPC encoder
+ * \author Florian Kaltenberger, Raymond Knopp, Kien le Trung (Eurecom)
+ * \email openair_tech@eurecom.fr
+ * \date 27-03-2018
+ * \version 1.0
+ * \note
+ * \warning
+ */
+
+#include <stdlib.h>
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+#include <types.h>
+#include "assertions.h"
+#include "common/utils/LOG/log.h"
+#include "PHY/TOOLS/time_meas.h"
+#include "openair1/PHY/CODING/nrLDPC_defs.h"
+//#define DEBUG_LDPC
+#include "ldpc_encode_parity_check.c" 
+#include "ldpc_generate_coefficient.c"
+
+
+
+int nrLDPC_encod(unsigned char **test_input,unsigned char **channel_input,int Zc,int Kb,short block_length, short BG, encoder_implemparams_t *impp)
+{
+
+  short nrows=0,ncols=0;
+  int i,i1,j,rate=3;
+  int no_punctured_columns,removed_bit;
+  char temp;
+  int simd_size;
+
+#ifdef __AVX2__
+  __m256i shufmask = _mm256_set_epi64x(0x0303030303030303, 0x0202020202020202,0x0101010101010101, 0x0000000000000000);
+  __m256i andmask  = _mm256_set1_epi64x(0x0102040810204080);  // every 8 bits -> 8 bytes, pattern repeats.
+  __m256i zero256   = _mm256_setzero_si256();
+  __m256i masks[8];
+  register __m256i c256;
+  masks[0] = _mm256_set1_epi8(0x1);
+  masks[1] = _mm256_set1_epi8(0x2);
+  masks[2] = _mm256_set1_epi8(0x4);
+  masks[3] = _mm256_set1_epi8(0x8);
+  masks[4] = _mm256_set1_epi8(0x10);
+  masks[5] = _mm256_set1_epi8(0x20);
+  masks[6] = _mm256_set1_epi8(0x40);
+  masks[7] = _mm256_set1_epi8(0x80);
+#endif
+
+  AssertFatal((impp->n_segments>0&&impp->n_segments<=8),"0 < n_segments %d <= 8\n",impp->n_segments);
+
+  //determine number of bits in codeword
+  //if (block_length>3840)
+  if (BG==1)
+    {
+      nrows=46; //parity check bits
+      ncols=22; //info bits
+      rate=3;
+    }
+    //else if (block_length<=3840)
+   else if	(BG==2)
+    {
+      //BG=2;
+      nrows=42; //parity check bits
+      ncols=10; // info bits
+      rate=5;
+
+      }
+
+#ifdef DEBUG_LDPC
+  LOG_D(PHY,"ldpc_encoder_optim_8seg: BG %d, Zc %d, Kb %d, block_length %d, segments %d\n",BG,Zc,Kb,block_length,n_segments);
+  LOG_D(PHY,"ldpc_encoder_optim_8seg: PDU (seg 0) %x %x %x %x\n",test_input[0][0],test_input[0][1],test_input[0][2],test_input[0][3]);
+#endif
+
+  AssertFatal(Zc>0,"no valid Zc found for block length %d\n",block_length);
+
+  if ((Zc&31) > 0) simd_size = 16;
+  else          simd_size = 32;
+
+  unsigned char c[22*Zc] __attribute__((aligned(32))); //padded input, unpacked, max size
+  unsigned char d[46*Zc] __attribute__((aligned(32))); //coded parity part output, unpacked, max size
+
+  unsigned char c_extension[2*22*Zc*simd_size] __attribute__((aligned(32)));      //double size matrix of c
+
+  // calculate number of punctured bits
+  no_punctured_columns=(int)((nrows-2)*Zc+block_length-block_length*rate)/Zc;
+  removed_bit=(nrows-no_punctured_columns-2) * Zc+block_length-(int)(block_length*rate);
+  // printf("%d\n",no_punctured_columns);
+  // printf("%d\n",removed_bit);
+  // unpack input
+  memset(c,0,sizeof(unsigned char) * ncols * Zc);
+  memset(d,0,sizeof(unsigned char) * nrows * Zc);
+
+  if(impp->tinput != NULL) start_meas(impp->tinput);
+#if 0
+  for (i=0; i<block_length; i++) {
+    for (j=0; j<n_segments; j++) {
+
+      temp = (test_input[j][i/8]&(128>>(i&7)))>>(7-(i&7));
+      //printf("c(%d,%d)=%d\n",j,i,temp);
+      c[i] |= (temp << j);
+    }
+  }
+#else
+#ifdef __AVX2__
+  for (i=0; i<block_length>>5; i++) {
+    c256 = _mm256_and_si256(_mm256_cmpeq_epi8(_mm256_andnot_si256(_mm256_shuffle_epi8(_mm256_set1_epi32(((uint32_t*)test_input[0])[i]), shufmask),andmask),zero256),masks[0]);
+    for (j=1; j<impp->n_segments; j++) {
+      c256 = _mm256_or_si256(_mm256_and_si256(_mm256_cmpeq_epi8(_mm256_andnot_si256(_mm256_shuffle_epi8(_mm256_set1_epi32(((uint32_t*)test_input[j])[i]), shufmask),andmask),zero256),masks[j]),c256);
+    }
+    ((__m256i *)c)[i] = c256;
+  }
+
+  for (i=(block_length>>5)<<5;i<block_length;i++) {
+    for (j=0; j<impp->n_segments; j++) {
+
+      temp = (test_input[j][i/8]&(128>>(i&7)))>>(7-(i&7));
+      //printf("c(%d,%d)=%d\n",j,i,temp);
+      c[i] |= (temp << j);
+    }
+  }
+#else
+  AssertFatal(1==0,"Need AVX2 for this\n");
+#endif
+#endif
+
+  if(impp->tinput != NULL) stop_meas(impp->tinput);
+
+  if ((BG==1 && Zc>176) || (BG==2 && Zc>64)) { 
+    // extend matrix
+    if(impp->tprep != NULL) start_meas(impp->tprep);
+    for (i1=0; i1 < ncols; i1++)
+      {
+	memcpy(&c_extension[2*i1*Zc], &c[i1*Zc], Zc*sizeof(unsigned char));
+	memcpy(&c_extension[(2*i1+1)*Zc], &c[i1*Zc], Zc*sizeof(unsigned char));
+      }
+    for (i1=1;i1<simd_size;i1++) {
+      memcpy(&c_extension[(2*ncols*Zc*i1)], &c_extension[i1], (2*ncols*Zc*sizeof(unsigned char))-i1);
+      //    memset(&c_extension[(2*ncols*Zc*i1)],0,i1);
+      /*
+	printf("shift %d: ",i1);
+	for (int j=0;j<64;j++) printf("%d ",c_extension[(2*ncols*Zc*i1)+j]);
+	printf("\n");
+      */
+    }
+    if(impp->tprep != NULL) stop_meas(impp->tprep);
+    //parity check part
+    if(impp->tparity != NULL) start_meas(impp->tparity);
+    encode_parity_check_part_optim(c_extension, d, BG, Zc, Kb);
+    if(impp->tparity != NULL) stop_meas(impp->tparity);
+  }
+  else {
+    if (encode_parity_check_part_orig(c, d, BG, Zc, Kb, block_length)!=0) {
+      printf("Problem with encoder\n");
+      return(-1);
+    }
+  }
+  if(impp->toutput != NULL) start_meas(impp->toutput);
+  // information part and puncture columns
+  /*
+  memcpy(&channel_input[0], &c[2*Zc], (block_length-2*Zc)*sizeof(unsigned char));
+  memcpy(&channel_input[block_length-2*Zc], &d[0], ((nrows-no_punctured_columns) * Zc-removed_bit)*sizeof(unsigned char));
+  */
+#ifdef __AVX2__
+  if ((((2*Zc)&31) == 0) && (((block_length-(2*Zc))&31) == 0)) {
+    //AssertFatal(((2*Zc)&31) == 0,"2*Zc needs to be a multiple of 32 for now\n");
+    //AssertFatal(((block_length-(2*Zc))&31) == 0,"block_length-(2*Zc) needs to be a multiple of 32 for now\n");
+    uint32_t l1 = (block_length-(2*Zc))>>5;
+    uint32_t l2 = ((nrows-no_punctured_columns) * Zc-removed_bit)>>5;
+    __m256i *c256p = (__m256i *)&c[2*Zc];
+    __m256i *d256p = (__m256i *)&d[0];
+    //  if (((block_length-(2*Zc))&31)>0) l1++;
+    
+    for (i=0;i<l1;i++)
+      for (j=0;j<impp->n_segments;j++) ((__m256i *)channel_input[j])[i] = _mm256_and_si256(_mm256_srai_epi16(c256p[i],j),masks[0]);
+    
+    //  if ((((nrows-no_punctured_columns) * Zc-removed_bit)&31)>0) l2++;
+    
+    for (i1=0;i1<l2;i1++,i++)
+      for (j=0;j<impp->n_segments;j++) ((__m256i *)channel_input[j])[i] = _mm256_and_si256(_mm256_srai_epi16(d256p[i1],j),masks[0]);
+  }
+  else {
+#ifdef DEBUG_LDPC
+  LOG_W(PHY,"using non-optimized version\n");
+#endif
+    // do non-SIMD version
+    for (i=0;i<(block_length-2*Zc);i++) 
+      for (j=0; j<impp->n_segments; j++)
+	channel_input[j][i] = (c[2*Zc+i]>>j)&1;
+    for (i=0;i<((nrows-no_punctured_columns) * Zc-removed_bit);i++)
+      for (j=0; j<impp->n_segments; j++)
+	channel_input[j][block_length-2*Zc+i] = (d[i]>>j)&1;
+    }
+
+#else
+    AssertFatal(1==0,"Need AVX2 for now\n");
+#endif
+
+  if(impp->toutput != NULL) stop_meas(impp->toutput);
+  return 0;
+}
+
+
diff --git a/openair1/PHY/CODING/nrLDPC_encoder/ldpc_encoder_optim8segmulti.c b/openair1/PHY/CODING/nrLDPC_encoder/ldpc_encoder_optim8segmulti.c
new file mode 100644
index 0000000000000000000000000000000000000000..28ab5b50293314cd05d41c2201502af56e5effc8
--- /dev/null
+++ b/openair1/PHY/CODING/nrLDPC_encoder/ldpc_encoder_optim8segmulti.c
@@ -0,0 +1,238 @@
+/*
+ * 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
+ */
+
+/*!\file ldpc_encoder2.c
+ * \brief Defines the optimized LDPC encoder
+ * \author Florian Kaltenberger, Raymond Knopp, Kien le Trung (Eurecom)
+ * \email openair_tech@eurecom.fr
+ * \date 27-03-2018
+ * \version 1.0
+ * \note
+ * \warning
+ */
+
+#include <stdlib.h>
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+#include <types.h>
+#include "assertions.h"
+#include "common/utils/LOG/log.h"
+#include "PHY/TOOLS/time_meas.h"
+#include "openair1/PHY/CODING/nrLDPC_defs.h"
+
+//#define DEBUG_LDPC
+
+#include "ldpc_encode_parity_check.c"
+#include "ldpc_generate_coefficient.c"
+
+
+int nrLDPC_encod(unsigned char **test_input,unsigned char **channel_input,int Zc,int Kb,short block_length, short BG, encoder_implemparams_t *impp)
+{
+
+  short nrows=0,ncols=0;
+  int i,i1,j,rate=3;
+  int no_punctured_columns,removed_bit;
+  //Table of possible lifting sizes
+  char temp;
+  int simd_size;
+  unsigned int macro_segment, macro_segment_end;
+
+  
+  macro_segment = 8*impp->macro_num;
+  // macro_segment_end = (n_segments > 8*(macro_num+1)) ? 8*(macro_num+1) : n_segments;
+  macro_segment_end = macro_segment + (impp->n_segments > 8 ? 8 : impp->n_segments);
+  ///printf("macro_segment: %d\n", macro_segment);
+  ///printf("macro_segment_end: %d\n", macro_segment_end );
+
+#ifdef __AVX2__
+  __m256i shufmask = _mm256_set_epi64x(0x0303030303030303, 0x0202020202020202,0x0101010101010101, 0x0000000000000000);
+  __m256i andmask  = _mm256_set1_epi64x(0x0102040810204080);  // every 8 bits -> 8 bytes, pattern repeats.
+  __m256i zero256   = _mm256_setzero_si256();
+  __m256i masks[8];
+  register __m256i c256;
+  masks[0] = _mm256_set1_epi8(0x1);
+  masks[1] = _mm256_set1_epi8(0x2);
+  masks[2] = _mm256_set1_epi8(0x4);
+  masks[3] = _mm256_set1_epi8(0x8);
+  masks[4] = _mm256_set1_epi8(0x10);
+  masks[5] = _mm256_set1_epi8(0x20);
+  masks[6] = _mm256_set1_epi8(0x40);
+  masks[7] = _mm256_set1_epi8(0x80);
+#endif
+
+
+
+  //determine number of bits in codeword
+  if (BG==1)
+    {
+      nrows=46; //parity check bits
+      ncols=22; //info bits
+      rate=3;
+    }
+    else if (BG==2)
+    {
+      nrows=42; //parity check bits
+      ncols=10; // info bits
+      rate=5;
+    }
+
+#ifdef DEBUG_LDPC
+  LOG_D(PHY,"ldpc_encoder_optim_8seg: BG %d, Zc %d, Kb %d, block_length %d, segments %d\n",BG,Zc,Kb,block_length,n_segments);
+  LOG_D(PHY,"ldpc_encoder_optim_8seg: PDU (seg 0) %x %x %x %x\n",test_input[0][0],test_input[0][1],test_input[0][2],test_input[0][3]);
+#endif
+
+  AssertFatal(Zc>0,"no valid Zc found for block length %d\n",block_length);
+
+  if ((Zc&31) > 0) simd_size = 16;
+  else          simd_size = 32;
+
+  unsigned char c[22*Zc] __attribute__((aligned(32))); //padded input, unpacked, max size
+  unsigned char d[46*Zc] __attribute__((aligned(32))); //coded parity part output, unpacked, max size
+
+  unsigned char c_extension[2*22*Zc*simd_size] __attribute__((aligned(32)));      //double size matrix of c
+
+  // calculate number of punctured bits
+  no_punctured_columns=(int)((nrows-2)*Zc+block_length-block_length*rate)/Zc;
+  removed_bit=(nrows-no_punctured_columns-2) * Zc+block_length-(int)(block_length*rate);
+  //printf("%d\n",no_punctured_columns);
+  //printf("%d\n",removed_bit);
+  // unpack input
+  memset(c,0,sizeof(unsigned char) * ncols * Zc);
+  memset(d,0,sizeof(unsigned char) * nrows * Zc);
+
+  if(impp->tinput != NULL) start_meas(impp->tinput);
+#if 0
+  for (i=0; i<block_length; i++) {
+	//for (j=0; j<n_segments; j++) {
+    for (j=macro_segment; j < macro_segment_end; j++) {
+
+      temp = (test_input[j][i/8]&(1<<(i&7)))>>(i&7);
+      //printf("c(%d,%d)=%d\n",j,i,temp);
+      c[i] |= (temp << (j-macro_segment));
+    }
+  }
+#else
+#ifdef __AVX2__
+  for (i=0; i<block_length>>5; i++) {
+    c256 = _mm256_and_si256(_mm256_cmpeq_epi8(_mm256_andnot_si256(_mm256_shuffle_epi8(_mm256_set1_epi32(((uint32_t*)test_input[macro_segment])[i]), shufmask),andmask),zero256),masks[0]);
+    //for (j=1; j<n_segments; j++) {
+    for (j=macro_segment+1; j < macro_segment_end; j++) {    
+      c256 = _mm256_or_si256(_mm256_and_si256(_mm256_cmpeq_epi8(_mm256_andnot_si256(_mm256_shuffle_epi8(_mm256_set1_epi32(((uint32_t*)test_input[j])[i]), shufmask),andmask),zero256),masks[j-macro_segment]),c256);
+    }
+    ((__m256i *)c)[i] = c256;
+  }
+
+  for (i=(block_length>>5)<<5;i<block_length;i++) {
+    //for (j=0; j<n_segments; j++) {
+	  for (j=macro_segment; j < macro_segment_end; j++) {
+
+	    temp = (test_input[j][i/8]&(128>>(i&7)))>>(7-(i&7));
+      //printf("c(%d,%d)=%d\n",j,i,temp);
+      c[i] |= (temp << (j-macro_segment));
+    }
+  }
+#else
+  AssertFatal(1==0,"Need AVX2 for this\n");
+#endif
+#endif
+
+  if(impp->tinput != NULL) stop_meas(impp->tinput);
+
+  if ((BG==1 && Zc>176) || (BG==2 && Zc>64)) {
+    // extend matrix
+    if(impp->tprep != NULL) start_meas(impp->tprep);
+    for (i1=0; i1 < ncols; i1++)
+      {
+	memcpy(&c_extension[2*i1*Zc], &c[i1*Zc], Zc*sizeof(unsigned char));
+	memcpy(&c_extension[(2*i1+1)*Zc], &c[i1*Zc], Zc*sizeof(unsigned char));
+      }
+    for (i1=1;i1<simd_size;i1++) {
+      memcpy(&c_extension[(2*ncols*Zc*i1)], &c_extension[i1], (2*ncols*Zc*sizeof(unsigned char))-i1);
+      //    memset(&c_extension[(2*ncols*Zc*i1)],0,i1);
+      /*
+	printf("shift %d: ",i1);
+	for (int j=0;j<64;j++) printf("%d ",c_extension[(2*ncols*Zc*i1)+j]);
+	printf("\n");
+      */
+    }
+    if(impp->tprep != NULL) stop_meas(impp->tprep);
+    //parity check part
+    if(impp->tparity != NULL) start_meas(impp->tparity);
+    encode_parity_check_part_optim(c_extension, d, BG, Zc, Kb);
+    if(impp->tparity != NULL) stop_meas(impp->tparity);
+  }
+  else {
+    if (encode_parity_check_part_orig(c, d, BG, Zc, Kb, block_length)!=0) {
+      printf("Problem with encoder\n");
+      return(-1);
+    }
+  }
+  if(impp->toutput != NULL) start_meas(impp->toutput);
+  // information part and puncture columns
+  /*
+  memcpy(&channel_input[0], &c[2*Zc], (block_length-2*Zc)*sizeof(unsigned char));
+  memcpy(&channel_input[block_length-2*Zc], &d[0], ((nrows-no_punctured_columns) * Zc-removed_bit)*sizeof(unsigned char));
+  */
+#ifdef __AVX2__
+  if ((((2*Zc)&31) == 0) && (((block_length-(2*Zc))&31) == 0)) {
+    //AssertFatal(((2*Zc)&31) == 0,"2*Zc needs to be a multiple of 32 for now\n");
+    //AssertFatal(((block_length-(2*Zc))&31) == 0,"block_length-(2*Zc) needs to be a multiple of 32 for now\n");
+    uint32_t l1 = (block_length-(2*Zc))>>5;
+    uint32_t l2 = ((nrows-no_punctured_columns) * Zc-removed_bit)>>5;
+    __m256i *c256p = (__m256i *)&c[2*Zc];
+    __m256i *d256p = (__m256i *)&d[0];
+    //  if (((block_length-(2*Zc))&31)>0) l1++;
+
+    for (i=0;i<l1;i++)
+      //for (j=0;j<n_segments;j++) ((__m256i *)channel_input[j])[i] = _mm256_and_si256(_mm256_srai_epi16(c256p[i],j),masks[0]);
+    	for (j=macro_segment; j < macro_segment_end; j++) ((__m256i *)channel_input[j])[i] = _mm256_and_si256(_mm256_srai_epi16(c256p[i],j-macro_segment),masks[0]);
+
+
+    //  if ((((nrows-no_punctured_columns) * Zc-removed_bit)&31)>0) l2++;
+
+    for (i1=0;i1<l2;i1++,i++)
+      //for (j=0;j<n_segments;j++) ((__m256i *)channel_input[j])[i] = _mm256_and_si256(_mm256_srai_epi16(d256p[i1],j),masks[0]);
+    	for (j=macro_segment; j < macro_segment_end; j++)  ((__m256i *)channel_input[j])[i] = _mm256_and_si256(_mm256_srai_epi16(d256p[i1],j-macro_segment),masks[0]);
+  }
+  else {
+#ifdef DEBUG_LDPC
+  LOG_W(PHY,"using non-optimized version\n");
+#endif
+    // do non-SIMD version
+    for (i=0;i<(block_length-2*Zc);i++)
+      //for (j=0; j<n_segments; j++)
+      for (j=macro_segment; j < macro_segment_end; j++)
+	channel_input[j][i] = (c[2*Zc+i]>>(j-macro_segment))&1;
+    for (i=0;i<((nrows-no_punctured_columns) * Zc-removed_bit);i++)
+      //for (j=0; j<n_segments; j++)
+    	  for (j=macro_segment; j < macro_segment_end; j++)
+	channel_input[j][block_length-2*Zc+i] = (d[i]>>(j-macro_segment))&1;
+    }
+
+#else
+    AssertFatal(1==0,"Need AVX2 for now\n");
+#endif
+
+  if(impp->toutput != NULL) stop_meas(impp->toutput);
+  return 0;
+}
+
diff --git a/openair1/PHY/CODING/nrLDPC_encoder/ldpc_generate_coefficient.c b/openair1/PHY/CODING/nrLDPC_encoder/ldpc_generate_coefficient.c
index 5988c9067d0d32a67fbd694f6a9e0398b3f747ec..3d26a190639f4ddac14cc70895f6b00fbb3558dd 100644
--- a/openair1/PHY/CODING/nrLDPC_encoder/ldpc_generate_coefficient.c
+++ b/openair1/PHY/CODING/nrLDPC_encoder/ldpc_generate_coefficient.c
@@ -35,9 +35,8 @@
 #include <string.h>
 #include "Gen_shift_value.h"
 #include "assertions.h"
-#include "defs.h"
 
-short *choose_generator_matrix(short BG,short Zc)
+static inline short *choose_generator_matrix(short BG,short Zc)
 {
   short *Gen_shift_values = NULL;
 
@@ -361,237 +360,70 @@ short *choose_generator_matrix(short BG,short Zc)
   return Gen_shift_values;
 }
 
-int ldpc_encoder_orig(unsigned char *test_input,unsigned char *channel_input,int Zc,int Kb,short block_length, short BG,unsigned char gen_code)
+static inline int encode_parity_check_part_orig(unsigned char *c,unsigned char *d, short BG,short Zc,short Kb,short block_length)
 {
-  unsigned char c[22*384]; //padded input, unpacked, max size
-  unsigned char d[68*384]; //coded output, unpacked, max size
+  short *Gen_shift_values=choose_generator_matrix(BG,Zc);
+  short *no_shift_values, *pointer_shift_values;
+  int no_punctured_columns;
+  short nrows,ncols,rate=3;
+  int i1,i2,i3,i4,i5,temp_prime;
   unsigned char channel_temp,temp;
-  short *Gen_shift_values, *no_shift_values, *pointer_shift_values;
-
-  short nrows = 46;//parity check bits
-  short ncols = 22;//info bits
-
-
-  int i,i1,i2,i3,i4,i5,temp_prime,var;
-  int no_punctured_columns,removed_bit,rate=3;
-  int nind=0;
-  int indlist[1000];
-  int indlist2[1000];
-
-  //determine number of bits in codeword
-  //if (block_length>3840)
-     if (BG==1)
-       {
-         nrows=46; //parity check bits
-         ncols=22; //info bits
-         rate=3;
-       }
-       //else if (block_length<=3840)
-      else if	(BG==2)
-       {
-         //BG=2;
-         nrows=42; //parity check bits
-         ncols=10; // info bits
-         rate=5;
-         }
-
-  Gen_shift_values=choose_generator_matrix(BG,Zc);
-  if (Gen_shift_values==NULL) {
-    printf("ldpc_encoder_orig: could not find generator matrix\n");
-    return(-1);
-  }
-
-  //printf("ldpc_encoder_orig: BG %d, Zc %d, Kb %d\n",BG, Zc, Kb);
 
-  // load base graph of generator matrix
   if (BG==1)
   {
     no_shift_values=(short *) no_shift_values_BG1;
     pointer_shift_values=(short *) pointer_shift_values_BG1;
+      nrows=46; //parity check bits
+      ncols=22; //info bits
+      rate=3;
   }
   else if (BG==2)
   {
     no_shift_values=(short *) no_shift_values_BG2;
     pointer_shift_values=(short *) pointer_shift_values_BG2;
+      nrows=42; //parity check bits
+      ncols=10; //info bits
+      rate=5;
   }
   else {
-    AssertFatal(0,"BG %d is not supported yet\n",BG);
-  }
-  
-  no_punctured_columns=(int)((nrows-2)*Zc+block_length-block_length*rate)/Zc;
-  removed_bit=(nrows-no_punctured_columns-2) * Zc+block_length-(block_length*rate);
-  //printf("%d\n",no_punctured_columns);
-  //printf("%d\n",removed_bit);
-  // unpack input
-  memset(c,0,sizeof(unsigned char) * ncols * Zc);
-  memset(d,0,sizeof(unsigned char) * nrows * Zc);
-
-  for (i=0; i<block_length; i++)
-  {
-    //c[i] = test_input[i/8]<<(i%8);
-    //c[i]=c[i]>>7&1;
-    c[i]=(test_input[i/8]&(128>>(i&7)))>>(7-(i&7));
+    printf("problem with BG\n");
+    return(-1);
   }
 
-  // parity check part
-
-  if (gen_code==1)
-  {
-    char fname[100];
-    sprintf(fname,"ldpc_BG%d_Zc%d_byte.c",BG,Zc);
-    FILE *fd=fopen(fname,"w");
-    AssertFatal(fd!=NULL,"cannot open %s\n",fname);
-    sprintf(fname,"ldpc_BG%d_Zc%d_16bit.c",BG,Zc);
-    FILE *fd2=fopen(fname,"w");
-    AssertFatal(fd2!=NULL,"cannot open %s\n",fname);
-
-    int shift;
-    char data_type[100];
-    char xor_command[100];
-    int mask;
-
-
 
+  no_punctured_columns=(int)((nrows-2)*Zc+block_length-block_length*rate)/Zc;
 
-    fprintf(fd,"#include \"PHY/sse_intrin.h\"\n");
-    fprintf(fd2,"#include \"PHY/sse_intrin.h\"\n");
+  //printf("no_punctured_columns = %d\n",no_punctured_columns);
 
-    if ((Zc&31)==0) {
-      shift=5; // AVX2 - 256-bit SIMD
-      mask=31;
-      strcpy(data_type,"__m256i");
-      strcpy(xor_command,"_mm256_xor_si256");
-    }
-    else if ((Zc&15)==0) {
-      shift=4; // SSE4 - 128-bit SIMD
-      mask=15;
-      strcpy(data_type,"__m128i");
-      strcpy(xor_command,"_mm_xor_si128");
+  for (i2=0; i2 < Zc; i2++)
+  {
+    //t=Kb*Zc+i2;
 
-    }
-    else if ((Zc&7)==0) {
-      shift=3; // MMX  - 64-bit SIMD
-      mask=7;
-      strcpy(data_type,"__m64");
-      strcpy(xor_command,"_mm_xor_si64"); 
-    }
-    else {
-      shift=0;                 // no SIMD
-      mask=0;
-      strcpy(data_type,"uint8_t");
-      strcpy(xor_command,"scalar_xor");
-      fprintf(fd,"#define scalar_xor(a,b) ((a)^(b))\n");
-      fprintf(fd2,"#define scalar_xor(a,b) ((a)^(b))\n");
-    }
-    fprintf(fd,"// generated code for Zc=%d, byte encoding\n",Zc);
-    fprintf(fd2,"// generated code for Zc=%d, 16bit encoding\n",Zc);
-    fprintf(fd,"static inline void ldpc_BG%d_Zc%d_byte(uint8_t *c,uint8_t *d) {\n",BG,Zc);
-    fprintf(fd2,"static inline void ldpc_BG%d_Zc%d_16bit(uint16_t *c,uint16_t *d) {\n",BG,Zc);
-    fprintf(fd,"  %s *csimd=(%s *)c,*dsimd=(%s *)d;\n\n",data_type,data_type,data_type);
-    fprintf(fd2,"  %s *csimd=(%s *)c,*dsimd=(%s *)d;\n\n",data_type,data_type,data_type);
-    fprintf(fd,"  %s *c2,*d2;\n\n",data_type);
-    fprintf(fd2,"  %s *c2,*d2;\n\n",data_type);
-    fprintf(fd,"  int i2;\n");
-    fprintf(fd2,"  int i2;\n");
-    fprintf(fd,"  for (i2=0; i2<%d; i2++) {\n",Zc>>shift);
-    if (shift > 0)
-      fprintf(fd2,"  for (i2=0; i2<%d; i2++) {\n",Zc>>(shift-1));
-    for (i2=0; i2 < 1; i2++)
+    //rotate matrix here
+    for (i5=0; i5 < Kb; i5++)
     {
-      //t=Kb*Zc+i2;
-    
-      // calculate each row in base graph
-     
-
-      fprintf(fd,"     c2=&csimd[i2];\n");
-      fprintf(fd,"     d2=&dsimd[i2];\n");
-      fprintf(fd2,"     c2=&csimd[i2];\n");
-      fprintf(fd2,"     d2=&dsimd[i2];\n");
-
-      for (i1=0; i1 < nrows; i1++)
-
-      {
-        channel_temp=0;
-        fprintf(fd,"\n//row: %d\n",i1);
-        fprintf(fd2,"\n//row: %d\n",i1);
-	fprintf(fd,"     d2[%d]=",(Zc*i1)>>shift);
-	fprintf(fd2,"     d2[%d]=",(Zc*i1)>>(shift-1));
-
-        nind=0;
-
-        for (i3=0; i3 < ncols; i3++)
-        {
-          temp_prime=i1 * ncols + i3;
-
-
-	  for (i4=0; i4 < no_shift_values[temp_prime]; i4++)
-	    {
-	          
-	      var=(int)((i3*Zc + (Gen_shift_values[ pointer_shift_values[temp_prime]+i4 ]+1)%Zc)/Zc);
-	      int index =var*2*Zc + (i3*Zc + (Gen_shift_values[ pointer_shift_values[temp_prime]+i4 ]+1)%Zc) % Zc;
-	      
-	      indlist[nind] = ((index&mask)*((2*Zc)>>shift)*Kb)+(index>>shift);
-	      indlist2[nind++] = ((index&(mask>>1))*((2*Zc)>>(shift-1))*Kb)+(index>>(shift-1));
-	      
-	    }
-	  
-
-        }
-	for (i4=0;i4<nind-1;i4++) {
-	  fprintf(fd,"%s(c2[%d],",xor_command,indlist[i4]);
-	  fprintf(fd2,"%s(c2[%d],",xor_command,indlist2[i4]);
-	}
-	fprintf(fd,"c2[%d]",indlist[i4]);
-	fprintf(fd2,"c2[%d]",indlist2[i4]);
-	for (i4=0;i4<nind-1;i4++) { fprintf(fd,")"); fprintf(fd2,")"); }
-	fprintf(fd,";\n");
-	fprintf(fd2,";\n");
-
-      }
-      fprintf(fd,"  }\n}\n");
-      fprintf(fd2,"  }\n}\n");
+      temp = c[i5*Zc];
+      memmove(&c[i5*Zc], &c[i5*Zc+1], (Zc-1)*sizeof(unsigned char));
+      c[i5*Zc+Zc-1] = temp;
     }
-    fclose(fd);
-    fclose(fd2);
-  }
-  else if(gen_code==0)
-  {
-    for (i2=0; i2 < Zc; i2++)
-    {
-      //t=Kb*Zc+i2;
-
-      //rotate matrix here
-      for (i5=0; i5 < Kb; i5++)
-      {
-        temp = c[i5*Zc];
-        memmove(&c[i5*Zc], &c[i5*Zc+1], (Zc-1)*sizeof(unsigned char));
-        c[i5*Zc+Zc-1] = temp;
-      }
 
-      // calculate each row in base graph
-      for (i1=0; i1 < nrows-no_punctured_columns; i1++)
+    // calculate each row in base graph
+    for (i1=0; i1 < nrows-no_punctured_columns; i1++)
+    {
+      channel_temp=0;
+      for (i3=0; i3 < Kb; i3++)
       {
-        channel_temp=0;
+        temp_prime=i1 * ncols + i3;
 
-        for (i3=0; i3 < Kb; i3++)
+        for (i4=0; i4 < no_shift_values[temp_prime]; i4++)
         {
-          temp_prime=i1 * ncols + i3;
-
-          for (i4=0; i4 < no_shift_values[temp_prime]; i4++)
-          {
-            channel_temp = channel_temp ^ c[ i3*Zc + Gen_shift_values[ pointer_shift_values[temp_prime]+i4 ] ];
-          }
+          channel_temp = channel_temp ^ c[ i3*Zc + Gen_shift_values[ pointer_shift_values[temp_prime]+i4 ] ];
         }
-
-        d[i2+i1*Zc]=channel_temp;
-        //channel_input[t+i1*Zc]=channel_temp;
       }
+      d[i2+i1*Zc]=channel_temp;
+      //channel_input[t+i1*Zc]=channel_temp;
     }
   }
-
-  // information part and puncture columns
-  memcpy(&channel_input[0], &c[2*Zc], (block_length-2*Zc)*sizeof(unsigned char));
-  memcpy(&channel_input[block_length-2*Zc], &d[0], ((nrows-no_punctured_columns) * Zc-removed_bit)*sizeof(unsigned char));
-  //memcpy(channel_input,c,Kb*Zc*sizeof(unsigned char));
-  return 0;
+  return(0);
 }
+
diff --git a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.h b/openair1/PHY/CODING/nrLDPC_extern.h
similarity index 60%
rename from openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.h
rename to openair1/PHY/CODING/nrLDPC_extern.h
index 4d2401db831258b2e1bd8c9abf81e4239f550ae8..c0bfa0fdd8fea89ce82d01c388a5529057d1768a 100644
--- a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.h
+++ b/openair1/PHY/CODING/nrLDPC_extern.h
@@ -18,29 +18,18 @@
  * For more information about the OpenAirInterface (OAI) Software Alliance:
  *      contact@openairinterface.org
  */
+#include "openair1/PHY/CODING/nrLDPC_defs.h"
 
-/*!\file nrLDPC_decoder.h
- * \brief Defines the LDPC decoder core prototypes
- * \author Sebastian Wagner (TCL Communications) Email: <mailto:sebastian.wagner@tcl.com>
- * \date 27-03-2018
- * \version 1.0
- * \note
- * \warning
- */
-
-#ifndef __NR_LDPC_DECODER__H__
-#define __NR_LDPC_DECODER__H__
-
-#include "nrLDPC_types.h"
-#include "nrLDPC_init_mem.h"
-
-/**
-   \brief LDPC decoder
-   \param p_decParams LDPC decoder parameters
-   \param p_llr Input LLRs
-   \param p_llrOut Output vector
-   \param p_profiler LDPC profiler statistics
-*/
-int32_t nrLDPC_decoder(t_nrLDPC_dec_params* p_decParams, int8_t* p_llr, int8_t* p_llrOut, t_nrLDPC_procBuf* p_procBuf, t_nrLDPC_time_stats* p_profiler);
-
-#endif
+#ifdef LDPC_LOADER
+nrLDPC_decoderfunc_t nrLDPC_decoder;
+nrLDPC_encoderfunc_t nrLDPC_encoder;
+#else
+/* functions to load the LDPC shared lib, implemented in openair1/PHY/CODING/nrLDPC_load.c */
+extern int load_nrLDPClib(void) ;
+extern int load_nrLDPClib_ref(char *libversion, nrLDPC_encoderfunc_t * nrLDPC_encoder_ptr); // for ldpctest
+/* ldpc coder/decoder functions, as loaded by load_nrLDPClib(). */
+extern nrLDPC_decoderfunc_t nrLDPC_decoder;
+extern nrLDPC_encoderfunc_t nrLDPC_encoder;
+// inline functions:
+#include "openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_init_mem.h"
+#endif
\ No newline at end of file
diff --git a/openair1/PHY/CODING/nrLDPC_load.c b/openair1/PHY/CODING/nrLDPC_load.c
new file mode 100644
index 0000000000000000000000000000000000000000..a74bdf7bd12a73c81ac6654f3e34495194e631a0
--- /dev/null
+++ b/openair1/PHY/CODING/nrLDPC_load.c
@@ -0,0 +1,76 @@
+/*
+ * 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
+ */
+
+/*! \file openair1/PHY/CODING/coding_nr_load.c
+ * \brief: load library implementing coding/decoding algorithms
+ * \author Francois TABURET
+ * \date 2020
+ * \version 0.1
+ * \company NOKIA BellLabs France
+ * \email: francois.taburet@nokia-bell-labs.com
+ * \note
+ * \warning
+ */
+#define _GNU_SOURCE 
+#include <sys/types.h>
+#include <stdlib.h>
+#include <malloc.h>
+#include "assertions.h"
+#include "common/utils/LOG/log.h"
+#define LDPC_LOADER
+#include "PHY/CODING/nrLDPC_extern.h"
+#include "common/config/config_userapi.h" 
+#include "common/utils/load_module_shlib.h" 
+
+
+/* function description array, to be used when loading the encoding/decoding shared lib */
+static loader_shlibfunc_t shlib_fdesc[2];
+
+char *arg[64]={"ldpctest","-O","cmdlineonly::dbgl0"};
+
+int load_nrLDPClib(void) {
+	 char *ptr = (char*)config_get_if();
+     if ( ptr==NULL )  {// phy simulators, config module possibly not loaded
+     	 load_configmodule(3,(char **)arg,CONFIG_ENABLECMDLINEONLY) ;
+     	 logInit();
+     }	 
+     shlib_fdesc[0].fname = "nrLDPC_decod";
+     shlib_fdesc[1].fname = "nrLDPC_encod";
+     int ret=load_module_shlib("ldpc",shlib_fdesc,sizeof(shlib_fdesc)/sizeof(loader_shlibfunc_t),NULL);
+     AssertFatal( (ret >= 0),"Error loading ldpc decoder");
+     nrLDPC_decoder = (nrLDPC_decoderfunc_t)shlib_fdesc[0].fptr;
+     nrLDPC_encoder = (nrLDPC_encoderfunc_t)shlib_fdesc[1].fptr;
+return 0;
+}
+
+int load_nrLDPClib_ref(char *libversion, nrLDPC_encoderfunc_t * nrLDPC_encoder_ptr) {
+	loader_shlibfunc_t shlib_encoder_fdesc;
+
+     shlib_encoder_fdesc.fname = "nrLDPC_encod";
+     char libpath[64];
+     sprintf(libpath,"ldpc%s",libversion);
+     int ret=load_module_shlib(libpath,&shlib_encoder_fdesc,1,NULL);
+     AssertFatal( (ret >= 0),"Error loading ldpc encoder %s\n",libpath);
+     *nrLDPC_encoder_ptr = (nrLDPC_encoderfunc_t)shlib_encoder_fdesc.fptr;
+return 0;
+}
+
+
diff --git a/openair1/PHY/INIT/nr_init.c b/openair1/PHY/INIT/nr_init.c
index f0ad3cbaaec19b19dfa18c8cd92e4399ee08760a..9024823c04882853f3af00a5681bc73f7e096844 100644
--- a/openair1/PHY/INIT/nr_init.c
+++ b/openair1/PHY/INIT/nr_init.c
@@ -31,6 +31,7 @@
 #include "TDD-Config.h"
 #include "MBSFN-SubframeConfigList.h"*/
 #include "openair1/PHY/defs_RU.h"
+#include "openair1/PHY/CODING/nrLDPC_extern.h"
 #include "LAYER2/NR_MAC_gNB/mac_proto.h"
 #include "assertions.h"
 #include <math.h>
@@ -85,6 +86,8 @@ int phy_init_nr_gNB(PHY_VARS_gNB *gNB,
   nfapi_nr_config_request_t *cfg    = &gNB->gNB_config;
   NR_gNB_COMMON *const common_vars  = &gNB->common_vars;
   NR_gNB_PUSCH **const pusch_vars   = gNB->pusch_vars;
+  dmrs_UplinkConfig_t *dmrs_Uplink_Config = &gNB->pusch_config.dmrs_UplinkConfig;
+  ptrs_UplinkConfig_t *ptrs_Uplink_Config = &gNB->pusch_config.dmrs_UplinkConfig.ptrs_UplinkConfig;
   /*LTE_eNB_SRS *const srs_vars       = gNB->srs_vars;
   LTE_eNB_PRACH *const prach_vars   = &gNB->prach_vars;*/
 
@@ -115,6 +118,7 @@ int phy_init_nr_gNB(PHY_VARS_gNB *gNB,
   LOG_D(PHY,"[MSC_NEW][FRAME 00000][PHY_gNB][MOD %02"PRIu8"][]\n", gNB->Mod_id);
   crcTableInit();
   init_dfts();
+  load_nrLDPClib();
   // PBCH DMRS gold sequences generation
   nr_init_pbch_dmrs(gNB);
   //PDCCH DMRS init
@@ -154,9 +158,9 @@ int phy_init_nr_gNB(PHY_VARS_gNB *gNB,
   }
 
   //------------- config PUSCH DMRS parameters(to be updated from RRC)--------------//
-  gNB->dmrs_UplinkConfig.pusch_dmrs_type = pusch_dmrs_type1;
-  gNB->dmrs_UplinkConfig.pusch_dmrs_AdditionalPosition = pusch_dmrs_pos0;
-  gNB->dmrs_UplinkConfig.pusch_maxLength = pusch_len1;
+  dmrs_Uplink_Config->pusch_dmrs_type = pusch_dmrs_type1;
+  dmrs_Uplink_Config->pusch_dmrs_AdditionalPosition = pusch_dmrs_pos0;
+  dmrs_Uplink_Config->pusch_maxLength = pusch_len1;
   //--------------------------------------------------------------------------------//
 
   nr_init_pdsch_dmrs(gNB, cfg->sch_config.physical_cell_id.value);
@@ -168,6 +172,17 @@ int phy_init_nr_gNB(PHY_VARS_gNB *gNB,
     gNB->pusch_config.pusch_TimeDomainResourceAllocation[i]->mappingType = typeB;
   }
 
+  gNB->ptrs_configured = 0;
+
+  //------------- config PUSCH PTRS parameters(to be updated from RRC)--------------//
+  ptrs_Uplink_Config->timeDensity.ptrs_mcs1 = 0; // setting MCS values to 0 indicate abscence of time_density field in the configuration
+  ptrs_Uplink_Config->timeDensity.ptrs_mcs2 = 0;
+  ptrs_Uplink_Config->timeDensity.ptrs_mcs3 = 0;
+  ptrs_Uplink_Config->frequencyDensity.n_rb0 = 0;     // setting N_RB values to 0 indicate abscence of frequency_density field in the configuration
+  ptrs_Uplink_Config->frequencyDensity.n_rb1 = 0;
+  ptrs_Uplink_Config->resourceElementOffset = 0;
+  //--------------------------------------------------------------------------------//
+
   /// Transport init necessary for NR synchro
   init_nr_transport(gNB);
 
@@ -221,32 +236,36 @@ int phy_init_nr_gNB(PHY_VARS_gNB *gNB,
   for (int UE_id=0; UE_id<NUMBER_OF_UE_MAX; UE_id++) {
     //FIXME
     pusch_vars[UE_id] = (NR_gNB_PUSCH *)malloc16_clear( sizeof(NR_gNB_PUSCH) );
-    pusch_vars[UE_id]->rxdataF_ext           = (int32_t **)malloc16( fp->nb_antennas_rx*sizeof(int32_t *) );
-    pusch_vars[UE_id]->rxdataF_ext2          = (int32_t **)malloc16( fp->nb_antennas_rx*sizeof(int32_t *) );
-    pusch_vars[UE_id]->ul_ch_estimates       = (int32_t **)malloc16( fp->nb_antennas_rx*sizeof(int32_t *) );
-    pusch_vars[UE_id]->ul_ch_estimates_ext   = (int32_t **)malloc16( fp->nb_antennas_rx*sizeof(int32_t *) );
-    pusch_vars[UE_id]->ul_ch_estimates_time  = (int32_t **)malloc16( fp->nb_antennas_rx*sizeof(int32_t *) );
-    pusch_vars[UE_id]->rxdataF_comp          = (int32_t **)malloc16( fp->nb_antennas_rx*sizeof(int32_t *) );
-    pusch_vars[UE_id]->ul_ch_mag0             = (int32_t **)malloc16( fp->nb_antennas_rx*sizeof(int32_t *) );
-    pusch_vars[UE_id]->ul_ch_magb0            = (int32_t **)malloc16( fp->nb_antennas_rx*sizeof(int32_t *) );
-    pusch_vars[UE_id]->ul_ch_mag             = (int32_t **)malloc16( fp->nb_antennas_rx*sizeof(int32_t *) );
-    pusch_vars[UE_id]->ul_ch_magb            = (int32_t **)malloc16( fp->nb_antennas_rx*sizeof(int32_t *) );
-    pusch_vars[UE_id]->rho                   = (int32_t **)malloc16_clear( fp->nb_antennas_rx*sizeof(int32_t*) );
+    pusch_vars[UE_id]->rxdataF_ext              = (int32_t **)malloc16( fp->nb_antennas_rx*sizeof(int32_t *) );
+    pusch_vars[UE_id]->rxdataF_ext2             = (int32_t **)malloc16( fp->nb_antennas_rx*sizeof(int32_t *) );
+    pusch_vars[UE_id]->ul_ch_estimates          = (int32_t **)malloc16( fp->nb_antennas_rx*sizeof(int32_t *) );
+    pusch_vars[UE_id]->ul_ch_estimates_ext      = (int32_t **)malloc16( fp->nb_antennas_rx*sizeof(int32_t *) );
+    pusch_vars[UE_id]->ul_ch_ptrs_estimates     = (int32_t **)malloc16( fp->nb_antennas_rx*sizeof(int32_t *) );
+    pusch_vars[UE_id]->ul_ch_ptrs_estimates_ext = (int32_t **)malloc16( fp->nb_antennas_rx*sizeof(int32_t *) );
+    pusch_vars[UE_id]->ul_ch_estimates_time     = (int32_t **)malloc16( fp->nb_antennas_rx*sizeof(int32_t *) );
+    pusch_vars[UE_id]->rxdataF_comp             = (int32_t **)malloc16( fp->nb_antennas_rx*sizeof(int32_t *) );
+    pusch_vars[UE_id]->ul_ch_mag0               = (int32_t **)malloc16( fp->nb_antennas_rx*sizeof(int32_t *) );
+    pusch_vars[UE_id]->ul_ch_magb0              = (int32_t **)malloc16( fp->nb_antennas_rx*sizeof(int32_t *) );
+    pusch_vars[UE_id]->ul_ch_mag                = (int32_t **)malloc16( fp->nb_antennas_rx*sizeof(int32_t *) );
+    pusch_vars[UE_id]->ul_ch_magb               = (int32_t **)malloc16( fp->nb_antennas_rx*sizeof(int32_t *) );
+    pusch_vars[UE_id]->rho                      = (int32_t **)malloc16_clear( fp->nb_antennas_rx*sizeof(int32_t*) );
 
     for (i=0; i<fp->nb_antennas_rx; i++) {
       // RK 2 times because of output format of FFT!
       // FIXME We should get rid of this
-      pusch_vars[UE_id]->rxdataF_ext[i]           = (int32_t *)malloc16_clear( sizeof(int32_t)*cfg->rf_config.ul_carrier_bandwidth.value*12*fp->symbols_per_slot );
-      pusch_vars[UE_id]->rxdataF_ext2[i]          = (int32_t *)malloc16_clear( sizeof(int32_t)*cfg->rf_config.ul_carrier_bandwidth.value*12*fp->symbols_per_slot );
-      pusch_vars[UE_id]->ul_ch_estimates[i]       = (int32_t *)malloc16_clear( sizeof(int32_t)*cfg->rf_config.ul_carrier_bandwidth.value*12*fp->symbols_per_slot );
-      pusch_vars[UE_id]->ul_ch_estimates_ext[i]   = (int32_t *)malloc16_clear( sizeof(int32_t)*cfg->rf_config.ul_carrier_bandwidth.value*12*fp->symbols_per_slot );
-      pusch_vars[UE_id]->ul_ch_estimates_time[i]  = (int32_t *)malloc16_clear( 2*sizeof(int32_t)*fp->ofdm_symbol_size );
-      pusch_vars[UE_id]->rxdataF_comp[i]          = (int32_t *)malloc16_clear( sizeof(int32_t)*cfg->rf_config.ul_carrier_bandwidth.value*12*fp->symbols_per_slot );
-      pusch_vars[UE_id]->ul_ch_mag0[i]             = (int32_t *)malloc16_clear( fp->symbols_per_slot*sizeof(int32_t)*cfg->rf_config.ul_carrier_bandwidth.value*12 );
-      pusch_vars[UE_id]->ul_ch_magb0[i]            = (int32_t *)malloc16_clear( fp->symbols_per_slot*sizeof(int32_t)*cfg->rf_config.ul_carrier_bandwidth.value*12 );
-      pusch_vars[UE_id]->ul_ch_mag[i]             = (int32_t *)malloc16_clear( fp->symbols_per_slot*sizeof(int32_t)*cfg->rf_config.ul_carrier_bandwidth.value*12 );
-      pusch_vars[UE_id]->ul_ch_magb[i]            = (int32_t *)malloc16_clear( fp->symbols_per_slot*sizeof(int32_t)*cfg->rf_config.ul_carrier_bandwidth.value*12 );
-      pusch_vars[UE_id]->rho[i]                   = (int32_t *)malloc16_clear( sizeof(int32_t)*(fp->N_RB_UL*12*7*2) );
+      pusch_vars[UE_id]->rxdataF_ext[i]                = (int32_t *)malloc16_clear( sizeof(int32_t)*cfg->rf_config.ul_carrier_bandwidth.value*12*fp->symbols_per_slot );
+      pusch_vars[UE_id]->rxdataF_ext2[i]               = (int32_t *)malloc16_clear( sizeof(int32_t)*cfg->rf_config.ul_carrier_bandwidth.value*12*fp->symbols_per_slot );
+      pusch_vars[UE_id]->ul_ch_estimates[i]            = (int32_t *)malloc16_clear( sizeof(int32_t)*cfg->rf_config.ul_carrier_bandwidth.value*12*fp->symbols_per_slot );
+      pusch_vars[UE_id]->ul_ch_estimates_ext[i]        = (int32_t *)malloc16_clear( sizeof(int32_t)*cfg->rf_config.ul_carrier_bandwidth.value*12*fp->symbols_per_slot );
+      pusch_vars[UE_id]->ul_ch_ptrs_estimates[i]       = (int32_t *)malloc16_clear( sizeof(int32_t)*cfg->rf_config.ul_carrier_bandwidth.value*2*fp->symbols_per_slot ); // max intensity in freq is 1 sc every 2 RBs
+      pusch_vars[UE_id]->ul_ch_ptrs_estimates_ext[i]   = (int32_t *)malloc16_clear( sizeof(int32_t)*cfg->rf_config.ul_carrier_bandwidth.value*2*fp->symbols_per_slot );
+      pusch_vars[UE_id]->ul_ch_estimates_time[i]       = (int32_t *)malloc16_clear( 2*sizeof(int32_t)*fp->ofdm_symbol_size );
+      pusch_vars[UE_id]->rxdataF_comp[i]               = (int32_t *)malloc16_clear( sizeof(int32_t)*cfg->rf_config.ul_carrier_bandwidth.value*12*fp->symbols_per_slot );
+      pusch_vars[UE_id]->ul_ch_mag0[i]                 = (int32_t *)malloc16_clear( fp->symbols_per_slot*sizeof(int32_t)*cfg->rf_config.ul_carrier_bandwidth.value*12 );
+      pusch_vars[UE_id]->ul_ch_magb0[i]                = (int32_t *)malloc16_clear( fp->symbols_per_slot*sizeof(int32_t)*cfg->rf_config.ul_carrier_bandwidth.value*12 );
+      pusch_vars[UE_id]->ul_ch_mag[i]                  = (int32_t *)malloc16_clear( fp->symbols_per_slot*sizeof(int32_t)*cfg->rf_config.ul_carrier_bandwidth.value*12 );
+      pusch_vars[UE_id]->ul_ch_magb[i]                 = (int32_t *)malloc16_clear( fp->symbols_per_slot*sizeof(int32_t)*cfg->rf_config.ul_carrier_bandwidth.value*12 );
+      pusch_vars[UE_id]->rho[i]                        = (int32_t *)malloc16_clear( sizeof(int32_t)*(fp->N_RB_UL*12*7*2) );
     }
 
     pusch_vars[UE_id]->llr = (int16_t *)malloc16_clear( (8*((3*8*6144)+12))*sizeof(int16_t) ); // [hna] 6144 is LTE and (8*((3*8*6144)+12)) is not clear 
@@ -350,6 +369,8 @@ void phy_free_nr_gNB(PHY_VARS_gNB *gNB)
       free_and_zero(pusch_vars[UE_id]->rxdataF_ext2[i]);
       free_and_zero(pusch_vars[UE_id]->ul_ch_estimates[i]);
       free_and_zero(pusch_vars[UE_id]->ul_ch_estimates_ext[i]);
+      free_and_zero(pusch_vars[UE_id]->ul_ch_ptrs_estimates[i]);
+      free_and_zero(pusch_vars[UE_id]->ul_ch_ptrs_estimates_ext[i]);
       free_and_zero(pusch_vars[UE_id]->ul_ch_estimates_time[i]);
       free_and_zero(pusch_vars[UE_id]->rxdataF_comp[i]);
       free_and_zero(pusch_vars[UE_id]->ul_ch_mag0[i]);
@@ -363,6 +384,8 @@ void phy_free_nr_gNB(PHY_VARS_gNB *gNB)
     free_and_zero(pusch_vars[UE_id]->rxdataF_ext2);
     free_and_zero(pusch_vars[UE_id]->ul_ch_estimates);
     free_and_zero(pusch_vars[UE_id]->ul_ch_estimates_ext);
+    free_and_zero(pusch_vars[UE_id]->ul_ch_ptrs_estimates);
+    free_and_zero(pusch_vars[UE_id]->ul_ch_ptrs_estimates_ext);
     free_and_zero(pusch_vars[UE_id]->ul_ch_estimates_time);
     free_and_zero(pusch_vars[UE_id]->rxdataF_comp);
     free_and_zero(pusch_vars[UE_id]->ul_ch_mag0);
diff --git a/openair1/PHY/INIT/nr_init_ue.c b/openair1/PHY/INIT/nr_init_ue.c
index 461f441b2cbdf764996af53b5a3c85db2e307f6c..7b7954583dfa725d83ec567127ddff53b90cd9d5 100644
--- a/openair1/PHY/INIT/nr_init_ue.c
+++ b/openair1/PHY/INIT/nr_init_ue.c
@@ -659,6 +659,8 @@ int init_nr_ue_signal(PHY_VARS_NR_UE *ue,
   abstraction_flag = 0;
   fp->nb_antennas_tx = 1;
   fp->nb_antennas_rx=1;
+  dmrs_UplinkConfig_t *dmrs_Uplink_Config = &ue->pusch_config.dmrs_UplinkConfig;
+  ptrs_UplinkConfig_t *ptrs_Uplink_Config = &ue->pusch_config.dmrs_UplinkConfig.ptrs_UplinkConfig;
   printf("Initializing UE vars (abstraction %"PRIu8") for eNB TXant %"PRIu8", UE RXant %"PRIu8"\n",abstraction_flag,fp->nb_antennas_tx,fp->nb_antennas_rx);
   //LOG_D(PHY,"[MSC_NEW][FRAME 00000][PHY_UE][MOD %02u][]\n", ue->Mod_id+NB_eNB_INST);
   nr_init_frame_parms_ue(fp,NR_MU_1,NORMAL,fp->N_RB_DL,n_ssb_crb,k_ssb);
@@ -711,9 +713,9 @@ int init_nr_ue_signal(PHY_VARS_NR_UE *ue,
   }
 
   //------------- config DMRS parameters--------------//
-  ue->dmrs_UplinkConfig.pusch_dmrs_type = pusch_dmrs_type1;
-  ue->dmrs_UplinkConfig.pusch_dmrs_AdditionalPosition = pusch_dmrs_pos0;
-  ue->dmrs_UplinkConfig.pusch_maxLength = pusch_len1;
+  dmrs_Uplink_Config->pusch_dmrs_type = pusch_dmrs_type1;
+  dmrs_Uplink_Config->pusch_dmrs_AdditionalPosition = pusch_dmrs_pos0;
+  dmrs_Uplink_Config->pusch_maxLength = pusch_len1;
   //-------------------------------------------------//
   ue->dmrs_DownlinkConfig.pdsch_dmrs_type = pdsch_dmrs_type1;
   ue->dmrs_DownlinkConfig.pdsch_dmrs_AdditionalPosition = pdsch_dmrs_pos0;
@@ -743,6 +745,23 @@ int init_nr_ue_signal(PHY_VARS_NR_UE *ue,
   ///////////
   ////////////////////////////////////////////////////////////////////////////////////////////
 
+  /////////////////////////PUSCH PTRS init/////////////////////////
+  ///////////
+
+  ue->ptrs_configured = 0; // flag to be toggled by RCC
+
+  //------------- config PTRS parameters--------------//
+  ptrs_Uplink_Config->timeDensity.ptrs_mcs1 = 0; // setting MCS values to 0 indicate abscence of time_density field in the configuration
+  ptrs_Uplink_Config->timeDensity.ptrs_mcs2 = 0;
+  ptrs_Uplink_Config->timeDensity.ptrs_mcs3 = 0;
+  ptrs_Uplink_Config->frequencyDensity.n_rb0 = 0;     // setting N_RB values to 0 indicate abscence of frequency_density field in the configuration
+  ptrs_Uplink_Config->frequencyDensity.n_rb1 = 0;
+  ptrs_Uplink_Config->resourceElementOffset = 0;
+  //-------------------------------------------------//
+
+  ///////////
+  ////////////////////////////////////////////////////////////////////////////////////////////
+
   for (i=0; i<10; i++)
     ue->tx_power_dBm[i]=-127;
 
diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c
index ab6ccd929bc28004befe4fdaf1868706265a8e29..83c6f054cd88d703378715430f150c0f48921321 100644
--- a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c
+++ b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c
@@ -117,7 +117,7 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB,
 
   //------------------generate DMRS------------------//
 
-  length_dmrs = gNB->dmrs_UplinkConfig.pusch_maxLength;
+  length_dmrs = dmrs_UplinkConfig->pusch_maxLength;
 
   nr_gold_pusch(gNB, symbol, n_idDMRS, length_dmrs);
 
diff --git a/openair1/PHY/NR_REFSIG/ptrs_nr.c b/openair1/PHY/NR_REFSIG/ptrs_nr.c
new file mode 100644
index 0000000000000000000000000000000000000000..9be37d2d952adb05bbf700f811394f3e463854b4
--- /dev/null
+++ b/openair1/PHY/NR_REFSIG/ptrs_nr.c
@@ -0,0 +1,429 @@
+/*
+ * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The OpenAirInterface Software Alliance licenses this file to You under
+ * the OAI Public License, Version 1.1  (the "License"); you may not use this file
+ * except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.openairinterface.org/?page_id=698
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *-------------------------------------------------------------------------------
+ * For more information about the OpenAirInterface (OAI) Software Alliance:
+ *      contact@openairinterface.org
+ */
+
+/**********************************************************************
+*
+* FILENAME    :  ptrs_nr.c
+*
+* MODULE      :  phase tracking reference signals
+*
+* DESCRIPTION :  resource element mapping of ptrs sequences
+*                3GPP TS 38.211 and 3GPP TS 38.214
+*
+************************************************************************/
+
+#include <stdint.h>
+#include <stdio.h>
+#include "dmrs_nr.h"
+#include "PHY/NR_REFSIG/ptrs_nr.h"
+
+/***********************************************************************/
+
+
+ //#define max(a,b) (((a) > (b)) ? (a) : (b))
+
+// TS 38.211 Table 6.4.1.2.2.1-1: The parameter kRE_ref.
+// The first 4 colomns are DM-RS Configuration type 1 and the last 4 colomns are DM-RS Configuration type 2.
+
+int16_t table_6_4_1_2_2_1_1_pusch_ptrs_kRE_ref [6][8] = {
+{ 0,            2,           6,          8,          0,          1,         6,         7},
+{ 2,            4,           8,         10,          1,          6,         7,         0},
+{ 1,            3,           7,          9,          2,          3,         8,         9},
+{ 3,            5,           9,         11,          3,          8,         9,         2},
+{-1,           -1,          -1,         -1,          4,          5,        10,        11},
+{-1,           -1,          -1,         -1,          5,         10,        11,         4},
+};
+
+
+/*******************************************************************
+*
+* NAME :         get_kRE_ref
+*
+* PARAMETERS :   dmrs_antenna_port      DMRS antenna port
+*                pusch_dmrs_type        PUSCH DMRS type
+*                resourceElementOffset  the parameter resourceElementOffset
+*
+* RETURN :       the parameter k_RE_ref
+*
+* DESCRIPTION :  3GPP TS 38.211 Table 6.4.1.2.2.1-1
+*
+*********************************************************************/
+
+int16_t get_kRE_ref(uint8_t dmrs_antenna_port, uint8_t pusch_dmrs_type, uint8_t resourceElementOffset) {
+
+  uint8_t colomn;
+  int16_t k_RE_ref;
+
+  colomn = resourceElementOffset;
+
+  if (pusch_dmrs_type == 2)
+    colomn += 4;
+
+  k_RE_ref = table_6_4_1_2_2_1_1_pusch_ptrs_kRE_ref[dmrs_antenna_port][colomn];
+
+  AssertFatal(k_RE_ref>=0,"invalid k_RE_ref < 0. Check PTRS Configuration\n");
+
+  return k_RE_ref;
+}
+
+
+/*******************************************************************
+*
+* NAME :         get_K_ptrs
+*
+* PARAMETERS :   ptrs_UplinkConfig      PTRS uplink configuration
+*                N_RB                   number of RBs scheduled for PUSCH
+*
+* RETURN :       the parameter K_ptrs
+*
+* DESCRIPTION :  3GPP TS 38.214 6.2.3 Table 6.2.3.1-2
+*
+*********************************************************************/
+
+uint8_t get_K_ptrs(ptrs_UplinkConfig_t *ptrs_UplinkConfig, uint16_t N_RB){
+
+	uint16_t nrb0, nrb1;
+
+	nrb0 = ptrs_UplinkConfig->frequencyDensity.n_rb0;
+	nrb1 = ptrs_UplinkConfig->frequencyDensity.n_rb1;
+
+	if (nrb0 == 0 || nrb0 == 0)
+		return 2;
+
+	if (N_RB < nrb0){
+		LOG_I(PHY,"PUSH PT-RS is not present.\n");
+		return 0;
+	}
+	else if (N_RB >= nrb0 && N_RB < nrb1)
+		return 2;
+	else
+		return 4;
+}
+
+/*******************************************************************
+*
+* NAME :         set_ptrs_symb_idx
+*
+* PARAMETERS :   ptrs_symbols           PTRS OFDM symbol indicies bit mask
+*                ptrs_UplinkConfig      PTRS uplink configuration
+*                dmrs_UplinkConfig      DMRS uplink configuration
+*                mapping_type           PUSCH time domain mapping type
+*                duration_in_symbols    number of scheduled PUSCH ofdm symbols
+*                start_symbol           first ofdm symbol of PUSCH within slot
+*                L_ptrs                 the parameter L_ptrs
+*                ofdm_symbol_size       FFT size
+*
+* RETURN :       sets the bit map of PTRS ofdm symbol indicies
+*
+* DESCRIPTION :  3GPP TS 38.211 6.4.1.2.2.1
+*
+*********************************************************************/
+
+void set_ptrs_symb_idx(uint16_t *ptrs_symbols,
+                       ptrs_UplinkConfig_t *ptrs_UplinkConfig,
+                       dmrs_UplinkConfig_t *dmrs_UplinkConfig,
+                       uint8_t mapping_type,
+                       uint8_t duration_in_symbols,
+                       uint8_t start_symbol,
+                       uint8_t L_ptrs,
+                       uint16_t ofdm_symbol_size) {
+
+	uint8_t i, last_symbol, is_dmrs_symbol1, is_dmrs_symbol2;
+	int16_t l_ref;
+
+	*ptrs_symbols = 0;
+	i = 0;
+	is_dmrs_symbol1 = 0;
+	is_dmrs_symbol2 = 0;
+	l_ref = start_symbol;
+	last_symbol = start_symbol + duration_in_symbols - 1;
+
+	while ( (l_ref + i*L_ptrs) <= last_symbol) {
+
+		is_dmrs_symbol1 = is_dmrs_symbol(max((l_ref + (i-1)*L_ptrs + 1), l_ref),
+                                         0,
+                                         0,
+                                         0,
+                                         0,
+                                         0,
+                                         duration_in_symbols,
+                                         dmrs_UplinkConfig,
+                                         mapping_type,
+                                         ofdm_symbol_size);
+
+		is_dmrs_symbol2 = is_dmrs_symbol(l_ref + i*L_ptrs,
+                                         0,
+                                         0,
+                                         0,
+                                         0,
+                                         0,
+                                         duration_in_symbols,
+                                         dmrs_UplinkConfig,
+                                         mapping_type,
+                                         ofdm_symbol_size);
+
+		if ( is_dmrs_symbol1 + is_dmrs_symbol2 > 0 ) {
+
+			if (dmrs_UplinkConfig->pusch_maxLength == 2)
+				l_ref = l_ref + i*L_ptrs + 1;
+			else
+				l_ref = l_ref + i*L_ptrs;
+
+			i = 1;
+
+			continue;
+
+		}
+
+		*ptrs_symbols = *ptrs_symbols | (1<<(l_ref + i*L_ptrs));
+		i++;
+	}
+}
+
+/*******************************************************************
+*
+* NAME :         get_L_ptrs
+*
+* PARAMETERS :   ptrs_UplinkConfig      PTRS uplink configuration
+*                I_mcs                  MCS index used for PUSCH
+*
+* RETURN :       the parameter L_ptrs
+*
+* DESCRIPTION :  3GPP TS 38.214 6.2.3 Table 6.2.3.1-1
+*
+*********************************************************************/
+
+uint8_t get_L_ptrs(ptrs_UplinkConfig_t *ptrs_UplinkConfig, uint8_t I_mcs) {
+
+	uint8_t mcs1, mcs2, mcs3;
+
+	mcs1 = ptrs_UplinkConfig->timeDensity.ptrs_mcs1;
+	mcs2 = ptrs_UplinkConfig->timeDensity.ptrs_mcs2;
+	mcs3 = ptrs_UplinkConfig->timeDensity.ptrs_mcs3;
+
+	if (mcs1 == 0 || mcs2 == 0 || mcs3 == 0)
+		return 1;
+
+	if (I_mcs < mcs1){
+		LOG_I(PHY,"PUSH PT-RS is not present.\n");
+		return 0;
+	}
+	else if (I_mcs >= mcs1 && I_mcs < mcs2)
+		return 4;
+	else if (I_mcs >= mcs2 && I_mcs < mcs3)
+		return 2;
+	else
+		return 1;
+}
+
+/*******************************************************************
+*
+* NAME :         is_ptrs_subcarrier
+*
+* PARAMETERS : k                      subcarrier index
+*              K_ptrs                 the parameter K_ptrs
+*              n_rnti                 UE CRNTI
+*              N_RB                   number of RBs scheduled for PUSCH
+*              k_RE_ref               the parameter k_RE_ref
+*              start_sc               first subcarrier index
+*              ofdm_symbol_size       FFT size
+*
+* RETURN :       1 if subcarrier k is PTRS, or 0 otherwise
+*
+* DESCRIPTION :  3GPP TS 38.211 6.4.1.2 Phase-tracking reference signal for PUSCH
+*
+*********************************************************************/
+
+uint8_t is_ptrs_subcarrier(uint16_t k, uint8_t K_ptrs, uint16_t n_rnti, uint16_t N_RB, int16_t k_RE_ref, uint16_t start_sc, uint16_t ofdm_symbol_size) {
+
+	uint16_t k_RB_ref, i, sc;
+
+	i = 0;
+	sc = 0;
+	k_RB_ref = 0;
+
+	if (N_RB % K_ptrs == 0)
+		k_RB_ref = n_rnti % K_ptrs;
+	else
+		k_RB_ref = n_rnti % (N_RB % K_ptrs);
+
+	while (k > sc){
+
+		sc = (start_sc + k_RE_ref + (i*K_ptrs + k_RB_ref)*NR_NB_SC_PER_RB)%ofdm_symbol_size;
+		i++;
+
+	}
+
+	if (k == sc)
+        return 1;
+	else
+        return 0;
+
+}
+
+/*******************************************************************
+*
+* NAME :         is_ptrs_symbol
+*
+* PARAMETERS : l                      ofdm symbol index within slot
+*              k                      subcarrier index
+*              n_rnti                 UE CRNTI
+*              N_RB                   number of RBs scheduled for PUSCH
+*              duration_in_symbols    number of scheduled PUSCH ofdm symbols
+*              dmrs_antenna_port      DMRS antenna port
+*              K_ptrs                 the parameter K_ptrs
+*              ptrs_symbols           bit mask of ptrs
+*              start_sc               first subcarrier index
+*              ofdm_symbol_size       FFT size
+*              pusch_dmrs_type        PUSCH DMRS type (1 or 2)
+*              ptrs_UplinkConfig      PTRS uplink configuration
+*
+* RETURN :       0 if symbol(k,l) is data, or 1 if symbol(k,l) is ptrs
+*
+* DESCRIPTION :  3GPP TS 38.211 6.4.1.2 Phase-tracking reference signal for PUSCH
+*
+*********************************************************************/
+
+uint8_t is_ptrs_symbol(uint8_t l,
+                       uint16_t k,
+                       uint16_t n_rnti,
+                       uint16_t N_RB,
+                       uint8_t duration_in_symbols,
+                       uint8_t dmrs_antenna_port,
+                       uint8_t K_ptrs,
+                       uint16_t ptrs_symbols,
+                       uint16_t start_sc,
+                       uint16_t ofdm_symbol_size,
+                       pusch_dmrs_type_t pusch_dmrs_type,
+                       ptrs_UplinkConfig_t *ptrs_UplinkConfig) {
+
+  uint8_t is_ptrs_freq, is_ptrs_time;
+  int16_t k_RE_ref;
+
+  is_ptrs_freq = 0;
+  is_ptrs_time = 0;
+
+  k_RE_ref = get_kRE_ref(dmrs_antenna_port, pusch_dmrs_type, ptrs_UplinkConfig->resourceElementOffset);
+
+  is_ptrs_freq = is_ptrs_subcarrier(k, K_ptrs, n_rnti, N_RB, k_RE_ref, start_sc, ofdm_symbol_size);
+
+  if (is_ptrs_freq == 0)
+    return 0;
+
+  if (((ptrs_symbols>>l)&1) == 1)
+    is_ptrs_time = 1;
+
+  if (is_ptrs_time && is_ptrs_freq)
+    return 1;
+  else
+    return 0;
+
+}
+
+/*
+int main(int argc, char const *argv[])
+{
+
+	dmrs_UplinkConfig_t dmrs_Uplink_Config;
+	ptrs_UplinkConfig_t ptrs_Uplink_Config;
+	uint8_t resourceElementOffset;
+	uint8_t dmrs_antenna_port;
+	uint8_t L_ptrs, K_ptrs;
+	int16_t k_RE_ref;
+	uint16_t N_RB, ptrs_symbols, ofdm_symbol_size, k;
+	uint8_t duration_in_symbols, I_mcs;
+	uint8_t start_symbol, l;
+	uint8_t ptrs_symbol_flag;
+	uint16_t n_rnti;
+
+    dmrs_Uplink_Config.pusch_dmrs_type = pusch_dmrs_type1;
+    dmrs_Uplink_Config.pusch_dmrs_AdditionalPosition = pusch_dmrs_pos1;
+    dmrs_Uplink_Config.pusch_maxLength = pusch_len2;
+
+    ptrs_Uplink_Config.timeDensity.ptrs_mcs1 = 0; // setting MCS values to 0 indicate abscence of time_density field in the configuration
+    ptrs_Uplink_Config.timeDensity.ptrs_mcs2 = 0;
+    ptrs_Uplink_Config.timeDensity.ptrs_mcs3 = 0;
+    ptrs_Uplink_Config.frequencyDensity.n_rb0 = 0;     // setting N_RB values to 0 indicate abscence of frequency_density field in the configuration
+    ptrs_Uplink_Config.frequencyDensity.n_rb1 = 0;
+    ptrs_Uplink_Config.resourceElementOffset = 0;
+
+    n_rnti = 0x1234;
+    resourceElementOffset = 0;
+    ptrs_symbols = 0;
+	dmrs_antenna_port = 0;
+	N_RB = 50;
+	duration_in_symbols = 14;
+	ofdm_symbol_size = 2048;
+	I_mcs = 9;
+	start_symbol = 0;
+	ptrs_symbol_flag = 0;
+
+    k_RE_ref = get_kRE_ref(dmrs_antenna_port, dmrs_Uplink_Config.pusch_dmrs_type, resourceElementOffset);
+
+    K_ptrs = get_K_ptrs(&ptrs_Uplink_Config, N_RB);
+
+    L_ptrs = get_L_ptrs(&ptrs_Uplink_Config, I_mcs);
+
+    set_ptrs_symb_idx(&ptrs_symbols,
+                      &ptrs_Uplink_Config,
+                      &dmrs_Uplink_Config,
+                      1,
+                      duration_in_symbols,
+                      start_symbol,
+                      L_ptrs,
+                      ofdm_symbol_size);
+
+    printf("PTRS OFDM symbol indicies: ");
+
+    for (l = start_symbol; l < start_symbol + duration_in_symbols; l++){
+
+        ptrs_symbol_flag = is_ptrs_symbol(l,
+                                          0,
+                                          n_rnti,
+                                          N_RB,
+                                          duration_in_symbols,
+                                          dmrs_antenna_port,
+                                          K_ptrs,
+                                          ptrs_symbols,
+                                          dmrs_Uplink_Config.pusch_dmrs_type,
+                                          &ptrs_Uplink_Config);
+
+        if (ptrs_symbol_flag == 1)
+            printf(" %d ", l);
+
+    }
+
+    printf("\n");
+
+    printf("PTRS subcarrier indicies: ");
+
+    for (k = 0; k < N_RB*12; k++){
+
+        if (is_ptrs_subcarrier(k, K_ptrs, n_rnti, N_RB, k_RE_ref) == 1)
+            printf(" %d ", k);
+
+    }
+
+    printf("\n");
+
+	return 0;
+}
+*/
\ No newline at end of file
diff --git a/openair1/PHY/NR_REFSIG/ptrs_nr.h b/openair1/PHY/NR_REFSIG/ptrs_nr.h
new file mode 100644
index 0000000000000000000000000000000000000000..f3b42fff30dd512112fe942fa57b245ef887c2a9
--- /dev/null
+++ b/openair1/PHY/NR_REFSIG/ptrs_nr.h
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The OpenAirInterface Software Alliance licenses this file to You under
+ * the OAI Public License, Version 1.1  (the "License"); you may not use this file
+ * except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.openairinterface.org/?page_id=698
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *-------------------------------------------------------------------------------
+ * For more information about the OpenAirInterface (OAI) Software Alliance:
+ *      contact@openairinterface.org
+ */
+
+/**********************************************************************
+*
+* FILENAME    :  dmrs.h
+*
+* MODULE      :  demodulation reference signals
+*
+* DESCRIPTION :  generation of dmrs sequences for NR 5G
+*                3GPP TS 38.211
+*
+************************************************************************/
+
+#ifndef PTRS_NR_H
+#define PTRS_NR_H
+
+#include "PHY/defs_nr_UE.h"
+
+/************** CODE GENERATION ***********************************/
+
+/************** DEFINE ********************************************/
+
+
+/************* STRUCTURES *****************************************/
+
+
+/************** VARIABLES *****************************************/
+
+/************** FUNCTION ******************************************/
+
+int16_t get_kRE_ref(uint8_t dmrs_antenna_port, uint8_t pusch_dmrs_type, uint8_t resourceElementOffset);
+
+uint8_t get_K_ptrs(ptrs_UplinkConfig_t *ptrs_UplinkConfig, uint16_t N_RB);
+
+void set_ptrs_symb_idx(uint16_t *ptrs_symbols,
+                       ptrs_UplinkConfig_t *ptrs_UplinkConfig,
+                       dmrs_UplinkConfig_t *dmrs_UplinkConfig,
+                       uint8_t mapping_type,
+                       uint8_t duration_in_symbols,
+                       uint8_t start_symbol,
+                       uint8_t L_ptrs,
+                       uint16_t ofdm_symbol_size);
+
+uint8_t get_L_ptrs(ptrs_UplinkConfig_t *ptrs_UplinkConfig, uint8_t I_mcs);
+
+uint8_t is_ptrs_subcarrier(uint16_t k, uint8_t K_ptrs, uint16_t n_rnti, uint16_t N_RB, int16_t k_RE_ref, uint16_t start_sc, uint16_t ofdm_symbol_size);
+
+uint8_t is_ptrs_symbol(uint8_t l,
+                       uint16_t k,
+                       uint16_t n_rnti,
+                       uint16_t N_RB,
+                       uint8_t duration_in_symbols,
+                       uint8_t dmrs_antenna_port,
+                       uint8_t K_ptrs,
+                       uint16_t ptrs_symbols,
+                       uint16_t start_sc,
+                       uint16_t ofdm_symbol_size,
+                       pusch_dmrs_type_t pusch_dmrs_type,
+                       ptrs_UplinkConfig_t *ptrs_UplinkConfig);
+
+
+
+#endif /* PTRS_NR_H */
\ No newline at end of file
diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c b/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c
index dae5586224948a1b94dfe1d094b7d938a5854c3c..17de9c02af8c8cf338272f472e04f7c17afed013 100644
--- a/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c
+++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c
@@ -35,12 +35,11 @@
 #include "PHY/CODING/coding_extern.h"
 #include "PHY/CODING/coding_defs.h"
 #include "PHY/CODING/lte_interleaver_inline.h"
-#include "PHY/CODING/nrLDPC_encoder/defs.h"
+#include "PHY/CODING/nrLDPC_extern.h"
 #include "PHY/NR_TRANSPORT/nr_transport.h"
 #include "PHY/NR_TRANSPORT/nr_transport_common_proto.h"
 #include "PHY/NR_TRANSPORT/nr_dlsch.h"
 #include "SCHED_NR/sched_nr.h"
-#include "defs.h"
 #include "common/utils/LOG/vcd_signal_dumper.h"
 #include "common/utils/LOG/log.h"
 #include <syscall.h>
@@ -404,9 +403,11 @@ int nr_dlsch_encoding(unsigned char *a,
       //ldpc_encoder_orig((unsigned char*)dlsch->harq_processes[harq_pid]->c[r],dlsch->harq_processes[harq_pid]->d[r],*Zc,Kb,Kr,BG,0);
       //ldpc_encoder_optim((unsigned char*)dlsch->harq_processes[harq_pid]->c[r],(unsigned char*)&dlsch->harq_processes[harq_pid]->d[r][0],*Zc,Kb,Kr,BG,NULL,NULL,NULL,NULL);
     }
-
+    encoder_implemparams_t impp;
+    impp.n_segments=dlsch->harq_processes[harq_pid]->C;
     for(int j=0;j<(dlsch->harq_processes[harq_pid]->C/8+1);j++) {
-      ldpc_encoder_optim_8seg_multi(dlsch->harq_processes[harq_pid]->c,dlsch->harq_processes[harq_pid]->d,*Zc,Kb,Kr,BG,dlsch->harq_processes[harq_pid]->C,j,NULL,NULL,NULL,NULL);
+      impp.macro_num=j;
+      nrLDPC_encoder(dlsch->harq_processes[harq_pid]->c,dlsch->harq_processes[harq_pid]->d,*Zc,Kb,Kr,BG,&impp);
     }
 
 
diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch_tools.c b/openair1/PHY/NR_TRANSPORT/nr_dlsch_tools.c
index 9736e97e34cd61035bca14859650789e3a249cd3..a158d5bf6244bb3b4b955afea313d30f01aa4fe0 100644
--- a/openair1/PHY/NR_TRANSPORT/nr_dlsch_tools.c
+++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch_tools.c
@@ -338,7 +338,7 @@ void nr_fill_ulsch(PHY_VARS_gNB *gNB,
   rel15_ul->ulsch_pdu_rel15.number_rbs     = ulsch_pdu->rb_size;
   rel15_ul->ulsch_pdu_rel15.start_symbol   = ulsch_pdu->start_symbol_index;
   rel15_ul->ulsch_pdu_rel15.number_symbols = ulsch_pdu->nr_of_symbols;
-  rel15_ul->ulsch_pdu_rel15.length_dmrs    = gNB->dmrs_UplinkConfig.pusch_maxLength;
+  rel15_ul->ulsch_pdu_rel15.length_dmrs    = gNB->pusch_config.dmrs_UplinkConfig.pusch_maxLength;
   rel15_ul->ulsch_pdu_rel15.Qm             = ulsch_pdu->qam_mod_order;
   rel15_ul->ulsch_pdu_rel15.mcs            = ulsch_pdu->mcs_index;
   rel15_ul->ulsch_pdu_rel15.rv             = ulsch_pdu->pusch_data.rv_index;
diff --git a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h
index 4c8d8650e3adee0c425825455a150ff7db05291c..d3985bfd8bd61c542cd89a8d9b127f19d678b30f 100644
--- a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h
+++ b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h
@@ -65,20 +65,18 @@ void nr_rx_pusch(PHY_VARS_gNB *gNB,
     @param is_dmrs_symbol, flag to indicate wether this OFDM symbol contains DMRS symbols or not.
 
 */
-void nr_ulsch_extract_rbs_single(int **rxdataF,
-                                 int **ul_ch_estimates,
-                                 int **rxdataF_ext,
-                                 int **ul_ch_estimates_ext,
-                                 uint32_t rxdataF_ext_offset,
-                                 // unsigned int *rb_alloc, [hna] Resource Allocation Type 1 is assumed only for the moment
+void nr_ulsch_extract_rbs_single(int32_t **rxdataF,
+                                 NR_gNB_PUSCH *pusch_vars,
                                  unsigned char symbol,
                                  unsigned short start_rb,
                                  unsigned short nb_rb_pusch,
+                                 uint16_t n_rnti,
                                  NR_DL_FRAME_PARMS *frame_parms,
-                                 uint8_t dmrs_symbol,
                                  uint16_t number_symbols,
                                  uint8_t mapping_type,
-                                 dmrs_UplinkConfig_t *dmrs_UplinkConfig);
+                                 uint8_t ptrs_configured,
+                                 dmrs_UplinkConfig_t *dmrs_UplinkConfig,
+                                 ptrs_UplinkConfig_t *ptrs_Uplink_Config);
 
 void nr_ulsch_scale_channel(int32_t **ul_ch_estimates_ext,
                             NR_DL_FRAME_PARMS *frame_parms,
diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c
index 3945439a45b495b487d48909bbb947d559e5b820..c58941b07712320756080d57220ec9b465638793 100644
--- a/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c
+++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c
@@ -37,8 +37,7 @@
 #include "PHY/CODING/coding_extern.h"
 #include "PHY/CODING/coding_defs.h"
 #include "PHY/CODING/lte_interleaver_inline.h"
-#include "PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.h"
-#include "PHY/CODING/nrLDPC_decoder/nrLDPC_types.h"
+#include "PHY/CODING/nrLDPC_extern.h"
 #include "PHY/NR_TRANSPORT/nr_transport_common_proto.h"
 #include "PHY/NR_TRANSPORT/nr_ulsch.h"
 #include "PHY/NR_TRANSPORT/nr_dlsch.h"
diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c
index eb35fd7dc6a2e6d949c1cc8834ede11dd133bd3b..93cb721f3679add8f30b62033862b64d6788b86e 100644
--- a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c
+++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c
@@ -4,6 +4,7 @@
 #include "PHY/impl_defs_top.h"
 #include "PHY/NR_TRANSPORT/nr_sch_dmrs.h"
 #include "PHY/NR_REFSIG/dmrs_nr.h"
+#include "PHY/NR_REFSIG/ptrs_nr.h"
 #include "PHY/NR_ESTIMATION/nr_ul_estimation.h"
 #include "PHY/defs_nr_common.h"
 
@@ -221,31 +222,32 @@ void nr_idft(uint32_t *z, uint32_t Msc_PUSCH)
 
 }
 
-void nr_ulsch_extract_rbs_single(int **rxdataF,
-                                 int **ul_ch_estimates,
-                                 int **rxdataF_ext,
-                                 int **ul_ch_estimates_ext,
-                                 uint32_t rxdataF_ext_offset,
-                                 // unsigned int *rb_alloc, [hna] Resource Allocation Type 1 is assumed only for the moment
+void nr_ulsch_extract_rbs_single(int32_t **rxdataF,
+                                 NR_gNB_PUSCH *pusch_vars,
                                  unsigned char symbol,
                                  unsigned short start_rb,
                                  unsigned short nb_rb_pusch,
+                                 uint16_t n_rnti,
                                  NR_DL_FRAME_PARMS *frame_parms,
-                                 uint8_t dmrs_symbol,
                                  uint16_t number_symbols,
                                  uint8_t mapping_type,
-                                 dmrs_UplinkConfig_t *dmrs_UplinkConfig)
+                                 uint8_t ptrs_configured,
+                                 dmrs_UplinkConfig_t *dmrs_UplinkConfig,
+                                 ptrs_UplinkConfig_t *ptrs_Uplink_Config)
 {
   unsigned short start_re, re, nb_re_pusch;
   unsigned char aarx;
+  uint8_t K_ptrs;
   uint32_t rxF_ext_index = 0;
   uint32_t ul_ch0_ext_index = 0;
   uint32_t ul_ch0_index = 0;
-  uint8_t is_dmrs_symbol_flag, k_prime;
-  uint16_t n=0;
-
+  uint32_t ul_ch0_ptrs_ext_index = 0;
+  uint32_t ul_ch0_ptrs_index = 0;
+  uint8_t is_dmrs_symbol_flag, is_ptrs_symbol_flag,k_prime;
+  uint16_t n=0, num_ptrs_symbols;
   int16_t *rxF,*rxF_ext;
   int *ul_ch0,*ul_ch0_ext;
+  int *ul_ch0_ptrs,*ul_ch0_ptrs_ext;
 
 #ifdef DEBUG_RB_EXT
 
@@ -258,15 +260,23 @@ void nr_ulsch_extract_rbs_single(int **rxdataF,
   
   nb_re_pusch = NR_NB_SC_PER_RB * nb_rb_pusch;
   is_dmrs_symbol_flag = 0;
+  is_ptrs_symbol_flag = 0;
+  num_ptrs_symbols = 0;
+
+  K_ptrs = get_K_ptrs(ptrs_Uplink_Config, nb_rb_pusch);
 
   for (aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) {
     
     rxF       = (int16_t *)&rxdataF[aarx][symbol * frame_parms->ofdm_symbol_size];
-    rxF_ext   = (int16_t *)&rxdataF_ext[aarx][symbol * nb_re_pusch]; // [hna] rxdataF_ext isn't contiguous in order to solve an alignment problem ib llr computation in case of mod_order = 4, 6
+    rxF_ext   = (int16_t *)&pusch_vars->rxdataF_ext[aarx][symbol * nb_re_pusch]; // [hna] rxdataF_ext isn't contiguous in order to solve an alignment problem ib llr computation in case of mod_order = 4, 6
+
+    ul_ch0     = &pusch_vars->ul_ch_estimates[aarx][pusch_vars->dmrs_symbol*frame_parms->ofdm_symbol_size]; // update channel estimates if new dmrs symbol are available
 
-    ul_ch0     = &ul_ch_estimates[aarx][dmrs_symbol*frame_parms->ofdm_symbol_size]; // update channel estimates if new dmrs symbol are available
+    ul_ch0_ext = &pusch_vars->ul_ch_estimates_ext[aarx][symbol*nb_re_pusch];
 
-    ul_ch0_ext = &ul_ch_estimates_ext[aarx][symbol*nb_re_pusch];
+    ul_ch0_ptrs     = &pusch_vars->ul_ch_ptrs_estimates[aarx][pusch_vars->ptrs_symbol_index*frame_parms->ofdm_symbol_size]; // update channel estimates if new dmrs symbol are available
+
+    ul_ch0_ptrs_ext = &pusch_vars->ul_ch_ptrs_estimates_ext[aarx][symbol*nb_re_pusch];
 
     n = 0;
     k_prime = 0;
@@ -283,15 +293,36 @@ void nr_ulsch_extract_rbs_single(int **rxdataF,
                                             dmrs_UplinkConfig,
                                             mapping_type,
                                             frame_parms->ofdm_symbol_size);
+
+      if (ptrs_configured == 1){
+        is_ptrs_symbol_flag = is_ptrs_symbol(symbol,
+                                             (start_re + re)%frame_parms->ofdm_symbol_size,
+                                             n_rnti,
+                                             nb_rb_pusch,
+                                             number_symbols,
+                                             aarx,
+                                             K_ptrs,
+                                             pusch_vars->ptrs_symbols,
+                                             start_re,
+                                             frame_parms->ofdm_symbol_size,
+                                             dmrs_UplinkConfig->pusch_dmrs_type,
+                                             ptrs_Uplink_Config);
+
+        if (is_ptrs_symbol_flag == 1)
+          num_ptrs_symbols++;
+
+      }
+
   #ifdef DEBUG_RB_EXT
       printf("re = %d, is_dmrs_symbol_flag = %d, symbol = %d\n", re, is_dmrs_symbol_flag, symbol);
   #endif
 
-      if ( is_dmrs_symbol_flag == 0 ) {
+      if ( is_dmrs_symbol_flag == 0 && is_ptrs_symbol_flag == 0) {
 
         rxF_ext[rxF_ext_index]     = (rxF[ ((start_re + re)*2)      % (frame_parms->ofdm_symbol_size*2)]);
         rxF_ext[rxF_ext_index + 1] = (rxF[(((start_re + re)*2) + 1) % (frame_parms->ofdm_symbol_size*2)]);
         ul_ch0_ext[ul_ch0_ext_index] = ul_ch0[ul_ch0_index];
+        ul_ch0_ptrs_ext[ul_ch0_ptrs_ext_index] = ul_ch0_ptrs[ul_ch0_ptrs_index];
 
   #ifdef DEBUG_RB_EXT
         printf("rxF_ext[%d] = %d\n", rxF_ext_index, rxF_ext[rxF_ext_index]);
@@ -299,6 +330,7 @@ void nr_ulsch_extract_rbs_single(int **rxdataF,
   #endif
 
         ul_ch0_ext_index++;
+        ul_ch0_ptrs_ext_index++;
         rxF_ext_index +=2;
       } else {
         k_prime++;
@@ -306,8 +338,12 @@ void nr_ulsch_extract_rbs_single(int **rxdataF,
         n+=(k_prime)?0:1;
       }
       ul_ch0_index++;
+      ul_ch0_ptrs_index++;
     }
   }
+
+  pusch_vars->ptrs_sc_per_ofdm_symbol = num_ptrs_symbols;
+
 }
 
 void nr_ulsch_scale_channel(int **ul_ch_estimates_ext,
@@ -1001,17 +1037,21 @@ void nr_rx_pusch(PHY_VARS_gNB *gNB,
                  unsigned char harq_pid)
 {
 
-  uint8_t first_symbol_flag, aarx, aatx, dmrs_symbol_flag; // dmrs_symbol_flag, a flag to indicate DMRS REs in current symbol
-  NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms;
-  nfapi_nr_ul_config_ulsch_pdu_rel15_t *rel15_ul = &gNB->ulsch[UE_id][0]->harq_processes[harq_pid]->ulsch_pdu.ulsch_pdu_rel15;
+  uint8_t first_symbol_flag, aarx, aatx, dmrs_symbol_flag, ptrs_symbol_flag; // dmrs_symbol_flag, a flag to indicate DMRS REs in current symbol
   uint32_t nb_re_pusch, bwp_start_subcarrier;
   uint8_t mapping_type;
+  uint8_t L_ptrs = 0; // PTRS parameter
   int avgs;
   int avg[4];
+  NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms;
+  nfapi_nr_ul_config_ulsch_pdu_rel15_t *rel15_ul = &gNB->ulsch[UE_id][0]->harq_processes[harq_pid]->ulsch_pdu.ulsch_pdu_rel15;
+  ptrs_UplinkConfig_t *ptrs_Uplink_Config = &gNB->pusch_config.dmrs_UplinkConfig.ptrs_UplinkConfig;
 
   dmrs_symbol_flag = 0;
+  ptrs_symbol_flag = 0;
   first_symbol_flag = 0;
   mapping_type = gNB->pusch_config.pusch_TimeDomainResourceAllocation[0]->mappingType;
+  gNB->pusch_vars[UE_id]->ptrs_sc_per_ofdm_symbol = 0;
 
   if (mapping_type == typeB) {
 
@@ -1019,6 +1059,20 @@ void nr_rx_pusch(PHY_VARS_gNB *gNB,
       gNB->pusch_vars[UE_id]->rxdataF_ext_offset = 0;
       gNB->pusch_vars[UE_id]->dmrs_symbol = 0;
       first_symbol_flag = 1;
+
+      L_ptrs = get_L_ptrs(ptrs_Uplink_Config, rel15_ul->mcs);
+
+      gNB->pusch_vars[UE_id]->ptrs_symbols = 0;
+
+      set_ptrs_symb_idx(&gNB->pusch_vars[UE_id]->ptrs_symbols,
+                        ptrs_Uplink_Config,
+                        &gNB->pusch_config.dmrs_UplinkConfig,
+                        1,
+                        rel15_ul->number_symbols,
+                        rel15_ul->start_symbol,
+                        L_ptrs,
+                        frame_parms->ofdm_symbol_size);
+
     }
 
     bwp_start_subcarrier = (rel15_ul->start_rb*NR_NB_SC_PER_RB + frame_parms->first_carrier_offset) % frame_parms->ofdm_symbol_size;
@@ -1030,17 +1084,36 @@ void nr_rx_pusch(PHY_VARS_gNB *gNB,
                                       0,
                                       0,
                                       rel15_ul->number_symbols,
-                                      &gNB->dmrs_UplinkConfig,
+                                      &gNB->pusch_config.dmrs_UplinkConfig,
                                       mapping_type,
                                       frame_parms->ofdm_symbol_size);
 
     if (dmrs_symbol_flag == 1){
-      nb_re_pusch = rel15_ul->number_rbs * ((gNB->dmrs_UplinkConfig.pusch_dmrs_type==pusch_dmrs_type1)?6:8);
+      nb_re_pusch = rel15_ul->number_rbs * ((gNB->pusch_config.dmrs_UplinkConfig.pusch_dmrs_type==pusch_dmrs_type1)?6:8);
       gNB->pusch_vars[UE_id]->dmrs_symbol = symbol;
     } else {
         nb_re_pusch = rel15_ul->number_rbs * NR_NB_SC_PER_RB;
     }
 
+    if (gNB->ptrs_configured == 1)
+        ptrs_symbol_flag = is_ptrs_symbol(symbol,
+                                          0,
+                                          gNB->ulsch[UE_id][0]->harq_processes[harq_pid]->ulsch_pdu.rnti,
+                                          rel15_ul->number_rbs,
+                                          rel15_ul->number_symbols,
+                                          0,
+                                          get_K_ptrs(ptrs_Uplink_Config, rel15_ul->number_rbs),
+                                          gNB->pusch_vars[UE_id]->ptrs_symbols,
+                                          0,
+                                          frame_parms->ofdm_symbol_size,
+                                          gNB->pusch_config.dmrs_UplinkConfig.pusch_dmrs_type,
+                                          ptrs_Uplink_Config);
+
+
+    if (ptrs_symbol_flag == 1){
+      gNB->pusch_vars[UE_id]->ptrs_symbol_index = symbol;
+    }
+
 
     //----------------------------------------------------------
     //--------------------- Channel estimation ---------------------
@@ -1054,26 +1127,24 @@ void nr_rx_pusch(PHY_VARS_gNB *gNB,
                                   symbol,
                                   bwp_start_subcarrier,
                                   rel15_ul->number_rbs,
-                                  &gNB->dmrs_UplinkConfig);
+                                  &gNB->pusch_config.dmrs_UplinkConfig);
 
     //----------------------------------------------------------
     //--------------------- RBs extraction ---------------------
     //----------------------------------------------------------
 
     nr_ulsch_extract_rbs_single(gNB->common_vars.rxdataF,
-                                gNB->pusch_vars[UE_id]->ul_ch_estimates,
-                                gNB->pusch_vars[UE_id]->rxdataF_ext,
-                                gNB->pusch_vars[UE_id]->ul_ch_estimates_ext,
-                                gNB->pusch_vars[UE_id]->rxdataF_ext_offset,
-                                // rb_alloc, [hna] Resource Allocation Type 1 is assumed only for the moment
+                                gNB->pusch_vars[UE_id],
                                 symbol,
                                 rel15_ul->start_rb,
                                 rel15_ul->number_rbs,
+                                gNB->ulsch[UE_id][0]->harq_processes[harq_pid]->ulsch_pdu.rnti,
                                 frame_parms,
-                                gNB->pusch_vars[UE_id]->dmrs_symbol,
                                 rel15_ul->number_symbols,
                                 mapping_type,
-                                &gNB->dmrs_UplinkConfig);
+                                gNB->ptrs_configured,
+                                &gNB->pusch_config.dmrs_UplinkConfig,
+                                ptrs_Uplink_Config);
 
     nr_ulsch_scale_channel(gNB->pusch_vars[UE_id]->ul_ch_estimates_ext,
                            frame_parms,
@@ -1081,7 +1152,7 @@ void nr_rx_pusch(PHY_VARS_gNB *gNB,
                            symbol,
                            dmrs_symbol_flag,
                            rel15_ul->number_rbs,
-                           gNB->dmrs_UplinkConfig.pusch_dmrs_type);
+                           gNB->pusch_config.dmrs_UplinkConfig.pusch_dmrs_type);
 
     if (first_symbol_flag==1) {
 
@@ -1131,7 +1202,7 @@ void nr_rx_pusch(PHY_VARS_gNB *gNB,
                          symbol,
                          rel15_ul->Qm);
 
-    gNB->pusch_vars[UE_id]->rxdataF_ext_offset = gNB->pusch_vars[UE_id]->rxdataF_ext_offset +  nb_re_pusch;
+    gNB->pusch_vars[UE_id]->rxdataF_ext_offset = gNB->pusch_vars[UE_id]->rxdataF_ext_offset +  nb_re_pusch - gNB->pusch_vars[UE_id]->ptrs_sc_per_ofdm_symbol;
   } else {
     LOG_E(PHY, "PUSCH mapping type A is not supported \n");
   }
diff --git a/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c b/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c
index 69077f027681e131f4171354214190965bf2f948..162ab6958ff3856a7b4676474c9ad7e633a33228 100644
--- a/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c
+++ b/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c
@@ -1975,7 +1975,7 @@ uint16_t nr_dci_format_size (PHY_VARS_NR_UE *ue,
   PUSCH_Config_t pusch_config       = ue->pusch_config;
   PUCCH_Config_t pucch_config_dedicated       = ue->pucch_config_dedicated_nr[eNB_id];
   crossCarrierSchedulingConfig_t crossCarrierSchedulingConfig = ue->crossCarrierSchedulingConfig;
-  dmrs_UplinkConfig_t dmrs_UplinkConfig = ue->dmrs_UplinkConfig;
+  dmrs_UplinkConfig_t dmrs_UplinkConfig = ue->pusch_config.dmrs_UplinkConfig;
   dmrs_DownlinkConfig_t dmrs_DownlinkConfig = ue->dmrs_DownlinkConfig;
   csi_MeasConfig_t csi_MeasConfig = ue->csi_MeasConfig;
   PUSCH_ServingCellConfig_t PUSCH_ServingCellConfig= ue->PUSCH_ServingCellConfig;
diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c
index b3a95e313e1be4432db7d1c3fcc985a67768807f..b81c01114d2a39b2193597d9583c079ddfc70660 100644
--- a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c
+++ b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c
@@ -41,8 +41,7 @@
 #include "SCHED_NR_UE/defs.h"
 #include "SIMULATION/TOOLS/sim.h"
 #include "executables/nr-uesoftmodem.h"
-#include "PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.h"
-#include "PHY/CODING/nrLDPC_decoder/nrLDPC_types.h"
+#include "PHY/CODING/nrLDPC_extern.h"
 //#define DEBUG_DLSCH_DECODING
 //#define ENABLE_PHY_PAYLOAD_DEBUG 1
 
diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h
index 39b037a6005a04d48a3aac7b7a6fa98f4857b368..a10b6231a0d82890840f8165120e4a772a9c1f91 100644
--- a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h
+++ b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h
@@ -240,6 +240,8 @@ typedef struct {
   int16_t Po_SRS;
   /// num active cba group
   uint8_t num_active_cba_groups;
+  /// bit mask of PT-RS ofdm symbol indicies
+  uint16_t ptrs_symbols;
   /// num dci found for cba
   //uint8_t num_cba_dci[10];
   /// allocated CBA RNTI
diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c
index 2eb6dcd7fe682e84e6dd670cccb959aea84cf588..8b80b1b219f8af8ac12d2d45977228a3af065cbf 100644
--- a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c
+++ b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c
@@ -36,7 +36,7 @@
 #include "PHY/CODING/coding_defs.h"
 #include "PHY/CODING/coding_extern.h"
 #include "PHY/CODING/lte_interleaver_inline.h"
-#include "PHY/CODING/nrLDPC_encoder/defs.h"
+#include "PHY/CODING/nrLDPC_extern.h"
 #include "PHY/NR_UE_TRANSPORT/nr_transport_ue.h"
 #include "common/utils/LOG/vcd_signal_dumper.h"
 
@@ -353,8 +353,11 @@ opp_enabled=0;
       printf("%d \n",  harq_process->d[0][cnt]);
       }
       printf("\n");*/
+    encoder_implemparams_t impp;
+    impp.n_segments=harq_process->C;
+    impp.macro_num=0;
 
-    ldpc_encoder_optim_8seg(harq_process->c,harq_process->d,*pz,Kb,Kr,BG,harq_process->C,NULL,NULL,NULL,NULL);
+    nrLDPC_encoder(harq_process->c,harq_process->d,*pz,Kb,Kr,BG,&impp);
 
     //stop_meas(te_stats);
     //printf("end ldpc encoder -- output\n");
diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c
index b912834f9d7cf0eed351c729fd8ad0e83f736e9f..26800ed584aa54f19416fc53f8915f6e5998ea98 100644
--- a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c
+++ b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c
@@ -31,6 +31,7 @@
 */
 #include <stdint.h>
 #include "PHY/NR_REFSIG/dmrs_nr.h"
+#include "PHY/NR_REFSIG/ptrs_nr.h"
 #include "PHY/NR_UE_TRANSPORT/nr_transport_ue.h"
 #include "PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h"
 #include "PHY/MODULATION/nr_modulation.h"
@@ -105,19 +106,22 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE,
   int32_t **txdataF;
   uint16_t start_sc, start_rb;
   int8_t Wf[2], Wt[2], l_prime[2], delta;
-  uint16_t n_dmrs, code_rate, number_dmrs_symbols;
+  uint16_t n_dmrs, code_rate, number_dmrs_symbols, k;
   uint8_t dmrs_type;
   uint8_t mapping_type;
   int ap, start_symbol, Nid_cell, i;
   int sample_offsetF, N_RE_prime, N_PRB_oh;
   uint16_t n_rnti;
   uint8_t data_existing =0;
+  uint8_t L_ptrs, K_ptrs; // PTRS parameters
+  uint16_t beta_ptrs; // PTRS parameter related to power control
 
   NR_UE_ULSCH_t *ulsch_ue;
   NR_UL_UE_HARQ_t *harq_process_ul_ue;
   NR_DL_FRAME_PARMS *frame_parms = &UE->frame_parms;
   NR_UE_PUSCH *pusch_ue = UE->pusch_vars[thread_id][gNB_id];
   uint8_t ulsch_input_buffer[MAX_ULSCH_PAYLOAD_BYTES];
+  ptrs_UplinkConfig_t *ptrs_Uplink_Config = &UE->pusch_config.dmrs_UplinkConfig.ptrs_UplinkConfig;
 
   num_of_codewords = 1; // tmp assumption
   n_rnti = 0x1234;
@@ -142,14 +146,14 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE,
                                             0,
                                             0,
                                             harq_process_ul_ue->number_of_symbols,
-                                            &UE->dmrs_UplinkConfig,
+                                            &UE->pusch_config.dmrs_UplinkConfig,
                                             mapping_type,
                                             frame_parms->ofdm_symbol_size);
 
-    ulsch_ue->length_dmrs = UE->dmrs_UplinkConfig.pusch_maxLength;
+    ulsch_ue->length_dmrs = UE->pusch_config.dmrs_UplinkConfig.pusch_maxLength;
     ulsch_ue->rnti        = n_rnti;
     ulsch_ue->Nid_cell    = Nid_cell;
-    ulsch_ue->nb_re_dmrs  = ((UE->dmrs_UplinkConfig.pusch_dmrs_type == pusch_dmrs_type1)?6:4)*number_dmrs_symbols;
+    ulsch_ue->nb_re_dmrs  = ((UE->pusch_config.dmrs_UplinkConfig.pusch_dmrs_type == pusch_dmrs_type1)?6:4)*number_dmrs_symbols;
 
     N_RE_prime = NR_NB_SC_PER_RB*harq_process_ul_ue->number_of_symbols - ulsch_ue->nb_re_dmrs - N_PRB_oh;
 
@@ -277,10 +281,40 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE,
   pusch_dmrs = UE->nr_gold_pusch_dmrs[slot];
   n_dmrs = (harq_process_ul_ue->nb_rb*ulsch_ue->nb_re_dmrs);
   int16_t mod_dmrs[n_dmrs<<1];
-  dmrs_type = UE->dmrs_UplinkConfig.pusch_dmrs_type;
+  dmrs_type = UE->pusch_config.dmrs_UplinkConfig.pusch_dmrs_type;
   ///////////
   ////////////////////////////////////////////////////////////////////////
 
+
+  /////////////////////////PTRS parameters' initialization/////////////////////////
+  ///////////
+
+  int16_t mod_ptrs[(harq_process_ul_ue->nb_rb/2)*(NR_SYMBOLS_PER_SLOT-1)*2]; // assume maximum number of PTRS per pusch allocation
+  K_ptrs = 0; // just to avoid a warning
+
+  if (UE->ptrs_configured == 1) {
+
+    K_ptrs = get_K_ptrs(ptrs_Uplink_Config, harq_process_ul_ue->nb_rb);
+
+    L_ptrs = get_L_ptrs(ptrs_Uplink_Config, harq_process_ul_ue->mcs);
+
+    beta_ptrs = 1; // temp value until power control is implemented
+
+    ulsch_ue->ptrs_symbols = 0;
+
+    set_ptrs_symb_idx(&ulsch_ue->ptrs_symbols,
+                      ptrs_Uplink_Config,
+                      &UE->pusch_config.dmrs_UplinkConfig,
+                      1,
+                      harq_process_ul_ue->number_of_symbols,
+                      start_symbol,
+                      L_ptrs,
+                      frame_parms->ofdm_symbol_size);
+  }
+
+  ///////////
+  ////////////////////////////////////////////////////////////////////////////////
+
   /////////////////////////ULSCH layer mapping/////////////////////////
   ///////////
 
@@ -313,7 +347,7 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE,
                              0,
                              0,
                              harq_process_ul_ue->number_of_symbols,
-                             &UE->dmrs_UplinkConfig,
+                             &UE->pusch_config.dmrs_UplinkConfig,
                              mapping_type,
                              frame_parms->ofdm_symbol_size);
 
@@ -357,8 +391,8 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE,
     
 
     uint8_t k_prime=0;
-    uint8_t is_dmrs;
-    uint16_t m=0, n=0, dmrs_idx=0, k=0;
+    uint8_t is_dmrs, is_ptrs;
+    uint16_t m=0, n=0, dmrs_idx=0, ptrs_idx = 0;
 
     for (l=start_symbol; l<start_symbol+harq_process_ul_ue->number_of_symbols; l++) {
 
@@ -371,6 +405,7 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE,
         sample_offsetF = l*frame_parms->ofdm_symbol_size + k;
 
         is_dmrs = 0;
+        is_ptrs = 0;
 
         is_dmrs = is_dmrs_symbol(l,
                                  k,
@@ -379,13 +414,30 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE,
                                  n,
                                  delta,
                                  harq_process_ul_ue->number_of_symbols,
-                                 &UE->dmrs_UplinkConfig,
+                                 &UE->pusch_config.dmrs_UplinkConfig,
                                  mapping_type,
                                  frame_parms->ofdm_symbol_size);
 
+        if (UE->ptrs_configured == 1){
+          is_ptrs = is_ptrs_symbol(l,
+                                   k,
+                                   ulsch_ue->rnti,
+                                   harq_process_ul_ue->nb_rb,
+                                   harq_process_ul_ue->number_of_symbols,
+                                   ap,
+                                   K_ptrs,
+                                   ulsch_ue->ptrs_symbols,
+                                   start_sc,
+                                   frame_parms->ofdm_symbol_size,
+                                   UE->pusch_config.dmrs_UplinkConfig.pusch_dmrs_type,
+                                   ptrs_Uplink_Config);
+        }
+
         if (is_dmrs == 1) {
 
-          nr_modulation(pusch_dmrs[l][0], n_dmrs*2, DMRS_MOD_ORDER, mod_dmrs); // currently only codeword 0 is modulated. Qm = 2 as DMRS is QPSK modulated
+          if (k == start_sc){
+            nr_modulation(pusch_dmrs[l][0], n_dmrs*2, DMRS_MOD_ORDER, mod_dmrs); // currently only codeword 0 is modulated. Qm = 2 as DMRS is QPSK modulated
+          }
 
           ((int16_t*)txdataF[ap])[(sample_offsetF)<<1] = (Wt[l_prime[0]]*Wf[k_prime]*AMP*mod_dmrs[dmrs_idx<<1]) >> 15;
           ((int16_t*)txdataF[ap])[((sample_offsetF)<<1) + 1] = (Wt[l_prime[0]]*Wf[k_prime]*AMP*mod_dmrs[(dmrs_idx<<1) + 1]) >> 15;
@@ -401,9 +453,19 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE,
           k_prime++;
           k_prime&=1;
           n+=(k_prime)?0:1;
-        }
 
-        else {
+        }  else if (is_ptrs == 1) {
+
+          if (k == start_sc){
+            nr_modulation(pusch_dmrs[l][0], harq_process_ul_ue->nb_rb/2, DMRS_MOD_ORDER, mod_ptrs);
+          }
+
+          ((int16_t*)txdataF[ap])[(sample_offsetF)<<1] = (beta_ptrs*AMP*mod_ptrs[ptrs_idx<<1]) >> 15;
+          ((int16_t*)txdataF[ap])[((sample_offsetF)<<1) + 1] = (beta_ptrs*AMP*mod_ptrs[(ptrs_idx<<1) + 1]) >> 15;
+
+          ptrs_idx++;
+
+          } else {
 
           ((int16_t*)txdataF[ap])[(sample_offsetF)<<1]       = ((int16_t *) ulsch_ue->y)[m<<1];
           ((int16_t*)txdataF[ap])[((sample_offsetF)<<1) + 1] = ((int16_t *) ulsch_ue->y)[(m<<1) + 1];
@@ -484,6 +546,7 @@ uint8_t nr_ue_pusch_common_procedures(PHY_VARS_NR_UE *UE,
            frame_parms);
       }
     }
+
   ///////////
   ////////////////////////////////////////////////////
   return 0;
diff --git a/openair1/PHY/defs_gNB.h b/openair1/PHY/defs_gNB.h
index 3c0f0db8dae9a34c3591d877d766be630a59fa39..d9a57c60ed05ada358bb2db09f16741ea9973cea 100644
--- a/openair1/PHY/defs_gNB.h
+++ b/openair1/PHY/defs_gNB.h
@@ -40,7 +40,7 @@
 #include "PHY/NR_TRANSPORT/nr_transport_common_proto.h"
 #include "PHY/impl_defs_top.h"
 #include "PHY/defs_common.h"
-#include "PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.h"
+#include "PHY/CODING/nrLDPC_extern.h"
 #include "PHY/CODING/nrLDPC_decoder/nrLDPC_types.h"
 
 #define MAX_NUM_RU_PER_gNB MAX_NUM_RU_PER_eNB
@@ -375,6 +375,14 @@ typedef struct {
   /// - first index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx
   /// - second index: ? [0..12*N_RB_UL*frame_parms->symbols_per_tti[
   int32_t **ul_ch_estimates_ext;
+  /// \brief Hold the PTRS phase estimates in frequency domain.
+  /// - first index: rx antenna id [0..nb_antennas_rx[
+  /// - second index: ? [0..12*N_RB_UL*frame_parms->symbols_per_tti[
+  int32_t **ul_ch_ptrs_estimates;
+  /// \brief Uplink phase estimates extracted in PRBS.
+  /// - first index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx
+  /// - second index: ? [0..12*N_RB_UL*frame_parms->symbols_per_tti[
+  int32_t **ul_ch_ptrs_estimates_ext;
   /// \brief Holds the compensated signal.
   /// - first index: rx antenna id [0..nb_antennas_rx[
   /// - second index: ? [0..12*N_RB_UL*frame_parms->symbols_per_tti[
@@ -416,6 +424,12 @@ typedef struct {
   int16_t *llr;
   // DMRS symbol index, to be updated every DMRS symbol within a slot.
   uint8_t dmrs_symbol;
+  // PTRS symbol index, to be updated every PTRS symbol within a slot.
+  uint8_t ptrs_symbol_index;
+  /// bit mask of PT-RS ofdm symbol indicies
+  uint16_t ptrs_symbols;
+  // PTRS subcarriers per OFDM symbol
+  uint16_t ptrs_sc_per_ofdm_symbol;
 } NR_gNB_PUSCH;
 
 
@@ -669,6 +683,9 @@ typedef struct PHY_VARS_gNB_s {
 
   /// PDSCH DMRS sequence
   uint32_t ****nr_gold_pdsch_dmrs;
+
+  /// flag to indicate if PTRS is configured
+  uint8_t ptrs_configured;
   
   /// PUSCH DMRS
   uint32_t nr_gold_pusch[2][20][2][NR_MAX_PUSCH_DMRS_INIT_LENGTH_DWORD];
@@ -727,8 +744,6 @@ typedef struct PHY_VARS_gNB_s {
   // SRS Variables
   SOUNDINGRS_UL_CONFIG_DEDICATED soundingrs_ul_config_dedicated[NUMBER_OF_UE_MAX];
 
-  dmrs_UplinkConfig_t dmrs_UplinkConfig;
-
   dmrs_DownlinkConfig_t dmrs_DownlinkConfig;
 
   uint8_t ncs_cell[20][7];
diff --git a/openair1/PHY/defs_nr_UE.h b/openair1/PHY/defs_nr_UE.h
index d72979262c3094f93c839bebe036122a73e575e3..de4f886903b7dac4b78130a5ae22d51d5b092de9 100644
--- a/openair1/PHY/defs_nr_UE.h
+++ b/openair1/PHY/defs_nr_UE.h
@@ -1012,6 +1012,9 @@ typedef struct {
   /// PUSCH DMRS sequence
   uint32_t ****nr_gold_pusch_dmrs;
 
+  /// flag to indicate if PTRS is configured
+  uint8_t ptrs_configured;
+
   uint32_t X_u[64][839];
 
   uint32_t high_speed_flag;
@@ -1143,7 +1146,6 @@ typedef struct {
 
   crossCarrierSchedulingConfig_t crossCarrierSchedulingConfig;
   supplementaryUplink_t supplementaryUplink;
-  dmrs_UplinkConfig_t dmrs_UplinkConfig;
   dmrs_DownlinkConfig_t dmrs_DownlinkConfig;
   csi_MeasConfig_t csi_MeasConfig;
   PUSCH_ServingCellConfig_t PUSCH_ServingCellConfig;
diff --git a/openair1/PHY/impl_defs_nr.h b/openair1/PHY/impl_defs_nr.h
index 6e13973dd9e59fda6b9f5a322577b3646853ef88..3519b97278cda699a3339b1388473e382a76a3f3 100644
--- a/openair1/PHY/impl_defs_nr.h
+++ b/openair1/PHY/impl_defs_nr.h
@@ -510,9 +510,6 @@ typedef struct {
   uint8_t         startSymbolAndLength;
 } PUSCH_TimeDomainResourceAllocation_t;
 ////////////////////////////////////////////////////////////////////////////////################################
-typedef struct { // The IE PTRS-UplinkConfig is used to configure uplink Phase-Tracking-Reference-Signals (PTRS)
-
-} ptrs_UplinkConfig_t;
 typedef enum{
   maxCodeBlockGroupsPerTransportBlock_n2 = 2,
   maxCodeBlockGroupsPerTransportBlock_n4 = 4,
@@ -544,6 +541,12 @@ typedef enum {
   pusch_dmrs_pos2 = 2,
   pusch_dmrs_pos3 = 3,
 } pusch_dmrs_AdditionalPosition_t;
+typedef enum {
+  offset00 = 0,
+  offset01 = 1,
+  offset10 = 2,
+  offset11 = 3,
+} ptrs_resource_elementoffset_t;
 typedef enum {
   pdsch_len1 = 1,
   pdsch_len2 = 2
@@ -552,6 +555,22 @@ typedef enum {
   pusch_len1 = 1,
   pusch_len2 = 2
 } pusch_maxLength_t;
+typedef struct {
+  uint8_t ptrs_mcs1;
+  uint8_t ptrs_mcs2;
+  uint8_t ptrs_mcs3;
+} ptrs_time_density_t;
+typedef struct {
+  uint16_t n_rb0;
+  uint16_t n_rb1;
+} ptrs_frequency_density_t;
+typedef struct { // The IE PTRS-UplinkConfig is used to configure uplink Phase-Tracking-Reference-Signals (PTRS)
+  uint8_t  num_ptrs_ports;
+  ptrs_resource_elementoffset_t resourceElementOffset;
+  ptrs_time_density_t  timeDensity;
+  ptrs_frequency_density_t  frequencyDensity;
+  uint32_t  ul_ptrs_power;
+} ptrs_UplinkConfig_t;
 typedef struct { // The IE DMRS-DownlinkConfig is used to configure downlink demodulation reference signals for PDSCH
   pdsch_dmrs_type_t pdsch_dmrs_type;
   pdsch_dmrs_AdditionalPosition_t pdsch_dmrs_AdditionalPosition;
@@ -563,6 +582,7 @@ typedef struct { // The IE DMRS-UplinkConfig is used to configure uplink demodul
   pusch_dmrs_type_t pusch_dmrs_type;
   pusch_dmrs_AdditionalPosition_t pusch_dmrs_AdditionalPosition;
   pusch_maxLength_t pusch_maxLength;
+  ptrs_UplinkConfig_t ptrs_UplinkConfig;
   uint16_t scramblingID0;
   uint16_t scramblingID1;
 } dmrs_UplinkConfig_t;
@@ -647,6 +667,10 @@ typedef struct {
  * resourceAllocation
  */
   ul_resourceAllocation_t ul_resourceAllocation;
+/*
+ * DMRS-Uplinkconfig
+ */
+  dmrs_UplinkConfig_t dmrs_UplinkConfig;
 /*
  * rgb_Size
  */
diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c
index fb6d1a6c37c01ba2598d276d214e650342f4c8af..40bbe7322da460520d439453e26035f3b80d0356 100644
--- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c
+++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c
@@ -244,11 +244,11 @@ void nr_ulsch_procedures(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, int UE_id
                                             0,
                                             0,
                                             number_symbols,
-                                            &gNB->dmrs_UplinkConfig,
+                                            &gNB->pusch_config.dmrs_UplinkConfig,
                                             mapping_type,
                                             frame_parms->ofdm_symbol_size);
 
-  nb_re_dmrs = ((gNB->dmrs_UplinkConfig.pusch_dmrs_type == pusch_dmrs_type1)?6:4)*number_dmrs_symbols;
+  nb_re_dmrs = ((gNB->pusch_config.dmrs_UplinkConfig.pusch_dmrs_type == pusch_dmrs_type1)?6:4)*number_dmrs_symbols;
 
   G = nr_get_G(nfapi_ulsch_pdu_rel15->number_rbs,
                number_symbols,
diff --git a/openair1/SIMULATION/NR_PHY/ulsim.c b/openair1/SIMULATION/NR_PHY/ulsim.c
index adfb09ea6eef74ab2ae5f9319cb8c76c77ba9960..36603c2ec0649ccac61b826645fc6ea76a2c5a4c 100644
--- a/openair1/SIMULATION/NR_PHY/ulsim.c
+++ b/openair1/SIMULATION/NR_PHY/ulsim.c
@@ -428,7 +428,7 @@ int main(int argc, char **argv)
   uint16_t number_dmrs_symbols = 0;
   unsigned int available_bits;
   uint8_t nb_re_dmrs;
-  uint8_t length_dmrs = UE->dmrs_UplinkConfig.pusch_maxLength;
+  uint8_t length_dmrs = UE->pusch_config.dmrs_UplinkConfig.pusch_maxLength;
   unsigned char mod_order;
   uint16_t code_rate;
 
@@ -440,12 +440,12 @@ int main(int argc, char **argv)
                                             0,
                                             0,
                                             nb_symb_sch,
-                                            &UE->dmrs_UplinkConfig,
+                                            &UE->pusch_config.dmrs_UplinkConfig,
                                             UE->pusch_config.pusch_TimeDomainResourceAllocation[0]->mappingType,
                                             frame_parms->ofdm_symbol_size);
 
   mod_order      = nr_get_Qm_ul(Imcs, 0);
-  nb_re_dmrs     = ((UE->dmrs_UplinkConfig.pusch_dmrs_type == pusch_dmrs_type1) ? 6 : 4) * number_dmrs_symbols;
+  nb_re_dmrs     = ((UE->pusch_config.dmrs_UplinkConfig.pusch_dmrs_type == pusch_dmrs_type1) ? 6 : 4) * number_dmrs_symbols;
   code_rate      = nr_get_code_rate_ul(Imcs, 0);
   available_bits = nr_get_G(nb_rb, nb_symb_sch, nb_re_dmrs, length_dmrs, mod_order, 1);
   TBS            = nr_compute_tbs(mod_order, code_rate, nb_rb, nb_symb_sch, nb_re_dmrs*length_dmrs, 0, precod_nbr_layers);
diff --git a/targets/ARCH/COMMON/common_lib.c b/targets/ARCH/COMMON/common_lib.c
index 757ad6f75dea02c3fc1bdec463e44d7f578f1e24..3066f0906fd8a193dffc12e257a4a40424124ae9 100644
--- a/targets/ARCH/COMMON/common_lib.c
+++ b/targets/ARCH/COMMON/common_lib.c
@@ -37,6 +37,7 @@
 #include <stdlib.h>
 
 #include "common_lib.h"
+#include "assertions.h"
 #include "common/utils/load_module_shlib.h"
 #include "common/utils/LOG/log.h"
 #include "targets/RT/USER/lte-softmodem.h"
@@ -91,38 +92,44 @@ int load_lib(openair0_device *device,
 {
   loader_shlibfunc_t shlib_fdesc[1];
   int ret=0;
-  char *libname;
+  char *deflibname=OAI_RF_LIBNAME;
   
   openair0_cfg->recplay_mode = read_recplayconfig(&(openair0_cfg->recplay_conf),&(device->recplay_state));
 
   if ( openair0_cfg->recplay_mode == RECPLAY_REPLAYMODE ) {
-  	  libname=OAI_IQPLAYER_LIBNAME;
+  	  deflibname=OAI_IQPLAYER_LIBNAME;
   	  shlib_fdesc[0].fname="device_init";
   	  set_softmodem_optmask(SOFTMODEM_RECPLAY_BIT);  // softmodem has to know we use the iqplayer to workaround randomized algorithms
   } else  if ( IS_SOFTMODEM_BASICSIM ) {
-	  libname=OAI_BASICSIM_LIBNAME;
+	  deflibname=OAI_BASICSIM_LIBNAME;
 	  shlib_fdesc[0].fname="device_init";
   } else if (IS_SOFTMODEM_RFSIM && flag == RAU_LOCAL_RADIO_HEAD) {
-	  libname=OAI_RFSIM_LIBNAME;
+	  deflibname=OAI_RFSIM_LIBNAME;
 	  shlib_fdesc[0].fname="device_init";
   } else if (flag == RAU_LOCAL_RADIO_HEAD) {
 	  if (IS_SOFTMODEM_RFSIM)
-		  libname="rfsimulator";
+		  deflibname="rfsimulator";
 	  else
-          libname=OAI_RF_LIBNAME;
+          deflibname=OAI_RF_LIBNAME;
       shlib_fdesc[0].fname="device_init";
   } else {
-	  libname=OAI_TP_LIBNAME;
+	  deflibname=OAI_TP_LIBNAME;
 	  shlib_fdesc[0].fname="transport_init";
   }
-  ret=load_module_shlib(libname,shlib_fdesc,1,NULL);
+  
+  char *devname=NULL;
+  paramdef_t device_params[]=DEVICE_PARAMS_DESC ;
+  int numparams = sizeof(device_params)/sizeof(paramdef_t);
+  int devname_pidx = config_paramidx_fromname(device_params,numparams, CONFIG_DEVICEOPT_NAME);
+  device_params[devname_pidx].defstrval=deflibname;
+  
+  config_get(device_params,numparams,DEVICE_SECTION);
+  
+  ret=load_module_shlib(devname,shlib_fdesc,1,NULL);
+  AssertFatal( (ret >= 0),
+  	           "Library %s couldn't be loaded\n",devname);
 
-  if (ret < 0) {
-    LOG_E(HW,"Library %s couldn't be loaded\n",libname);
-  } else {
-    ret=((devfunc_t)shlib_fdesc[0].fptr)(device,openair0_cfg,cfg);
-  }
-  return ret;
+  return ((devfunc_t)shlib_fdesc[0].fptr)(device,openair0_cfg,cfg);
 }
 
 
diff --git a/targets/ARCH/COMMON/common_lib.h b/targets/ARCH/COMMON/common_lib.h
index 7e51bdc81a6ad9690f119cfb25b4292ea847960f..ecadb68c0ca7917fc870faf63d6cd88d5835993d 100644
--- a/targets/ARCH/COMMON/common_lib.h
+++ b/targets/ARCH/COMMON/common_lib.h
@@ -448,6 +448,24 @@ typedef struct {
 extern "C"
 {
 #endif
+
+
+#define  DEVICE_SECTION   "device"
+#define  CONFIG_HLP_DEVICE  "Identifies the oai device (the interface to RF) to use, the shared lib \"lib_<name>.so\" will be loaded"
+
+#define  CONFIG_DEVICEOPT_NAME "name"
+
+/* inclusion for device configuration */
+/*---------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
+/*                                            config parameters for oai device                                                                                               */
+/*   optname                     helpstr                paramflags                      XXXptr                  defXXXval                            type           numelt   */
+/*---------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
+#define DEVICE_PARAMS_DESC {\
+    { CONFIG_DEVICEOPT_NAME,      CONFIG_HLP_DEVICE,          0,                strptr:&devname,                 defstrval:NULL,         TYPE_STRING,     0}\
+}
+
+
+
 /*! \brief get device name from device type */
 char *get_devname(int devtype);
 /*! \brief Initialize openair RF target. It returns 0 if OK */
diff --git a/targets/ARCH/COMMON/record_player.h b/targets/ARCH/COMMON/record_player.h
index 903dda006b02e0eb79e1107665220d80090ea225..500acdd709950c167f4513e87b30f65a7f5bb6f7 100644
--- a/targets/ARCH/COMMON/record_player.h
+++ b/targets/ARCH/COMMON/record_player.h
@@ -37,19 +37,6 @@
 extern "C"
 {
 #endif
-#define CONFIG_OPT_RECPLAY "enable_recplay"
-
-#define  CONFIG_HLP_RECPLAY  "Allow record player"
-#define USRP_SECTION "device.usrp"
-/* inclusion for device configuration */
-/*---------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
-/*                                            command line parameters for USRP record/playback                                                                               */
-/*   optname                     helpstr                paramflags                      XXXptr                  defXXXval                            type           numelt   */
-/*---------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
-#define DEVICE_PARAMS_DESC {  \
-    {CONFIG_OPT_RECPLAY,      CONFIG_HLP_RECPLAY, PARAMFLAG_BOOL,   uptr:&enable_recplay,                 defuintval:0,                    TYPE_UINT,     0} \
-  }
-
 
 /* inclusions for record player */
 #define RECPLAY_DISABLED     0
@@ -114,7 +101,7 @@ typedef struct {
     {CONFIG_OPT_SF_LOOPS,     CONFIG_HLP_SF_LOOPS,  0,                uptr:&((*recplay_conf)->u_sf_loops),                defintval:DEF_SF_NB_LOOP,        TYPE_UINT,   0}, \
     {CONFIG_OPT_SF_RDELAY,    CONFIG_HLP_SF_RDELAY, 0,                uptr:&((*recplay_conf)->u_sf_read_delay),           defintval:DEF_SF_DELAY_READ,     TYPE_UINT,   0}, \
     {CONFIG_OPT_SF_WDELAY,    CONFIG_HLP_SF_WDELAY, 0,                uptr:&((*recplay_conf)->u_sf_write_delay),          defintval:DEF_SF_DELAY_WRITE,    TYPE_UINT,   0}, \
-  }/*! \brief USRP Configuration and state */
+  }/*! \brief Record Player Configuration and state */
 typedef struct {
   char            u_sf_filename[1024];              // subframes file path
   unsigned int    u_sf_max ;                  // max number of recorded subframes
diff --git a/targets/ARCH/iqplayer/iqplayer_lib.c b/targets/ARCH/iqplayer/iqplayer_lib.c
index beb05de3fdbf9859f33ad549319bf4ad94def31e..c4133d1b11652615f320065b405f65016ba48970 100644
--- a/targets/ARCH/iqplayer/iqplayer_lib.c
+++ b/targets/ARCH/iqplayer/iqplayer_lib.c
@@ -25,6 +25,7 @@
  */
 #define _LARGEFILE_SOURCE
 #define _FILE_OFFSET_BITS 64
+#define NB_ANTENNAS_RX  2
 #include <string.h>
 #include <pthread.h>
 #include <unistd.h>
@@ -45,7 +46,9 @@
 
 
 static void parse_iqfile_header(openair0_device *device, iqfile_header_t *iq_fh) {
-  AssertFatal((memcmp(iq_fh->oaiid,OAIIQFILE_ID,sizeof(OAIIQFILE_ID)) == 0),"iqfile doesn't seem to be compatible with oai (invalid id in header)\n");
+  AssertFatal((memcmp(iq_fh->oaiid,OAIIQFILE_ID,sizeof(OAIIQFILE_ID)) == 0),
+  	           "iqfile doesn't seem to be compatible with oai (invalid id %.4s in header)\n",
+  	           iq_fh->oaiid);
   device->type = iq_fh->devtype;
   device->openair0_cfg[0].tx_sample_advance=iq_fh->tx_sample_advance;
   device->openair0_cfg[0].tx_bw =  device->openair0_cfg[0].rx_bw = iq_fh->bw;
@@ -138,6 +141,13 @@ static int iqplayer_loadfile(openair0_device *device, openair0_config_t *openair
   return 0;
 }
 
+/*! \brief start the oai iq player
+ * \param device, the hardware used
+ */
+static int trx_iqplayer_start(openair0_device *device){
+	return 0;
+}
+
 /*! \brief Terminate operation of the oai iq player
  * \param device, the hardware used
  */
@@ -287,7 +297,7 @@ static int trx_iqplayer_read(openair0_device *device, openair0_timestamp *ptimes
 
 int device_init(openair0_device *device, openair0_config_t *openair0_cfg) {
   device->openair0_cfg = openair0_cfg;
-  device->trx_start_func = NULL;
+  device->trx_start_func = trx_iqplayer_start;
   device->trx_get_stats_func = NULL;
   device->trx_reset_stats_func = NULL;
   device->trx_end_func   = trx_iqplayer_end;
diff --git a/targets/RT/USER/lte-ru.c b/targets/RT/USER/lte-ru.c
index fa08d96b5f8a6c88ef376a178d18948588f2559e..e6364cad237799bbb81d0c0b781e3a965beb851c 100644
--- a/targets/RT/USER/lte-ru.c
+++ b/targets/RT/USER/lte-ru.c
@@ -2194,7 +2194,9 @@ int start_rf(RU_t *ru) {
 }
 
 int stop_rf(RU_t *ru) {
-  ru->rfdevice.trx_end_func(&ru->rfdevice);
+    if(ru->rfdevice.trx_end_func != NULL) {
+      ru->rfdevice.trx_end_func(&ru->rfdevice);
+    }
   return 0;
 }