Add DL and UL PHY traces on transmission and reception statistics
authorMarco Miozzo <marco.miozzo@cttc.es>
Thu, 13 Dec 2012 11:45:59 +0100
changeset 9519 fc6e45584ef4
parent 9468 4513b57ab94b
child 9520 fd100080b747
Add DL and UL PHY traces on transmission and reception statistics
src/lte/helper/lte-helper.cc
src/lte/helper/lte-helper.h
src/lte/helper/phy-rx-stats-calculator.cc
src/lte/helper/phy-rx-stats-calculator.h
src/lte/helper/phy-tx-stats-calculator.cc
src/lte/helper/phy-tx-stats-calculator.h
src/lte/model/lte-common.h
src/lte/model/lte-enb-phy.cc
src/lte/model/lte-enb-phy.h
src/lte/model/lte-spectrum-phy.cc
src/lte/model/lte-spectrum-phy.h
src/lte/model/lte-ue-phy.cc
src/lte/model/lte-ue-phy.h
src/lte/model/pf-ff-mac-scheduler.cc
src/lte/wscript
--- a/src/lte/helper/lte-helper.cc	Tue Dec 04 13:16:20 2012 +0100
+++ b/src/lte/helper/lte-helper.cc	Thu Dec 13 11:45:59 2012 +0100
@@ -116,6 +116,8 @@
       m_downlinkChannel->AddSpectrumPropagationLossModel (m_fadingModule);
       m_uplinkChannel->AddSpectrumPropagationLossModel (m_fadingModule);
     }
+  m_phyTxStats = CreateObject<PhyTxStatsCalculator> ();
+  m_phyRxStats = CreateObject<PhyRxStatsCalculator> ();
   m_macStats = CreateObject<MacStatsCalculator> ();
   m_rlcStats = CreateObject<RadioBearerStatsCalculator> ("RLC");
   m_pdcpStats = CreateObject<RadioBearerStatsCalculator> ("PDCP");
@@ -796,12 +798,16 @@
   LogComponentEnable ("LteEnbNetDevice", LOG_LEVEL_ALL);
 
   LogComponentEnable ("RadioBearerStatsCalculator", LOG_LEVEL_ALL);
+  LogComponentEnable ("LteStatsCalculator", LOG_LEVEL_ALL);
   LogComponentEnable ("MacStatsCalculator", LOG_LEVEL_ALL);
+  LogComponentEnable ("PhyTxStatsCalculator", LOG_LEVEL_ALL);
+  LogComponentEnable ("PhyRxStatsCalculator", LOG_LEVEL_ALL);
 }
 
 void
 LteHelper::EnableTraces (void)
 {
+  EnablePhyTraces ();
   EnableMacTraces ();
   EnableRlcTraces ();
   EnablePdcpTraces ();
@@ -866,6 +872,29 @@
     }
 }
 
