HARQ first draft version: RR works, PF todo, LteMiErrorModel on-going

This commit is contained in:
mmiozzo
2012-10-08 17:18:22 +02:00
parent d046808859
commit c212d885fc
39 changed files with 1958 additions and 213 deletions

View File

@@ -568,12 +568,26 @@ from the index reported in [R1-081483]_.
The alternative model is based on the physical error model developed for this simulator and explained in the following subsections. This scheme is able to adapt the MCS selection to the actual PHY layer performance according to the specific CQI report. According to their definition, a CQI index is assigned when a single PDSCH TB with the modulation coding scheme and code rate correspondent to that CQI index in table 7.2.3-1 of [TS36213]_ can be received with an error probability less than 0.1. In case of wideband CQIs, the reference TB includes all the RBGs available in order to have a reference based on the whole available resources; while, for subband CQIs, the reference TB is sized as the RBGs.
.. only:: latex
.. raw:: latex
\clearpage
Round Robin (RR) Scheduler
--------------------------
The Round Robin (RR) scheduler is probably the simplest scheduler found in the literature. It works by dividing the
available resources among the active flows, i.e., those logical channels which have a non-empty RLC queue. If the number of RBGs is greater than the number of active flows, all the flows can be allocated in the same subframe. Otherwise, if the number of active flows is greater than the number of RBGs, not all the flows can be scheduled in a given subframe; then, in the next subframe the allocation will start from the last flow that was not allocated. The MCS to be adopted for each user is done according to the received wideband CQIs.
available resources among the active flows, i.e., those logical channels which have a non-empty RLC queue. If the number of RBGs is greater than the number of active flows, all the flows can be allocated in the same subframe. Otherwise, if the number of active flows is greater than the number of RBGs, not all the flows can be scheduled in a given subframe; then, in the next subframe the allocation will start from the last flow that was not allocated. The MCS to be adopted for each user is done according to the received wideband CQIs.
For what concern the HARQ, RR implements the non adaptive version, which implies that in allocating the retransmission RR uses a similar allocation configuration of the original block, which means maintaining the same RBGs and MCS. UEs that are allocated for HARQ retransmissions are not considered for the transmission of new data in case they have a transmission opportunity in the same TTI.
.. only:: latex
.. raw:: latex
\clearpage
Proportional Fair (PF) Scheduler
--------------------------------
@@ -643,6 +657,7 @@ where :math:`|\cdot|` indicates the cardinality of the set; finally,
\right)}{\tau}
*HARQ PF specifications: to be defined*.
Transport Blocks
----------------
@@ -1550,9 +1565,6 @@ Therefore the PHY layer implements the MIMO model as the gain perceived by the r
.. only:: latex
.. raw:: latex
@@ -1563,9 +1575,23 @@ Therefore the PHY layer implements the MIMO model as the gain perceived by the r
HARQ Model
----------
The HARQ scheme implemented is based on a incremental redundancy (IR) solutions combined with multiple stop-and-wait processes for enabling a continuous data flow. The core of the HARQ algorithm has been implemented within the respective schedulers class (i.e., ``RrFfMacScheduler`` and ``PfFfMacScheduler``), while the decodification part of the HARQ has been implemented in the ``LteSpectrumPhy`` class.
The HARQ scheme implemented is based on a incremental redundancy (IR) solutions combined with multiple stop-and-wait processes for enabling a continuous data flow. In detail, the solution adopted is the *soft combining hybrid IR Full incremental redundancy* (also called IR Type II), which implies that the retransmissions include only new information. The resource allocation algorithm of the HARQ has been implemented within the respective schedulers class (i.e., ``RrFfMacScheduler`` and ``PfFfMacScheduler``, refer to their respective sections for more info), while the decodification part of the HARQ has been implemented in the ``LteSpectrumPhy`` class which will be detailed in this section.
At the MAC layer, the HARQ entity residing in the scheduler is in charge of controlling the 8 HARQ processes for generating new packets and managing the retransmissions both for the DL and the UL. The scheduler collects the HARQ feedbacks from eNB and UE PHY layers (respectively UL and DL connection) by means of the FF API ``SchedUlTriggerReq`` and ``SchedUlTriggerReq`` in a FIFO buffer for maintaining the order of arrival. According to the HARQ feedbacks and the RLC buffers status, the scheduler generates a set of DCIs including both retransmissions of HARQ blocks received erroneous and new transmissions giving priority to the former. In allocating the retransmission we adopt this assumption, the scheduler uses a similar allocation configuration of the original block, which means maintaining the same number of RBGs and the same MCS. In case of the RGBs used for the original transmission are available they will be reused, otherwise the closest in frequency are selected in order to maintain similar channel conditions. It is to be noted that, the choice of maintaining in the retransmissions the same MCS of the original block is mandatory, otherwise the PHY would not be able of estimating the error probability of aggregated retransmissions. According to the standard, the UL retransmissions are synchronous and therefore are allocated 7 ms after the original transmission. While for the DL, they are asynchronous ans therefore can be allocated in a more flexible way starting from 7 ms. In detail, they receive highest priority for being transmitted after 7 ms; however, due to resource constraints they might be delayed a bit more. The HARQ processes behavior is depicted in Figure:ref:`fig-harq-processes-scheme`.
According to the standard, the UL retransmissions are synchronous and therefore are allocated 7 ms after the original transmission. On the other hand, for the DL, they are asynchronous ans therefore can be allocated in a more flexible way starting from 7 ms and it is a matter of the specific scheduler implementation. The HARQ processes behavior is depicted in Figure:ref:`fig-harq-processes-scheme`.
At the MAC layer, the HARQ entity residing in the scheduler is in charge of controlling the 8 HARQ processes for generating new packets and managing the retransmissions both for the DL and the UL. The scheduler collects the HARQ feedback from eNB and UE PHY layers (respectively UL and DL connection) by means of the FF API primitives ``SchedUlTriggerReq`` and ``SchedUlTriggerReq``, and stores them in a FIFO buffer for maintaining the order of arrival. According to the HARQ feedback and the RLC buffers status, the scheduler generates a set of DCIs including both retransmissions of HARQ blocks received erroneous and new transmissions, in general, giving priority to the former. On this matter, the scheduler has to take into consideration one constraint when allocating the resource for HARQ retransmissions, it must use the same modulation order of the first transmission attempt (i.e., QPSK for MCS :math:`\in [0..9]`, 16QAM for MCS :math:`\in [10..16]` and 64QAM for MCS :math:`\in [17..28]`). This restriction comes from the specification of the rate matcher in the 3GPP standard [TS36212]_, where for generating the different TBs of the redundancy version the algorithm fixes the modulation order.
The PHY Error Model model has been extended for considering IR HARQ according to [wimaxEmd]_, where the parameters for the AWGN curves mapping for MIESM mapping in case of retransmissions are given by:
.. math::
R_{eff} = \frac{X}{\sum\limits_{i=1}^q C_i}
M_{I eff} = \frac{\sum\limits_{i=1}^q C_i M_i}{\sum\limits_{i=1}^q C_i}
where :math:`X` is the number of original information bits, :math:`C_i` are number of coded bits, :math:`M_i` are the mutual informations per HARQ block received on the total number of :math:`q` retransmissions. Therefore, in order to be able to return the error probability with the error model implemented in the simulator evaluates the :math:`R_{eff}` and the :math:`MI_{I eff}` and return the value of error probability of the ECR of the same modulation with closest rate respect to the :math:`R_{eff}`. In order to consider the effect of HARQ retransmissions a new sets of curves have been integrated respect to the standard one used for the original MCS, especially for covering the cases when the most conservative MCS of a modulation is used. On this matter the curves for 1, 2 and 3 retransmissions have been evaluated for MCS 0, 10 and 17.
It is to be noted that, the first tranmission has been assumed as containing all the information bits to be coded; therefore :math:`X` is equal to the size of the first TB sent of a an HARQ process.
.. _fig-harq-processes-scheme:
@@ -1577,7 +1603,8 @@ At the MAC layer, the HARQ entity residing in the scheduler is in charge of cont
At the PHY layer the HARQ is involved in the evaluation of the error distribution process by controlling the information received per process bases and combining it with previous blocks, when necessary in retransmitted ones, by means of the MIESM mutual information scheme presented before. This part of HARQ devoted to manage the decodification of the HARQ blocks has been implemented in the ``LteSpectrumPhy`` class, where it has been also included the messaging algorithm in charge of communicating to the HARQ in the scheduler the result of the decodifications. These messages are encapsulated in the ``dlInfoListElement`` for DL and ``ulInfoListElement`` for UL and sent through the PUCCH and the PHICH respectively in an ideal error free way according to the assumptions in their implementation. A scketch of the iteration bewteen HARQ and LTE protocol stack in represented in Figure:ref:`fig-harq-architecture`.
This part of HARQ devoted to manage the decodification of the HARQ blocks has been implemented in the ``LteSpectrumPhy`` class, where it has been also included the messaging algorithm in charge of communicating to the HARQ in the scheduler the result of the decodifications. These messages are encapsulated in the ``dlInfoListElement`` for DL and ``ulInfoListElement`` for UL and sent through the PUCCH and the PHICH respectively in an ideal error free way according to the assumptions in their implementation. A sketch of the iteration between HARQ and LTE protocol stack in represented in Figure:ref:`fig-harq-architecture`.
.. _fig-harq-architecture:
@@ -1597,7 +1624,6 @@ At the PHY layer the HARQ is involved in the evaluation of the error distributio
-----------------------
Channel and Propagation
-----------------------

View File

@@ -308,6 +308,11 @@ LteHelper::InstallSingleEnbDevice (Ptr<Node> n)
Ptr<LteEnbPhy> phy = CreateObject<LteEnbPhy> (dlPhy, ulPhy);
Ptr<LteHarqPhy> harq = Create<LteHarqPhy> ();
dlPhy->SetHarqPhyModule (harq);
ulPhy->SetHarqPhyModule (harq);
phy->SetHarqPhyModule (harq);
Ptr<LteCtrlSinrChunkProcessor> pCtrl = Create<LteCtrlSinrChunkProcessor> (phy->GetObject<LtePhy> ());
ulPhy->AddCtrlSinrChunkProcessor (pCtrl); // for evaluating SRS UL-CQI
@@ -374,6 +379,7 @@ LteHelper::InstallSingleEnbDevice (Ptr<Node> n)
n->AddDevice (dev);
ulPhy->SetLtePhyRxDataEndOkCallback (MakeCallback (&LteEnbPhy::PhyPduReceived, phy));
ulPhy->SetLtePhyRxCtrlEndOkCallback (MakeCallback (&LteEnbPhy::ReceiveLteControlMessageList, phy));
ulPhy->SetLtePhyUlHarqFeedbackCallback (MakeCallback (&LteEnbPhy::ReceiveLteUlHarqFeedback, phy));
rrc->SetForwardUpCallback (MakeCallback (&LteEnbNetDevice::Receive, dev));
NS_LOG_LOGIC ("set the propagation model frequencies");
@@ -426,6 +432,11 @@ LteHelper::InstallSingleUeDevice (Ptr<Node> n)
Ptr<LteUePhy> phy = CreateObject<LteUePhy> (dlPhy, ulPhy);
Ptr<LteHarqPhy> harq = Create<LteHarqPhy> ();
dlPhy->SetHarqPhyModule (harq);
ulPhy->SetHarqPhyModule (harq);
phy->SetHarqPhyModule (harq);
Ptr<LteCtrlSinrChunkProcessor> pCtrl = Create<LteCtrlSinrChunkProcessor> (phy->GetObject<LtePhy> (), dlPhy);
dlPhy->AddCtrlSinrChunkProcessor (pCtrl);
@@ -474,6 +485,7 @@ LteHelper::InstallSingleUeDevice (Ptr<Node> n)
n->AddDevice (dev);
dlPhy->SetLtePhyRxDataEndOkCallback (MakeCallback (&LteUePhy::PhyPduReceived, phy));
dlPhy->SetLtePhyRxCtrlEndOkCallback (MakeCallback (&LteUePhy::ReceiveLteControlMessageList, phy));
dlPhy->SetLtePhyDlHarqFeedbackCallback (MakeCallback (&LteUePhy::ReceiveLteDlHarqFeedback, phy));
nas->SetForwardUpCallback (MakeCallback (&LteUeNetDevice::Receive, dev));

View File

@@ -27,6 +27,8 @@
// see 36.213 section 8
#define UL_PUSCH_TTIS_DELAY 4
#define HARQ_PERIOD 7
namespace ns3 {

View File

@@ -176,5 +176,34 @@ BsrLteControlMessage::GetBsr (void)
}
// ---------------------------------------------------------------------------
DlHarqFeedbackLteControlMessage::DlHarqFeedbackLteControlMessage (void)
{
SetMessageType (LteControlMessage::DL_HARQ);
}
DlHarqFeedbackLteControlMessage::~DlHarqFeedbackLteControlMessage (void)
{
}
void
DlHarqFeedbackLteControlMessage::SetDlHarqFeedback (DlInfoListElement_s m)
{
m_dlInfoListElement = m;
}
DlInfoListElement_s
DlHarqFeedbackLteControlMessage::GetDlHarqFeedback (void)
{
return m_dlInfoListElement;
}
} // namespace ns3

View File

@@ -48,7 +48,8 @@ public:
{
DL_DCI, UL_DCI, // Downlink/Uplink Data Control Indicator
DL_CQI, UL_CQI, // Downlink/Uplink Channel Quality Indicator
BSR // Buffer Status Report
BSR, // Buffer Status Report
DL_HARQ // UL HARQ feedback
};
LteControlMessage (void);
@@ -77,7 +78,7 @@ private:
// ----------------------------------------------------------------------------------------------------------
// -----------------------------------------------------------------------
#ifndef DL_DCI_LTE_CONTROL_MESSAGES_H
@@ -120,7 +121,7 @@ private:
#endif /* DL_DCI_LTE_CONTROL_MESSAGES_H */
// ----------------------------------------------------------------------------------------------------------
// ---------------------------------------------------------------------------
#ifndef UL_DCI_LTE_CONTROL_MESSAGES_H
@@ -164,7 +165,7 @@ private:
// ----------------------------------------------------------------------------------------------------------
// ---------------------------------------------------------------------------
@@ -210,7 +211,7 @@ private:
#endif /* DLCQI_LTE_CONTROL_MESSAGES_H */
// ----------------------------------------------------------------------------------------------------------
// ---------------------------------------------------------------------------
#ifndef BSR_LTE_CONTROL_MESSAGES_H
#define BSR_LTE_CONTROL_MESSAGES_H
@@ -253,5 +254,49 @@ private:
};
} // namespace ns3
#endif /* LTE_CONTROL_MESSAGES_H */
#endif /* BSR_LTE_CONTROL_MESSAGES_H */
// ---------------------------------------------------------------------------
#ifndef DL_HARQ_LTE_CONTROL_MESSAGES_H
#define DL_HARQ_LTE_CONTROL_MESSAGES_H
#include <ns3/object.h>
#include <ns3/ff-mac-common.h>
namespace ns3 {
/**
* \ingroup lte
* The downlink DlHarqFeedbackLteControlMessage defines the specific
* messages for transmitting the DL HARQ feedback through PUCCH
*/
class DlHarqFeedbackLteControlMessage : public LteControlMessage
{
public:
DlHarqFeedbackLteControlMessage (void);
virtual ~DlHarqFeedbackLteControlMessage (void);
/**
* \brief add a DL HARQ feedback record into the message.
* \param DlInfoListElement_s the dl HARQ feedback
*/
void SetDlHarqFeedback (DlInfoListElement_s m);
/**
* \brief Get DL HARQ informations
* \return DL HARQ message
*/
DlInfoListElement_s GetDlHarqFeedback (void);
private:
DlInfoListElement_s m_dlInfoListElement;
};
} // namespace ns3
#endif /* DL_HARQ_LTE_CONTROL_MESSAGES_H */

View File