+
+uint64_t
+FindImsiFromLteNetDevice (std::string path)
+{
+  NS_LOG_FUNCTION (path);
+  // Sample path input:
+  // /NodeList/#NodeId/DeviceList/#DeviceId/
+
+  // We retrieve the Imsi associated to the LteUeNetDevice
+  Config::MatchContainer match = Config::LookupMatches (path);
+
+  if (match.GetN () != 0)
+    {
+      Ptr<Object> ueNetDevice = match.Get (0);
+      NS_LOG_LOGIC ("FindImsiFromLteNetDevice: " << path << ", " << ueNetDevice->GetObject<LteUeNetDevice> ()->GetImsi ());
+      return ueNetDevice->GetObject<LteUeNetDevice> ()->GetImsi ();
+    }
+  else
+    {
+      NS_FATAL_ERROR ("Lookup " << path << " got no matches");
+    }
+}
+
 uint16_t
 FindCellIdFromEnbRlcPath (std::string path)
 {
@@ -876,7 +905,6 @@
   // We retrieve the CellId associated to the Enb
   std::string enbNetDevicePath = path.substr (0, path.find ("/LteEnbRrc"));
   Config::MatchContainer match = Config::LookupMatches (enbNetDevicePath);
-
   if (match.GetN () != 0)
     {
       Ptr<Object> enbNetDevice = match.Get (0);
@@ -893,6 +921,7 @@
 FindImsiFromEnbMac (std::string path, uint16_t rnti)
 {
   NS_LOG_FUNCTION (path << rnti);
+
   // /NodeList/#NodeId/DeviceList/#DeviceId/LteEnbMac/DlScheduling
   std::ostringstream oss;
   std::string p = path.substr (0, path.find ("/LteEnbMac"));
@@ -918,6 +947,183 @@
 }
 
 
+uint64_t
+FindImsiForEnb (std::string path, uint16_t rnti)
+{
+  NS_LOG_FUNCTION (path << rnti);
+  uint64_t imsi;
+  if (path.find ("/DlPhyTransmission"))
+    {
+      // /NodeList/0/DeviceList/0/LteEnbPhy/DlPhyTransmission/LteEnbRrc/UeMap/1
+      std::ostringstream oss;
+      std::string p = path.substr (0, path.find ("/LteEnbPhy"));
+      oss << rnti;
+      p += "/LteEnbRrc/UeMap/" + oss.str ();
+      imsi = FindImsiFromEnbRlcPath (p);
+      NS_LOG_LOGIC ("FindImsiForEnb[Tx]: " << path << ", " << rnti << ", " << imsi);
+    }
+  else if (path.find ("/UIlPhyReception"))
+    {
+      std::string p = path.substr (0, path.find ("/LteUePhy"));
+      imsi = FindImsiFromLteNetDevice (p);
+      NS_LOG_LOGIC ("FindImsiForEnb[Rx]: " << path << ", " << rnti << ", " << imsi);
+    }
+  return imsi;
+}
+
+
+uint64_t
+FindImsiForUe (std::string path, uint16_t rnti)
+{
+  NS_LOG_FUNCTION (path << rnti);
+  uint64_t imsi;
+  if (path.find ("/UIlPhyTransmission"))
+    {
+      std::string p = path.substr (0, path.find ("/LteUePhy"));
+      imsi = FindImsiFromLteNetDevice (p);
+      NS_LOG_LOGIC ("FindImsiForUe[Tx]: " << path << ", " << rnti << ", " << imsi);
+    }
+  else if (path.find ("/DIlPhyReception"))
+    {
+      // /NodeList/0/DeviceList/0/LteEnbPhy/LteSpectrumPhy
+      std::ostringstream oss;
+      std::string p = path.substr (0, path.find ("/LteEnbPhy"));
+      oss << rnti;
+      p += "/LteEnbRrc/UeMap/" + oss.str ();
+      imsi = FindImsiFromEnbRlcPath (p);
+      NS_LOG_LOGIC ("FindImsiForUe[Rx]: " << path << ", " << rnti << ", " << imsi);
+    }
+  return imsi;
+}
+
+void
+DlPhyTransmissionCallback (Ptr<PhyTxStatsCalculator> phyTxStats,
+                      std::string path, PhyTransmissionStatParameters params)
+{
+  NS_LOG_FUNCTION (phyTxStats << path);
+  uint64_t imsi = 0;
+  std::ostringstream pathAndRnti;
+  pathAndRnti << path << "/" << params.m_rnti;
+  if (phyTxStats->ExistsImsiPath (pathAndRnti.str ()) == true)
+    {
+      imsi = phyTxStats->GetImsiPath (pathAndRnti.str ());
+    }
+  else
+    {
+      imsi = FindImsiForEnb (path, params.m_rnti);
+      phyTxStats->SetImsiPath (pathAndRnti.str (), imsi);
+    }
+
+  params.m_imsi = imsi;
+  phyTxStats->DlPhyTransmission (params);
+}
+
+void
+UlPhyTransmissionCallback (Ptr<PhyTxStatsCalculator> phyTxStats,
+                      std::string path, PhyTransmissionStatParameters params)
+{
+  NS_LOG_FUNCTION (phyTxStats << path);
+  uint64_t imsi = 0;
+  std::ostringstream pathAndRnti;
+  pathAndRnti << path << "/" << params.m_rnti;
+  if (phyTxStats->ExistsImsiPath (pathAndRnti.str ()) == true)
+    {
+      imsi = phyTxStats->GetImsiPath (pathAndRnti.str ());
+    }
+  else
+    {
+      imsi = FindImsiForUe (path, params.m_rnti);
+      phyTxStats->SetImsiPath (pathAndRnti.str (), imsi);
+    }
+
+  params.m_imsi = imsi;
+  phyTxStats->UlPhyTransmission (params);
+}
+
+
+void
+DlPhyReceptionCallback (Ptr<PhyRxStatsCalculator> phyRxStats,
+                      std::string path, PhyReceptionStatParameters params)
+{
+  NS_LOG_FUNCTION (phyRxStats << path);
+  uint64_t imsi = 0;
+  std::ostringstream pathAndRnti;
+  pathAndRnti << path << "/" << params.m_rnti;
+  if (phyRxStats->ExistsImsiPath (pathAndRnti.str ()) == true)
+    {
+      imsi = phyRxStats->GetImsiPath (pathAndRnti.str ());
+    }
+  else
+    {
+      imsi = FindImsiForUe (path, params.m_rnti);
+      phyRxStats->SetImsiPath (pathAndRnti.str (), imsi);
+    }
+
+  params.m_imsi = imsi;
+  phyRxStats->DlPhyReception (params);
+}
+
+void
+UlPhyReceptionCallback (Ptr<PhyRxStatsCalculator> phyRxStats,
+                      std::string path, PhyReceptionStatParameters params)
+{
+  NS_LOG_FUNCTION (phyRxStats << path);
+  uint64_t imsi = 0;
+  std::ostringstream pathAndRnti;
+  pathAndRnti << path << "/" << params.m_rnti;
+  if (phyRxStats->ExistsImsiPath (pathAndRnti.str ()) == true)
+    {
+      imsi = phyRxStats->GetImsiPath (pathAndRnti.str ());
+    }
+  else
+    {
+      imsi = FindImsiForEnb (path, params.m_rnti);
+      phyRxStats->SetImsiPath (pathAndRnti.str (), imsi);
+    }
+
+  params.m_imsi = imsi;
+  phyRxStats->UlPhyReception (params);
+}
+
+void
+LteHelper::EnablePhyTraces (void)
+{
+  EnableDlTxPhyTraces ();
+  EnableUlTxPhyTraces ();
+  EnableDlRxPhyTraces ();
+  EnableUlRxPhyTraces ();
+}
+
+void
+LteHelper::EnableDlTxPhyTraces (void)
+{
+  Config::Connect ("/NodeList/*/DeviceList/*/LteEnbPhy/DlPhyTransmission",
+                   MakeBoundCallback (&DlPhyTransmissionCallback, m_phyTxStats));
+}
+
+void
+LteHelper::EnableUlTxPhyTraces (void)
+{
+  Config::Connect ("/NodeList/*/DeviceList/*/LteUePhy/UlPhyTransmission",
+                   MakeBoundCallback (&UlPhyTransmissionCallback, m_phyTxStats));
+}
+
+void
+LteHelper::EnableDlRxPhyTraces (void)
+{
+  Config::Connect ("/NodeList/*/DeviceList/*/LteUePhy/DlSpectrumPhy/DlPhyReception",
+                   MakeBoundCallback (&DlPhyReceptionCallback, m_phyRxStats));
+}
+
+void
+LteHelper::EnableUlRxPhyTraces (void)
+{
+  Config::Connect ("/NodeList/*/DeviceList/*/LteEnbPhy/UlSpectrumPhy/UlPhyReception",
+                   MakeBoundCallback (&UlPhyReceptionCallback, m_phyRxStats));
+}
+
+
+
 void
 DlSchedulingCallback (Ptr<MacStatsCalculator> macStats,
                       std::string path, uint32_t frameNo, uint32_t subframeNo,
@@ -952,6 +1158,8 @@
   macStats->DlScheduling (cellId, imsi, frameNo, subframeNo, rnti, mcsTb1, sizeTb1, mcsTb2, sizeTb2);
 }
 
+
+
 void
 LteHelper::EnableMacTraces (void)
 {
--- a/src/lte/helper/lte-helper.h	Tue Dec 04 13:16:20 2012 +0100
+++ b/src/lte/helper/lte-helper.h	Thu Dec 13 11:45:59 2012 +0100
@@ -29,6 +29,8 @@
 #include <ns3/node.h>
 #include <ns3/node-container.h>
 #include <ns3/eps-bearer.h>
+#include <ns3/phy-tx-stats-calculator.h>
+#include <ns3/phy-rx-stats-calculator.h>
 #include <ns3/mac-stats-calculator.h>
 #include <ns3/radio-bearer-stats-calculator.h>
 #include <ns3/radio-bearer-stats-connector.h>
@@ -292,11 +294,36 @@
   void EnableLogComponents (void);
 
   /**
-   * Enables trace sinks for MAC, RLC and PDCP
+   * Enables trace sinks for PHY, MAC, RLC and PDCP
    */
   void EnableTraces (void);
 
   /**
+   * Enable trace sinks for PHY layer
+   */
+  void EnablePhyTraces (void);
+
+  /**
+   * Enable trace sinks for DL transmission PHY layer
+   */
+  void EnableDlTxPhyTraces (void);
+
+  /**
+   * Enable trace sinks for UL transmission PHY layer
+   */
+  void EnableUlTxPhyTraces (void);
+
+  /**
+   * Enable trace sinks for DL reception PHY layer
+   */
+  void EnableDlRxPhyTraces (void);
+
+  /**
+   * Enable trace sinks for UL reception PHY layer
+   */
+  void EnableUlRxPhyTraces (void);
+
+  /**
    * Enable trace sinks for MAC layer
    */
   void EnableMacTraces (void);
@@ -381,6 +408,8 @@
   std::string m_fadingModelType;
   ObjectFactory m_fadingModelFactory;
 
+  Ptr<PhyTxStatsCalculator> m_phyTxStats;
+  Ptr<PhyRxStatsCalculator> m_phyRxStats;
   Ptr<MacStatsCalculator> m_macStats;
   Ptr<RadioBearerStatsCalculator> m_rlcStats;
   Ptr<RadioBearerStatsCalculator> m_pdcpStats;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lte/helper/phy-rx-stats-calculator.cc	Thu Dec 13 11:45:59 2012 +0100
@@ -0,0 +1,179 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2011 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Jaume Nin <jnin@cttc.es>
+ * modified by: Marco Miozzo <mmiozzo@cttc.es>
+ *        Convert MacStatsCalculator in PhyRxStatsCalculator
+ */
+
+#include "phy-rx-stats-calculator.h"
+#include "ns3/string.h"
+#include <ns3/simulator.h>
+#include <ns3/log.h>
+
+namespace ns3 {
+
+NS_LOG_COMPONENT_DEFINE ("PhyRxStatsCalculator");
+
+NS_OBJECT_ENSURE_REGISTERED (PhyRxStatsCalculator);
+
+PhyRxStatsCalculator::PhyRxStatsCalculator ()
+  : m_dlRxFirstWrite (true),
+    m_ulRxFirstWrite (true)
+{
+  NS_LOG_FUNCTION (this);
+
+}
+
+PhyRxStatsCalculator::~PhyRxStatsCalculator ()
+{
+  NS_LOG_FUNCTION (this);
+}
+
+TypeId
+PhyRxStatsCalculator::GetTypeId (void)
+{
+  static TypeId tid = TypeId ("ns3::PhyRxStatsCalculator")
+    .SetParent<LteStatsCalculator> ()
+    .AddConstructor<PhyRxStatsCalculator> ()
+    .AddAttribute ("DlRxOutputFilename",
+                   "Name of the file where the downlink results will be saved.",
+                   StringValue ("DlRxPhyStats.txt"),
+                   MakeStringAccessor (&PhyRxStatsCalculator::SetDlRxOutputFilename),
+                   MakeStringChecker ())
+    .AddAttribute ("UlRxOutputFilename",
+                   "Name of the file where the uplink results will be saved.",
+                   StringValue ("UlRxPhyStats.txt"),
+                   MakeStringAccessor (&PhyRxStatsCalculator::SetUlRxOutputFilename),
+                   MakeStringChecker ())
+  ;
+  return tid;
+}
+
+void
+PhyRxStatsCalculator::SetUlRxOutputFilename (std::string outputFilename)
+{
+  LteStatsCalculator::SetUlOutputFilename (outputFilename);
+}
+
+std::string
+PhyRxStatsCalculator::GetUlRxOutputFilename (void)
+{
+  return LteStatsCalculator::GetUlOutputFilename ();
+}
+
+void
+PhyRxStatsCalculator::SetDlRxOutputFilename (std::string outputFilename)
+{
+  LteStatsCalculator::SetDlOutputFilename (outputFilename);
+}
+
+std::string
+PhyRxStatsCalculator::GetDlRxOutputFilename (void)
+{
+  return LteStatsCalculator::GetDlOutputFilename ();
+}
+
+void
+PhyRxStatsCalculator::DlPhyReception (PhyReceptionStatParameters params)
+{
+  NS_LOG_FUNCTION (this << params.m_cellId << params.m_imsi << params.m_timestamp << params.m_rnti << params.m_layer << params.m_mcs << params.m_size << params.m_rv << params.m_ndi << params.m_correctness);
+  NS_LOG_INFO ("Write DL Rx Phy Stats in " << GetDlRxOutputFilename ().c_str ());
+
+  std::ofstream outFile;
+  if ( m_dlRxFirstWrite == true )
+    {
+      outFile.open (GetDlRxOutputFilename ().c_str ());
+      if (!outFile.is_open ())
+        {
+          NS_LOG_ERROR ("Can't open file " << GetDlRxOutputFilename ().c_str ());
+          return;
+        }
+      m_dlRxFirstWrite = false;
+      outFile << "% time\tcellId\tIMSI\tRNTI\ttxMode\tlayer\tmcs\tsize\trv\tndi\tcorrect";
+      outFile << std::endl;
+    }
+  else
+    {
+      outFile.open (GetDlRxOutputFilename ().c_str (),  std::ios_base::app);
+      if (!outFile.is_open ())
+        {
+          NS_LOG_ERROR ("Can't open file " << GetDlRxOutputFilename ().c_str ());
+          return;
+        }
+    }
+
+//   outFile << Simulator::Now ().GetNanoSeconds () / (double) 1e9 << "\t";
+  outFile << params.m_timestamp << "\t";
+  outFile << (uint32_t) params.m_cellId << "\t";
+  outFile << params.m_imsi << "\t";
+  outFile << params.m_rnti << "\t";
+  outFile << (uint32_t) params.m_txMode << "\t";
+  outFile << (uint32_t) params.m_layer << "\t";
+  outFile << (uint32_t) params.m_mcs << "\t";
+  outFile << params.m_size << "\t";
+  outFile << (uint32_t) params.m_rv << "\t";
+  outFile << (uint32_t) params.m_ndi << "\t";
+  outFile << (uint32_t) params.m_correctness << std::endl;
+  outFile.close ();
+}
+
+void
+PhyRxStatsCalculator::UlPhyReception (PhyReceptionStatParameters params)
+{
+  NS_LOG_FUNCTION (this << params.m_cellId << params.m_imsi << params.m_timestamp << params.m_rnti << params.m_layer << params.m_mcs << params.m_size << params.m_rv << params.m_ndi << params.m_correctness);
+  NS_LOG_INFO ("Write UL Rx Phy Stats in " << GetUlRxOutputFilename ().c_str ());
+
+  std::ofstream outFile;
+  if ( m_ulRxFirstWrite == true )
+    {
+      outFile.open (GetUlRxOutputFilename ().c_str ());
+      if (!outFile.is_open ())
+        {
+          NS_LOG_ERROR ("Can't open file " << GetUlRxOutputFilename ().c_str ());
+          return;
+        }
+      m_ulRxFirstWrite = false;
+      outFile << "% time\tcellId\tIMSI\tRNTI\ttxMode\tlayer\tmcs\tsize\trv\tndi\tcorrect";
+      outFile << std::endl;
+    }
+  else
+    {
+      outFile.open (GetUlRxOutputFilename ().c_str (),  std::ios_base::app);
+      if (!outFile.is_open ())
+        {
+          NS_LOG_ERROR ("Can't open file " << GetUlRxOutputFilename ().c_str ());
+          return;
+        }
+    }
+
+//   outFile << Simulator::Now ().GetNanoSeconds () / (double) 1e9 << "\t";
+  outFile << params.m_timestamp << "\t";
+  outFile << (uint32_t) params.m_cellId << "\t";
+  outFile << params.m_imsi << "\t";
+  outFile << params.m_rnti << "\t";
+  outFile << (uint32_t) params.m_txMode << "\t";
+  outFile << (uint32_t) params.m_layer << "\t";
+  outFile << (uint32_t) params.m_mcs << "\t";
+  outFile << params.m_size << "\t";
+  outFile << (uint32_t) params.m_rv << "\t";
+  outFile << (uint32_t) params.m_ndi << "\t";
+  outFile << (uint32_t) params.m_correctness << std::endl;
+  outFile.close ();
+}
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lte/helper/phy-rx-stats-calculator.h	Thu Dec 13 11:45:59 2012 +0100
@@ -0,0 +1,134 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2011 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Jaume Nin <jnin@cttc.es>
+ * modified by: Marco Miozzo <mmiozzo@cttc.es>
+ *        Convert MacStatsCalculator in PhyRxStatsCalculator
+ */
+
+#ifndef PHY_RX_STATS_CALCULATOR_H_
+#define PHY_RX_STATS_CALCULATOR_H_
+
+#include "ns3/lte-stats-calculator.h"
+#include "ns3/nstime.h"
+#include "ns3/uinteger.h"
+#include <string>
+#include <fstream>
+#include <ns3/lte-common.h>
+
+namespace ns3 {
+
+/**
+ * Takes care of storing the information generated at PHY layer regarding 
+ * reception. Metrics saved are:
+ *time\tframe\tsframe\tRNTI\tmcsTb1\tsizeTb1\tmcsTb2\tsizeTb2
+ *   - Timestamp (in seconds)
+ *   - Frame index
+ *   - Subframe index
+ *   - C-RNTI
+ *   - MCS for transport block 1
+ *   - Size of transport block 1
+ *   - MCS for transport block 2 (0 if not used)
+ *   - Size of transport block 2 (0 if not used)
+ */
+class PhyRxStatsCalculator : public LteStatsCalculator
+{
+public:
+  /**
+   * Constructor
+   */
+  PhyRxStatsCalculator ();
+
+  /**
+   * Destructor
+   */
+  virtual ~PhyRxStatsCalculator ();
+
+  /**
+   * Inherited from ns3::Object
+   */
+  static TypeId GetTypeId (void);
+
+  /**
+   * Set the name of the file where the UL Rx PHY statistics will be stored.
+   *
+   * \param outputFilename string with the name of the file
+   */
+  void SetUlRxOutputFilename (std::string outputFilename);
+
+  /**
+   * Get the name of the file where the UL RX PHY statistics will be stored.
+   */
+  std::string GetUlRxOutputFilename (void);
+
+  /**
+   * Set the name of the file where the DL RX PHY statistics will be stored.
+   *
+   * @param outputFilename string with the name of the file
+   */
+  void SetDlRxOutputFilename (std::string outputFilename);
+
+  /**
+   * Get the name of the file where the DL RX PHY statistics will be stored.
+   */
+  std::string GetDlRxOutputFilename (void);
+
+  /**
+   * Notifies the stats calculator that an downlink reception has occurred.
+   * @param cellId Cell ID of the attached Enb
+   * @param imsi IMSI of the scheduled UE
+   * @param frameNo Frame number
+   * @param subframeNo Subframe number
+   * @param rnti C-RNTI scheduled
+   * @param layer the layer (cw) of the transmission
+   * @param txMode the transmission Mode
+   * @param mcs MCS for transport block
+   * @param size Size of transport block
+   * @param rv the redundancy version (HARQ)
+   * @param ndi new data indicator flag
+   * @param correctness correctness of the TB received
+   */
+  void DlPhyReception (PhyReceptionStatParameters params);
+
+  /**
+   * Notifies the stats calculator that an uplink reception has occurred.
+   * @param cellId Cell ID of the attached Enb
+   * @param imsi IMSI of the scheduled UE
+   * @param frameNo Frame number
+   * @param subframeNo Subframe number
+   * @param rnti C-RNTI scheduled
+   * @param layer the layer (cw) of the transmission
+   * @param txMode the transmission Mode
+   * @param mcs MCS for transport block
+   * @param size Size of transport block
+   * @param rv the redundancy version (HARQ)
+   * @param ndi new data indicator flag
+   * @param correctness correctness of the TB received
+   */
+  void UlPhyReception (PhyReceptionStatParameters params);
+
+
+private:
+
+  bool m_dlRxFirstWrite;
+  bool m_ulRxFirstWrite;
+
+};
+
+} // namespace ns3
+
+#endif /* PHY_RX_STATS_CALCULATOR_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lte/helper/phy-tx-stats-calculator.cc	Thu Dec 13 11:45:59 2012 +0100
@@ -0,0 +1,178 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2011 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Jaume Nin <jnin@cttc.es>
+ * modified by: Marco Miozzo <mmiozzo@cttc.es>
+ *        Convert MacStatsCalculator in PhyTxStatsCalculator
+ */
+
+#include "phy-tx-stats-calculator.h"
+#include "ns3/string.h"
+#include <ns3/simulator.h>
+#include <ns3/log.h>
+
+namespace ns3 {
+
+NS_LOG_COMPONENT_DEFINE ("PhyTxStatsCalculator");
+
+NS_OBJECT_ENSURE_REGISTERED (PhyTxStatsCalculator);
+
+PhyTxStatsCalculator::PhyTxStatsCalculator ()
+  : m_dlTxFirstWrite (true),
+    m_ulTxFirstWrite (true)
+{
+  NS_LOG_FUNCTION (this);
+
+}
+
+PhyTxStatsCalculator::~PhyTxStatsCalculator ()
+{
+  NS_LOG_FUNCTION (this);
+}
+
+TypeId
+PhyTxStatsCalculator::GetTypeId (void)
+{
+  static TypeId tid = TypeId ("ns3::PhyTxStatsCalculator")
+    .SetParent<LteStatsCalculator> ()
+    .AddConstructor<PhyTxStatsCalculator> ()
+    .AddAttribute ("DlTxOutputFilename",
+                   "Name of the file where the downlink results will be saved.",
+                   StringValue ("DlTxPhyStats.txt"),
+                   MakeStringAccessor (&PhyTxStatsCalculator::SetDlTxOutputFilename),
+                   MakeStringChecker ())
+    .AddAttribute ("UlTxOutputFilename",
+                   "Name of the file where the uplink results will be saved.",
+                   StringValue ("UlTxPhyStats.txt"),
+                   MakeStringAccessor (&PhyTxStatsCalculator::SetUlTxOutputFilename),
+                   MakeStringChecker ())
+  ;
+  return tid;
+}
+
+void
+PhyTxStatsCalculator::SetUlTxOutputFilename (std::string outputFilename)
+{
+  LteStatsCalculator::SetUlOutputFilename (outputFilename);
+}
+
+std::string
+PhyTxStatsCalculator::GetUlTxOutputFilename (void)
+{
+  return LteStatsCalculator::GetUlOutputFilename ();
+}
+
+void
+PhyTxStatsCalculator::SetDlTxOutputFilename (std::string outputFilename)
+{
+  LteStatsCalculator::SetDlOutputFilename (outputFilename);
+}
+
+std::string
+PhyTxStatsCalculator::GetDlTxOutputFilename (void)
+{
+  return LteStatsCalculator::GetDlOutputFilename ();
+}
+
+void
+PhyTxStatsCalculator::DlPhyTransmission (PhyTransmissionStatParameters params)
+{
+  NS_LOG_FUNCTION (this << params.m_cellId << params.m_imsi << params.m_timestamp << params.m_rnti << params.m_layer << params.m_mcs << params.m_size << params.m_rv << params.m_ndi);
+  NS_LOG_INFO ("Write DL Tx Phy Stats in " << GetDlTxOutputFilename ().c_str ());
+
+  std::ofstream outFile;
+  if ( m_dlTxFirstWrite == true )
+    {
+      outFile.open (GetDlOutputFilename ().c_str ());
+      if (!outFile.is_open ())
+        {
+          NS_LOG_ERROR ("Can't open file " << GetDlTxOutputFilename ().c_str ());
+          return;
+        }
+      m_dlTxFirstWrite = false;
+      //outFile << "% time\tcellId\tIMSI\tRNTI\tlayer\tmcs\tsize\trv\tndi"; // txMode is not available at dl tx side
+      outFile << "% time\tcellId\tIMSI\tRNTI\ttxMode\tlayer\tmcs\tsize\trv\tndi";
+      outFile << std::endl;
+    }
+  else
+    {
+      outFile.open (GetDlTxOutputFilename ().c_str (),  std::ios_base::app);
+      if (!outFile.is_open ())
+        {
+          NS_LOG_ERROR ("Can't open file " << GetDlTxOutputFilename ().c_str ());
+          return;
+        }
+    }
+
+//   outFile << Simulator::Now ().GetNanoSeconds () / (double) 1e9 << "\t";
+  outFile << params.m_timestamp << "\t";
+  outFile << (uint32_t) params.m_cellId << "\t";
+  outFile << params.m_imsi << "\t";
+  outFile << params.m_rnti << "\t";
+  //outFile << (uint32_t) params.m_txMode << "\t"; // txMode is not available at dl tx side
+  outFile << (uint32_t) params.m_layer << "\t";
+  outFile << (uint32_t) params.m_mcs << "\t";
+  outFile << params.m_size << "\t";
+  outFile << (uint32_t) params.m_rv << "\t";
+  outFile << (uint32_t) params.m_ndi << std::endl;
+  outFile.close ();
+}
+
+void
+PhyTxStatsCalculator::UlPhyTransmission (PhyTransmissionStatParameters params)
+{
+  NS_LOG_FUNCTION (this << params.m_cellId << params.m_imsi << params.m_timestamp << params.m_rnti << params.m_layer << params.m_mcs << params.m_size << params.m_rv << params.m_ndi);
+  NS_LOG_INFO ("Write UL Tx Phy Stats in " << GetUlTxOutputFilename ().c_str ());
+
+  std::ofstream outFile;
+  if ( m_ulTxFirstWrite == true )
+    {
+      outFile.open (GetUlTxOutputFilename ().c_str ());
+      if (!outFile.is_open ())
+        {
+          NS_LOG_ERROR ("Can't open file " << GetUlTxOutputFilename ().c_str ());
+          return;
+        }
+      m_ulTxFirstWrite = false;
+      outFile << "% time\tcellId\tIMSI\tRNTI\ttxMode\tlayer\tmcs\tsize\trv\tndi";
+      outFile << std::endl;
+    }
+  else
+    {
+      outFile.open (GetUlTxOutputFilename ().c_str (),  std::ios_base::app);
+      if (!outFile.is_open ())
+        {
+          NS_LOG_ERROR ("Can't open file " << GetUlTxOutputFilename ().c_str ());
+          return;
+        }
+    }
+
+//   outFile << Simulator::Now ().GetNanoSeconds () / (double) 1e9 << "\t";
+  outFile << params.m_timestamp << "\t";
+  outFile << (uint32_t) params.m_cellId << "\t";
+  outFile << params.m_imsi << "\t";
+  outFile << params.m_rnti << "\t";
+  outFile << (uint32_t) params.m_txMode << "\t";
+  outFile << (uint32_t) params.m_layer << "\t";
+  outFile << (uint32_t) params.m_mcs << "\t";
+  outFile << params.m_size << "\t";
+  outFile << (uint32_t) params.m_rv << "\t";
+  outFile << (uint32_t) params.m_ndi << std::endl;
+  outFile.close ();
+}
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lte/helper/phy-tx-stats-calculator.h	Thu Dec 13 11:45:59 2012 +0100
@@ -0,0 +1,134 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2011 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Jaume Nin <jnin@cttc.es>
+ * modified by: Marco Miozzo <mmiozzo@cttc.es>
+ *        Convert MacStatsCalculator in PhyTxStatsCalculator
+ */
+
+#ifndef PHY_TX_STATS_CALCULATOR_H_
+#define PHY_TX_STATS_CALCULATOR_H_
+
+#include "ns3/lte-stats-calculator.h"
+#include "ns3/nstime.h"
+#include "ns3/uinteger.h"
+#include <string>
+#include <fstream>
+#include <ns3/lte-common.h>
+
+namespace ns3 {
+
+
+
+/**
+ * Takes care of storing the information generated at PHY layer regarding 
+ * transmission. Metrics saved are:
+ *time\tframe\tsframe\tRNTI\tmcsTb1\tsizeTb1\tmcsTb2\tsizeTb2
+ *   - Timestamp (in seconds)
+ *   - Frame index
+ *   - Subframe index
+ *   - C-RNTI
+ *   - MCS for transport block 1
+ *   - Size of transport block 1
+ *   - MCS for transport block 2 (0 if not used)
+ *   - Size of transport block 2 (0 if not used)
+ */
+class PhyTxStatsCalculator : public LteStatsCalculator
+{
+public:
+  /**
+   * Constructor
+   */
+  PhyTxStatsCalculator ();
+
+  /**
+   * Destructor
+   */
+  virtual ~PhyTxStatsCalculator ();
+
+  /**
+   * Inherited from ns3::Object
+   */
+  static TypeId GetTypeId (void);
+
+  /**
+   * Set the name of the file where the UL Tx PHY statistics will be stored.
+   *
+   * \param outputFilename string with the name of the file
+   */
+  void SetUlTxOutputFilename (std::string outputFilename);
+
+  /**
+   * Get the name of the file where the UL RX PHY statistics will be stored.
+   */
+  std::string GetUlTxOutputFilename (void);
+
+  /**
+   * Set the name of the file where the DL TX PHY statistics will be stored.
+   *
+   * @param outputFilename string with the name of the file
+   */
+  void SetDlTxOutputFilename (std::string outputFilename);
+
+  /**
+   * Get the name of the file where the DL TX PHY statistics will be stored.
+   */
+  std::string GetDlTxOutputFilename (void);
+
+  /**
+   * Notifies the stats calculator that an downlink trasmission has occurred.
+   * @param cellId Cell ID of the attached Enb
+   * @param imsi IMSI of the scheduled UE
+   * @param frameNo Frame number
+   * @param subframeNo Subframe number
+   * @param rnti C-RNTI scheduled
+   * @param layer the layer (cw) of the transmission
+   * @param txMode the transmission Mode
+   * @param mcs MCS for transport block
+   * @param size Size of transport block
+   * @param rv the redundancy version (HARQ)
+   * @param ndi new data indicator flag
+   */
+  void DlPhyTransmission (PhyTransmissionStatParameters params);
+
+  /**
+   * Notifies the stats calculator that an uplink trasmission has occurred.
+   * @param cellId Cell ID of the attached Enb
+   * @param imsi IMSI of the scheduled UE
+   * @param frameNo Frame number
+   * @param subframeNo Subframe number
+   * @param rnti C-RNTI scheduled
+   * @param layer the layer (cw) of the transmission
+   * @param txMode the transmission Mode
+   * @param mcs MCS for transport block
+   * @param size Size of transport block
+   * @param rv the redundancy version (HARQ)
+   * @param ndi new data indicator flag
+   */
+  void UlPhyTransmission (PhyTransmissionStatParameters params);
+
+
+private:
+
+  bool m_dlTxFirstWrite;
+  bool m_ulTxFirstWrite;
+
+};
+
+} // namespace ns3
+
+#endif /* PHY_TX_STATS_CALCULATOR_H_ */
--- a/src/lte/model/lte-common.h	Tue Dec 04 13:16:20 2012 +0100
+++ b/src/lte/model/lte-common.h	Thu Dec 13 11:45:59 2012 +0100
@@ -117,6 +117,37 @@
 };
 
 
+struct PhyTransmissionStatParameters
+{
+  int64_t  m_timestamp; // in millisecond
+  uint16_t m_cellId;
+  uint64_t m_imsi;
+  uint16_t m_rnti;
+  uint8_t  m_txMode;
+  uint8_t  m_layer;
+  uint8_t  m_mcs;
+  uint16_t m_size;
+  uint8_t  m_rv;
+  uint8_t  m_ndi;
+};
+
+
+struct PhyReceptionStatParameters
+{
+  int64_t  m_timestamp; // in millisecond
+  uint16_t m_cellId;
+  uint64_t m_imsi;
+  uint16_t m_rnti;
+  uint8_t  m_txMode;
+  uint8_t  m_layer;
+  uint8_t  m_mcs;
+  uint16_t m_size;
+  uint8_t  m_rv;
+  uint8_t  m_ndi;
+  uint8_t  m_correctness;
+};
+
+
 }; // namespace ns3
 
 
--- a/src/lte/model/lte-enb-phy.cc	Tue Dec 04 13:16:20 2012 +0100
+++ b/src/lte/model/lte-enb-phy.cc	Thu Dec 13 11:45:59 2012 +0100
@@ -42,6 +42,7 @@
 #include <ns3/node-list.h>
 #include <ns3/node.h>
 #include <ns3/lte-ue-net-device.h>
+#include <ns3/pointer.h>
 
 NS_LOG_COMPONENT_DEFINE ("LteEnbPhy");
 
@@ -194,6 +195,21 @@
                    UintegerValue (1),
                    MakeUintegerAccessor (&LteEnbPhy::m_interferenceSamplePeriod),
                    MakeUintegerChecker<uint16_t> ())
+    .AddTraceSource ("DlPhyTransmission",
+                     "DL transmission PHY layer statistics.",
+                     MakeTraceSourceAccessor (&LteEnbPhy::m_dlPhyTransmission))
+    .AddAttribute ("DlSpectrumPhy",
+                   "The downlink LteSpectrumPhy associated to this LtePhy",
+                   TypeId::ATTR_GET,
+                   PointerValue (),
+                   MakePointerAccessor (&LteEnbPhy::m_downlinkSpectrumPhy),
+                   MakePointerChecker <LteSpectrumPhy> ())
+    .AddAttribute ("UlSpectrumPhy",
+                   "The uplink LteSpectrumPhy associated to this LtePhy",
+                   TypeId::ATTR_GET,
+                   PointerValue (),
+                   MakePointerAccessor (&LteEnbPhy::m_uplinkSpectrumPhy),
+                   MakePointerChecker <LteSpectrumPhy> ())
   ;
   return tid;
 }
@@ -500,7 +516,7 @@
             {
               rbMap.push_back (i);
             }
-          m_uplinkSpectrumPhy->AddExpectedTb ((*dciIt).GetDci ().m_rnti, (*dciIt).GetDci ().m_ndi, (*dciIt).GetDci ().m_tbSize, (*dciIt).GetDci ().m_mcs, rbMap, 0 /* always SISO*/, 0 /* no HARQ proc id in UL*/, false /* UL*/);
+          m_uplinkSpectrumPhy->AddExpectedTb ((*dciIt).GetDci ().m_rnti, (*dciIt).GetDci ().m_ndi, (*dciIt).GetDci ().m_tbSize, (*dciIt).GetDci ().m_mcs, rbMap, 0 /* always SISO*/, 0 /* no HARQ proc id in UL*/, 0 /*evaluated by LteSpectrumPhy*/, false /* UL*/);
           if ((*dciIt).GetDci ().m_ndi==1)
             {
               NS_LOG_DEBUG (this << " RNTI " << (*dciIt).GetDci ().m_rnti << " NEW TB");
@@ -525,21 +541,38 @@
           if (msg->GetMessageType () == LteControlMessage::DL_DCI)
             {
               Ptr<DlDciLteControlMessage> dci = DynamicCast<DlDciLteControlMessage> (msg);
-                  // get the tx power spectral density according to DL-DCI(s)
-                  // translate the DCI to Spectrum framework
-                  uint32_t mask = 0x1;
-                  for (int i = 0; i < 32; i++)
+              // get the tx power spectral density according to DL-DCI(s)
+              // translate the DCI to Spectrum framework
+              uint32_t mask = 0x1;
+              for (int i = 0; i < 32; i++)
+                {
+                  if (((dci->GetDci ().m_rbBitmap & mask) >> i) == 1)
                     {
-                      if (((dci->GetDci ().m_rbBitmap & mask) >> i) == 1)
+                      for (int k = 0; k < GetRbgSize (); k++)
                         {
-                          for (int k = 0; k < GetRbgSize (); k++)
-                            {
-                              m_dlDataRbMap.push_back ((i * GetRbgSize ()) + k);
-                              //NS_LOG_DEBUG(this << " [enb]DL-DCI allocated PRB " << (i*GetRbgSize()) + k);
-                            }
+                          m_dlDataRbMap.push_back ((i * GetRbgSize ()) + k);
+                          //NS_LOG_DEBUG(this << " [enb]DL-DCI allocated PRB " << (i*GetRbgSize()) + k);
                         }
-                      mask = (mask << 1);
                     }
+                  mask = (mask << 1);
+                }
+              // fire trace of DL Tx PHY stats
+              for (uint8_t i = 0; i < dci->GetDci ().m_mcs.size (); i++)
+                {
+                  PhyTransmissionStatParameters params;
+                  params.m_cellId = m_cellId;
+                  params.m_imsi = 0; // it will be set by DlPhyTransmissionCallback in LteHelper
+                  params.m_timestamp = Simulator::Now ().GetMilliSeconds ();
+                  params.m_rnti = dci->GetDci ().m_rnti;
+                  params.m_txMode = 0; // TBD
+                  params.m_layer = i;
+                  params.m_mcs = dci->GetDci ().m_mcs.at (i);
+                  params.m_size = dci->GetDci ().m_tbsSize.at (i);
+                  params.m_rv = dci->GetDci ().m_rv.at (i);
+                  params.m_ndi = dci->GetDci ().m_ndi.at (i);
+                  m_dlPhyTransmission (params);
+                }
+              
             }
           else if (msg->GetMessageType () == LteControlMessage::UL_DCI)
             {
--- a/src/lte/model/lte-enb-phy.h	Tue Dec 04 13:16:20 2012 +0100
+++ b/src/lte/model/lte-enb-phy.h	Thu Dec 13 11:45:59 2012 +0100
@@ -307,6 +307,12 @@
   TracedCallback<uint16_t, Ptr<SpectrumValue> > m_reportInterferenceTrace;
   uint16_t m_interferenceSamplePeriod;
   uint16_t m_interferenceSampleCounter;
+
+  /**
+   * Trace information regarding PHY stats from UL Tx perspective
+   * PhyTrasmissionStatParameters see lte-common.h
+   */
+  TracedCallback<PhyTransmissionStatParameters> m_dlPhyTransmission;
   
 };
 
--- a/src/lte/model/lte-spectrum-phy.cc	Tue Dec 04 13:16:20 2012 +0100
+++ b/src/lte/model/lte-spectrum-phy.cc	Thu Dec 13 11:45:59 2012 +0100
@@ -37,6 +37,7 @@
 #include <ns3/lte-radio-bearer-tag.h>
 #include <ns3/boolean.h>
 #include <ns3/double.h>
+#include <ns3/config.h>
 
 NS_LOG_COMPONENT_DEFINE ("LteSpectrumPhy");
 
@@ -114,8 +115,7 @@
 LteSpectrumPhy::LteSpectrumPhy ()
   : m_state (IDLE),
   m_transmissionMode (0),
-  m_layersNum (1),
-  errors (0)
+  m_layersNum (1)
 {
   NS_LOG_FUNCTION (this);
   m_random = CreateObject<UniformRandomVariable> ();
@@ -211,6 +211,12 @@
                     BooleanValue (true),
                     MakeBooleanAccessor (&LteSpectrumPhy::m_ctrlErrorModelEnabled),
                     MakeBooleanChecker ())
+    .AddTraceSource ("DlPhyReception",
+                     "DL reception PHY layer statistics.",
+                     MakeTraceSourceAccessor (&LteSpectrumPhy::m_dlPhyReception))
+    .AddTraceSource ("UlPhyReception",
+                     "DL reception PHY layer statistics.",
+                     MakeTraceSourceAccessor (&LteSpectrumPhy::m_ulPhyReception))
   ;
   return tid;
 }
@@ -782,9 +788,9 @@
 
 
 void
-LteSpectrumPhy::AddExpectedTb (uint16_t  rnti, uint8_t ndi, uint16_t size, uint8_t mcs, std::vector<int> map, uint8_t layer, uint8_t harqId, bool downlink)
+LteSpectrumPhy::AddExpectedTb (uint16_t  rnti, uint8_t ndi, uint16_t size, uint8_t mcs, std::vector<int> map, uint8_t layer, uint8_t harqId,uint8_t rv,  bool downlink)
 {
-  NS_LOG_FUNCTION (this << " rnti: " << rnti << " NDI " << (uint16_t)ndi << " size " << size << " mcs " << (uint16_t)mcs << " layer " << (uint16_t)layer);
+  NS_LOG_FUNCTION (this << " rnti: " << rnti << " NDI " << (uint16_t)ndi << " size " << size << " mcs " << (uint16_t)mcs << " layer " << (uint16_t)layer << " rv " << (uint16_t)rv);
   TbId_t tbId;
   tbId.m_rnti = rnti;
   tbId.m_layer = layer;
@@ -796,8 +802,7 @@
       m_expectedTbs.erase (it);
     }
   // insert new entry
-  std::vector<uint8_t> rv;
-  tbInfo_t tbInfo = {ndi, size, mcs, map, harqId, 0.0, downlink, false};
+  tbInfo_t tbInfo = {ndi, size, mcs, map, harqId, 0.0, rv, downlink, false};
   m_expectedTbs.insert (std::pair<TbId_t, tbInfo_t> (tbId,tbInfo));
 }
 
@@ -845,6 +850,30 @@
           (*itTb).second.mi = tbStats.mi;
           (*itTb).second.corrupt = m_random->GetValue () > tbStats.tbler ? false : true;
           NS_LOG_DEBUG (this << "RNTI " << (*itTb).first.m_rnti << " size " << (*itTb).second.size << " mcs " << (uint32_t)(*itTb).second.mcs << " bitmap " << (*itTb).second.rbBitmap.size () << " layer " << (uint16_t)(*itTb).first.m_layer << " TBLER " << tbStats.tbler << " corrupted " << (*itTb).second.corrupt);
+          // fire traces on DL/UL reception PHY stats
+          PhyReceptionStatParameters params;
+          params.m_timestamp = Simulator::Now ().GetMilliSeconds ();
+          params.m_cellId = m_cellId;
+          params.m_imsi = 0; // it will be set by DlPhyTransmissionCallback in LteHelper
+          params.m_rnti = (*itTb).first.m_rnti;
+          params.m_txMode = m_transmissionMode;
+          params.m_layer =  (*itTb).first.m_layer;
+          params.m_mcs = (*itTb).second.mcs;
+          params.m_size = (*itTb).second.size;
+          params.m_rv = (*itTb).second.rv;
+          params.m_ndi = (*itTb).second.ndi;
+          params.m_correctness = (uint8_t)!(*itTb).second.corrupt;
+          if ((*itTb).second.downlink)
+            {
+              // DL
+              m_dlPhyReception (params);
+            }
+          else
+            {
+              // UL
+              params.m_rv = harqInfoList.size ();
+              m_ulPhyReception (params);
+            }
        }
       
       itTb++;