@@ -234,6 +234,8 @@ public:
virtual void SubframeIndication (uint32_t frameNo, uint32_t subframeNo);
virtual void ReceiveLteControlMessage (Ptr<LteControlMessage> msg);
virtual void UlCqiReport (FfMacSchedSapProvider::SchedUlCqiInfoReqParameters ulcqi);
virtual void UlInfoListElementHarqFeeback (UlInfoListElement_s params);
virtual void DlInfoListElementHarqFeeback (DlInfoListElement_s params);
private:
LteEnbMac* m_mac;
@@ -268,6 +270,18 @@ EnbMacMemberLteEnbPhySapUser::UlCqiReport (FfMacSchedSapProvider::SchedUlCqiInfo
m_mac->DoUlCqiReport (ulcqi);
}
void
EnbMacMemberLteEnbPhySapUser::UlInfoListElementHarqFeeback (UlInfoListElement_s params)
{
m_mac->DoUlInfoListElementHarqFeeback (params);
}
void
EnbMacMemberLteEnbPhySapUser::DlInfoListElementHarqFeeback (DlInfoListElement_s params)
{
m_mac->DoDlInfoListElementHarqFeeback (params);
}
// //////////////////////////////////////
// generic LteEnbMac methods
@@ -312,6 +326,12 @@ void
LteEnbMac::DoDispose ()
{
NS_LOG_FUNCTION (this);
m_dlCqiReceived.clear ();
m_ulCqiReceived.clear ();
m_ulCeReceived.clear ();
m_dlInfoListReceived.clear ();
m_ulInfoListReceived.clear ();
m_miDlHarqProcessesPackets.clear ();
delete m_macSapProvider;
delete m_cmacSapProvider;
delete m_schedSapUser;
@@ -412,7 +432,6 @@ LteEnbMac::DoSubframeIndication (uint32_t frameNo, uint32_t subframeNo)
m_schedSapProvider->SchedDlCqiInfoReq (dlcqiInfoReq);
}
// Get downlink transmission opportunities
uint32_t dlSchedFrameNo = m_frameNo;
uint32_t dlSchedSubframeNo = m_subframeNo;
@@ -426,9 +445,18 @@ LteEnbMac::DoSubframeIndication (uint32_t frameNo, uint32_t subframeNo)
{
dlSchedSubframeNo = dlSchedSubframeNo + m_macChTtiDelay;
}
FfMacSchedSapProvider::SchedDlTriggerReqParameters params; // to be filled
params.m_sfnSf = ((0x3FF & dlSchedFrameNo) << 4) | (0xF & dlSchedSubframeNo);
m_schedSapProvider->SchedDlTriggerReq (params);
FfMacSchedSapProvider::SchedDlTriggerReqParameters dlparams;
dlparams.m_sfnSf = ((0x3FF & dlSchedFrameNo) << 4) | (0xF & dlSchedSubframeNo);
// Forward DL HARQ feebacks collected during last TTI
if (m_dlInfoListReceived.size () > 0)
{
dlparams.m_dlInfoList = m_dlInfoListReceived;
// empty local buffer
m_dlInfoListReceived.clear ();
}
m_schedSapProvider->SchedDlTriggerReq (dlparams);
// --- UPLINK ---
@@ -475,26 +503,34 @@ LteEnbMac::DoSubframeIndication (uint32_t frameNo, uint32_t subframeNo)
FfMacSchedSapProvider::SchedUlTriggerReqParameters ulparams;
ulparams.m_sfnSf = ((0x3FF & ulSchedFrameNo) << 4) | (0xF & ulSchedSubframeNo);
std::map <uint16_t,UlInfoListElement_s>::iterator it;
for (it = m_ulInfoListElements.begin (); it != m_ulInfoListElements.end (); it++)
// Forward DL HARQ feebacks collected during last TTI
if (m_ulInfoListReceived.size () > 0)
{
ulparams.m_ulInfoList.push_back ((*it).second);
ulparams.m_ulInfoList = m_ulInfoListReceived;
// empty local buffer
m_ulInfoListReceived.clear ();
}
// std::map <uint16_t,UlInfoListElement_s>::iterator it;
// for (it = m_ulInfoListElements.begin (); it != m_ulInfoListElements.end (); it++)
// {
// ulparams.m_ulInfoList.push_back ((*it).second);
// }
m_schedSapProvider->SchedUlTriggerReq (ulparams);
// reset UL info
for (it = m_ulInfoListElements.begin (); it != m_ulInfoListElements.end (); it++)
{
for (uint16_t i = 0; i < (*it).second.m_ulReception.size (); i++)
{
(*it).second.m_ulReception.at (i) = 0;
}
(*it).second.m_receptionStatus = UlInfoListElement_s::Ok;
(*it).second.m_tpc = 0;
}
// for (it = m_ulInfoListElements.begin (); it != m_ulInfoListElements.end (); it++)
// {
// for (uint16_t i = 0; i < (*it).second.m_ulReception.size (); i++)
// {
// (*it).second.m_ulReception.at (i) = 0;
// }
// (*it).second.m_receptionStatus = UlInfoListElement_s::Ok;
// (*it).second.m_tpc = 0;
// }
}
void
@@ -511,6 +547,11 @@ LteEnbMac::DoReceiveLteControlMessage (Ptr<LteControlMessage> msg)
Ptr<BsrLteControlMessage> bsr = DynamicCast<BsrLteControlMessage> (msg);
ReceiveBsrMessage (bsr->GetBsr ());
}
else if (msg->GetMessageType () == LteControlMessage::DL_HARQ)
{
Ptr<DlHarqFeedbackLteControlMessage> dlharq = DynamicCast<DlHarqFeedbackLteControlMessage> (msg);
DoDlInfoListElementHarqFeeback (dlharq->GetDlHarqFeedback ());
}
else
{
NS_LOG_LOGIC (this << " LteControlMessage not recognized");
@@ -525,7 +566,6 @@ LteEnbMac::DoUlCqiReport (FfMacSchedSapProvider::SchedUlCqiInfoReqParameters ulc
{
NS_LOG_DEBUG (this << " eNB rxed an PUSCH UL-CQI");
}
// TODO store UL-CQI to send them to scheduler
m_ulCqiReceived.push_back (ulcqi);
}
@@ -561,33 +601,33 @@ LteEnbMac::DoReceivePhyPdu (Ptr<Packet> p)
// store info of the packet received
std::map <uint16_t,UlInfoListElement_s>::iterator it;
// std::map <uint16_t,UlInfoListElement_s>::iterator it;
// u_int rnti = tag.GetRnti ();
// u_int lcid = tag.GetLcid ();
it = m_ulInfoListElements.find (tag.GetRnti ());
if (it == m_ulInfoListElements.end ())
{
// new RNTI
UlInfoListElement_s ulinfonew;
ulinfonew.m_rnti = tag.GetRnti ();
// always allocate full size of ulReception vector, initializing all elements to 0
ulinfonew.m_ulReception.assign (MAX_LC_LIST+1, 0);
// set the element for the current LCID
ulinfonew.m_ulReception.at (tag.GetLcid ()) = p->GetSize ();
ulinfonew.m_receptionStatus = UlInfoListElement_s::Ok;
ulinfonew.m_tpc = 0; // Tx power control not implemented at this stage
m_ulInfoListElements.insert (std::pair<uint16_t, UlInfoListElement_s > (tag.GetRnti (), ulinfonew));
}
else
{
// existing RNTI: we just set the value for the current
// LCID. Note that the corresponding element had already been
// allocated previously.
NS_ASSERT_MSG ((*it).second.m_ulReception.at (tag.GetLcid ()) == 0, "would overwrite previously written ulReception element");
(*it).second.m_ulReception.at (tag.GetLcid ()) = p->GetSize ();
(*it).second.m_receptionStatus = UlInfoListElement_s::Ok;
}
// it = m_ulInfoListElements.find (tag.GetRnti ());
// if (it == m_ulInfoListElements.end ())
// {
// // new RNTI
// UlInfoListElement_s ulinfonew;
// ulinfonew.m_rnti = tag.GetRnti ();
// // always allocate full size of ulReception vector, initializing all elements to 0
// ulinfonew.m_ulReception.assign (MAX_LC_LIST+1, 0);
// // set the element for the current LCID
// ulinfonew.m_ulReception.at (tag.GetLcid ()) = p->GetSize ();
// ulinfonew.m_receptionStatus = UlInfoListElement_s::Ok;
// ulinfonew.m_tpc = 0; // Tx power control not implemented at this stage
// m_ulInfoListElements.insert (std::pair<uint16_t, UlInfoListElement_s > (tag.GetRnti (), ulinfonew));
//
// }
// else
// {
// // existing RNTI: we just set the value for the current
// // LCID. Note that the corresponding element had already been
// // allocated previously.
// NS_ASSERT_MSG ((*it).second.m_ulReception.at (tag.GetLcid ()) == 0, "would overwrite previously written ulReception element");
// (*it).second.m_ulReception.at (tag.GetLcid ()) = p->GetSize ();
// (*it).second.m_receptionStatus = UlInfoListElement_s::Ok;
// }
@@ -629,6 +669,16 @@ LteEnbMac::DoAddUe (uint16_t rnti)
params.m_rnti = rnti;
params.m_transmissionMode = 0; // set to default value (SISO) for avoiding random initialization (valgrind error)
m_cschedSapProvider->CschedUeConfigReq (params);
// Create DL trasmission HARQ buffers
std::vector < Ptr<Packet> > dlHarqLayer0pkt;
dlHarqLayer0pkt.resize (8);
std::vector < Ptr<Packet> > dlHarqLayer1pkt;
dlHarqLayer1pkt.resize (8);
DlHarqProcessesBuffer_t buf;
buf.push_back (dlHarqLayer0pkt);
buf.push_back (dlHarqLayer1pkt);
m_miDlHarqProcessesPackets.insert (std::pair <uint16_t, DlHarqProcessesBuffer_t> (rnti, buf));
}
void
@@ -703,9 +753,12 @@ LteEnbMac::DoTransmitPdu (LteMacSapProvider::TransmitPduParameters params)
NS_LOG_FUNCTION (this);
LteRadioBearerTag tag (params.rnti, params.lcid, params.layer);
params.pdu->AddPacketTag (tag);
// Ptr<PacketBurst> pb = CreateObject<PacketBurst> ();
// pb->AddPacket (params.pdu);
// Store pkt in HARQ buffer
std::map <uint16_t, DlHarqProcessesBuffer_t>::iterator it = m_miDlHarqProcessesPackets.find (params.rnti);
NS_ASSERT (it!=m_miDlHarqProcessesPackets.end ());
NS_LOG_DEBUG (this << " LAYER " <<(uint16_t)tag.GetLayer () << " HARQ ID " << (uint16_t)params.harqProcessId);
// NS_ASSERT ((*it).second.at (params.layer).at (params.harqProcessId) == 0);
(*it).second.at (params.layer).at (params.harqProcessId) = params.pdu;//->Copy ();
m_enbPhySapProvider->SendMacPdu (params.pdu);
}
@@ -746,12 +799,30 @@ LteEnbMac::DoSchedDlConfigInd (FfMacSchedSapUser::SchedDlConfigIndParameters ind
{
for (uint16_t k = 0; k < ind.m_buildDataList.at (i).m_rlcPduList.at (j).size (); k++)
{
LteFlowId_t flow (ind.m_buildDataList.at (i).m_rnti,
ind.m_buildDataList.at (i).m_rlcPduList.at (j).at (k).m_logicalChannelIdentity);
it = m_rlcAttached.find (flow);
NS_ASSERT_MSG (it != m_rlcAttached.end (), "rnti=" << flow.m_rnti << " lcid=" << (uint32_t) flow.m_lcId);
NS_LOG_DEBUG (this << " rnti= " << flow.m_rnti << " lcid= " << (uint32_t) flow.m_lcId << " layer= " << k);
(*it).second->NotifyTxOpportunity (ind.m_buildDataList.at (i).m_rlcPduList.at (j).at (k).m_size, k);
// NS_ASSERT_MSG (ind.m_buildDataList.at (i).m_dci.m_ndi.size ()<=1, " NOT MIMO, layer " << k);
// NS_ASSERT_MSG (ind.m_buildDataList.size ()>i, " I " << i);
// NS_ASSERT_MSG (ind.m_buildDataList.at (i).m_dci.m_ndi.size ()>k, " k " << ind.m_buildDataList.at (i).m_rlcPduList.at (j).size ());
if (ind.m_buildDataList.at (i).m_dci.m_ndi.at (k) == 1)
{
// New Data -> retrieve it from RLC
LteFlowId_t flow (ind.m_buildDataList.at (i).m_rnti,
ind.m_buildDataList.at (i).m_rlcPduList.at (j).at (k).m_logicalChannelIdentity);
it = m_rlcAttached.find (flow);
NS_ASSERT_MSG (it != m_rlcAttached.end (), "rnti=" << flow.m_rnti << " lcid=" << (uint32_t) flow.m_lcId);
NS_LOG_DEBUG (this << " rnti= " << flow.m_rnti << " lcid= " << (uint32_t) flow.m_lcId << " layer= " << k);
(*it).second->NotifyTxOpportunity (ind.m_buildDataList.at (i).m_rlcPduList.at (j).at (k).m_size, k, ind.m_buildDataList.at (i).m_dci.m_harqProcess);
}
else
{
if (ind.m_buildDataList.at (i).m_dci.m_tbsSize.at (k)>0)
{
// HARQ retransmission -> retrieve TB from HARQ buffer
std::map <uint16_t, DlHarqProcessesBuffer_t>::iterator it = m_miDlHarqProcessesPackets.find (ind.m_buildDataList.at (i).m_rnti);
NS_ASSERT(it!=m_miDlHarqProcessesPackets.end());
Ptr<Packet> pkt = (*it).second.at (k).at ( ind.m_buildDataList.at (i).m_dci.m_harqProcess)->Copy ();
m_enbPhySapProvider->SendMacPdu (pkt);
}
}
}
}
// send the relative DCI
@@ -884,5 +955,39 @@ LteEnbMac::DoCschedCellConfigUpdateInd (FfMacCschedSapUser::CschedCellConfigUpda
NS_LOG_FUNCTION (this);
}
void
LteEnbMac::DoUlInfoListElementHarqFeeback (UlInfoListElement_s params)
{
NS_LOG_FUNCTION (this);
m_ulInfoListReceived.push_back (params);
}
void
LteEnbMac::DoDlInfoListElementHarqFeeback (DlInfoListElement_s params)
{
NS_LOG_FUNCTION (this);
// Update HARQ buffer
std::map <uint16_t, DlHarqProcessesBuffer_t>::iterator it = m_miDlHarqProcessesPackets.find (params.m_rnti);
NS_ASSERT (it!=m_miDlHarqProcessesPackets.end ());
for (uint8_t layer = 0; layer < params.m_harqStatus.size (); layer++)
{
if (params.m_harqStatus.at (layer)==DlInfoListElement_s::ACK)
{
// discard buffer
(*it).second.at (layer).at (params.m_harqProcessId) = 0;
NS_LOG_DEBUG (this << " HARQ-ACK UE " << params.m_rnti << " harqId " << (uint16_t)params.m_harqProcessId << " layer " << (uint16_t)layer);
}
else if (params.m_harqStatus.at (layer)==DlInfoListElement_s::NACK)
{
NS_LOG_DEBUG (this << " HARQ-NACK UE " << params.m_rnti << " harqId " << (uint16_t)params.m_harqProcessId << " layer " << (uint16_t)layer);
}
else
{
NS_FATAL_ERROR (" HARQ functionality not implemented");
}
}
m_dlInfoListReceived.push_back (params);
}
} // namespace ns3

View File

@@ -33,6 +33,7 @@
#include <ns3/lte-enb-phy-sap.h>
#include "ns3/traced-value.h"
#include "ns3/trace-source-accessor.h"
#include <ns3/packet.h>
namespace ns3 {
@@ -40,7 +41,7 @@ class DlCqiLteControlMessage;
class UlCqiLteControlMessage;
class PdcchMapLteControlMessage;
typedef std::vector <std::vector < Ptr<Packet> > > DlHarqProcessesBuffer_t;
/**
* This class implements the MAC layer of the eNodeB device
@@ -184,18 +185,23 @@ public:
void DoReceivePhyPdu (Ptr<Packet> p);
private:
private:
void DoUlInfoListElementHarqFeeback (UlInfoListElement_s params);
void DoDlInfoListElementHarqFeeback (DlInfoListElement_s params);
std::map <LteFlowId_t, LteMacSapUser*> m_rlcAttached;
std::vector <CqiListElement_s> m_dlCqiReceived; // DL-CQI received
std::vector <FfMacSchedSapProvider::SchedUlCqiInfoReqParameters> m_ulCqiReceived; // UL-CQI received
std::vector <MacCeListElement_s> m_ulCeReceived; // CE received (BSR up to now)
std::vector <DlInfoListElement_s> m_dlInfoListReceived; // DL HARQ feedback received
std::vector <UlInfoListElement_s> m_ulInfoListReceived; // UL HARQ feedback received
/*
* Map of UE's info element (see 4.3.12 of FF MAC Scheduler API)
*/
std::map <uint16_t,UlInfoListElement_s> m_ulInfoListElements;
// std::map <uint16_t,UlInfoListElement_s> m_ulInfoListElements;
@@ -229,6 +235,9 @@ private:
TracedCallback<uint32_t, uint32_t, uint16_t, uint8_t, uint16_t> m_ulScheduling;
uint8_t m_macChTtiDelay; // delay of MAC, PHY and channel in terms of TTIs
std::map <uint16_t, DlHarqProcessesBuffer_t> m_miDlHarqProcessesPackets; // Packet under trasmission of the DL HARQ process
};

View File

@@ -103,6 +103,21 @@ public:
*/
virtual void UlCqiReport (FfMacSchedSapProvider::SchedUlCqiInfoReqParameters ulcqi) = 0;
/**
* Notify the HARQ on the UL tranmission status
*
* \param params
*/
virtual void UlInfoListElementHarqFeeback (UlInfoListElement_s params) = 0;
/**
* Notify the HARQ on the DL tranmission status
*
* \param params
*/
virtual void DlInfoListElementHarqFeeback (DlInfoListElement_s params) = 0;
};

View File

@@ -155,6 +155,9 @@ LteEnbPhy::LteEnbPhy (Ptr<LteSpectrumPhy> dlPhy, Ptr<LteSpectrumPhy> ulPhy)
{
m_enbPhySapProvider = new EnbMemberLteEnbPhySapProvider (this);
m_enbCphySapProvider = new MemberLteEnbCphySapProvider<LteEnbPhy> (this);
m_harqPhyModule = Create <LteHarqPhy> ();
m_downlinkSpectrumPhy->SetHarqPhyModule (m_harqPhyModule);
m_uplinkSpectrumPhy->SetHarqPhyModule (m_harqPhyModule);
Simulator::ScheduleNow (&LteEnbPhy::StartFrame, this);
}
@@ -450,7 +453,7 @@ LteEnbPhy::StartSubFrame (void)
m_currentSrsOffset = (m_currentSrsOffset + 1) % m_srsPeriodicity;
}
NS_LOG_INFO ("-----sub frame " << m_nrSubFrames << "-----");
m_harqPhyModule->SubframeIndication (m_nrFrames, m_nrSubFrames);
// update info on TB to be received
std::list<UlDciLteControlMessage> uldcilist = DequeueUlDci ();
@@ -475,7 +478,15 @@ LteEnbPhy::StartSubFrame (void)
{
rbMap.push_back (i);
}
m_uplinkSpectrumPhy->AddExpectedTb ((*dciIt).GetDci ().m_rnti, (*dciIt).GetDci ().m_tbSize, (*dciIt).GetDci ().m_mcs, rbMap, 0 /* always SISO*/);
m_uplinkSpectrumPhy->AddExpectedTb ((*dciIt).GetDci ().m_rnti, (*dciIt).GetDci ().m_tbSize, (*dciIt).GetDci ().m_mcs, rbMap, 0 /* always SISO*/, 0 /* no HARQ proc id in UL*/, 0.0 /* MI TBD */, false /* UL*/);
if ((*dciIt).GetDci ().m_ndi==1)
{
NS_LOG_DEBUG (this << " RNTI " << (*dciIt).GetDci ().m_rnti << " NEW TB");
}
else
{
NS_LOG_DEBUG (this << " RNTI " << (*dciIt).GetDci ().m_rnti << " HARQ RETX");
}
m_ulRntiRxed.push_back ((*dciIt).GetDci ().m_rnti);
}
}
@@ -772,4 +783,18 @@ LteEnbPhy::DoSetSrsConfigurationIndex (uint16_t rnti, uint16_t srcCi)
}
void
LteEnbPhy::SetHarqPhyModule (Ptr<LteHarqPhy> harq)
{
m_harqPhyModule = harq;
}
void
LteEnbPhy::ReceiveLteUlHarqFeedback (UlInfoListElement_s mes)
{
NS_LOG_FUNCTION (this);
m_enbPhySapUser->UlInfoListElementHarqFeeback (mes);
}
};

View File

@@ -27,6 +27,7 @@
#include <ns3/lte-enb-phy-sap.h>
#include <ns3/lte-enb-cphy-sap.h>
#include <ns3/lte-phy.h>
#include <ns3/lte-harq-phy.h>
#include <map>
#include <set>
@@ -230,6 +231,13 @@ public:
virtual void GenerateCtrlCqiReport (const SpectrumValue& sinr);
virtual void GenerateDataCqiReport (const SpectrumValue& sinr);
/**
* \brief PhySpectrum generated a new UL HARQ feedback
*/
virtual void ReceiveLteUlHarqFeedback (UlInfoListElement_s mes);
void SetHarqPhyModule (Ptr<LteHarqPhy> harq);
private:
@@ -274,6 +282,8 @@ private:
std::map <uint16_t,uint16_t> m_srsCounter;
std::vector <uint16_t> m_srsUeOffset;
uint16_t m_currentSrsOffset;
Ptr<LteHarqPhy> m_harqPhyModule;
};

View File

@@ -414,9 +414,11 @@ LteEnbRrc::DoRecvConnectionRequest (uint64_t imsi)
ueRrc->DoRecvConnectionSetup (ueConfig);
// configure MAC (and scheduler)
FfMacCschedSapProvider::CschedUeConfigReqParameters req;
req.m_rnti = rnti;
req.m_transmissionMode = (*it).second->GetTransmissionMode ();
LteEnbCmacSapProvider::UeConfig params;
params.m_rnti = rnti;
params.m_transmissionMode = (*it).second->GetTransmissionMode ();
m_cmacSapProvider->UeUpdateConfigurationReq (params);
// configure PHY
m_cphySapProvider->SetTransmissionMode (rnti, (*it).second->GetTransmissionMode ());
@@ -745,6 +747,7 @@ LteEnbRrc::CreateUeInfo ()
m_lastAllocatedRnti = rnti;
Ptr<UeInfo> ueInfo = CreateObject<UeInfo> ();
ueInfo->SetSrsConfigurationIndex (GetNewSrsConfigurationIndex ());
ueInfo->SetTransmissionMode (m_defaultTransmissionMode);
m_ueMap.insert (std::pair<uint16_t, Ptr<UeInfo> > (rnti, ueInfo));
NS_LOG_DEBUG (this << " New UE RNTI " << rnti << " cellId " << m_cellId << " srs CI " << ueInfo->GetSrsConfigurationIndex ());
return rnti;

View File

@@ -0,0 +1,203 @@
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2012 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: Marco Miozzo <marco.miozzo@cttc.es>
*/
#include <ns3/lte-harq-phy.h>
#include <ns3/log.h>
#include <ns3/assert.h>
NS_LOG_COMPONENT_DEFINE ("LteHarqPhy");
namespace ns3 {
//NS_OBJECT_ENSURE_REGISTERED (LteHarqPhy);
LteHarqPhy::LteHarqPhy ()
{
// Create DL Decodification HARQ buffers
std::vector <HarqProcessInfoList_t> dlHarqLayer0;
dlHarqLayer0.resize (8);
std::vector <HarqProcessInfoList_t> dlHarqLayer1;
dlHarqLayer1.resize (8);
m_miDlHarqProcessesInfoMap.push_back (dlHarqLayer0);
m_miDlHarqProcessesInfoMap.push_back (dlHarqLayer1);
}
LteHarqPhy::~LteHarqPhy ()
{
m_miDlHarqProcessesInfoMap.clear ();
m_miUlHarqProcessesInfoMap.clear ();
}
void
LteHarqPhy::SubframeIndication (uint32_t frameNo, uint32_t subframeNo)
{
NS_LOG_FUNCTION (this);
// left shift UL HARQ buffers
std::map <uint16_t, std::vector <HarqProcessInfoList_t> >:: iterator it;
for (it = m_miUlHarqProcessesInfoMap.begin (); it != m_miUlHarqProcessesInfoMap.end (); it++)
{
(*it).second.erase ((*it).second.begin ());
HarqProcessInfoList_t h;
(*it).second.push_back (h);
}
}
double
LteHarqPhy::GetAccumulatedMiDl (uint8_t harqProcId, uint8_t layer)
{
NS_LOG_FUNCTION (this << (uint32_t)harqProcId << (uint16_t)layer);
HarqProcessInfoList_t list = m_miDlHarqProcessesInfoMap.at (layer).at (harqProcId);
double mi = 0.0;
for (uint8_t i = 0; i < list.size (); i++)
{
mi += list.at (i).m_mi;
}
return (mi);
}
HarqProcessInfoList_t
LteHarqPhy::GetHarqProcessInfoDl (uint8_t harqProcId, uint8_t layer)
{
NS_LOG_FUNCTION (this << (uint32_t)harqProcId << (uint16_t)layer);
return (m_miDlHarqProcessesInfoMap.at (layer).at (harqProcId));
}
double
LteHarqPhy::GetAccumulatedMiUl (uint16_t rnti)
{
NS_LOG_FUNCTION (this << rnti);
std::map <uint16_t, std::vector <HarqProcessInfoList_t> >::iterator it;
it = m_miUlHarqProcessesInfoMap.find (rnti);
NS_ASSERT_MSG (it!=m_miUlHarqProcessesInfoMap.end (), " Does not find MI for RNTI");
HarqProcessInfoList_t list = (*it).second.at (0);
double mi = 0.0;
for (uint8_t i = 0; i < list.size (); i++)
{
mi += list.at (i).m_mi;
}
return (mi);
}
HarqProcessInfoList_t
LteHarqPhy::GetHarqProcessInfoUl (uint16_t rnti, uint8_t harqProcId)
{
NS_LOG_FUNCTION (this << rnti << (uint16_t)harqProcId);
std::map <uint16_t, std::vector <HarqProcessInfoList_t> >::iterator it;
it = m_miUlHarqProcessesInfoMap.find (rnti);
if (it==m_miUlHarqProcessesInfoMap.end ())
{
// new entry
std::vector <HarqProcessInfoList_t> harqList;
harqList.resize (8);
m_miUlHarqProcessesInfoMap.insert (std::pair <uint16_t, std::vector <HarqProcessInfoList_t> > (rnti, harqList));
return (harqList.at (harqProcId));
}
else
{
return ((*it).second.at (harqProcId));
}
}
void
LteHarqPhy::UpdateDlHarqProcessStatus (uint8_t id, uint8_t layer, double mi, uint16_t infoBits, uint16_t codeBits)
{
NS_LOG_FUNCTION (this << (uint16_t) id << mi);
HarqProcessInfoElement_t el;
el.m_mi = mi;
el.m_infoBits = infoBits;
el.m_codeBits = codeBits;
m_miDlHarqProcessesInfoMap.at (layer).at (id).push_back (el);
}
void
LteHarqPhy::ResetDlHarqProcessStatus (uint8_t id)
{
NS_LOG_FUNCTION (this << (uint16_t) id);
for (uint8_t i = 0; i < m_miDlHarqProcessesInfoMap.size (); i++)
{
m_miDlHarqProcessesInfoMap.at (i).at (id).clear ();
}
}
void
LteHarqPhy::UpdateUlHarqProcessStatus (uint16_t rnti, double mi, uint16_t infoBits, uint16_t codeBits)
{
NS_LOG_FUNCTION (this << rnti << mi);
std::map <uint16_t, std::vector <HarqProcessInfoList_t> >::iterator it;
it = m_miUlHarqProcessesInfoMap.find (rnti);
if (it==m_miUlHarqProcessesInfoMap.end ())
{
// new entry
std::vector <HarqProcessInfoList_t> harqList;
harqList.resize (8);
HarqProcessInfoElement_t el;
el.m_mi = mi;
el.m_infoBits = infoBits;
el.m_codeBits = codeBits;
harqList.at (7).push_back (el);
m_miUlHarqProcessesInfoMap.insert (std::pair <uint16_t, std::vector <HarqProcessInfoList_t> > (rnti, harqList));
}
else
{
HarqProcessInfoElement_t el;
el.m_mi = mi;
el.m_infoBits = infoBits;
el.m_codeBits = codeBits;
(*it).second.at (7).push_back (el);
}
}
void
LteHarqPhy::ResetUlHarqProcessStatus (uint16_t rnti, uint8_t id)
{
NS_LOG_FUNCTION (this << rnti << (uint16_t)id);
std::map <uint16_t, std::vector <HarqProcessInfoList_t> >::iterator it;
it = m_miUlHarqProcessesInfoMap.find (rnti);
if (it==m_miUlHarqProcessesInfoMap.end ())
{
// new entry
std::vector <HarqProcessInfoList_t> harqList;
harqList.resize (8);
m_miUlHarqProcessesInfoMap.insert (std::pair <uint16_t, std::vector <HarqProcessInfoList_t> > (rnti, harqList));
}
else
{
(*it).second.at (id).clear ();
}
}
} // end namespace

View File

@@ -0,0 +1,143 @@
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2012 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: Marco Miozzo <marco.miozzo@cttc.es>
*/
#ifndef LTE_HARQ_PHY_MODULE_H
#define LTE_HARQ_PHY_MODULE_H
#include <ns3/log.h>
#include <ns3/assert.h>
#include <math.h>
#include <vector>
#include <map>
#include <ns3/simple-ref-count.h>
namespace ns3 {
struct HarqProcessInfoElement_t
{
double m_mi;
uint8_t m_rv;
uint16_t m_infoBits;
uint16_t m_codeBits;
};
typedef std::vector <HarqProcessInfoElement_t> HarqProcessInfoList_t;
/**
* \ingroup lte
* \brief The LteHarqPhy class implements the HARQ functionalities related to PHY layer
*(i.e., decodification buffers for incremental redundancy managment)
*
*/
class LteHarqPhy : public SimpleRefCount<LteHarqPhy>
{
public:
LteHarqPhy ();
~LteHarqPhy ();
void SubframeIndication (uint32_t frameNo, uint32_t subframeNo);
/**
* \brief Return the cumulated MI of the HARQ procId in case of retranmissions
* for DL (asynchronous)
* \param harqProcId the HARQ proc id
* \param layer layer no. (for MIMO spatial multiplexing)
* \return the MI accumulated
*/
double GetAccumulatedMiDl (uint8_t harqProcId, uint8_t layer);
/**
* \brief Return the info of the HARQ procId in case of retranmissions
* for DL (asynchronous)
* \param harqProcId the HARQ proc id
* \param layer layer no. (for MIMO spatail multiplexing)
* \return the vector of the info related to HARQ proc Id
*/
HarqProcessInfoList_t GetHarqProcessInfoDl (uint8_t harqProcId, uint8_t layer);
/**
* \brief Return the cumulated MI of the HARQ procId in case of retranmissions
* for UL (synchronous)
* \return the MI accumulated
*/
double GetAccumulatedMiUl (uint16_t rnti);
/**
* \brief Return the info of the HARQ procId in case of retranmissions
* for UL (asynchronous)
* \param harqProcId the HARQ proc id
* \param layer layer no. (for MIMO spatail multiplexing)
* \return the vector of the info related to HARQ proc Id
*/
HarqProcessInfoList_t GetHarqProcessInfoUl (uint16_t rnti, uint8_t harqProcId);
/**
* \brief Update the Info associated to the decodification of an HARQ process
* for DL (asynchronous)
* \param id the HARQ proc id
* \param layer layer no. (for MIMO spatail multiplexing)
* \param mi the new MI
*/
void UpdateDlHarqProcessStatus (uint8_t id, uint8_t layer, double mi, uint16_t infoBits, uint16_t codeBits);
/**
* \brief Reset the info associated to the decodification of an HARQ process
* for DL (asynchronous)
* \param id the HARQ proc id
*/
void ResetDlHarqProcessStatus(uint8_t id);
/**
* \brief Update the MI value associated to the decodification of an HARQ process
* for DL (asynchronous)
* \param rnti the RNTI of the transmitter
* \param mi the new MI
*/
void UpdateUlHarqProcessStatus (uint16_t rnti, double mi, uint16_t infoBits, uint16_t codeBits);
/**
* \brief Reset the info associated to the decodification of an HARQ process
* for DL (asynchronous)
* \param id the HARQ proc id
*/
void ResetUlHarqProcessStatus(uint16_t rnti, uint8_t id);
private:
std::vector <std::vector <HarqProcessInfoList_t> > m_miDlHarqProcessesInfoMap;
std::map <uint16_t, std::vector <HarqProcessInfoList_t> > m_miUlHarqProcessesInfoMap;
};
}
#endif /* LTE_HARQ_PHY_MODULE_H */

View File