--- a/src/lte/model/lte-spectrum-phy.h	Tue Dec 04 13:16:20 2012 +0100
+++ b/src/lte/model/lte-spectrum-phy.h	Thu Dec 13 11:45:59 2012 +0100
@@ -65,6 +65,7 @@
   uint8_t mcs;
   std::vector<int> rbBitmap;
   uint8_t harqProcessId;
+  uint8_t rv;
   double mi;
   bool downlink;
   bool corrupt;
@@ -338,7 +339,7 @@
   * \param harqId the id of the HARQ process (valid only for DL)
   * \param downlink true when the TB is for DL
   */
-  void AddExpectedTb (uint16_t  rnti, uint8_t ndi, uint16_t size, uint8_t mcs, std::vector<int> map, uint8_t layer, uint8_t harqId, bool downlink);
+  void AddExpectedTb (uint16_t  rnti, uint8_t ndi, uint16_t size, uint8_t mcs, std::vector<int> map, uint8_t layer, uint8_t harqId, uint8_t rv, bool downlink);
 
 
   /** 
@@ -437,7 +438,19 @@
   LtePhyDlHarqFeedbackCallback m_ltePhyDlHarqFeedbackCallback;
   LtePhyUlHarqFeedbackCallback m_ltePhyUlHarqFeedbackCallback;
 
-  uint16_t errors; // DEBUG
+
+  /**
+   * Trace information regarding PHY stats from DL Rx perspective
+   * PhyReceptionStatParameters (see lte-common.h)
+   */
+  TracedCallback<PhyReceptionStatParameters> m_dlPhyReception;
+
+  
+  /**
+   * Trace information regarding PHY stats from UL Rx perspective
+   * PhyReceptionStatParameters (see lte-common.h)
+   */
+  TracedCallback<PhyReceptionStatParameters> m_ulPhyReception;
 
 };
 