@@ -48,6 +48,7 @@ public:
uint16_t rnti; /**< the C-RNTI identifying the UE */
uint8_t lcid; /**< the logical channel id corresponding to the sending RLC instance */
uint8_t layer; /**< the layer value that was passed by the MAC in the call to NotifyTxOpportunity that generated this PDU */
uint8_t harqProcessId; /**< the HARQ process id that was passed by the MAC in the call to NotifyTxOpportunity that generated this PDU */
};
/**
@@ -101,7 +102,7 @@ public:
* \param bytes the number of bytes to transmit
* \param layer the layer of transmission (MIMO)
*/
virtual void NotifyTxOpportunity (uint32_t bytes, uint8_t layer) = 0;
virtual void NotifyTxOpportunity (uint32_t bytes, uint8_t layer, uint8_t harqId) = 0;
/**
* Called by the MAC to notify the RLC that an HARQ process related

View File

@@ -492,6 +492,126 @@ LteMiErrorModel::GetTbError (const SpectrumValue& sinr, const std::vector<int>&
return errorRate;
}
TbStats_t
LteMiErrorModel::GetTbDecodificationStats (const SpectrumValue& sinr, const std::vector<int>& map, uint16_t size, uint8_t mcs, double mi)
{
NS_LOG_FUNCTION (sinr << &map << (uint32_t) size << (uint32_t) mcs);
double MI = Mib(sinr, map, mcs) + mi;
// estimate CB size (according to sec 5.1.2 of TS 36.212)
uint16_t Z = 6144; // max size of a codeblock (including CRC)
uint32_t B = size * 8;
// B = 1234;
uint32_t L = 0;
uint32_t C = 0; // no. of codeblocks
uint32_t Cplus = 0; // no. of codeblocks with size K+
uint32_t Kplus = 0; // no. of codeblocks with size K+
uint32_t Cminus = 0; // no. of codeblocks with size K+
uint32_t Kminus = 0; // no. of codeblocks with size K+
uint32_t B1 = 0;
uint32_t deltaK = 0;
if (B <= Z)
{
// only one codeblock
L = 0;
C = 1;
B1 = B;
}
else
{
L = 24;
C = ceil ((double)B / ((double)(Z-L)));
B1 = B + C * L;
}
// first segmentation: K+ = minimum K in table such that C * K >= B1
// uint i = 0;
// while (B1 > cbSizeTable[i] * C)
// {
// // NS_LOG_INFO (" K+ " << cbSizeTable[i] << " means " << cbSizeTable[i] * C);
// i++;
// }
// uint16_t KplusId = i;
// Kplus = cbSizeTable[i];
// implement a modified binary search
int min = 0;
int max = 187;
int mid = 0;
do
{
mid = (min+max) / 2;
if (B1 > cbSizeTable[mid]*C)
{
if (B1 < cbSizeTable[mid+1]*C)
{
break;
}
else
{
min = mid + 1;
}
}
else
{
if (B1 > cbSizeTable[mid-1]*C)
{
break;
}
else
{
max = mid - 1;
}
}
} while ((cbSizeTable[mid]*C != B1) && (min < max));
// adjust binary search to the largest integer value of K containing B1
if (B1 > cbSizeTable[mid]*C)
{
mid ++;
}
uint16_t KplusId = mid;
Kplus = cbSizeTable[mid];
if (C==1)
{
Cplus = 1;
Cminus = 0;
Kminus = 0;
}
else
{
// second segmentation size: K- = maximum K in table such that K < K+
Kminus = cbSizeTable[KplusId-1 > 0 ? KplusId-1 : 0];
deltaK = Kplus - Kminus;
Cminus = floor ((((double) C * Kplus) - (double)B1) / (double)deltaK);
Cplus = C - Cminus;
}
NS_LOG_INFO ("--------------------LteMiErrorModel: TB size of " << B << " needs of " << B1 << " bits reparted in " << C << " CBs as "<< Cplus << " block(s) of " << Kplus << " and " << Cminus << " of " << Kminus);
double errorRate = 1.0;
if (C!=1)
{
double cbler = MappingMiBler (MI, mcs, Kplus);
errorRate *= pow (1.0 - cbler, Cplus);
cbler = MappingMiBler (MI, mcs, Kminus);
errorRate *= pow (1.0 - cbler, Cminus);
errorRate = 1.0 - errorRate;
}
else
{
errorRate = MappingMiBler (MI, mcs, Kplus);
}
NS_LOG_LOGIC (" Error rate " << errorRate);
TbStats_t ret;
ret.error = errorRate;
ret.mi = MI;
return ret;
}
double
LteMiErrorModel::GetPcfichPdcchError (const SpectrumValue& sinr)
{
@@ -578,6 +698,148 @@ LteMiErrorModel::GetPcfichPdcchError (const SpectrumValue& sinr)
return (errorRate);
}
TbStats_t
LteMiErrorModel::GetTbDecodificationStats (const SpectrumValue& sinr, const std::vector<int>& map, uint16_t size, uint8_t mcs, HarqProcessInfoList_t miHistory)
{
NS_LOG_FUNCTION (sinr << &map << (uint32_t) size << (uint32_t) mcs);
double tbMi = Mib(sinr, map, mcs);
double MI = 0.0;
double Reff = 0.0;
if (miHistory.size ()>0)
{
// evaluate R_eff and MI_eff
uint16_t codeBitsSum = 0;
double miSum = 0.0;
for (uint16_t i = 0; i < miHistory.size (); i++)
{
codeBitsSum += miHistory.at (i).m_codeBits;
miSum += (miHistory.at (i).m_mi*miHistory.at (i).m_codeBits);
}
Reff = miHistory.at (0).m_infoBits / codeBitsSum; // information bits are the size of the first TB
MI = miSum / (double)codeBitsSum;
}
else
{
MI = tbMi;
}
NS_LOG_DEBUG (" MI " << MI << " Reff " << Reff);
// estimate CB size (according to sec 5.1.2 of TS 36.212)
uint16_t Z = 6144; // max size of a codeblock (including CRC)
uint32_t B = size * 8;
// B = 1234;
uint32_t L = 0;
uint32_t C = 0; // no. of codeblocks
uint32_t Cplus = 0; // no. of codeblocks with size K+
uint32_t Kplus = 0; // no. of codeblocks with size K+
uint32_t Cminus = 0; // no. of codeblocks with size K+
uint32_t Kminus = 0; // no. of codeblocks with size K+
uint32_t B1 = 0;
uint32_t deltaK = 0;
if (B <= Z)
{
// only one codeblock
L = 0;
C = 1;
B1 = B;
}
else
{
L = 24;
C = ceil ((double)B / ((double)(Z-L)));
B1 = B + C * L;
}
// first segmentation: K+ = minimum K in table such that C * K >= B1
// uint i = 0;
// while (B1 > cbSizeTable[i] * C)
// {
// // NS_LOG_INFO (" K+ " << cbSizeTable[i] << " means " << cbSizeTable[i] * C);
// i++;
// }
// uint16_t KplusId = i;
// Kplus = cbSizeTable[i];
// implement a modified binary search
int min = 0;
int max = 187;
int mid = 0;
do
{
mid = (min+max) / 2;
if (B1 > cbSizeTable[mid]*C)
{
if (B1 < cbSizeTable[mid+1]*C)
{
break;
}
else
{
min = mid + 1;
}
}
else
{
if (B1 > cbSizeTable[mid-1]*C)
{
break;
}
else
{
max = mid - 1;
}
}
} while ((cbSizeTable[mid]*C != B1) && (min < max));
// adjust binary search to the largest integer value of K containing B1
if (B1 > cbSizeTable[mid]*C)
{
mid ++;
}
uint16_t KplusId = mid;
Kplus = cbSizeTable[mid];
if (C==1)
{
Cplus = 1;
Cminus = 0;
Kminus = 0;
}
else
{
// second segmentation size: K- = maximum K in table such that K < K+
Kminus = cbSizeTable[KplusId-1 > 0 ? KplusId-1 : 0];
deltaK = Kplus - Kminus;
Cminus = floor ((((double) C * Kplus) - (double)B1) / (double)deltaK);
Cplus = C - Cminus;
}
NS_LOG_INFO ("--------------------LteMiErrorModel: TB size of " << B << " needs of " << B1 << " bits reparted in " << C << " CBs as "<< Cplus << " block(s) of " << Kplus << " and " << Cminus << " of " << Kminus);
double errorRate = 1.0;
if (C!=1)
{
double cbler = MappingMiBler (MI, mcs, Kplus);
errorRate *= pow (1.0 - cbler, Cplus);
cbler = MappingMiBler (MI, mcs, Kminus);
errorRate *= pow (1.0 - cbler, Cminus);
errorRate = 1.0 - errorRate;
}
else
{
errorRate = MappingMiBler (MI, mcs, Kplus);
}
NS_LOG_LOGIC (" Error rate " << errorRate);
TbStats_t ret;
ret.error = errorRate;
ret.mi = tbMi;
return ret;
}
} // namespace ns3

View File

@@ -38,6 +38,7 @@
#include <ns3/ptr.h>
#include <stdint.h>
#include <ns3/spectrum-value.h>
#include <ns3/lte-harq-phy.h>
@@ -48,6 +49,12 @@ namespace ns3 {
const uint16_t MI_MAP_QPSK_SIZE = 766;
const uint16_t MI_MAP_16QAM_SIZE = 843;
const uint16_t MI_MAP_64QAM_SIZE = 725;
struct TbStats_t
{
double error;
double mi;
};
@@ -85,6 +92,19 @@ public:
* \return the TB error rate
*/
static double GetTbError (const SpectrumValue& sinr, const std::vector<int>& map, uint16_t size, uint8_t mcs);
/**
* \brief run the error-model algorithm for the specified TB
* \param sinr the perceived sinrs in the whole bandwidth
* \param map the actives RBs for the TB
* \param size the size in bytes of the TB
* \param mcs the MCS of the TB
* \param cumulatedMi MI of past transmissions (in case of retx)
* \return the TB error rate
*/
static TbStats_t GetTbDecodificationStats (const SpectrumValue& sinr, const std::vector<int>& map, uint16_t size, uint8_t mcs, double cumulatedMi);
static TbStats_t GetTbDecodificationStats (const SpectrumValue& sinr, const std::vector<int>& map, uint16_t size, uint8_t mcs, HarqProcessInfoList_t miHistory);
/**
* \brief run the error-model algorithm for the specified PCFICH+PDCCH channels

View File

@@ -91,7 +91,7 @@ LteRadioBearerTag::SetLayer (uint8_t layer)
uint32_t
LteRadioBearerTag::GetSerializedSize (void) const
{
return 3;
return 4;
}
void
@@ -99,6 +99,7 @@ LteRadioBearerTag::Serialize (TagBuffer i) const
{
i.WriteU16 (m_rnti);
i.WriteU8 (m_lcid);
i.WriteU8 (m_layer);
}
void
@@ -106,6 +107,7 @@ LteRadioBearerTag::Deserialize (TagBuffer i)
{
m_rnti = (uint16_t) i.ReadU16 ();
m_lcid = (uint8_t) i.ReadU8 ();
m_layer = (uint8_t) i.ReadU8 ();
}
uint16_t
@@ -129,7 +131,7 @@ LteRadioBearerTag::GetLayer () const
void
LteRadioBearerTag::Print (std::ostream &os) const
{
os << "rnti=" << m_rnti << ", lcid=" << (uint16_t) m_lcid;
os << "rnti=" << m_rnti << ", lcid=" << (uint16_t) m_lcid << ", layer=" << (uint16_t)m_layer;
}
} // namespace ns3

View File

@@ -162,7 +162,7 @@ LteRlcAm::DoTransmitPdcpPdu (Ptr<Packet> p)
*/
void
LteRlcAm::DoNotifyTxOpportunity (uint32_t bytes, uint8_t layer)
LteRlcAm::DoNotifyTxOpportunity (uint32_t bytes, uint8_t layer, uint8_t harqId)
{
NS_LOG_FUNCTION (this << m_rnti << (uint32_t) m_lcid << bytes);
@@ -190,6 +190,8 @@ LteRlcAm::DoNotifyTxOpportunity (uint32_t bytes, uint8_t layer)
params.pdu = packet;
params.rnti = m_rnti;
params.lcid = m_lcid;
params.layer = layer;
params.harqProcessId = harqId;
m_macSapProvider->TransmitPdu (params);
return;
@@ -211,6 +213,8 @@ LteRlcAm::DoNotifyTxOpportunity (uint32_t bytes, uint8_t layer)
params.pdu = packet;
params.rnti = m_rnti;
params.lcid = m_lcid;
params.layer = layer;
params.harqProcessId = harqId;
m_macSapProvider->TransmitPdu (params);
return;
@@ -539,6 +543,7 @@ LteRlcAm::DoNotifyTxOpportunity (uint32_t bytes, uint8_t layer)
params.rnti = m_rnti;
params.lcid = m_lcid;
params.layer = layer;
params.harqProcessId = harqId;
m_macSapProvider->TransmitPdu (params);
}

View File

@@ -48,7 +48,7 @@ public:
/**
* MAC SAP
*/
virtual void DoNotifyTxOpportunity (uint32_t bytes, uint8_t layer);
virtual void DoNotifyTxOpportunity (uint32_t bytes, uint8_t layer, uint8_t harqId);
virtual void DoNotifyHarqDeliveryFailure ();
virtual void DoReceivePdu (Ptr<Packet> p);

View File

@@ -115,7 +115,7 @@ LteRlcUm::DoTransmitPdcpPdu (Ptr<Packet> p)
*/
void
LteRlcUm::DoNotifyTxOpportunity (uint32_t bytes, uint8_t layer)
LteRlcUm::DoNotifyTxOpportunity (uint32_t bytes, uint8_t layer, uint8_t harqId)
{
NS_LOG_FUNCTION (this << m_rnti << (uint32_t) m_lcid << bytes);
@@ -372,6 +372,7 @@ LteRlcUm::DoNotifyTxOpportunity (uint32_t bytes, uint8_t layer)
params.rnti = m_rnti;
params.lcid = m_lcid;
params.layer = layer;
params.harqProcessId = harqId;
m_macSapProvider->TransmitPdu (params);

View File

@@ -47,7 +47,7 @@ public:
/**
* MAC SAP
*/
virtual void DoNotifyTxOpportunity (uint32_t bytes, uint8_t layer);
virtual void DoNotifyTxOpportunity (uint32_t bytes, uint8_t layer, uint8_t harqId);
virtual void DoNotifyHarqDeliveryFailure ();
virtual void DoReceivePdu (Ptr<Packet> p);

View File

@@ -42,7 +42,7 @@ public:
LteRlcSpecificLteMacSapUser (LteRlc* rlc);
// Interface implemented from LteMacSapUser
virtual void NotifyTxOpportunity (uint32_t bytes, uint8_t layer);
virtual void NotifyTxOpportunity (uint32_t bytes, uint8_t layer, uint8_t harqId);
virtual void NotifyHarqDeliveryFailure ();
virtual void ReceivePdu (Ptr<Packet> p);
@@ -61,9 +61,9 @@ LteRlcSpecificLteMacSapUser::LteRlcSpecificLteMacSapUser ()
}
void
LteRlcSpecificLteMacSapUser::NotifyTxOpportunity (uint32_t bytes, uint8_t layer)
LteRlcSpecificLteMacSapUser::NotifyTxOpportunity (uint32_t bytes, uint8_t layer, uint8_t harqId)
{
m_rlc->DoNotifyTxOpportunity (bytes, layer);
m_rlc->DoNotifyTxOpportunity (bytes, layer, harqId);
}
void
@@ -210,7 +210,7 @@ LteRlcSm::DoReceivePdu (Ptr<Packet> p)
}
void
LteRlcSm::DoNotifyTxOpportunity (uint32_t bytes, uint8_t layer)
LteRlcSm::DoNotifyTxOpportunity (uint32_t bytes, uint8_t layer, uint8_t harqId)
{
NS_LOG_FUNCTION (this << bytes);
LteMacSapProvider::TransmitPduParameters params;
@@ -218,6 +218,7 @@ LteRlcSm::DoNotifyTxOpportunity (uint32_t bytes, uint8_t layer)
params.rnti = m_rnti;
params.lcid = m_lcid;
params.layer = layer;
params.harqProcessId = harqId;
// RLC Performance evaluation
RlcTag tag (Simulator::Now());

View File

@@ -111,7 +111,7 @@ protected:
LteRlcSapProvider* m_rlcSapProvider;
// Interface forwarded by LteMacSapUser
virtual void DoNotifyTxOpportunity (uint32_t bytes, uint8_t layer) = 0;
virtual void DoNotifyTxOpportunity (uint32_t bytes, uint8_t layer, uint8_t harqId) = 0;
virtual void DoNotifyHarqDeliveryFailure () = 0;
virtual void DoReceivePdu (Ptr<Packet> p) = 0;
@@ -150,7 +150,7 @@ public:
static TypeId GetTypeId (void);
virtual void DoTransmitPdcpPdu (Ptr<Packet> p);
virtual void DoNotifyTxOpportunity (uint32_t bytes, uint8_t layer);
virtual void DoNotifyTxOpportunity (uint32_t bytes, uint8_t layer, uint8_t harqId);
virtual void DoNotifyHarqDeliveryFailure ();
virtual void DoReceivePdu (Ptr<Packet> p);

View File

@@ -52,6 +52,38 @@ static const Time UL_SRS_DURATION = NanoSeconds (71429 -1);
// = 0.001 / 14 * 3 (ctrl fixed to 3 symbols) -1ns as margin to avoid overlapping simulator events
static const Time DL_CTRL_DURATION = NanoSeconds (214286 -1);
double EffectiveCodingRate[29] = {
0.08,
0.1,
0.11,
0.15,
0.19,
0.24,
0.3,
0.37,
0.44,
0.51,
0.3,
0.33,
0.37,
0.42,
0.48,
0.54,
0.6,
0.43,
0.45,
0.5,
0.55,
0.6,
0.65,
0.7,
0.75,
0.8,
0.85,
0.89,
0.92
};
@@ -81,7 +113,9 @@ NS_OBJECT_ENSURE_REGISTERED (LteSpectrumPhy);
LteSpectrumPhy::LteSpectrumPhy ()
: m_state (IDLE),
m_transmissionMode (0)
m_transmissionMode (0),
m_layersNum (1),
errors (0)
{
NS_LOG_FUNCTION (this);
m_random = CreateObject<UniformRandomVariable> ();
@@ -119,6 +153,8 @@ void LteSpectrumPhy::DoDispose ()
m_ltePhyRxDataEndOkCallback = MakeNullCallback< void, Ptr<Packet> > ();
m_ltePhyRxCtrlEndOkCallback = MakeNullCallback< void, std::list<Ptr<LteControlMessage> > > ();
m_ltePhyRxCtrlEndErrorCallback = MakeNullCallback< void > ();
m_ltePhyDlHarqFeedbackCallback = MakeNullCallback< void, DlInfoListElement_s > ();
m_ltePhyUlHarqFeedbackCallback = MakeNullCallback< void, UlInfoListElement_s > ();
SpectrumPhy::DoDispose ();
}
@@ -285,6 +321,20 @@ LteSpectrumPhy::SetLtePhyRxCtrlEndErrorCallback (LtePhyRxCtrlEndErrorCallback c)
m_ltePhyRxCtrlEndErrorCallback = c;
}
void
LteSpectrumPhy::SetLtePhyDlHarqFeedbackCallback (LtePhyDlHarqFeedbackCallback c)
{
NS_LOG_FUNCTION (this);
m_ltePhyDlHarqFeedbackCallback = c;
}
void
LteSpectrumPhy::SetLtePhyUlHarqFeedbackCallback (LtePhyUlHarqFeedbackCallback c)
{
NS_LOG_FUNCTION (this);
m_ltePhyUlHarqFeedbackCallback = c;
}
Ptr<AntennaModel>
LteSpectrumPhy::GetRxAntenna ()
@@ -314,6 +364,14 @@ LteSpectrumPhy::ChangeState (State newState)
}
void
LteSpectrumPhy::SetHarqPhyModule (Ptr<LteHarqPhy> harq)
{
m_harqPhyModule = harq;
}
bool
LteSpectrumPhy::StartTxDataFrame (Ptr<PacketBurst> pb, std::list<Ptr<LteControlMessage> > ctrlMsgList, Time duration)
@@ -717,22 +775,23 @@ LteSpectrumPhy::UpdateSinrPerceived (const SpectrumValue& sinr)
void
LteSpectrumPhy::AddExpectedTb (uint16_t rnti, uint16_t size, uint8_t mcs, std::vector<int> map, uint8_t layer)
LteSpectrumPhy::AddExpectedTb (uint16_t rnti, uint16_t size, uint8_t mcs, std::vector<int> map, uint8_t layer, uint8_t harqId, double miCumulated, bool downlink)
{
NS_LOG_LOGIC (this << " rnti: " << rnti << " size " << size << " mcs " << (uint16_t)mcs << " layer " << (uint8_t)layer);
NS_LOG_FUNCTION (this << " rnti: " << rnti << " size " << size << " mcs " << (uint16_t)mcs << " layer " << (uint16_t)layer << " MI " << miCumulated);
TbId_t tbId;
tbId.m_rnti = rnti;
tbId.m_layer = layer;
expectedTbs_t::iterator it;
it = m_expectedTbs.find (tbId);
if (it != m_expectedTbs.end ())
{
// migth be a TB of an unreceived packet (due to high progpalosses)
m_expectedTbs.erase (it);
}
{
// migth be a TB of an unreceived packet (due to high progpalosses)
m_expectedTbs.erase (it);
}
// insert new entry
tbInfo_t tbInfo = {size, mcs, map, false};
m_expectedTbs.insert (std::pair<TbId_t, tbInfo_t> (tbId,tbInfo ));
std::vector<uint8_t> rv;
tbInfo_t tbInfo = {size, mcs, map, harqId, miCumulated, downlink, false};
m_expectedTbs.insert (std::pair<TbId_t, tbInfo_t> (tbId,tbInfo));
}
@@ -760,9 +819,33 @@ LteSpectrumPhy::EndRxData ()
{
if (m_dataErrorModelEnabled)
{
double errorRate = LteMiErrorModel::GetTbError (m_sinrPerceived, (*itTb).second.rbBitmap, (*itTb).second.size, (*itTb).second.mcs);
(*itTb).second.corrupt = m_random->GetValue () > errorRate ? 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 << " ErrorRate " << errorRate << " corrupted " << (*itTb).second.corrupt);
// double errorRate = LteMiErrorModel::GetTbError (m_sinrPerceived, (*itTb).second.rbBitmap, (*itTb).second.size, (*itTb).second.mcs);
// retrieve HARQ info
HarqProcessInfoList_t harqInfoList;
uint16_t ulHarqId = 0; // TODO 0 means current HARQ porc under evaluation
if ((*itTb).second.downlink)
{
harqInfoList = m_harqPhyModule->GetHarqProcessInfoDl ((*itTb).second.harqProcessId, (*itTb).first.m_layer);
}
else
{
harqInfoList = m_harqPhyModule->GetHarqProcessInfoUl ((*itTb).first.m_rnti, ulHarqId);
}
// TbStats_t tbStats = LteMiErrorModel::GetTbDecodificationStats (m_sinrPerceived, (*itTb).second.rbBitmap, (*itTb).second.size, (*itTb).second.mcs, (*itTb).second.mi);
TbStats_t tbStats = LteMiErrorModel::GetTbDecodificationStats (m_sinrPerceived, (*itTb).second.rbBitmap, (*itTb).second.size, (*itTb).second.mcs, harqInfoList);
(*itTb).second.mi = tbStats.mi;
(*itTb).second.corrupt = m_random->GetValue () > tbStats.error ? false : true;
// DEBUG: force error for testing HARQ
if ((*itTb).second.downlink)
{
// if (((*itTb).second.harqProcessId == 0)&&(Simulator::Now ().GetNanoSeconds ()<=20000000))
if ((errors<1) && ( ((*itTb).first.m_rnti==1)||((*itTb).first.m_rnti==3)) )
{
(*itTb).second.corrupt = true;
errors++;
}
}
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 << " ErrorRate " << tbStats.error << " corrupted " << (*itTb).second.corrupt);
}
// for (uint16_t i = 0; i < (*itTb).second.rbBitmap.size (); i++)
@@ -771,6 +854,7 @@ LteSpectrumPhy::EndRxData ()
// }
itTb++;
}
std::map <uint16_t, DlInfoListElement_s> harqDlInfoMap;
for (std::list<Ptr<PacketBurst> >::const_iterator i = m_rxPacketBurstList.begin ();
i != m_rxPacketBurstList.end (); ++i)
{
@@ -783,7 +867,7 @@ LteSpectrumPhy::EndRxData ()
tbId.m_rnti = tag.GetRnti ();
tbId.m_layer = tag.GetLayer ();
itTb = m_expectedTbs.find (tbId);
NS_LOG_INFO (this << " Packet of " << tbId.m_rnti << " layer " << (uint8_t) tbId.m_layer);
NS_LOG_INFO (this << " Packet of " << tbId.m_rnti << " layer " << (uint16_t) tag.GetLayer ());
if (itTb!=m_expectedTbs.end ())
{
if (!(*itTb).second.corrupt)
@@ -800,10 +884,84 @@ LteSpectrumPhy::EndRxData ()
// TB received with errors
m_phyRxEndErrorTrace (*j);
}
// send HARQ feedback
if (!(*itTb).second.downlink)
{
UlInfoListElement_s harqUlInfo;
harqUlInfo.m_rnti = tbId.m_rnti;
if ((*itTb).second.corrupt)
{
harqUlInfo.m_receptionStatus = UlInfoListElement_s::NotOk;
NS_LOG_DEBUG (this << " RNTI " << tbId.m_rnti << " send UL-HARQ-NACK");
m_harqPhyModule->UpdateUlHarqProcessStatus (tbId.m_rnti, (*itTb).second.mi, (*itTb).second.size, EffectiveCodingRate [(*itTb).second.mcs] * (*itTb).second.size);
}
else
{
harqUlInfo.m_receptionStatus = UlInfoListElement_s::Ok;
NS_LOG_DEBUG (this << " RNTI " << tbId.m_rnti << " send UL-HARQ-ACK");
m_harqPhyModule->ResetUlHarqProcessStatus (tbId.m_rnti, (*itTb).second.harqProcessId);
}
if (!m_ltePhyUlHarqFeedbackCallback.IsNull ())
{
m_ltePhyUlHarqFeedbackCallback (harqUlInfo);
}
}
else
{
std::map <uint16_t, DlInfoListElement_s>::iterator itHarq = harqDlInfoMap.find (tbId.m_rnti);
if (itHarq==harqDlInfoMap.end ())
{
DlInfoListElement_s harqDlInfo;
harqDlInfo.m_harqStatus.resize (m_layersNum, DlInfoListElement_s::NACK);
harqDlInfo.m_rnti = tbId.m_rnti;
harqDlInfo.m_harqProcessId = (*itTb).second.harqProcessId;
if ((*itTb).second.corrupt)
{
harqDlInfo.m_harqStatus.at (tbId.m_layer) = DlInfoListElement_s::NACK;
NS_LOG_DEBUG (this << " RNTI " << tbId.m_rnti << " harqId " << (uint16_t)(*itTb).second.harqProcessId << " layer " <<(uint16_t)tbId.m_layer << " send DL-HARQ-NACK");
m_harqPhyModule->UpdateDlHarqProcessStatus ((*itTb).second.harqProcessId, tbId.m_layer, (*itTb).second.mi, (*itTb).second.size, EffectiveCodingRate [(*itTb).second.mcs] * (*itTb).second.size);
}
else
{
harqDlInfo.m_harqStatus.at (tbId.m_layer) = DlInfoListElement_s::ACK;
NS_LOG_DEBUG (this << " RNTI " << tbId.m_rnti << " harqId " << (uint16_t)(*itTb).second.harqProcessId << " layer " <<(uint16_t)tbId.m_layer << " size " << (*itTb).second.size << " send DL-HARQ-ACK");
m_harqPhyModule->ResetDlHarqProcessStatus ((*itTb).second.harqProcessId);
}
harqDlInfoMap.insert (std::pair <uint16_t, DlInfoListElement_s> (tbId.m_rnti, harqDlInfo));
}
else
{
if ((*itTb).second.corrupt)
{
(*itHarq).second.m_harqStatus.at (tbId.m_layer) = DlInfoListElement_s::NACK;
NS_LOG_DEBUG (this << " RNTI " << tbId.m_rnti << " harqId " << (uint16_t)(*itTb).second.harqProcessId << " layer " <<(uint16_t)tbId.m_layer << " size " << (*itHarq).second.m_harqStatus.size () << " send DL-HARQ-NACK");
m_harqPhyModule->UpdateDlHarqProcessStatus ((*itTb).second.harqProcessId, tbId.m_layer, (*itTb).second.mi, (*itTb).second.size, EffectiveCodingRate [(*itTb).second.mcs] * (*itTb).second.size);
}
else
{
NS_ASSERT_MSG (tbId.m_layer < (*itHarq).second.m_harqStatus.size (), " layer " << (uint16_t)tbId.m_layer);
(*itHarq).second.m_harqStatus.at (tbId.m_layer) = DlInfoListElement_s::ACK;
NS_LOG_DEBUG (this << " RNTI " << tbId.m_rnti << " harqId " << (uint16_t)(*itTb).second.harqProcessId << " layer " << (uint16_t)tbId.m_layer << " size " << (*itHarq).second.m_harqStatus.size () << " send DL-HARQ-ACK");
m_harqPhyModule->ResetDlHarqProcessStatus ((*itTb).second.harqProcessId);
}
}
} // end if ((*itTb).second.downlink) HARQ
}
}
}
// send DL HARQ feedback to LtePhy
std::map <uint16_t, DlInfoListElement_s>::iterator itHarq;
for (itHarq = harqDlInfoMap.begin (); itHarq != harqDlInfoMap.end (); itHarq++)
{
if (!m_ltePhyDlHarqFeedbackCallback.IsNull ())
{
m_ltePhyDlHarqFeedbackCallback ((*itHarq).second);
}
}
// forward control messages of this frame to LtePhy
if (!m_rxControlMessageList.empty ())
{
if (!m_ltePhyRxCtrlEndOkCallback.IsNull ())
@@ -851,6 +1009,7 @@ LteSpectrumPhy::EndRxDlCtrl ()
{
if (!m_ltePhyRxCtrlEndOkCallback.IsNull ())
{
NS_LOG_DEBUG (this << " PCFICH-PDCCH Rxed OK");
m_ltePhyRxCtrlEndOkCallback (m_rxControlMessageList);
}
}
@@ -858,6 +1017,7 @@ LteSpectrumPhy::EndRxDlCtrl ()
{
if (!m_ltePhyRxCtrlEndErrorCallback.IsNull ())
{
NS_LOG_DEBUG (this << " PCFICH-PDCCH Error");
m_ltePhyRxCtrlEndErrorCallback ();
}
}
@@ -899,6 +1059,7 @@ LteSpectrumPhy::SetTransmissionMode (uint8_t txMode)
NS_LOG_FUNCTION (this << (uint16_t) txMode);
NS_ASSERT_MSG (txMode < m_txModeGain.size (), "TransmissionMode not available: 1.." << m_txModeGain.size ());
m_transmissionMode = txMode;
m_layersNum = TransmissionModesLayers::TxMode2LayerNum (txMode);
}