--- a/src/lte/model/lte-ue-phy.cc	Tue Dec 04 13:16:20 2012 +0100
+++ b/src/lte/model/lte-ue-phy.cc	Thu Dec 13 11:45:59 2012 +0100
@@ -36,7 +36,7 @@
 #include "ff-mac-common.h"
 #include "lte-sinr-chunk-processor.h"
 #include <ns3/lte-common.h>
-
+#include <ns3/pointer.h>
 
 NS_LOG_COMPONENT_DEFINE ("LteUePhy");
 
@@ -239,6 +239,21 @@
                    UintegerValue (1),
                    MakeUintegerAccessor (&LteUePhy::m_rsrpRsrqSamplePeriod),
                    MakeUintegerChecker<uint16_t> ())
+    .AddTraceSource ("UlPhyTransmission",
+                     "DL transmission PHY layer statistics.",
+                     MakeTraceSourceAccessor (&LteUePhy::m_ulPhyTransmission))
+    .AddAttribute ("DlSpectrumPhy",
+                   "The downlink LteSpectrumPhy associated to this LtePhy",
+                   TypeId::ATTR_GET,
+                   PointerValue (),
+                   MakePointerAccessor (&LteUePhy::m_downlinkSpectrumPhy),
+                   MakePointerChecker <LteSpectrumPhy> ())
+    .AddAttribute ("UlSpectrumPhy",
+                   "The uplink LteSpectrumPhy associated to this LtePhy",
+                   TypeId::ATTR_GET,
+                   PointerValue (),
+                   MakePointerAccessor (&LteUePhy::m_uplinkSpectrumPhy),
+                   MakePointerChecker <LteSpectrumPhy> ())
   ;
   return tid;
 }
@@ -598,7 +613,7 @@
       NS_LOG_DEBUG (this << " UE " << m_rnti << " DL-DCI " << dci.m_rnti << " bitmap "  << dci.m_rbBitmap);
       for (uint8_t i = 0; i < dci.m_tbsSize.size (); i++)
       {
-        m_downlinkSpectrumPhy->AddExpectedTb (dci.m_rnti, dci.m_ndi.at (i), dci.m_tbsSize.at (i), dci.m_mcs.at (i), dlRb, i, dci.m_harqProcess, true /* DL */);
+        m_downlinkSpectrumPhy->AddExpectedTb (dci.m_rnti, dci.m_ndi.at (i), dci.m_tbsSize.at (i), dci.m_mcs.at (i), dlRb, i, dci.m_harqProcess, dci.m_rv.at (i), true /* DL */);
       }
       
       SetSubChannelsForReception (dlRb);
@@ -623,6 +638,20 @@
         //NS_LOG_DEBUG (this << " UE RB " << i + dci.m_rbStart);
       }
       QueueSubChannelsForTransmission (ulRb);
+      // fire trace of UL Tx PHY stats
+      HarqProcessInfoList_t harqInfoList = m_harqPhyModule->GetHarqProcessInfoUl (m_rnti, 0);
+      PhyTransmissionStatParameters params;
+      params.m_cellId = m_cellId;
+      params.m_imsi = 0; // it will be set by DlPhyTransmissionCallback in LteHelper
+      params.m_timestamp = Simulator::Now ().GetMilliSeconds () + UL_PUSCH_TTIS_DELAY;
+      params.m_rnti = m_rnti;
+      params.m_txMode = 0; // always SISO for UE
+      params.m_layer = 0;
+      params.m_mcs = dci.m_mcs;
+      params.m_size = dci.m_tbSize;
+      params.m_rv = harqInfoList.size ();
+      params.m_ndi = dci.m_ndi;
+      m_ulPhyTransmission (params);
       // pass the info to the MAC
       m_uePhySapUser->ReceiveLteControlMessage (msg);
     }