View File

@@ -39,6 +39,8 @@
#include "ns3/random-variable-stream.h"
#include <map>
#include <ns3/ff-mac-common.h>
#include <ns3/lte-harq-phy.h>
#include <ns3/lte-common.h>
namespace ns3 {
@@ -61,6 +63,9 @@ struct tbInfo_t
uint16_t size;
uint8_t mcs;
std::vector<int> rbBitmap;
uint8_t harqProcessId;
double mi;
bool downlink;
bool corrupt;
};
@@ -113,6 +118,18 @@ typedef Callback< void, std::list<Ptr<LteControlMessage> > > LtePhyRxCtrlEndOkCa
*/
typedef Callback< void > LtePhyRxCtrlEndErrorCallback;
/**
* This method is used by the LteSpectrumPhy to notify the PHY about
* the status of a certain DL HARQ process
*/
typedef Callback< void, DlInfoListElement_s > LtePhyDlHarqFeedbackCallback;
/**
* This method is used by the LteSpectrumPhy to notify the PHY about
* the status of a certain UL HARQ process
*/
typedef Callback< void, UlInfoListElement_s > LtePhyUlHarqFeedbackCallback;
/**
@@ -154,6 +171,8 @@ public:
void StartRxData (Ptr<LteSpectrumSignalParametersDataFrame> params);
void StartRxCtrl (Ptr<SpectrumSignalParameters> params);
void SetHarqPhyModule (Ptr<LteHarqPhy> harq);
/**
* set the Power Spectral Density of outgoing signals in W/Hz.
*
@@ -253,6 +272,22 @@ public:
*/
void SetLtePhyRxCtrlEndErrorCallback (LtePhyRxCtrlEndErrorCallback c);
/**
* set the callback for the DL HARQ feedback as part of the
* interconnections betweenthe LteSpectrumPhy and the PHY
*
* @param c the callback
*/
void SetLtePhyDlHarqFeedbackCallback (LtePhyDlHarqFeedbackCallback c);
/**
* set the callback for the UL HARQ feedback as part of the
* interconnections betweenthe LteSpectrumPhy and the PHY
*
* @param c the callback
*/
void SetLtePhyUlHarqFeedbackCallback (LtePhyUlHarqFeedbackCallback c);
/**
* \brief Set the state of the phy layer
* \param newState the state
@@ -290,9 +325,13 @@ public:
* \param mcs the MCS of the TB
* \param map the map of RB(s) used
* \param layer the layer (in case of MIMO tx)
* \param harqId the id of the HARQ process (valid only for DL)
* \param miCumulated the MI cumulated (in case of HARQ retx)
* \param downlink true when the TB is for DL
*/
void AddExpectedTb (uint16_t rnti, uint16_t size, uint8_t mcs, std::vector<int> map, uint8_t layer);
void AddExpectedTb (uint16_t rnti, uint16_t size, uint8_t mcs, std::vector<int> map, uint8_t layer, uint8_t harqId, double miCumulated, bool downlink);
/**
*
*
@@ -375,8 +414,15 @@ private:
bool m_ctrlErrorModelEnabled; // when true (default) the phy error model is enabled for DL ctrl frame
uint8_t m_transmissionMode; // for UEs: store the transmission mode
uint8_t m_layersNum;
std::vector <double> m_txModeGain; // duplicate value of LteUePhy
Ptr<LteHarqPhy> m_harqPhyModule;
LtePhyDlHarqFeedbackCallback m_ltePhyDlHarqFeedbackCallback;
LtePhyUlHarqFeedbackCallback m_ltePhyUlHarqFeedbackCallback;
uint16_t errors; // DEBUG
};

View File

@@ -179,10 +179,12 @@ LteUeMac::GetTypeId (void)
LteUeMac::LteUeMac ()
: m_bsrPeriodicity (MilliSeconds (1)), // ideal behavior
m_bsrLast (MilliSeconds (0)),
m_freshUlBsr (false)
m_freshUlBsr (false),
m_harqProcessId (0)
{
NS_LOG_FUNCTION (this);
m_miUlHarqProcessesPacket.resize (HARQ_PERIOD);
m_macSapProvider = new UeMemberLteMacSapProvider (this);
m_cmacSapProvider = new UeMemberLteUeCmacSapProvider (this);
m_uePhySapUser = new UeMemberLteUePhySapUser (this);
@@ -198,6 +200,7 @@ void
LteUeMac::DoDispose ()
{
NS_LOG_FUNCTION (this);
m_miUlHarqProcessesPacket.clear ();
delete m_macSapProvider;
delete m_cmacSapProvider;
delete m_uePhySapUser;
@@ -244,11 +247,9 @@ LteUeMac::DoTransmitPdu (LteMacSapProvider::TransmitPduParameters params)
NS_ASSERT_MSG (m_rnti == params.rnti, "RNTI mismatch between RLC and MAC");
LteRadioBearerTag tag (params.rnti, params.lcid, 0 /* UE works in SISO mode*/);
params.pdu->AddPacketTag (tag);
// Ptr<PacketBurst> pb = CreateObject<PacketBurst> ();
// pb->AddPacket (params.pdu);
// store pdu in HARQ buffer
m_miUlHarqProcessesPacket.at (m_harqProcessId) = params.pdu;//->Copy ();
m_uePhySapProvider->SendMacPdu (params.pdu);
// Uplink not implemented yet, so we wait can wait for the PHY SAP
// to be defined before we implement the transmission method.
}
void
@@ -354,39 +355,51 @@ LteUeMac::DoReceiveLteControlMessage (Ptr<LteControlMessage> msg)
{
Ptr<UlDciLteControlMessage> msg2 = DynamicCast<UlDciLteControlMessage> (msg);
UlDciListElement_s dci = msg2->GetDci ();
std::map <uint8_t, uint64_t>::iterator itBsr;
NS_ASSERT_MSG (m_ulBsrReceived.size () <=4, " Too many LCs (max is 4)");
uint16_t activeLcs = 0;
for (itBsr = m_ulBsrReceived.begin (); itBsr != m_ulBsrReceived.end (); itBsr++)
if (dci.m_ndi==1)
{
if ((*itBsr).second > 0)
// New transmission -> retrieve data from RLC
std::map <uint8_t, uint64_t>::iterator itBsr;
NS_ASSERT_MSG (m_ulBsrReceived.size () <=4, " Too many LCs (max is 4)");
uint16_t activeLcs = 0;
for (itBsr = m_ulBsrReceived.begin (); itBsr != m_ulBsrReceived.end (); itBsr++)
{
activeLcs++;
}
}
if (activeLcs == 0)
{
NS_LOG_ERROR (this << " No active flows for this UL-DCI");
return;
}
std::map <uint8_t, LteMacSapUser*>::iterator it;
NS_LOG_FUNCTION (this << " UE: UL-CQI notified TxOpportunity of " << dci.m_tbSize);
for (it = m_macSapUserMap.begin (); it!=m_macSapUserMap.end (); it++)
{
itBsr = m_ulBsrReceived.find ((*it).first);
if (itBsr!=m_ulBsrReceived.end ())
{
NS_LOG_FUNCTION (this << "\t" << dci.m_tbSize / m_macSapUserMap.size () << " bytes to LC " << (uint16_t)(*it).first << " queue " << (*itBsr).second);
(*it).second->NotifyTxOpportunity (dci.m_tbSize / activeLcs, 0);
if ((*itBsr).second >= static_cast<uint64_t> (dci.m_tbSize / activeLcs))
if ((*itBsr).second > 0)
{
(*itBsr).second -= dci.m_tbSize / activeLcs;
}
else
{
(*itBsr).second = 0;
activeLcs++;
}
}
if (activeLcs == 0)
{
NS_LOG_ERROR (this << " No active flows for this UL-DCI");
return;
}
std::map <uint8_t, LteMacSapUser*>::iterator it;
NS_LOG_FUNCTION (this << " UE: UL-CQI notified TxOpportunity of " << dci.m_tbSize);
for (it = m_macSapUserMap.begin (); it!=m_macSapUserMap.end (); it++)
{
itBsr = m_ulBsrReceived.find ((*it).first);
if (itBsr!=m_ulBsrReceived.end ())
{
NS_LOG_FUNCTION (this << "\t" << dci.m_tbSize / m_macSapUserMap.size () << " bytes to LC " << (uint16_t)(*it).first << " queue " << (*itBsr).second);
(*it).second->NotifyTxOpportunity (dci.m_tbSize / activeLcs, 0, 0); // layer and HARQ ID are not used in UL
if ((*itBsr).second >= static_cast<uint64_t> (dci.m_tbSize / activeLcs))
{
(*itBsr).second -= dci.m_tbSize / activeLcs;
}
else
{
(*itBsr).second = 0;
}
}
}
}
else
{
// HARQ retransmission -> retrieve data from HARQ buffer
NS_LOG_DEBUG (this << " UE MAC RETX HARQ " << (uint16_t)m_harqProcessId);
Ptr<Packet> pkt = m_miUlHarqProcessesPacket.at (m_harqProcessId);
m_uePhySapProvider->SendMacPdu (pkt);
}
}
@@ -406,6 +419,7 @@ LteUeMac::DoSubframeIndication (uint32_t frameNo, uint32_t subframeNo)
SendReportBufferStatus ();
m_bsrLast = Simulator::Now ();
m_freshUlBsr = false;
m_harqProcessId = (m_harqProcessId + 1) % HARQ_PERIOD;
}
}

View File

@@ -30,7 +30,8 @@
#include <ns3/lte-ue-cmac-sap.h>
#include <ns3/lte-ue-phy-sap.h>
#include <ns3/nstime.h>
#include <vector>
#include <ns3/packet.h>
namespace ns3 {
@@ -107,6 +108,9 @@ private:
bool m_freshUlBsr; // true when a BSR has been received in the last TTI
uint8_t m_harqProcessId;
std::vector < Ptr<Packet> > m_miUlHarqProcessesPacket; // Packets under trasmission of the UL HARQ processes
uint16_t m_rnti;

View File

@@ -539,7 +539,7 @@ LteUePhy::ReceiveLteControlMessageList (std::list<Ptr<LteControlMessage> > msgLi
for (int k = 0; k < GetRbgSize (); k++)
{
dlRb.push_back ((i * GetRbgSize ()) + k);
//NS_LOG_DEBUG(this << "DL-DCI allocated PRB " << (i*GetRbgSize()) + k);
// NS_LOG_DEBUG(this << " RNTI " << m_rnti << " RBG " << i << " DL-DCI allocated PRB " << (i*GetRbgSize()) + k);
}
}
mask = (mask << 1);
@@ -549,7 +549,13 @@ LteUePhy::ReceiveLteControlMessageList (std::list<Ptr<LteControlMessage> > msgLi
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_tbsSize.at (i), dci.m_mcs.at (i), dlRb, i);
double miCumulated = 0.0;
if (dci.m_ndi.at (i)!=0)
{
// TODO : retrieve MI info on retransmissions
miCumulated = 0.0;
}
m_downlinkSpectrumPhy->AddExpectedTb (dci.m_rnti, dci.m_tbsSize.at (i), dci.m_mcs.at (i), dlRb, i, dci.m_harqProcess, miCumulated, true /* DL */);
}
SetSubChannelsForReception (dlRb);
@@ -633,11 +639,11 @@ LteUePhy::SubframeIndication (uint32_t frameNo, uint32_t subframeNo)
std::list<Ptr<LteControlMessage> > ctrlMsg = GetControlMessages ();
// send packets in queue
NS_LOG_LOGIC (this << " UE - start TX PUSCH + PUCCH");
// send the current burts of packets
Ptr<PacketBurst> pb = GetPacketBurst ();
if (pb)
{
NS_LOG_LOGIC (this << " UE - start TX PUSCH + PUCCH");
m_uplinkSpectrumPhy->StartTxDataFrame (pb, ctrlMsg, UL_DATA_DURATION);
}
else
@@ -835,4 +841,22 @@ LteUePhy::UpdateNoisePsd ()
}
void
LteUePhy::ReceiveLteDlHarqFeedback (DlInfoListElement_s m)
{
NS_LOG_FUNCTION (this);
// generate feedback to eNB and send it through ideal PUCCH
Ptr<DlHarqFeedbackLteControlMessage> msg = Create<DlHarqFeedbackLteControlMessage> ();
msg->SetDlHarqFeedback (m);
SetControlMessages (msg);
}
void
LteUePhy::SetHarqPhyModule (Ptr<LteHarqPhy> harq)
{
m_harqPhyModule = harq;
}
} // namespace ns3

View File

@@ -39,6 +39,7 @@ namespace ns3 {
class PacketBurst;
class LteNetDevice;
class LteEnbPhy;
class LteHarqPhy;
/**
* \ingroup lte
@@ -196,7 +197,17 @@ public:
*/
void SendSrs ();
/**
* \brief PhySpectrum generated a new DL HARQ feedback
*/
virtual void ReceiveLteDlHarqFeedback (DlInfoListElement_s mes);
/**
* \brief Set the HARQ PHY module
*/
void SetHarqPhyModule (Ptr<LteHarqPhy> harq);
private:
@@ -254,6 +265,8 @@ private:
uint16_t m_srsPeriodicity;
uint16_t m_srsCounter;
Ptr<LteHarqPhy> m_harqPhyModule;
};

View File

@@ -29,6 +29,7 @@
#include <ns3/lte-amc.h>
#include <ns3/pf-ff-mac-scheduler.h>
#include <ns3/lte-vendor-specific-parameters.h>
#include <ns3/boolean.h>
NS_LOG_COMPONENT_DEFINE ("PfFfMacScheduler");
@@ -247,6 +248,11 @@ PfFfMacScheduler::GetTypeId (void)
UintegerValue (1000),
MakeUintegerAccessor (&PfFfMacScheduler::m_cqiTimersThreshold),
MakeUintegerChecker<uint32_t> ())
.AddAttribute ("HarqEnabled",
"Activate/Deactivate the HARQ [by default is active].",
BooleanValue (true),
MakeBooleanAccessor (&PfFfMacScheduler::m_harqOn),
MakeBooleanChecker ())
;
return tid;
}
@@ -564,7 +570,6 @@ PfFfMacScheduler::DoSchedDlTriggerReq (const struct FfMacSchedSapProvider::Sched
newEl.m_rnti = (*itMap).first;
// create the DlDciListElement_s
DlDciListElement_s newDci;
std::vector <struct RlcPduListElement_s> newRlcPduLe;
newDci.m_rnti = (*itMap).first;
uint16_t lcActives = LcActivePerFlow ((*itMap).first);
@@ -649,6 +654,7 @@ PfFfMacScheduler::DoSchedDlTriggerReq (const struct FfMacSchedSapProvider::Sched
|| ((*itBufReq).second.m_rlcRetransmissionQueueSize > 0)
|| ((*itBufReq).second.m_rlcStatusPduSize > 0) ))
{
std::vector <struct RlcPduListElement_s> newRlcPduLe;
for (uint8_t j = 0; j < nLayer; j++)
{
RlcPduListElement_s newRlcEl;
@@ -658,21 +664,24 @@ PfFfMacScheduler::DoSchedDlTriggerReq (const struct FfMacSchedSapProvider::Sched
newRlcPduLe.push_back (newRlcEl);
UpdateDlRlcBufferInfo (newDci.m_rnti, newRlcEl.m_logicalChannelIdentity, newRlcEl.m_size);
}
newEl.m_rlcPduList.push_back (newRlcPduLe);
}
if ((*itBufReq).first.m_rnti > (*itMap).first)
{
break;
}
}
newDci.m_ndi.push_back (1); // TBD (new data indicator)
newDci.m_rv.push_back (0); // TBD (redundancy version)
for (uint8_t j = 0; j < nLayer; j++)
{
newDci.m_ndi.push_back (1); // TBD (new data indicator)
newDci.m_rv.push_back (0); // TBD (redundancy version)
}
newDci.m_harqProcess = 0; // NO HARQ
newEl.m_dci = newDci;
// ...more parameters -> ingored in this version
newEl.m_rlcPduList.push_back (newRlcPduLe);
ret.m_buildDataList.push_back (newEl);
// update UE stats
std::map <uint16_t, pfsFlowPerf_t>::iterator it;
it = m_flowStatsDl.find ((*itMap).first);

View File

@@ -218,6 +218,13 @@ private:
uint32_t m_cqiTimersThreshold; // # of TTIs for which a CQI canbe considered valid
std::map <uint16_t,uint8_t> m_uesTxMode; // txMode of the UEs
// HARQ attributes
/**
* m_harqOn when false inhibit te HARQ mechanisms (by default active)
*/
bool m_harqOn;
};
} // namespace ns3

View File