--- a/src/lte/model/lte-ue-phy.h	Tue Dec 04 13:16:20 2012 +0100
+++ b/src/lte/model/lte-ue-phy.h	Thu Dec 13 11:45:59 2012 +0100
@@ -278,6 +278,12 @@
   uint16_t m_rsrpRsrqSamplePeriod;
   uint16_t m_rsrpRsrqSampleCounter;
 
+  /**
+   * Trace information regarding PHY stats from DL Tx perspective
+   * PhyTrasmissionStatParameters  see lte-common.h
+   */
+  TracedCallback<PhyTransmissionStatParameters> m_ulPhyTransmission;
+
 };
 
 
--- a/src/lte/model/pf-ff-mac-scheduler.cc	Tue Dec 04 13:16:20 2012 +0100
+++ b/src/lte/model/pf-ff-mac-scheduler.cc	Thu Dec 13 11:45:59 2012 +0100
@@ -737,7 +737,7 @@
               std::map <uint16_t, DlHarqProcessesStatus_t>::iterator it = m_dlHarqProcessesStatus.find (rnti);
               if (it == m_dlHarqProcessesStatus.end ())
                 {
-                  NS_FATAL_ERROR ("No info found in HARQ buffer for UE " << m_dlInfoListBuffered.at (i).m_rnti);
+                  NS_LOG_ERROR ("No info find in HARQ buffer for UE (might change eNB) " << m_dlInfoListBuffered.at (i).m_rnti);
                 }
               (*it).second.at (harqId) = 0;
               std::map <uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu =  m_dlHarqProcessesRlcPduListBuffer.find (rnti);