@@ -24,12 +24,14 @@
#include <ns3/log.h>
#include <ns3/pointer.h>
#include <set>
#include <ns3/lte-amc.h>
#include <ns3/rr-ff-mac-scheduler.h>
#include <ns3/simulator.h>
#include <ns3/lte-common.h>
#include <ns3/lte-vendor-specific-parameters.h>
#include <ns3/boolean.h>
NS_LOG_COMPONENT_DEFINE ("RrFfMacScheduler");
@@ -234,6 +236,12 @@ void
RrFfMacScheduler::DoDispose ()
{
NS_LOG_FUNCTION (this);
m_dlHarqProcessesDciBuffer.clear ();
m_dlHarqProcessesRlcPduListBuffer.clear ();
m_dlInfoListBuffered.clear ();
m_ulHarqCurrentProcessId.clear ();
m_ulHarqProcessesStatus.clear ();
m_ulHarqProcessesDciBuffer.clear ();
delete m_cschedSapProvider;
delete m_schedSapProvider;
}
@@ -249,6 +257,11 @@ RrFfMacScheduler::GetTypeId (void)
UintegerValue (1000),
MakeUintegerAccessor (&RrFfMacScheduler::m_cqiTimersThreshold),
MakeUintegerChecker<uint32_t> ())
.AddAttribute ("HarqEnabled",
"Activate/Deactivate the HARQ [by default is active].",
BooleanValue (true),
MakeBooleanAccessor (&RrFfMacScheduler::m_harqOn),
MakeBooleanChecker ())
;
return tid;
}
@@ -299,6 +312,26 @@ RrFfMacScheduler::DoCschedUeConfigReq (const struct FfMacCschedSapProvider::Csch
if (it==m_uesTxMode.end ())
{
m_uesTxMode.insert (std::pair <uint16_t, double> (params.m_rnti, params.m_transmissionMode));
// generate HARQ buffers
m_dlHarqCurrentProcessId.insert (std::pair <uint16_t,uint8_t > (params.m_rnti, 0));
DlHarqProcessesStatus_t dlHarqPrcStatus;
dlHarqPrcStatus.resize (8,0);
m_dlHarqProcessesStatus.insert (std::pair <uint16_t, DlHarqProcessesStatus_t> (params.m_rnti, dlHarqPrcStatus));
DlHarqProcessesDciBuffer_t dlHarqdci;
dlHarqdci.resize (8);
m_dlHarqProcessesDciBuffer.insert (std::pair <uint16_t, DlHarqProcessesDciBuffer_t> (params.m_rnti, dlHarqdci));
DlHarqRlcPduListBuffer_t dlHarqRlcPdu;
dlHarqRlcPdu.resize (2);
dlHarqRlcPdu.at (0).resize (8);
dlHarqRlcPdu.at (1).resize (8);
m_dlHarqProcessesRlcPduListBuffer.insert (std::pair <uint16_t, DlHarqRlcPduListBuffer_t> (params.m_rnti, dlHarqRlcPdu));
m_ulHarqCurrentProcessId.insert (std::pair <uint16_t,uint8_t > (params.m_rnti, 0));
UlHarqProcessesStatus_t ulHarqPrcStatus;
ulHarqPrcStatus.resize (8,0);
m_ulHarqProcessesStatus.insert (std::pair <uint16_t, UlHarqProcessesStatus_t> (params.m_rnti, ulHarqPrcStatus));
UlHarqProcessesDciBuffer_t ulHarqdci;
ulHarqdci.resize (8);
m_ulHarqProcessesDciBuffer.insert (std::pair <uint16_t, UlHarqProcessesDciBuffer_t> (params.m_rnti, ulHarqdci));
}
else
{
@@ -402,6 +435,41 @@ RrFfMacScheduler::SortRlcBufferReq (FfMacSchedSapProvider::SchedDlRlcBufferReqPa
}
uint8_t
RrFfMacScheduler::UpdateHarqProcessId (uint16_t rnti)
{
NS_LOG_FUNCTION (this << rnti);
std::map <uint16_t, uint8_t>::iterator it = m_dlHarqCurrentProcessId.find (rnti);
if (it==m_dlHarqCurrentProcessId.end ())
{
NS_FATAL_ERROR ("No Process Id found for this RNTI " << rnti);
}
std::map <uint16_t, DlHarqProcessesStatus_t>::iterator itStat = m_dlHarqProcessesStatus.find (rnti);
if (itStat==m_dlHarqProcessesStatus.end ())
{
NS_FATAL_ERROR ("No Process Id Statusfound for this RNTI " << rnti);
}
uint8_t i = (*it).second;
do
{
i = (i + 1) % HARQ_PROC_NUM;
// NS_LOG_DEBUG (this << " check i " << (uint16_t)i << " stat " << (uint16_t)(*itStat).second.at (i));
} while ( ((*itStat).second.at (i)!=0)&&(i!=(*it).second));
if ((*itStat).second.at (i)==0)
{
(*it).second = i;
(*itStat).second.at (i) = 1;
}
else
{
return (9); // return a not valid harq proc id
}
return ((*it).second);
}
void
RrFfMacScheduler::DoSchedDlTriggerReq (const struct FfMacSchedSapProvider::SchedDlTriggerReqParameters& params)
{
@@ -409,6 +477,255 @@ RrFfMacScheduler::DoSchedDlTriggerReq (const struct FfMacSchedSapProvider::Sched
// API generated by RLC for triggering the scheduling of a DL subframe
RefreshDlCqiMaps ();
int rbgSize = GetRbgSize (m_cschedCellConfig.m_dlBandwidth);
int rbgNum = m_cschedCellConfig.m_dlBandwidth / rbgSize;
FfMacSchedSapUser::SchedDlConfigIndParameters ret;
// Generate RBGs map
std::vector <bool> rbgMap;
uint16_t rbgAllocatedNum = 0;
std::set <uint16_t> rntiAllocated;
rbgMap.resize (m_cschedCellConfig.m_dlBandwidth/rbgSize, false);
// Process DL HARQ feedback
// retrieve past HARQ retx buffered
if (m_dlInfoListBuffered.size ()>0)
{
if (params.m_dlInfoList.size ()>0)
{
NS_LOG_DEBUG (this << " RECEIVED DL-HARQ");
m_dlInfoListBuffered.insert (m_dlInfoListBuffered.end (), params.m_dlInfoList.begin (), params.m_dlInfoList.end ());
}
}
else
{
if (params.m_dlInfoList.size ()>0)
{
m_dlInfoListBuffered = params.m_dlInfoList;
}
}
if (m_harqOn == false)
{
// Ignore HARQ feedbacks
m_dlInfoListBuffered.clear ();
NS_LOG_DEBUG (this << " HARQ OFF");
}
std::vector <struct DlInfoListElement_s> dlInfoListUntxed;
for (uint8_t i = 0; i < m_dlInfoListBuffered.size (); i++)
{
uint8_t nLayers = m_dlInfoListBuffered.at (i).m_harqStatus.size ();
std::vector <bool> retx;
NS_LOG_DEBUG (this << " Processing DLHARQ-FEEDBACK");
if (nLayers == 1)
{
retx.push_back (m_dlInfoListBuffered.at (i).m_harqStatus.at (0) == DlInfoListElement_s::NACK);
retx.push_back (false);
}
else
{
retx.push_back (m_dlInfoListBuffered.at (i).m_harqStatus.at (0) == DlInfoListElement_s::NACK);
retx.push_back (m_dlInfoListBuffered.at (i).m_harqStatus.at (1) == DlInfoListElement_s::NACK);
}
if (retx.at (0) || retx.at (1))
{
// retrieve HARQ process information
uint16_t rnti = m_dlInfoListBuffered.at (i).m_rnti;
uint8_t harqId = m_dlInfoListBuffered.at (i).m_harqProcessId;
NS_LOG_DEBUG (this << " HARQ retx RNTI " << rnti << " harqId " << (uint16_t)harqId);
std::map <uint16_t, DlHarqProcessesDciBuffer_t>::iterator itHarq = m_dlHarqProcessesDciBuffer.find (rnti);
if (itHarq==m_dlHarqProcessesDciBuffer.end ())
{
NS_FATAL_ERROR ("No info find in HARQ buffer for UE " << rnti);
}
DlDciListElement_s dci = (*itHarq).second.at (harqId);
int rv = 0;
if (dci.m_rv.size ()==1)
{
rv = dci.m_rv.at (0);
}
else
{
rv = (dci.m_rv.at (0) > dci.m_rv.at (1) ? dci.m_rv.at (0) : dci.m_rv.at (1));
}
if (rv == 3)
{
// maximum number of retx reached -> drop process
NS_LOG_DEBUG ("Max number of retransmissions reached -> drop process");
std::map <uint16_t, DlHarqProcessesStatus_t>::iterator it = m_dlHarqProcessesStatus.find (rnti);
if (it==m_dlHarqProcessesStatus.end ())
{
NS_FATAL_ERROR ("No info find in HARQ buffer for UE " << m_dlInfoListBuffered.at (i).m_rnti);
}
(*it).second.at (harqId) = 0;
std::map <uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu = m_dlHarqProcessesRlcPduListBuffer.find (rnti);
if (itRlcPdu==m_dlHarqProcessesRlcPduListBuffer.end ())
{
NS_FATAL_ERROR ("Unable to find RlcPdcList in HARQ buffer for RNTI " << m_dlInfoListBuffered.at (i).m_rnti);
}
for (uint16_t k = 0; k < (*itRlcPdu).second.size (); k++)
{
(*itRlcPdu).second.at (k).at (harqId).clear ();
}
continue;
}
// check the feasibility of retransmitting on the same RBGs
// translate the DCI to Spectrum framework
std::vector <int> dciRbg;
uint32_t mask = 0x1;
NS_LOG_DEBUG ("Original RBGs " << dci.m_rbBitmap << " rnti " << dci.m_rnti);
for (int j = 0; j < 32; j++)
{
if (((dci.m_rbBitmap & mask) >> j) == 1)
{
dciRbg.push_back (j);
NS_LOG_DEBUG ("\t"<<j);
// for (int k = 0; k < rbgSize; k++)
// {
// dciRb.push_back ((j * rbgSize) + k);
// //NS_LOG_DEBUG(this << "DL-DCI allocated PRB " << (i*GetRbgSize()) + k);
// }
}
mask = (mask << 1);
}
bool free = true;
for (uint8_t j = 0; j < dciRbg.size (); j++)
{
if (rbgMap.at (dciRbg.at (j))==true)
{
free = false;
break;
}
}
if (free)
{
// use the same RBGs for the retx
// reserve RBGs
for (uint8_t j = 0; j < dciRbg.size (); j++)
{
rbgMap.at (dciRbg.at (j)) = true;
NS_LOG_DEBUG ("RBG " << dciRbg.at (j) << " assigned");
rbgAllocatedNum++;
}
NS_LOG_DEBUG (this << " Send retx in the same RBGs");
}
else
{
// find RBGs for sending HARQ retx
uint8_t j = 0;
uint8_t rbgId = (dciRbg.at (dciRbg.size () - 1) + 1) % rbgNum;
uint8_t startRbg = dciRbg.at (dciRbg.size () - 1) + 1;
std::vector <bool> rbgMapCopy = rbgMap;
while ((j < dciRbg.size ())&&(startRbg!=rbgId))
{
if (rbgMapCopy.at (rbgId) == false)
{
rbgMapCopy.at (rbgId) = true;
dciRbg.at (j) = rbgId;
j++;
}
rbgId++;
}
if (j == dciRbg.size ())
{
// find new RBGs -> update DCI map
uint32_t rbgMask = 0;
for (uint16_t k = 0; k < dciRbg.size (); k++)
{
rbgMask = rbgMask + (0x1 << dciRbg.at (k));
// NS_LOG_DEBUG (this << " Allocated PRB " << (*itMap).second.at (k));
rbgAllocatedNum++;
}
dci.m_rbBitmap = rbgMask;
rbgMap = rbgMapCopy;
NS_LOG_DEBUG (this << " Move retx in RBGs " << dciRbg.size ());
}
else
{
// HARQ retx cannot be performed on this TTI -> store it
dlInfoListUntxed.push_back (params.m_dlInfoList.at (i));
NS_LOG_DEBUG (this << " No resource for this retx -> buffer it");
}
}
// retrieve RLC PDU list for retx TBsize and update DCI
BuildDataListElement_s newEl;
std::map <uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu = m_dlHarqProcessesRlcPduListBuffer.find (rnti);
if (itRlcPdu==m_dlHarqProcessesRlcPduListBuffer.end ())
{
NS_FATAL_ERROR ("Unable to find RlcPdcList in HARQ buffer for RNTI " << rnti);
}
for (uint8_t j = 0; j < nLayers; j++)
{
if (retx.at (j))
{
if (j >= dci.m_ndi.size ())
{
// for avoiding errors in MIMO transient phases
dci.m_ndi.push_back (0);
dci.m_rv.push_back (0);
dci.m_mcs.push_back (0);
dci.m_tbsSize.push_back (0);
NS_LOG_DEBUG (this << " layer " << (uint16_t)j << " no txed (MIMO transition)");
}
else
{
dci.m_ndi.at (j) = 0;
dci.m_rv.at (j) ++;
(*itHarq).second.at (harqId).m_rv.at (j)++;
NS_LOG_DEBUG (this << " layer " << (uint16_t)j << " RV " << (uint16_t)dci.m_rv.at (j));
newEl.m_rlcPduList.push_back ((*itRlcPdu).second.at (j).at (dci.m_harqProcess));
}
// NS_ASSERT_MSG ((*itRlcPdu).second.size () >dci.m_harqProcess, " size " << (*itRlcPdu).second.size ());
// NS_ASSERT ((*itRlcPdu).second.at (j).size () > dci.m_harqProcess);
// newEl.m_rlcPduList.push_back ((*itRlcPdu).second.at (j).at (dci.m_harqProcess));
// NS_LOG_DEBUG (this << " size 1 " << (*itRlcPdu).second.size () << " size 2 " << (*itRlcPdu).second.at (j).size ());
// NS_ASSERT_MSG ((*itRlcPdu).second.at (j).at (dci.m_harqProcess).size () <= 1, " MIMO ERRROR 1");
// for (uint16_t k = 0; k < (*itRlcPdu).second.at (j).at (dci.m_harqProcess).size (); k++)
// {
// NS_LOG_DEBUG (this << " k " << k);
// }
}
else
{
// empty TB of layer j
dci.m_ndi.at (j) = 0;
dci.m_rv.at (j) = 0;
dci.m_mcs.at (j) = 0;
dci.m_tbsSize.at (j) = 0;
NS_LOG_DEBUG (this << " layer " << (uint16_t)j << " no retx");
}
}
newEl.m_rnti = rnti;
newEl.m_dci = dci;
ret.m_buildDataList.push_back (newEl);
rntiAllocated.insert (rnti);
}
else
{
// update HARQ process status
NS_LOG_DEBUG (this << " RR HARQ ACK UE " << m_dlInfoListBuffered.at (i).m_rnti);
std::map <uint16_t, DlHarqProcessesStatus_t>::iterator it = m_dlHarqProcessesStatus.find (m_dlInfoListBuffered.at (i).m_rnti);
if (it==m_dlHarqProcessesStatus.end ())
{
NS_FATAL_ERROR ("No info find in HARQ buffer for UE " << m_dlInfoListBuffered.at (i).m_rnti);
}
(*it).second.at (m_dlInfoListBuffered.at (i).m_harqProcessId) = 0;
std::map <uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu = m_dlHarqProcessesRlcPduListBuffer.find (m_dlInfoListBuffered.at (i).m_rnti);
if (itRlcPdu==m_dlHarqProcessesRlcPduListBuffer.end ())
{
NS_FATAL_ERROR ("Unable to find RlcPdcList in HARQ buffer for RNTI " << m_dlInfoListBuffered.at (i).m_rnti);
}
for (uint16_t k = 0; k < (*itRlcPdu).second.size (); k++)
{
(*itRlcPdu).second.at (k).at (m_dlInfoListBuffered.at (i).m_harqProcessId).clear ();
}
}
}
m_dlInfoListBuffered.clear ();
m_dlInfoListBuffered = dlInfoListUntxed;
// Get the actual active flows (queue!=0)
std::list<FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it;
@@ -421,9 +738,11 @@ RrFfMacScheduler::DoSchedDlTriggerReq (const struct FfMacSchedSapProvider::Sched
{
// NS_LOG_INFO (this << " User " << (*it).m_rnti << " LC " << (uint16_t)(*it).m_logicalChannelIdentity);
// remove old entries of this UE-LC
if ( ((*it).m_rlcTransmissionQueueSize > 0)
std::set <uint16_t>::iterator itRnti = rntiAllocated.find ((*it).m_rnti);
if ( (((*it).m_rlcTransmissionQueueSize > 0)
|| ((*it).m_rlcRetransmissionQueueSize > 0)
|| ((*it).m_rlcStatusPduSize > 0) )
|| ((*it).m_rlcStatusPduSize > 0))
&& (itRnti == rntiAllocated.end ()) ) // UE must not be allocated for HARQ retx
{
std::map <uint16_t,uint8_t>::iterator itCqi = m_p10CqiRxed.find ((*it).m_rnti);
uint8_t cqi = 0;
@@ -456,23 +775,24 @@ RrFfMacScheduler::DoSchedDlTriggerReq (const struct FfMacSchedSapProvider::Sched
if (nflows == 0)
{
return;
if (ret.m_buildDataList.size ()>0)
{
m_schedSapUser->SchedDlConfigInd (ret);
}
return;
}
// Divide the resource equally among the active users according to
// Resource allocation type 0 (see sec 7.1.6.1 of 36.213)
int rbgSize = GetRbgSize (m_cschedCellConfig.m_dlBandwidth);
int rbgNum = m_cschedCellConfig.m_dlBandwidth / rbgSize;
int rbgPerTb = rbgNum / nTbs;
int rbgPerTb = (rbgNum - rbgAllocatedNum) / nTbs;
if (rbgPerTb == 0)
{
rbgPerTb = 1; // at least 1 rbg per TB (till available resource)
}
int rbgAllocated = 0;
FfMacSchedSapUser::SchedDlConfigIndParameters ret;
// round robin assignment to all UE-LC registered starting from the subsequent of the one
// served last scheduling trigger
//NS_LOG_DEBUG (this << " next to be served " << m_nextRntiDl << " nflows " << nflows);
// round robin assignment to all UEs registered starting from the subsequent of the one
// served last scheduling trigger event
if (m_nextRntiDl != 0)
{
for (it = m_rlcBufferReq.begin (); it != m_rlcBufferReq.end (); it++)
@@ -497,9 +817,10 @@ RrFfMacScheduler::DoSchedDlTriggerReq (const struct FfMacSchedSapProvider::Sched
do
{
itLcRnti = lcActivesPerRnti.find ((*it).m_rnti);
if (itLcRnti == lcActivesPerRnti.end ())
std::set <uint16_t>::iterator itRnti = rntiAllocated.find ((*it).m_rnti);
if ((itLcRnti == lcActivesPerRnti.end ())||(itRnti!=rntiAllocated.end ()))
{
// skip this entry
// skip this entry (no active queue or yet allocated for HARQ)
it++;
if (it == m_rlcBufferReq.end ())
{
@@ -514,6 +835,7 @@ RrFfMacScheduler::DoSchedDlTriggerReq (const struct FfMacSchedSapProvider::Sched
NS_FATAL_ERROR ("No Transmission Mode info on user " << (*it).m_rnti);
}
int nLayer = TransmissionModesLayers::TxMode2LayerNum ((*itTxMode).second);
NS_LOG_DEBUG (this << " NLAYERS " << nLayer);
int lcNum = (*itLcRnti).second;
// create new BuildDataListElement_s for this RNTI
BuildDataListElement_s newEl;
@@ -521,6 +843,26 @@ RrFfMacScheduler::DoSchedDlTriggerReq (const struct FfMacSchedSapProvider::Sched
// create the DlDciListElement_s
DlDciListElement_s newDci;
newDci.m_rnti = (*it).m_rnti;
if (m_harqOn == true)
{
newDci.m_harqProcess = UpdateHarqProcessId ((*it).m_rnti);
if (newDci.m_harqProcess>8)
{
// not valid HARQ ID -> no more HARQ proc available, stop allocation for this user
it++;
if (it == m_rlcBufferReq.end ())
{
// restart from the first
it = m_rlcBufferReq.begin ();
}
NS_LOG_DEBUG (this << " All HARQ process busy, drop UE allocation");
continue;
}
}
else
{
newDci.m_harqProcess = 0;
}
newDci.m_resAlloc = 0;
newDci.m_rbBitmap = 0;
std::map <uint16_t,uint8_t>::iterator itCqi = m_p10CqiRxed.find (newEl.m_rnti);
@@ -535,15 +877,11 @@ RrFfMacScheduler::DoSchedDlTriggerReq (const struct FfMacSchedSapProvider::Sched
newDci.m_mcs.push_back ( m_amc->GetMcsFromCqi ((*itCqi).second) );
}
}
// group the LCs of this RNTI
std::vector <struct RlcPduListElement_s> newRlcPduLe;
// int totRbg = lcNum * rbgPerFlow;
// totRbg = rbgNum / nTbs;
int tbSize = (m_amc->GetTbSizeFromMcs (newDci.m_mcs.at (0), rbgPerTb * rbgSize) / 8);
NS_LOG_DEBUG (this << " DL - Allocate user " << newEl.m_rnti << " LCs " << (uint16_t)(*itLcRnti).second << " bytes " << tbSize << " PRBs " << rbgAllocated * rbgSize << "..." << (rbgAllocated* rbgSize) + (rbgPerTb * rbgSize) - 1 << " mcs " << (uint16_t) newDci.m_mcs.at (0) << " layers " << nLayer);
uint16_t rlcPduSize = tbSize / lcNum;
for (int i = 0; i < lcNum ; i++)
{
std::vector <struct RlcPduListElement_s> newRlcPduLe;
for (uint8_t j = 0; j < nLayer; j++)
{
RlcPduListElement_s newRlcEl;
@@ -552,35 +890,61 @@ RrFfMacScheduler::DoSchedDlTriggerReq (const struct FfMacSchedSapProvider::Sched
newRlcEl.m_size = rlcPduSize;
UpdateDlRlcBufferInfo ((*it).m_rnti, newRlcEl.m_logicalChannelIdentity, rlcPduSize);
newRlcPduLe.push_back (newRlcEl);
// store RLC PDU list for HARQ
std::map <uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu = m_dlHarqProcessesRlcPduListBuffer.find ((*it).m_rnti);
if (itRlcPdu==m_dlHarqProcessesRlcPduListBuffer.end ())
{
NS_FATAL_ERROR ("Unable to find RlcPdcList in HARQ buffer for RNTI " << (*it).m_rnti);
}
// NS_ASSERT_MSG ((*itRlcPdu).second.at (j).at (newDci.m_harqProcess).size () <= 1, " MIMO ERR 4" <<(*itRlcPdu).second.at (j).at (newDci.m_harqProcess).size () );
(*itRlcPdu).second.at (j).at (newDci.m_harqProcess).push_back (newRlcEl);
// NS_ASSERT_MSG ((*itRlcPdu).second.at (j).at (newDci.m_harqProcess).size () <= 1, " MIMO ERR 3" <<(*itRlcPdu).second.at (j).at (newDci.m_harqProcess).size () );
}
it++;
if (it == m_rlcBufferReq.end ())
{
// restart from the first
it = m_rlcBufferReq.begin ();
}
newEl.m_rlcPduList.push_back (newRlcPduLe);
it++;
if (it == m_rlcBufferReq.end ())
{
// restart from the first
it = m_rlcBufferReq.begin ();
}
}
uint32_t rbgMask = 0;
for (int i = 0; i < rbgPerTb; i++)
uint16_t i = 0;
NS_LOG_DEBUG (this << " DL - Allocate user " << newEl.m_rnti << " LCs " << (uint16_t)(*itLcRnti).second << " bytes " << tbSize << " mcs " << (uint16_t) newDci.m_mcs.at (0) << " harqId " << (uint16_t)newDci.m_harqProcess << " layers " << nLayer);
NS_LOG_DEBUG ("RBG:");
while (i < rbgPerTb)
{
rbgMask = rbgMask + (0x1 << rbgAllocated);
rbgAllocated++;
if (rbgMap.at (rbgAllocated)==false)
{
rbgMask = rbgMask + (0x1 << rbgAllocated);
NS_LOG_DEBUG ("\t " << rbgAllocated);
i++;
rbgMap.at (rbgAllocated) = true;
}
rbgAllocated++;
}
newDci.m_rbBitmap = rbgMask; // (32 bit bitmap see 7.1.6 of 36.213)
for (int i = 0; i < nLayer; i++)
{
newDci.m_tbsSize.push_back (tbSize);
newDci.m_ndi.push_back (1); // TBD (new data indicator)
newDci.m_rv.push_back (0); // TBD (redundancy version)
newDci.m_ndi.push_back (1);
newDci.m_rv.push_back (0);
}
newEl.m_dci = newDci;
if (m_harqOn == true)
{
// store DCI for HARQ
std::map <uint16_t, DlHarqProcessesDciBuffer_t>::iterator itDci = m_dlHarqProcessesDciBuffer.find (newEl.m_rnti);
if (itDci==m_dlHarqProcessesDciBuffer.end ())
{
NS_FATAL_ERROR ("Unable to find RNTI entry in DCI HARQ buffer for RNTI " << (*it).m_rnti);
}
(*itDci).second.at (newDci.m_harqProcess) = newDci;
}
// ...more parameters -> ignored in this version
newEl.m_rlcPduList.push_back (newRlcPduLe);
ret.m_buildDataList.push_back (newEl);
if (rbgAllocated == rbgNum)
{
@@ -657,14 +1021,93 @@ RrFfMacScheduler::DoSchedUlTriggerReq (const struct FfMacSchedSapProvider::Sched
RefreshUlCqiMaps ();
// Generate RBs map
FfMacSchedSapUser::SchedUlConfigIndParameters ret;
std::vector <bool> rbMap;
uint16_t rbAllocatedNum = 0;
std::set <uint16_t> rntiAllocated;
std::vector <uint16_t> rbgAllocationMap;
rbgAllocationMap.resize (m_cschedCellConfig.m_ulBandwidth, 0);
rbMap.resize (m_cschedCellConfig.m_ulBandwidth, false);
// Process UL HARQ feedback
// update UL HARQ proc id
std::map <uint16_t, uint8_t>::iterator itProcId;
for (itProcId = m_ulHarqCurrentProcessId.begin (); itProcId!= m_ulHarqCurrentProcessId.end (); itProcId++)
{
(*itProcId).second = ((*itProcId).second + 1) % HARQ_PROC_NUM;
}
for (uint8_t i = 0; i < params.m_ulInfoList.size (); i++)
{
if (params.m_ulInfoList.at (i).m_receptionStatus==UlInfoListElement_s::NotOk)
{
// retx correspondent block: retrieve the UL-DCI
uint16_t rnti = params.m_ulInfoList.at (i).m_rnti;
uint8_t harqId = (uint8_t)((*itProcId).second - HARQ_PERIOD) % HARQ_PROC_NUM;
NS_LOG_DEBUG (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);
}
itProcId = m_ulHarqCurrentProcessId.find (rnti);
if (itProcId==m_ulHarqCurrentProcessId.end ())
{
NS_FATAL_ERROR ("No info find in HARQ buffer for UE " << 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);
}
if ((*itStat).second.at (harqId)>3)
{
NS_LOG_DEBUG ("Max number of retransmissions reached (UL)-> drop process");
continue;
}
bool free = true;
for (int j = dci.m_rbStart; j < dci.m_rbStart + dci.m_rbLen; j++)
{
if (rbMap.at (j)==true)
{
free = false;
NS_LOG_DEBUG (this << " BUSY " << j);
}
}
if (free)
{
// retx on the same RBs
for (int j = dci.m_rbStart; j < dci.m_rbStart + dci.m_rbLen; j++)
{
rbMap.at (j) = true;
rbgAllocationMap.at (j) = dci.m_rnti;
NS_LOG_DEBUG ("\t" << j);
rbAllocatedNum++;
}
NS_LOG_DEBUG (this << " Send retx in the same RBGs " << (uint16_t)dci.m_rbStart << " to " << dci.m_rbStart + dci.m_rbLen);
}
else
{
NS_FATAL_ERROR ("Cannot allocare retx for UE " << rnti);
}
dci.m_ndi = 0;
ret.m_dciList.push_back (dci);
rntiAllocated.insert (dci.m_rnti);
}
}
std::map <uint16_t,uint32_t>::iterator it;
int nflows = 0;
for (it = m_ceBsrRxed.begin (); it != m_ceBsrRxed.end (); it++)
{
// remove old entries of this UE-LC
if ((*it).second > 0)
std::set <uint16_t>::iterator itRnti = rntiAllocated.find ((*it).first);
// select UEs with queues not empty and not yet allocated for HARQ
if (((*it).second > 0)&&(itRnti == rntiAllocated.end ()))
{
nflows++;
}
@@ -676,16 +1119,15 @@ RrFfMacScheduler::DoSchedUlTriggerReq (const struct FfMacSchedSapProvider::Sched
}
// Divide the resource equally among the active users starting from the subsequent one served last scheduling trigger
int rbPerFlow = m_cschedCellConfig.m_ulBandwidth / nflows;
// Divide the remaining resources equally among the active users starting from the subsequent one served last scheduling trigger
//uint16_t rbPerFlow = (m_cschedCellConfig.m_ulBandwidth - rbAllocatedNum) / nflows;
uint16_t rbPerFlow = (m_cschedCellConfig.m_ulBandwidth) / (nflows + rntiAllocated.size ());
if (rbPerFlow == 0)
{
rbPerFlow = 1; // at least 1 rbg per flow (till available resource)
}
int rbAllocated = 0;
FfMacSchedSapUser::SchedUlConfigIndParameters ret;
std::vector <uint16_t> rbgAllocationMap;
uint16_t rbAllocated = 0;
if (m_nextRntiUl != 0)
{
for (it = m_ceBsrRxed.begin (); it != m_ceBsrRxed.end (); it++)
@@ -705,8 +1147,21 @@ RrFfMacScheduler::DoSchedUlTriggerReq (const struct FfMacSchedSapProvider::Sched
it = m_ceBsrRxed.begin ();
m_nextRntiUl = (*it).first;
}
NS_LOG_DEBUG (this << " rbPerFlow " << rbPerFlow);
do
{
std::set <uint16_t>::iterator itRnti = rntiAllocated.find ((*it).first);
if (itRnti!=rntiAllocated.end ())
{
// UE already allocated for UL-HARQ -> skip it
it++;
if (it == m_ceBsrRxed.end ())
{
// restart from the first
it = m_ceBsrRxed.begin ();
}
continue;
}
if (rbAllocated + rbPerFlow > m_cschedCellConfig.m_ulBandwidth)
{
// limit to physical resources last resource assignment
@@ -715,8 +1170,47 @@ RrFfMacScheduler::DoSchedUlTriggerReq (const struct FfMacSchedSapProvider::Sched
UlDciListElement_s uldci;
uldci.m_rnti = (*it).first;
uldci.m_rbStart = rbAllocated;
uldci.m_rbLen = rbPerFlow;
bool allocated = false;
while ((!allocated)&&(rbAllocated<m_cschedCellConfig.m_ulBandwidth))
{
// check availability
bool free = true;
for (uint16_t j = rbAllocated; j < rbAllocated + rbPerFlow; j++)
{
if (rbMap.at (j) == true)
{
free = false;
break;
}
}
if (free)
{
uldci.m_rbStart = rbAllocated;
for (uint16_t j = rbAllocated; j < rbAllocated + rbPerFlow; j++)
{
rbMap.at (j) = false;
// store info on allocation for managing ul-cqi interpretation
rbgAllocationMap.at (j) = (*it).first;
NS_LOG_DEBUG ("\t " << j);
}
rbAllocated += rbPerFlow;
allocated = true;
break;
}
rbAllocated++;
}
if (!allocated)
{
// unable to allocate new resource: finish scheduling
if (ret.m_dciList.size ()>0)
{
m_schedSapUser->SchedUlConfigInd (ret);
}
m_allocationMaps.insert (std::pair <uint16_t, std::vector <uint16_t> > (params.m_sfnSf, rbgAllocationMap));
return;
}
std::map <uint16_t, std::vector <double> >::iterator itCqi = m_ueCqi.find ((*it).first);
int cqi = 0;
if (itCqi == m_ueCqi.end ())
@@ -757,16 +1251,8 @@ RrFfMacScheduler::DoSchedUlTriggerReq (const struct FfMacSchedSapProvider::Sched
// NS_LOG_DEBUG (this << " UE " << (*it).first << " minsinr " << minSinr << " -> mcs " << (uint16_t)uldci.m_mcs);
}
rbAllocated += rbPerFlow;
// store info on allocation for managing ul-cqi interpretation
for (int i = 0; i < rbPerFlow; i++)
{
rbgAllocationMap.push_back ((*it).first);
}
uldci.m_tbSize = (m_amc->GetTbSizeFromMcs (uldci.m_mcs, rbPerFlow) / 8); // MCS 0 -> UL-AMC TBD
NS_LOG_DEBUG (this << " UL - UE " << (*it).first << " startPRB " << (uint32_t)uldci.m_rbStart << " nPRB " << (uint32_t)uldci.m_rbLen << " CQI " << cqi << " MCS " << (uint32_t)uldci.m_mcs << " TBsize " << uldci.m_tbSize);
UpdateUlRlcBufferInfo (uldci.m_rnti, uldci.m_tbSize);
uldci.m_ndi = 1;
uldci.m_cceIndex = 0;
@@ -781,6 +1267,21 @@ RrFfMacScheduler::DoSchedUlTriggerReq (const struct FfMacSchedSapProvider::Sched
uldci.m_freqHopping = 0;
uldci.m_pdcchPowerOffset = 0; // not used
ret.m_dciList.push_back (uldci);
// store DCI for HARQ_PERIOD
itProcId = m_ulHarqCurrentProcessId.find (uldci.m_rnti);
if (itProcId==m_ulHarqCurrentProcessId.end ())
{
NS_FATAL_ERROR ("No info find in HARQ buffer for UE " << uldci.m_rnti);
}
uint8_t harqId = (*itProcId).second;
std::map <uint16_t, UlHarqProcessesDciBuffer_t>::iterator itDci = m_ulHarqProcessesDciBuffer.find (uldci.m_rnti);
if (itDci==m_ulHarqProcessesDciBuffer.end ())
{
NS_FATAL_ERROR ("Unable to find RNTI entry in UL DCI HARQ buffer for RNTI " << uldci.m_rnti);
}
(*itDci).second.at (harqId) = uldci;
NS_LOG_DEBUG (this << " UL Allocation - UE " << (*it).first << " startPRB " << (uint32_t)uldci.m_rbStart << " nPRB " << (uint32_t)uldci.m_rbLen << " CQI " << cqi << " MCS " << (uint32_t)uldci.m_mcs << " TBsize " << uldci.m_tbSize << " harqId " << (uint16_t)harqId);
it++;
if (it == m_ceBsrRxed.end ())
{

View File

@@ -30,10 +30,21 @@
#include <ns3/lte-common.h>
#include <ns3/lte-amc.h>
#define HARQ_PROC_NUM 8
namespace ns3 {
typedef std::vector < uint8_t > DlHarqProcessesStatus_t;
typedef std::vector < DlDciListElement_s > DlHarqProcessesDciBuffer_t;
typedef std::vector < std::vector <struct RlcPduListElement_s> > RlcPduList_t; // vector of the LCs and layers per UE
typedef std::vector < RlcPduList_t > DlHarqRlcPduListBuffer_t; // vector of the 8 HARQ processes per UE
typedef std::vector < UlDciListElement_s > UlHarqProcessesDciBuffer_t;
typedef std::vector < uint8_t > UlHarqProcessesStatus_t;
/**
* \ingroup ff-api
@@ -129,6 +140,14 @@ private:
void UpdateDlRlcBufferInfo (uint16_t rnti, uint8_t lcid, uint16_t size);
void UpdateUlRlcBufferInfo (uint16_t rnti, uint16_t size);
/**
* \brief Update and return a new process Id for the RNTI specified
*
* \param rnti the RNTI of the UE to be updated
* \return the process id value
*/
uint8_t UpdateHarqProcessId (uint16_t rnti);
Ptr<LteAmc> m_amc;
@@ -185,6 +204,27 @@ private:
std::map <uint16_t,uint8_t> m_uesTxMode; // txMode of the UEs
// HARQ attributes
/**
* m_harqOn when false inhibit te HARQ mechanisms (by default active)
*/
bool m_harqOn;
std::map <uint16_t, uint8_t> m_dlHarqCurrentProcessId;
//HARQ status
// 0: process Id available
// x>0: process Id equal to `x` trasmission count
std::map <uint16_t, DlHarqProcessesStatus_t> m_dlHarqProcessesStatus;
std::map <uint16_t, DlHarqProcessesDciBuffer_t> m_dlHarqProcessesDciBuffer;
std::map <uint16_t, DlHarqRlcPduListBuffer_t> m_dlHarqProcessesRlcPduListBuffer;
std::vector <DlInfoListElement_s> m_dlInfoListBuffered; // HARQ retx buffered
std::map <uint16_t, uint8_t> m_ulHarqCurrentProcessId;
//HARQ status
// 0: process Id available
// x>0: process Id equal to `x` trasmission count
std::map <uint16_t, UlHarqProcessesStatus_t> m_ulHarqProcessesStatus;
std::map <uint16_t, UlHarqProcessesDciBuffer_t> m_ulHarqProcessesDciBuffer;
};
} // namespace ns3

View File

@@ -450,7 +450,7 @@ void
LteTestMac::SendTxOpportunity (Time time, uint32_t bytes)
{
NS_LOG_FUNCTION (this << time << bytes);
Simulator::Schedule (time, &LteMacSapUser::NotifyTxOpportunity, m_macSapUser, bytes, 0);
Simulator::Schedule (time, &LteMacSapUser::NotifyTxOpportunity, m_macSapUser, bytes, 0, 0);
if (m_txOpportunityMode == RANDOM_MODE)
{
if (m_txOppTime != Seconds (0))
@@ -572,17 +572,17 @@ LteTestMac::DoReportBufferStatus (LteMacSapProvider::ReportBufferStatusParameter
if (params.statusPduSize)
{
Simulator::Schedule (Seconds (0.1), &LteMacSapUser::NotifyTxOpportunity,
m_macSapUser, params.statusPduSize + 2, 0);
m_macSapUser, params.statusPduSize + 2, 0, 0);
}
else if (params.txQueueSize)
{
Simulator::Schedule (Seconds (0.1), &LteMacSapUser::NotifyTxOpportunity,
m_macSapUser, params.txQueueSize + 2, 0);
m_macSapUser, params.txQueueSize + 2, 0, 0);
}
else if (params.retxQueueSize)
{
Simulator::Schedule (Seconds (0.1), &LteMacSapUser::NotifyTxOpportunity,
m_macSapUser, params.retxQueueSize + 2, 0);
m_macSapUser, params.retxQueueSize + 2, 0, 0);
}
}
}

View File

@@ -83,15 +83,15 @@ LenaTestMimoSuite::LenaTestMimoSuite ()
static LenaTestMimoSuite lenaTestMimoSuite;
std::string
LenaMimoTestCase::BuildNameString (uint16_t dist)
LenaMimoTestCase::BuildNameString (uint16_t dist, std::string schedulerType)
{
std::ostringstream oss;
oss << " UE distance " << dist << " m";
oss << " UE distance " << dist << " m" << " Scheduler " << schedulerType;
return oss.str ();
}
LenaMimoTestCase::LenaMimoTestCase (uint16_t dist, std::vector<uint32_t> estThrDl, std::string schedulerType)
: TestCase (BuildNameString (dist)),
: TestCase (BuildNameString (dist, schedulerType)),
m_dist (dist),
m_estThrDl (estThrDl),
m_schedulerType (schedulerType)
@@ -105,7 +105,7 @@ LenaMimoTestCase::~LenaMimoTestCase ()
void
LenaMimoTestCase::DoRun (void)
{
// Config::SetDefault ("ns3::LteSpectrumPhy::PemEnabled", BooleanValue (false));
Config::SetDefault ("ns3::LteSpectrumPhy::DataErrorModelEnabled", BooleanValue (false));
Config::SetDefault ("ns3::LteAmc::AmcModel", EnumValue (LteAmc::PiroEW2010));
@@ -115,6 +115,10 @@ LenaMimoTestCase::DoRun (void)
Ptr<LteHelper> lteHelper = CreateObject<LteHelper> ();
Config::SetDefault ("ns3::RrFfMacScheduler::HarqEnabled", BooleanValue (false));
Config::SetDefault ("ns3::PfFfMacScheduler::HarqEnabled", BooleanValue (false));
// lteHelper->SetSchedulerAttribute ("HarqEnabled", BooleanValue (false));
lteHelper->SetAttribute ("PathlossModel", StringValue ("ns3::HybridBuildingsPropagationLossModel"));
@@ -122,7 +126,7 @@ LenaMimoTestCase::DoRun (void)
lteHelper->SetPathlossModelAttribute ("ShadowSigmaIndoor", DoubleValue (0.0));
lteHelper->SetPathlossModelAttribute ("ShadowSigmaExtWalls", DoubleValue (0.0));
// lteHelper->EnableLogComponents ();
lteHelper->EnableLogComponents ();
// Create Nodes: eNodeB and UE
NodeContainer enbNodes;
@@ -188,7 +192,6 @@ LenaMimoTestCase::DoRun (void)
{
NS_FATAL_ERROR ("No RR Scheduler available");
}
Simulator::Schedule (Seconds (0.2), &RrFfMacScheduler::TransmissionModeConfigurationUpdate, rrsched, rnti, 1);
Simulator::Schedule (Seconds (0.3), &RrFfMacScheduler::TransmissionModeConfigurationUpdate, rrsched, rnti, 2);
}

View File

@@ -42,7 +42,7 @@ private:
void GetRlcBufferSample (Ptr<RadioBearerStatsCalculator> rlcStats, uint64_t imsi, uint8_t rnti);
static std::string BuildNameString (uint16_t dist);
static std::string BuildNameString (uint16_t dist, std::string schedulerType);
uint16_t m_nUser;
uint16_t m_nLc;
uint16_t m_dist;

View File

@@ -213,7 +213,7 @@ LenaPfFfMacSchedulerTestCase1::DoRun (void)
Config::SetDefault ("ns3::LteSpectrumPhy::DataErrorModelEnabled", BooleanValue (false)); LogComponentDisableAll (LOG_LEVEL_ALL);
// LogComponentEnable ("LteEnbRrc", LOG_LEVEL_ALL);
// LogComponentEnable ("LteUeRrc", LOG_LEVEL_ALL);
// LogComponentEnable ("LteEnbMac", LOG_LEVEL_ALL);
// LogComponentEnable ("LteEnbMac", LOG_LEVEL_ALL);
// LogComponentEnable ("LteUeMac", LOG_LEVEL_ALL);
// LogComponentEnable ("LteRlc", LOG_LEVEL_ALL);
//

View File

@@ -122,7 +122,8 @@ LenaDataPhyErrorModelTestCase::DoRun (void)
Config::SetDefault ("ns3::LteAmc::Ber", DoubleValue (ber));
Config::SetDefault ("ns3::LteAmc::AmcModel", EnumValue (LteAmc::PiroEW2010));
Config::SetDefault ("ns3::LteSpectrumPhy::CtrlErrorModelEnabled", BooleanValue (false));
Config::SetDefault ("ns3::LteSpectrumPhy::DataErrorModelEnabled", BooleanValue (true));
Config::SetDefault ("ns3::LteSpectrumPhy::DataErrorModelEnabled", BooleanValue (true));
Config::SetDefault ("ns3::RrFfMacScheduler::HarqEnabled", BooleanValue (false));
// LogComponentEnable ("LteEnbRrc", LOG_LEVEL_ALL);
// LogComponentEnable ("LteUeRrc", LOG_LEVEL_ALL);
// LogComponentEnable ("LteEnbMac", LOG_LEVEL_ALL);
@@ -163,7 +164,7 @@ LenaDataPhyErrorModelTestCase::DoRun (void)
// LogComponentEnable ("LteMiErrorModel", LOG_LEVEL_ALL);
// LogComponentEnable ("LteAmc", LOG_LEVEL_ALL);
//
LogComponentDisableAll (LOG_LEVEL_ALL);
// LogComponentDisableAll (LOG_LEVEL_ALL);
LogComponentEnable ("LenaTestPhyErrorModel", LOG_LEVEL_ALL);
@@ -306,7 +307,8 @@ LenaDlCtrlPhyErrorModelTestCase::DoRun (void)
Config::SetDefault ("ns3::LteAmc::Ber", DoubleValue (ber));
Config::SetDefault ("ns3::LteAmc::AmcModel", EnumValue (LteAmc::PiroEW2010));
Config::SetDefault ("ns3::LteSpectrumPhy::CtrlErrorModelEnabled", BooleanValue (true));
Config::SetDefault ("ns3::LteSpectrumPhy::DataErrorModelEnabled", BooleanValue (false));
Config::SetDefault ("ns3::LteSpectrumPhy::DataErrorModelEnabled", BooleanValue (false));
Config::SetDefault ("ns3::RrFfMacScheduler::HarqEnabled", BooleanValue (false));
// LogComponentEnable ("LteEnbRrc", LOG_LEVEL_ALL);
// LogComponentEnable ("LteUeRrc", LOG_LEVEL_ALL);
// LogComponentEnable ("LteEnbMac", LOG_LEVEL_ALL);
@@ -341,13 +343,13 @@ LenaDlCtrlPhyErrorModelTestCase::DoRun (void)
// LogComponentEnable ("LteEnbMac", LOG_LEVEL_ALL);
// LogComponentEnable ("LteEnbPhy", LOG_LEVEL_ALL);
// LogComponentEnable ("LteUePhy", LOG_LEVEL_ALL);
// LogComponentEnable ("RrFfMacScheduler", LOG_LEVEL_ALL);
// LogComponentEnable ("RrFfMacScheduler", LOG_LEVEL_ALL);
// LogComponentEnable ("LenaHelper", LOG_LEVEL_ALL);
// LogComponentEnable ("BuildingsPropagationLossModel", LOG_LEVEL_ALL);
// LogComponentEnable ("LteMiErrorModel", LOG_LEVEL_ALL);
// LogComponentEnable ("LteAmc", LOG_LEVEL_ALL);
//
LogComponentDisableAll (LOG_LEVEL_ALL);
// LogComponentDisableAll (LOG_LEVEL_ALL);
LogComponentEnable ("LenaTestPhyErrorModel", LOG_LEVEL_ALL);

View File

@@ -74,6 +74,7 @@ def build(bld):
'model/epc-enb-s1-sap.cc',
'model/lte-as-sap.cc',
'model/epc-ue-nas.cc',
'model/lte-harq-phy.cc',
]
module_test = bld.create_ns3_module_test_library('lte')
@@ -181,6 +182,7 @@ def build(bld):
'model/epc-enb-s1-sap.h',
'model/lte-as-sap.h',
'model/epc-ue-nas.h',
'model/lte-harq-phy.h',
]
if (bld.env['ENABLE_EXAMPLES']):