@@ -1359,20 +1359,20 @@
               itProcId = m_ulHarqCurrentProcessId.find (rnti);
               if (itProcId == m_ulHarqCurrentProcessId.end ())
                 {
-                  NS_FATAL_ERROR ("No info find in HARQ buffer for UE " << rnti);
+                  NS_LOG_ERROR ("No info find in HARQ buffer for UE (might change eNB) " << rnti);
                 }
               uint8_t harqId = (uint8_t)((*itProcId).second - HARQ_PERIOD) % HARQ_PROC_NUM;
               NS_LOG_INFO (this << " UL-HARQ retx RNTI " << rnti << " harqId " << (uint16_t)harqId);
               std::map <uint16_t, UlHarqProcessesDciBuffer_t>::iterator itHarq = m_ulHarqProcessesDciBuffer.find (rnti);
               if (itHarq == m_ulHarqProcessesDciBuffer.end ())
                 {
-                  NS_FATAL_ERROR ("No info find in UL-HARQ buffer for UE " << rnti);
+                  NS_LOG_ERROR ("No info find in HARQ buffer for UE (might change eNB) " << rnti);
                 }
               UlDciListElement_s dci = (*itHarq).second.at (harqId);
               std::map <uint16_t, UlHarqProcessesStatus_t>::iterator itStat = m_ulHarqProcessesStatus.find (rnti);
               if (itStat == m_ulHarqProcessesStatus.end ())
                 {
-                  NS_FATAL_ERROR ("No info find in HARQ buffer for UE " << rnti);
+                  NS_LOG_ERROR ("No info find in HARQ buffer for UE (might change eNB) " << rnti);
                 }
               if ((*itStat).second.at (harqId) >= 3)
                 {
--- a/src/lte/wscript	Tue Dec 04 13:16:20 2012 +0100
+++ b/src/lte/wscript	Thu Dec 13 11:45:59 2012 +0100
@@ -43,6 +43,8 @@
         'helper/radio-bearer-stats-calculator.cc',
         'helper/radio-bearer-stats-connector.cc',
         'helper/mac-stats-calculator.cc',
+        'helper/phy-tx-stats-calculator.cc',
+        'helper/phy-rx-stats-calculator.cc',
         'helper/radio-environment-map-helper.cc',
         'helper/lte-hex-grid-enb-topology-helper.cc',
         'model/rem-spectrum-phy.cc',
@@ -162,6 +164,8 @@
         'helper/lte-stats-calculator.h',
         'helper/epc-helper.h',
         'helper/mac-stats-calculator.h',
+        'helper/phy-tx-stats-calculator.h',
+        'helper/phy-rx-stats-calculator.h',
         'helper/radio-bearer-stats-calculator.h',
         'helper/radio-bearer-stats-connector.h',
         'helper/radio-environment-map-helper.h',